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) } }