nip/internal/pkg/httptunnel/httptunnel.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)
}
}