func allocateDaemonPort(addr string) error { host, port, err := net.SplitHostPort(addr) if err != nil { return err } intPort, err := strconv.Atoi(port) if err != nil { return err } var hostIPs []net.IP if parsedIP := net.ParseIP(host); parsedIP != nil { hostIPs = append(hostIPs, parsedIP) } else if hostIPs, err = net.LookupIP(host); err != nil { return fmt.Errorf("failed to lookup %s address in host specification", host) } for _, hostIP := range hostIPs { if _, err := portallocator.RequestPort(hostIP, "tcp", intPort); err != nil { return fmt.Errorf("failed to allocate daemon listening port %d (err: %v)", intPort, err) } } return nil }
func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err error) { lock.Lock() defer lock.Unlock() var ( m *mapping proto string allocatedHostPort int ) switch container.(type) { case *net.TCPAddr: proto = "tcp" if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { return nil, err } m = &mapping{ proto: proto, host: &net.TCPAddr{IP: hostIP, Port: allocatedHostPort}, container: container, } case *net.UDPAddr: proto = "udp" if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { return nil, err } m = &mapping{ proto: proto, host: &net.UDPAddr{IP: hostIP, Port: allocatedHostPort}, container: container, } default: return nil, ErrUnknownBackendAddressType } // release the allocated port on any further error during return. defer func() { if err != nil { portallocator.ReleasePort(hostIP, proto, allocatedHostPort) } }() key := getKey(m.host) if _, exists := currentMappings[key]; exists { return nil, ErrPortMappedForIP } containerIP, containerPort := getIPAndPort(m.container) if err := forward(iptables.Add, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil { return nil, err } p, err := newProxy(m.host, m.container) if err != nil { // need to undo the iptables rules before we return forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) return nil, err } m.userlandProxy = p currentMappings[key] = m go p.Run() return m.host, nil }
func Map(container net.Addr, hostIP net.IP, hostPort int) (host net.Addr, err error) { lock.Lock() defer lock.Unlock() var ( m *mapping proto string allocatedHostPort int proxy UserlandProxy ) switch container.(type) { case *net.TCPAddr: proto = "tcp" if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { return nil, err } m = &mapping{ proto: proto, host: &net.TCPAddr{IP: hostIP, Port: allocatedHostPort}, container: container, } proxy = NewProxy(proto, hostIP, allocatedHostPort, container.(*net.TCPAddr).IP, container.(*net.TCPAddr).Port) case *net.UDPAddr: proto = "udp" if allocatedHostPort, err = portallocator.RequestPort(hostIP, proto, hostPort); err != nil { return nil, err } m = &mapping{ proto: proto, host: &net.UDPAddr{IP: hostIP, Port: allocatedHostPort}, container: container, } proxy = NewProxy(proto, hostIP, allocatedHostPort, container.(*net.UDPAddr).IP, container.(*net.UDPAddr).Port) default: return nil, ErrUnknownBackendAddressType } // release the allocated port on any further error during return. defer func() { if err != nil { portallocator.ReleasePort(hostIP, proto, allocatedHostPort) } }() key := getKey(m.host) if _, exists := currentMappings[key]; exists { return nil, ErrPortMappedForIP } containerIP, containerPort := getIPAndPort(m.container) if err := forward(iptables.Append, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort); err != nil { return nil, err } cleanup := func() error { // need to undo the iptables rules before we return proxy.Stop() forward(iptables.Delete, m.proto, hostIP, allocatedHostPort, containerIP.String(), containerPort) if err := portallocator.ReleasePort(hostIP, m.proto, allocatedHostPort); err != nil { return err } return nil } if err := proxy.Start(); err != nil { if err := cleanup(); err != nil { return nil, fmt.Errorf("Error during port allocation cleanup: %v", err) } return nil, err } m.userlandProxy = proxy currentMappings[key] = m return m.host, nil }