summaryrefslogtreecommitdiff
path: root/pkg/server/socket
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/server/socket')
-rw-r--r--pkg/server/socket/defer.go49
-rw-r--r--pkg/server/socket/dial.go2
-rw-r--r--pkg/server/socket/listen.go2
-rw-r--r--pkg/server/socket/loop.go14
-rw-r--r--pkg/server/socket/proxy.go134
-rw-r--r--pkg/server/socket/socket.go19
-rw-r--r--pkg/server/socket/tun.go14
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() {