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
}
|