71 lines
1.3 KiB
Go
71 lines
1.3 KiB
Go
|
package httptunnel
|
||
|
|
||
|
import (
|
||
|
"bufio"
|
||
|
"errors"
|
||
|
"log"
|
||
|
"net"
|
||
|
"net/http"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
type Server struct {
|
||
|
addr string
|
||
|
forward func(src net.Conn, dst string) (err error)
|
||
|
}
|
||
|
|
||
|
func New(addr string, forward func(src net.Conn, dst string) (err error)) *Server {
|
||
|
return &Server{
|
||
|
addr,
|
||
|
forward,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *Server) ListenAndServe() (err error) {
|
||
|
l, err := net.Listen("tcp", s.addr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer l.Close()
|
||
|
|
||
|
for {
|
||
|
conn, err := l.Accept()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
go s.Serve(conn)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (s *Server) Parse(conn net.Conn) (target string, err error) {
|
||
|
reader := bufio.NewReader(conn)
|
||
|
line, _, err := reader.ReadLine()
|
||
|
if err != nil {
|
||
|
return "", err
|
||
|
}
|
||
|
|
||
|
terms := strings.Split(string(line), " ")
|
||
|
if len(terms) != 3 {
|
||
|
return "", errors.New("bad protocol")
|
||
|
}
|
||
|
if terms[0] != http.MethodConnect {
|
||
|
return "", errors.New("method is not connect")
|
||
|
}
|
||
|
_, err = conn.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
|
||
|
return terms[1], err
|
||
|
}
|
||
|
|
||
|
func (s *Server) Serve(conn net.Conn) {
|
||
|
defer conn.Close()
|
||
|
|
||
|
target, err := s.Parse(conn)
|
||
|
if err != nil {
|
||
|
log.Printf("failed to parse http tunnel protocol error: %v", err)
|
||
|
return
|
||
|
}
|
||
|
|
||
|
if err := s.forward(conn, target); err != nil {
|
||
|
log.Printf("http tunnel server forward request error: %v", err)
|
||
|
}
|
||
|
}
|