func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) { defer func() { proxy.connTrackLock.Lock() delete(proxy.connTrackTable, *clientKey) proxy.connTrackLock.Unlock() utils.Debugf("Done proxying between udp/%v and udp/%v", clientAddr.String(), proxy.backendAddr.String()) proxyConn.Close() }() readBuf := make([]byte, UDPBufSize) for { proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout)) again: read, err := proxyConn.Read(readBuf) if err != nil { if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED { // This will happen if the last write failed // (e.g: nothing is actually listening on the // proxied port on the container), ignore it // and continue until UDPConnTrackTimeout // expires: goto again } return } for i := 0; i != read; { written, err := proxy.listener.WriteToUDP(readBuf[i:read], clientAddr) if err != nil { return } i += written utils.Debugf("Forwarded %v/%v bytes to udp/%v", i, read, clientAddr.String()) } } }
// CreateBridgeIface creates a network bridge interface on the host system with the name `ifaceName`, // and attempts to configure it with an address which doesn't conflict with any other interface on the host. // If it can't find an address which doesn't conflict, it will return an error. func CreateBridgeIface(ifaceName string) error { addrs := []string{ // Here we don't follow the convention of using the 1st IP of the range for the gateway. // This is to use the same gateway IPs as the /24 ranges, which predate the /16 ranges. // In theory this shouldn't matter - in practice there's bound to be a few scripts relying // on the internal addressing or other stupid things like that. // The shouldn't, but hey, let's not break them unless we really have to. "172.17.42.1/16", // Don't use 172.16.0.0/16, it conflicts with EC2 DNS 172.16.0.23 "10.0.42.1/16", // Don't even try using the entire /8, that's too intrusive "10.1.42.1/16", "10.42.42.1/16", "172.16.42.1/24", "172.16.43.1/24", "172.16.44.1/24", "10.0.42.1/24", "10.0.43.1/24", "192.168.42.1/24", "192.168.43.1/24", "192.168.44.1/24", } var ifaceAddr string for _, addr := range addrs { _, dockerNetwork, err := net.ParseCIDR(addr) if err != nil { return err } routes, err := ip("route") if err != nil { return err } if err := checkRouteOverlaps(routes, dockerNetwork); err == nil { ifaceAddr = addr break } else { utils.Debugf("%s: %s", addr, err) } } if ifaceAddr == "" { return fmt.Errorf("Could not find a free IP address range for interface '%s'. Please configure its address manually and run 'docker -b %s'", ifaceName, ifaceName) } utils.Debugf("Creating bridge %s with network %s", ifaceName, ifaceAddr) if output, err := ip("link", "add", ifaceName, "type", "bridge"); err != nil { return fmt.Errorf("Error creating bridge: %s (output: %s)", err, output) } if output, err := ip("addr", "add", ifaceAddr, "dev", ifaceName); err != nil { return fmt.Errorf("Unable to add private network: %s (%s)", err, output) } if output, err := ip("link", "set", ifaceName, "up"); err != nil { return fmt.Errorf("Unable to start network bridge: %s (%s)", err, output) } if err := iptables("-t", "nat", "-A", "POSTROUTING", "-s", ifaceAddr, "!", "-d", ifaceAddr, "-j", "MASQUERADE"); err != nil { return fmt.Errorf("Unable to enable network bridge NAT: %s", err) } return nil }
func (proxy *TCPProxy) Run() { quit := make(chan bool) defer close(quit) utils.Debugf("Starting proxy on tcp/%v for tcp/%v", proxy.frontendAddr, proxy.backendAddr) for { client, err := proxy.listener.Accept() if err != nil { utils.Debugf("Stopping proxy on tcp/%v for tcp/%v (%v)", proxy.frontendAddr, proxy.backendAddr, err.Error()) return } go proxy.clientLoop(client.(*net.TCPConn), quit) } }
func Unmount(target string) error { _, err := os.Stat(target) if err != nil { return err } if err := exec.Command("auplink", target, "flush").Run(); err != nil { utils.Debugf("[warning]: couldn't run auplink before unmount: %s", err) } if err := syscall.Unmount(target, 0); err != nil { return err } // Even though we just unmounted the filesystem, AUFS will prevent deleting the mntpoint // for some time. We'll just keep retrying until it succeeds. for retries := 0; retries < 1000; retries++ { err := os.Remove(target) if err == nil { // rm mntpoint succeeded return nil } if os.IsNotExist(err) { // mntpoint doesn't exist anymore. Success. return nil } // fmt.Printf("(%v) Remove %v returned: %v\n", retries, target, err) time.Sleep(10 * time.Millisecond) } return fmt.Errorf("Umount: Failed to umount %v", target) }
func checkRouteOverlaps(routes string, dockerNetwork *net.IPNet) error { utils.Debugf("Routes:\n\n%s", routes) for _, line := range strings.Split(routes, "\n") { if strings.Trim(line, "\r\n\t ") == "" || strings.Contains(line, "default") { continue } _, network, err := net.ParseCIDR(strings.Split(line, " ")[0]) if err != nil { // is this a mask-less IP address? if ip := net.ParseIP(strings.Split(line, " ")[0]); ip == nil { // fail only if it's neither a network nor a mask-less IP address return fmt.Errorf("Unexpected ip route output: %s (%s)", err, line) } else { _, network, err = net.ParseCIDR(ip.String() + "/32") if err != nil { return err } } } if err == nil && network != nil { if networkOverlaps(dockerNetwork, network) { return fmt.Errorf("Network %s is already routed: '%s'", dockerNetwork, line) } } } return nil }
func (b *buildFile) addContext(container *env.Container, orig, dest string) error { origPath := path.Join(b.context, orig) destPath := path.Join(container.RootfsPath(), dest) // Preserve the trailing '/' if strings.HasSuffix(dest, "/") { destPath = destPath + "/" } fi, err := os.Stat(origPath) if err != nil { return err } if fi.IsDir() { if err := utils.CopyWithTar(origPath, destPath); err != nil { return err } // First try to unpack the source as an archive } else if err := utils.UntarPath(origPath, destPath); err != nil { utils.Debugf("Couldn't untar %s to %s: %s", origPath, destPath, err) // If that fails, just copy it as a regular file if err := os.MkdirAll(path.Dir(destPath), 0755); err != nil { return err } if err := utils.CopyWithTar(origPath, destPath); err != nil { return err } } return nil }
func (proxy *TCPProxy) clientLoop(client *net.TCPConn, quit chan bool) { backend, err := net.DialTCP("tcp", nil, proxy.backendAddr) if err != nil { log.Printf("Can't forward traffic to backend tcp/%v: %v\n", proxy.backendAddr, err.Error()) client.Close() return } event := make(chan int64) var broker = func(to, from *net.TCPConn) { written, err := io.Copy(to, from) if err != nil { err, ok := err.(*net.OpError) // If the socket we are writing to is shutdown with // SHUT_WR, forward it to the other end of the pipe: if ok && err.Err == syscall.EPIPE { from.CloseWrite() } } to.CloseRead() event <- written } utils.Debugf("Forwarding traffic between tcp/%v and tcp/%v", client.RemoteAddr(), backend.RemoteAddr()) go broker(client, backend) go broker(backend, client) var transferred int64 = 0 for i := 0; i < 2; i++ { select { case written := <-event: transferred += written case <-quit: // Interrupt the two brokers and "join" them. client.Close() backend.Close() for ; i < 2; i++ { transferred += <-event } goto done } } client.Close() backend.Close() done: utils.Debugf("%v bytes transferred between tcp/%v and tcp/%v", transferred, client.RemoteAddr(), backend.RemoteAddr()) }
func (b *buildFile) CmdCmd(args string) error { var cmd []string if err := json.Unmarshal([]byte(args), &cmd); err != nil { utils.Debugf("Error unmarshalling: %s, setting cmd to /bin/sh -c", err) cmd = []string{"/bin/sh", "-c", args} } b.config.Cmd = cmd return nil }
func (proxy *UDPProxy) Run() { readBuf := make([]byte, UDPBufSize) utils.Debugf("Starting proxy on udp/%v for udp/%v", proxy.frontendAddr, proxy.backendAddr) for { read, from, err := proxy.listener.ReadFromUDP(readBuf) if err != nil { // NOTE: Apparently ReadFrom doesn't return // ECONNREFUSED like Read do (see comment in // UDPProxy.replyLoop) utils.Debugf("Stopping proxy on udp/%v for udp/%v (%v)", proxy.frontendAddr, proxy.backendAddr, err.Error()) break } fromKey := newConnTrackKey(from) proxy.connTrackLock.Lock() proxyConn, hit := proxy.connTrackTable[*fromKey] if !hit { proxyConn, err = net.DialUDP("udp", nil, proxy.backendAddr) if err != nil { log.Printf("Can't proxy a datagram to udp/%s: %v\n", proxy.backendAddr.String(), err) continue } proxy.connTrackTable[*fromKey] = proxyConn go proxy.replyLoop(proxyConn, from, fromKey) } proxy.connTrackLock.Unlock() for i := 0; i != read; { written, err := proxyConn.Write(readBuf[i:read]) if err != nil { log.Printf("Can't proxy a datagram to udp/%s: %v\n", proxy.backendAddr.String(), err) break } i += written utils.Debugf("Forwarded %v/%v bytes to udp/%v", i, read, proxy.backendAddr.String()) } } }
// Release: Network cleanup - release all resources func (iface *NetworkInterface) Release() { if iface.disabled { return } for _, nat := range iface.extPorts { utils.Debugf("Unmaping %v/%v", nat.Proto, nat.Frontend) if err := iface.manager.portMapper.Unmap(nat.Frontend, nat.Proto); err != nil { log.Printf("Unable to unmap port %v/%v: %v", nat.Proto, nat.Frontend, err) } if nat.Proto == "tcp" { if err := iface.manager.ipAllocator.ReleaseTCPPort(nat.Frontend); err != nil { log.Printf("Unable to release port tcp/%v: %v", nat.Frontend, err) } } else if err := iface.manager.ipAllocator.ReleaseUDPPort(nat.Frontend); err != nil { log.Printf("Unable to release port udp/%v: %v", nat.Frontend, err) } } iface.manager.ipAllocator.Release(iface.IPNet.IP) }