github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/libnetwork/portmapper/proxy.go (about) 1 package portmapper 2 3 import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "net" 8 "os" 9 "os/exec" 10 "time" 11 ) 12 13 const userlandProxyCommandName = "docker-proxy" 14 15 type userlandProxy interface { 16 Start() error 17 Stop() error 18 } 19 20 // proxyCommand wraps an exec.Cmd to run the userland TCP and UDP 21 // proxies as separate processes. 22 type proxyCommand struct { 23 cmd *exec.Cmd 24 } 25 26 func (p *proxyCommand) Start() error { 27 r, w, err := os.Pipe() 28 if err != nil { 29 return fmt.Errorf("proxy unable to open os.Pipe %s", err) 30 } 31 defer r.Close() 32 p.cmd.ExtraFiles = []*os.File{w} 33 if err := p.cmd.Start(); err != nil { 34 return err 35 } 36 w.Close() 37 38 errchan := make(chan error, 1) 39 go func() { 40 buf := make([]byte, 2) 41 r.Read(buf) 42 43 if string(buf) != "0\n" { 44 errStr, err := ioutil.ReadAll(r) 45 if err != nil { 46 errchan <- fmt.Errorf("Error reading exit status from userland proxy: %v", err) 47 return 48 } 49 50 errchan <- fmt.Errorf("Error starting userland proxy: %s", errStr) 51 return 52 } 53 errchan <- nil 54 }() 55 56 select { 57 case err := <-errchan: 58 return err 59 case <-time.After(16 * time.Second): 60 return fmt.Errorf("Timed out proxy starting the userland proxy") 61 } 62 } 63 64 func (p *proxyCommand) Stop() error { 65 if p.cmd.Process != nil { 66 if err := p.cmd.Process.Signal(os.Interrupt); err != nil { 67 return err 68 } 69 return p.cmd.Wait() 70 } 71 return nil 72 } 73 74 // dummyProxy just listen on some port, it is needed to prevent accidental 75 // port allocations on bound port, because without userland proxy we using 76 // iptables rules and not net.Listen 77 type dummyProxy struct { 78 listener io.Closer 79 addr net.Addr 80 } 81 82 func newDummyProxy(proto string, hostIP net.IP, hostPort int) userlandProxy { 83 switch proto { 84 case "tcp": 85 addr := &net.TCPAddr{IP: hostIP, Port: hostPort} 86 return &dummyProxy{addr: addr} 87 case "udp": 88 addr := &net.UDPAddr{IP: hostIP, Port: hostPort} 89 return &dummyProxy{addr: addr} 90 } 91 return nil 92 } 93 94 func (p *dummyProxy) Start() error { 95 switch addr := p.addr.(type) { 96 case *net.TCPAddr: 97 l, err := net.ListenTCP("tcp", addr) 98 if err != nil { 99 return err 100 } 101 p.listener = l 102 case *net.UDPAddr: 103 l, err := net.ListenUDP("udp", addr) 104 if err != nil { 105 return err 106 } 107 p.listener = l 108 default: 109 return fmt.Errorf("Unknown addr type: %T", p.addr) 110 } 111 return nil 112 } 113 114 func (p *dummyProxy) Stop() error { 115 if p.listener != nil { 116 return p.listener.Close() 117 } 118 return nil 119 }