package socket import ( "errors" "fmt" "log" "net" "tunnel/pkg/server/env" ) type listenSocket struct { Proto string `opts:"default:tcp"` Addr string `opts:"required"` Redirect bool Tproxy bool listen net.Listener } func (s *listenSocket) Prepare(e env.Env) error { if s.Redirect && s.Proto != "tcp" { return errors.New("redirect not supported") } if s.Tproxy && s.Proto != "tcp" { return errors.New("tproxy not supported") } if s.Redirect && s.Tproxy { return errors.New("redirect and tproxy cannot be used together") } proto, addr := parseProtoAddr(s.Proto, s.Addr) listen, err := net.Listen(proto, addr) if err != nil { return err } e.Set("listen", listen.Addr().String()) if s.Tproxy { if err := setConnTransparent(listen); err != nil { listen.Close() return err } } s.listen = listen return nil } func setOriginHostPort(env env.Env, origin, host, port string) { env.Set("origin", origin) env.Set("origin.host", host) env.Set("origin.port", port) } func (s *listenSocket) New(env env.Env) (Conn, error) { var origin string conn, err := s.listen.Accept() if err != nil { return nil, err } ra := conn.RemoteAddr() desc := fmt.Sprintf("%s/%s->%s", s.Proto, ra, s.Addr) info := fmt.Sprintf("<%s/%s", ra.Network(), ra) if s.Redirect { host, port, err := getConnOriginalHostPort(conn) if err != nil { defer conn.Close() return nil, fmt.Errorf("accept %s failed: %s", desc, err) } origin = net.JoinHostPort(host, port) setOriginHostPort(env, origin, host, port) } if s.Tproxy { origin = conn.LocalAddr().String() host, port, err := net.SplitHostPort(origin) if err != nil { defer conn.Close() return nil, fmt.Errorf("accept %s failed: %s", desc, err) } setOriginHostPort(env, origin, host, port) } if origin == "" { log.Println("accept", desc) } else { log.Println("accept", desc, "origin", origin) } return newConn(conn, desc, info), nil } func (s *listenSocket) String() string { return fmt.Sprintf("%s/%s,listen", s.Proto, s.Addr) } func (s *listenSocket) Close() { s.listen.Close() } func init() { register("listen", "accept connections on the local network address", listenSocket{}) }