func Unmap(host net.Addr) error { lock.Lock() defer lock.Unlock() key := getKey(host) data, exists := currentMappings[key] if !exists { return ErrPortNotMapped } data.userlandProxy.Close() delete(currentMappings, key) containerIP, containerPort := getIPAndPort(data.container) hostIP, hostPort := getIPAndPort(data.host) if err := forward(iptables.Delete, data.proto, hostIP, hostPort, containerIP.String(), containerPort); err != nil { return err } switch a := host.(type) { case *net.TCPAddr: if err := portallocator.ReleasePort(a.IP, "tcp", a.Port); err != nil { return err } case *net.UDPAddr: if err := portallocator.ReleasePort(a.IP, "udp", a.Port); err != nil { return err } } return nil }
// Allocate an external port and map it to the interface func AllocatePort(job *engine.Job) engine.Status { var ( err error ip = defaultBindingIP id = job.Args[0] hostIP = job.Getenv("HostIP") hostPort = job.GetenvInt("HostPort") containerPort = job.GetenvInt("ContainerPort") proto = job.Getenv("Proto") network = currentInterfaces[id] ) if hostIP != "" { ip = net.ParseIP(hostIP) } // host ip, proto, and host port hostPort, err = portallocator.RequestPort(ip, proto, hostPort) if err != nil { return job.Error(err) } var ( container net.Addr host net.Addr ) if proto == "tcp" { host = &net.TCPAddr{IP: ip, Port: hostPort} container = &net.TCPAddr{IP: network.IP, Port: containerPort} } else { host = &net.UDPAddr{IP: ip, Port: hostPort} container = &net.UDPAddr{IP: network.IP, Port: containerPort} } if err := portmapper.Map(container, ip, hostPort); err != nil { portallocator.ReleasePort(ip, proto, hostPort) return job.Error(err) } network.PortMappings = append(network.PortMappings, host) out := engine.Env{} out.Set("HostIP", ip.String()) out.SetInt("HostPort", hostPort) if _, err := out.WriteTo(job.Stdout); err != nil { return job.Error(err) } return engine.StatusOK }
// release an interface for a select ip func Release(job *engine.Job) engine.Status { var ( id = job.Args[0] containerInterface = currentInterfaces.Get(id) ip net.IP port int proto string ) if containerInterface == nil { return job.Errorf("No network information to release for %s", id) } for _, nat := range containerInterface.PortMappings { if err := portmapper.Unmap(nat); err != nil { log.Printf("Unable to unmap port %s: %s", nat, err) } // this is host mappings switch a := nat.(type) { case *net.TCPAddr: proto = "tcp" ip = a.IP port = a.Port case *net.UDPAddr: proto = "udp" ip = a.IP port = a.Port } if err := portallocator.ReleasePort(ip, proto, port); err != nil { log.Printf("Unable to release port %s", nat) } } if err := ipallocator.ReleaseIP(bridgeNetwork, &containerInterface.IP); err != nil { log.Printf("Unable to release ip %s\n", err) } return engine.StatusOK }
func Map(container net.Addr, hostIP net.IP, hostPort int) (net.Addr, error) { lock.Lock() defer lock.Unlock() var ( m *mapping err error proto string allocatedHostPort int ) // release the port on any error during return. defer func() { if err != nil { portallocator.ReleasePort(hostIP, proto, allocatedHostPort) } }() 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: err = ErrUnknownBackendAddressType return nil, err } key := getKey(m.host) if _, exists := currentMappings[key]; exists { err = ErrPortMappedForIP return nil, err } 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 }