File: ip.go

package info (click to toggle)
golang-github-containers-common 0.64.1%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 5,932 kB
  • sloc: makefile: 132; sh: 111
file content (125 lines) | stat: -rw-r--r-- 4,378 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package etchosts

import (
	"net"
	"sync"

	"github.com/containers/common/libnetwork/types"
	"github.com/containers/common/libnetwork/util"
	"github.com/containers/common/pkg/config"
	"github.com/containers/common/pkg/machine"
	"github.com/containers/storage/pkg/unshare"
	"github.com/sirupsen/logrus"
)

// HostContainersInternalOptions contains the options for GetHostContainersInternalIP()
type HostContainersInternalOptions struct {
	// Conf is the containers.Conf, must not be nil
	Conf *config.Config
	// NetStatus is the network status for the container,
	// if this is set networkInterface must not be nil
	NetStatus map[string]types.StatusBlock
	// NetworkInterface of the current runtime
	NetworkInterface types.ContainerNetwork
	// Exclude are then ips that should not be returned, this is
	// useful to prevent returning the same ip as in the container.
	Exclude []net.IP
	// PreferIP is a ip that should be used if set but it has a
	// lower priority than the containers.conf config option.
	// This is used for the pasta --map-guest-addr ip.
	PreferIP string
}

// Lookup "host.containers.internal" dns name so we can add it to /etc/hosts when running inside podman machine.
var machineHostContainersInternalIP = sync.OnceValue(func() string {
	var errMsg string
	addrs, err := net.LookupIP(HostContainersInternal)
	if err == nil {
		if len(addrs) > 0 {
			return addrs[0].String()
		}
		errMsg = "lookup result is empty"
	} else {
		errMsg = err.Error()
	}
	logrus.Warnf("Failed to resolve %s for the host entry ip address: %s", HostContainersInternal, errMsg)
	return ""
})

// GetHostContainersInternalIP returns the host.containers.internal ip
func GetHostContainersInternalIP(opts HostContainersInternalOptions) string {
	switch opts.Conf.Containers.HostContainersInternalIP {
	case "":
		// If empty (default) we will automatically choose one below.
		// If machine using gvproxy we let the gvproxy dns server handle resolve the name and then use that ip.
		if machine.IsGvProxyBased() {
			return machineHostContainersInternalIP()
		}
	case "none":
		return ""
	default:
		return opts.Conf.Containers.HostContainersInternalIP
	}

	// caller has a specific ip it prefers
	if opts.PreferIP != "" {
		return opts.PreferIP
	}

	ip := ""
	// Only use the bridge ip when root, as rootless the interfaces are created
	// inside the special netns and not the host so we cannot use them.
	if unshare.IsRootless() {
		return util.GetLocalIPExcluding(opts.Exclude)
	}
	for net, status := range opts.NetStatus {
		network, err := opts.NetworkInterface.NetworkInspect(net)
		// only add the host entry for bridge networks
		// ip/macvlan gateway is normally not on the host
		if err != nil || network.Driver != types.BridgeNetworkDriver {
			continue
		}
		for _, netInt := range status.Interfaces {
			for _, netAddress := range netInt.Subnets {
				if netAddress.Gateway != nil {
					if util.IsIPv4(netAddress.Gateway) {
						return netAddress.Gateway.String()
					}
					// ipv6 address but keep looking since we prefer to use ipv4
					ip = netAddress.Gateway.String()
				}
			}
		}
	}
	if ip != "" {
		return ip
	}
	return util.GetLocalIPExcluding(opts.Exclude)
}

// GetHostContainersInternalIPExcluding returns the host.containers.internal ip
// Exclude are ips that should not be returned, this is useful to prevent returning the same ip as in the container.
// if netStatus is not nil then networkInterface also must be non nil otherwise this function panics
func GetHostContainersInternalIPExcluding(conf *config.Config, netStatus map[string]types.StatusBlock, networkInterface types.ContainerNetwork, exclude []net.IP) string {
	return GetHostContainersInternalIP(HostContainersInternalOptions{
		Conf:             conf,
		NetStatus:        netStatus,
		NetworkInterface: networkInterface,
		Exclude:          exclude,
	})
}

// GetNetworkHostEntries returns HostEntries for all ips in the network status
// with the given hostnames.
func GetNetworkHostEntries(netStatus map[string]types.StatusBlock, names ...string) HostEntries {
	hostEntries := make(HostEntries, 0, len(netStatus))
	for _, status := range netStatus {
		for _, netInt := range status.Interfaces {
			for _, netAddress := range netInt.Subnets {
				e := HostEntry{IP: netAddress.IPNet.IP.String(), Names: names}
				hostEntries = append(hostEntries, e)
			}
		}
	}
	return hostEntries
}