diff options
Diffstat (limited to 'pkg/server/socket/proxy.go')
| -rw-r--r-- | pkg/server/socket/proxy.go | 134 |
1 files changed, 134 insertions, 0 deletions
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 +} |
