diff options
Diffstat (limited to 'pkg/server/socket')
| -rw-r--r-- | pkg/server/socket/defer.go | 49 | ||||
| -rw-r--r-- | pkg/server/socket/dial.go | 2 | ||||
| -rw-r--r-- | pkg/server/socket/listen.go | 2 | ||||
| -rw-r--r-- | pkg/server/socket/loop.go | 14 | ||||
| -rw-r--r-- | pkg/server/socket/proxy.go | 134 | ||||
| -rw-r--r-- | pkg/server/socket/socket.go | 19 | ||||
| -rw-r--r-- | pkg/server/socket/tun.go | 14 |
7 files changed, 187 insertions, 47 deletions
diff --git a/pkg/server/socket/defer.go b/pkg/server/socket/defer.go index bfb2157..7ed303d 100644 --- a/pkg/server/socket/defer.go +++ b/pkg/server/socket/defer.go @@ -9,10 +9,11 @@ type deferSocket struct { S } -type deferChannel struct { - s *deferSocket - c chan Channel - e env.Env +type deferConn struct { + sock *deferSocket + wait chan bool + env env.Env + conn Conn } func newDeferSocket(proto, addr string) (S, error) { @@ -24,42 +25,43 @@ func newDeferSocket(proto, addr string) (S, error) { return &deferSocket{s}, nil } -func (s *deferSocket) Open(env env.Env) (Channel, error) { - c := &deferChannel{ - s: s, - c: make(chan Channel), - e: env, +func (s *deferSocket) Open(env env.Env) (Conn, error) { + c := &deferConn{ + sock: s, + wait: make(chan bool), + env: env, } return c, nil } -func (c *deferChannel) String() string { +func (c *deferConn) String() string { return "defer" } -func (c *deferChannel) Send(wq queue.Q) error { - if x := <-c.c; x == nil { +func (c *deferConn) Send(wq queue.Q) error { + if !<-c.wait { return nil } else { - return x.Send(wq) + return c.conn.Send(wq) } } -func (c *deferChannel) Recv(rq queue.Q) error { +func (c *deferConn) Recv(rq queue.Q) error { b := <-rq if b == nil { - close(c.c) + c.wait <- false return nil } - x, err := c.s.S.Open(c.e) + conn, err := c.sock.S.Open(c.env) if err != nil { - close(c.c) + c.wait <- false return err } - c.c <- x + c.conn = conn + c.wait <- true q := queue.New() @@ -71,10 +73,13 @@ func (c *deferChannel) Recv(rq queue.Q) error { defer q.Dry() - return x.Recv(q) + return c.conn.Recv(q) } -/* TODO */ -func (c *deferChannel) Close() error { - return nil +func (c *deferConn) Close() (err error) { + if c.conn != nil { + err = c.conn.Close() + } + + return } diff --git a/pkg/server/socket/dial.go b/pkg/server/socket/dial.go index d4c20e1..d7b232c 100644 --- a/pkg/server/socket/dial.go +++ b/pkg/server/socket/dial.go @@ -26,7 +26,7 @@ func (s *dialSocket) String() string { return fmt.Sprintf("%s/%s", s.proto, s.addr) } -func (s *dialSocket) Open(e env.Env) (Channel, error) { +func (s *dialSocket) Open(e env.Env) (Conn, error) { conn, err := net.Dial(s.proto, e.Eval(s.addr)) if err != nil { return nil, err diff --git a/pkg/server/socket/listen.go b/pkg/server/socket/listen.go index c328945..caf5fcf 100644 --- a/pkg/server/socket/listen.go +++ b/pkg/server/socket/listen.go @@ -28,7 +28,7 @@ func newListenSocket(proto, addr string) (S, error) { return s, nil } -func (s *listenSocket) Open(env.Env) (Channel, error) { +func (s *listenSocket) Open(env.Env) (Conn, error) { conn, err := s.listen.Accept() if err != nil { return nil, err diff --git a/pkg/server/socket/loop.go b/pkg/server/socket/loop.go index 88e9491..a06448a 100644 --- a/pkg/server/socket/loop.go +++ b/pkg/server/socket/loop.go @@ -7,31 +7,31 @@ import ( type loopSocket struct{} -type loopChannel struct { +type loopConn struct { c chan queue.Q q chan error } -func (c *loopChannel) Send(wq queue.Q) error { +func (c *loopConn) Send(wq queue.Q) error { c.c <- wq return <-c.q } -func (c *loopChannel) Recv(rq queue.Q) error { +func (c *loopConn) Recv(rq queue.Q) error { defer close(c.q) return queue.Copy(rq, <-c.c) } -func (c *loopChannel) String() string { +func (c *loopConn) String() string { return "loop" } -func (c *loopChannel) Close() error { +func (c *loopConn) Close() error { return nil } -func (s *loopSocket) Open(env.Env) (Channel, error) { - return &loopChannel{make(chan queue.Q), make(chan error)}, nil +func (s *loopSocket) Open(env.Env) (Conn, error) { + return &loopConn{make(chan queue.Q), make(chan error)}, nil } func (s *loopSocket) String() string { diff --git a/pkg/server/socket/proxy.go b/pkg/server/socket/proxy.go new file mode 100644 index 0000000..ef14f48 --- /dev/null +++ b/pkg/server/socket/proxy.go @@ -0,0 +1,134 @@ +package socket + +import ( + "bytes" + "errors" + "fmt" + "tunnel/pkg/http" + "tunnel/pkg/server/env" + "tunnel/pkg/server/queue" +) + +type status struct { + code int + desc string +} + +type proxySocket struct { + proto string +} + +type proxyServer struct { + sock *proxySocket + addr string + auth string + wait chan status + env env.Env + conn Conn +} + +func newProxySocket(proto string) (S, error) { + return &proxySocket{proto}, nil +} + +func (sock *proxySocket) Open(env env.Env) (Conn, error) { + s := &proxyServer{ + sock: sock, + auth: env.GetLocal("proxy.auth"), + wait: make(chan status), + env: env, + } + + return s, nil +} + +func (sock *proxySocket) Close() { +} + +func (s *proxyServer) String() string { + return "proxy" +} + +func (s *proxyServer) Send(wq queue.Q) error { + var out bytes.Buffer + + status := <-s.wait + + fmt.Fprintf(&out, "HTTP/1.0 %d %s\r\n", status.code, status.desc) + switch status.code { + case http.OK: + fmt.Fprintf(&out, "Proxy-Agent: tunnel\r\n") + case 407: + fmt.Fprintf(&out, "Proxy-Authenticate: Basic realm=\"tunnel\"\r\n") + fallthrough + default: + fmt.Fprintf(&out, "Server: tunnel\r\n") + fmt.Fprintf(&out, "Connection: close\r\n") + } + fmt.Fprintf(&out, "\r\n") + + wq <- out.Bytes() + + if status.code != http.OK { + return nil + } + + return s.conn.Send(wq) +} + +func (s *proxyServer) initConn(addr string) error { + dial, err := newDialSocket(s.sock.proto, addr) + if err != nil { + return err + } + + conn, err := dial.Open(s.env) + if err != nil { + dial.Close() + return err + } + + s.conn = conn + + return nil +} + +func (s *proxyServer) Recv(rq queue.Q) error { + req, err := http.ParseRequest(rq.Reader()) + if err != nil { + s.wait <- status{400, "Bad Request"} + return err + } + + if req.Method != "CONNECT" { + s.wait <- status{400, "Bad Request"} + return errors.New("bad method") + } + + if s.auth != "" { + if auth, ok := req.Header["Proxy-Authorization"]; !ok { + s.wait <- status{407, "Proxy Authentication Required"} + return errors.New("auth required") + } else if !http.BasicAuthCheck(s.auth, auth) { + s.wait <- status{401, "Unauthorized"} + return errors.New("auth failed") + } + } + + if err := s.initConn(req.URI); err != nil { + s.wait <- status{500, "Unable to connect"} + return err + } + + s.wait <- status{200, "Connection established"} + + return s.conn.Recv(rq) +} + +func (s *proxyServer) Close() (err error) { + if s.conn != nil { + err = s.conn.Close() + } + + return +} diff --git a/pkg/server/socket/socket.go b/pkg/server/socket/socket.go index 1d447f8..48c06b4 100644 --- a/pkg/server/socket/socket.go +++ b/pkg/server/socket/socket.go @@ -16,17 +16,17 @@ var ErrAlreadyClosed = errors.New("already closed") type exported struct { info string - Channel + Conn } -type Channel interface { +type Conn interface { Send(wq queue.Q) error Recv(rq queue.Q) error Close() error } type S interface { - Open(env env.Env) (Channel, error) + Open(env env.Env) (Conn, error) Close() } @@ -44,7 +44,7 @@ func (c exported) String() string { return c.info } -func newConn(cn net.Conn) Channel { +func newConn(cn net.Conn) Conn { c := &conn{Conn: cn} log.Println("open", c) return c @@ -87,15 +87,16 @@ func New(desc string, env env.Env) (S, error) { proto, addr = args[0], args[1] } - if addr == "loop" { - return newLoopSocket() - } - if proto == "" { proto = "tcp" } - if addr == "" { + switch addr { + case "loop": + return newLoopSocket() + case "proxy": + return newProxySocket(proto) + case "": return nil, fmt.Errorf("bad socket '%s'", desc) } diff --git a/pkg/server/socket/tun.go b/pkg/server/socket/tun.go index 78bdfd4..c14125b 100644 --- a/pkg/server/socket/tun.go +++ b/pkg/server/socket/tun.go @@ -27,7 +27,7 @@ type tunSocket struct { name string } -type tunChannel struct { +type tunConn struct { name string s *tunSocket fp *os.File @@ -52,7 +52,7 @@ func (s *tunSocket) String() string { return fmt.Sprintf("tun/%s", s.name) } -func (s *tunSocket) Open(env.Env) (Channel, error) { +func (s *tunSocket) Open(env.Env) (Conn, error) { fd, err := unix.Open("/dev/net/tun", unix.O_RDWR, 0) if err != nil { return nil, err @@ -72,7 +72,7 @@ func (s *tunSocket) Open(env.Env) (Channel, error) { return nil, fmt.Errorf("set nonblock %s: %w", s.name, err) } - c := &tunChannel{ + c := &tunConn{ name: strings.Trim(string(ifr.name[:]), "\x00"), fp: os.NewFile(uintptr(fd), "tun"), } @@ -83,7 +83,7 @@ func (s *tunSocket) Open(env.Env) (Channel, error) { func (s *tunSocket) Close() { } -func (c *tunChannel) Send(wq queue.Q) error { +func (c *tunConn) Send(wq queue.Q) error { buf := make([]byte, maxTunBufSize) enc := pack.NewEncoder(wq.Writer()) @@ -97,7 +97,7 @@ func (c *tunChannel) Send(wq queue.Q) error { } } -func (c *tunChannel) Recv(rq queue.Q) error { +func (c *tunConn) Recv(rq queue.Q) error { dec := pack.NewDecoder(rq.Reader()) for { @@ -117,11 +117,11 @@ func (c *tunChannel) Recv(rq queue.Q) error { } } -func (c *tunChannel) String() string { +func (c *tunConn) String() string { return "tun/" + c.name } -func (c *tunChannel) Close() error { +func (c *tunConn) Close() error { err := ErrAlreadyClosed c.once.Do(func() { |
