diff --git a/alpine/packages/proxy/libproxy/proxy.go b/alpine/packages/proxy/libproxy/proxy.go index e8fbbe0c5..457b1ba6e 100644 --- a/alpine/packages/proxy/libproxy/proxy.go +++ b/alpine/packages/proxy/libproxy/proxy.go @@ -28,22 +28,16 @@ type Proxy interface { // NewProxy creates a Proxy according to the specified frontendAddr and backendAddr. -func NewProxy(frontendAddr, backendAddr net.Addr) (Proxy, error) { - switch frontendAddr.(type) { +func NewProxy(frontendAddr *vsock.VsockAddr, backendAddr net.Addr) (Proxy, error) { + switch backendAddr.(type) { case *net.UDPAddr: - listener, err := net.ListenUDP("udp", frontendAddr.(*net.UDPAddr)) + listener, err := vsock.Listen(frontendAddr.Port) if err != nil { return nil, err } - return NewUDPProxy(frontendAddr, listener, backendAddr.(*net.UDPAddr)) + return NewUDPProxy(frontendAddr, NewUDPListener(listener), backendAddr.(*net.UDPAddr)) case *net.TCPAddr: - listener, err := net.Listen("tcp", frontendAddr.String()) - if err != nil { - return nil, err - } - return NewTCPProxy(listener, backendAddr.(*net.TCPAddr)) - case *vsock.VsockAddr: - listener, err := vsock.Listen(frontendAddr.(*vsock.VsockAddr).Port) + listener, err := vsock.Listen(frontendAddr.Port) if err != nil { return nil, err } diff --git a/alpine/packages/proxy/libproxy/udp_encapsulation.go b/alpine/packages/proxy/libproxy/udp_encapsulation.go new file mode 100644 index 000000000..8f9fa1277 --- /dev/null +++ b/alpine/packages/proxy/libproxy/udp_encapsulation.go @@ -0,0 +1,100 @@ +package libproxy + +import ( + //"encoding/binary" + "errors" + "net" + //"strings" + "sync" + //"syscall" + + "github.com/Sirupsen/logrus" +) + +type udpListener interface { + ReadFromUDP(b []byte) (int, *net.UDPAddr, error) + WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) + Close() error +} + +type udpEncapsulator struct { + conn *net.Conn + listener net.Listener + m *sync.Mutex + r *sync.Mutex + w *sync.Mutex +} + +func (u *udpEncapsulator) getConn() (net.Conn, error) { + u.m.Lock() + defer u.m.Unlock() + if u.conn != nil { + return *u.conn, nil + } + conn, err := u.listener.Accept() + if err != nil { + logrus.Printf("Failed to accept connection: %#v", err) + return nil, err + } + u.conn = &conn + return conn, nil +} + +func (u *udpEncapsulator) ReadFromUDP(b []byte) (int, *net.UDPAddr, error) { + conn, err := u.getConn() + if err != nil { + return 0, nil, err + } + u.r.Lock() + defer u.r.Unlock() + datagram := &udpDatagram{payload: b} + err = datagram.Unmarshal(conn) + if err != nil { + return 0, nil, err + } + return len(datagram.payload), &net.UDPAddr{IP: *datagram.IP, Port: datagram.Port, Zone: datagram.Zone}, nil +} + +func (u *udpEncapsulator) WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) { + conn, err := u.getConn() + if err != nil { + return 0, err + } + u.w.Lock() + defer u.w.Unlock() + datagram := &udpDatagram{payload: b, IP: &addr.IP, Port: addr.Port, Zone: addr.Zone} + return len(b), datagram.Marshal(conn) +} + +func (u *udpEncapsulator) Close() error { + if u.conn != nil { + conn := *u.conn + conn.Close() + } + u.listener.Close() + return nil +} + +func NewUDPListener(listener net.Listener) udpListener { + var m sync.Mutex; + return &udpEncapsulator{ + conn: nil, + listener: listener, + m: &m, + } +} + +type udpDatagram struct { + payload []byte + IP *net.IP + Port int + Zone string +} + +func (u *udpDatagram) Marshal(conn net.Conn) error { + return errors.New("Marshal unimplemented") +} + +func (u *udpDatagram) Unmarshal(conn net.Conn) error { + return errors.New("Unmarshal unimplemented") +} diff --git a/alpine/packages/proxy/libproxy/udp_proxy.go b/alpine/packages/proxy/libproxy/udp_proxy.go index 9b6cefc42..3e5a971c6 100644 --- a/alpine/packages/proxy/libproxy/udp_proxy.go +++ b/alpine/packages/proxy/libproxy/udp_proxy.go @@ -18,12 +18,6 @@ const ( UDPBufSize = 65507 ) -type udpListener interface { - ReadFromUDP(b []byte) (int, *net.UDPAddr, error) - WriteToUDP(b []byte, addr *net.UDPAddr) (int, error) - Close() error -} - // A net.Addr where the IP is split into two fields so you can use it as a key // in a map: type connTrackKey struct {