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 (s *listenSocket) New(env env.Env) (Conn, error) { var original string conn, err := s.listen.Accept() if err != nil { return nil, err } la, ra := conn.LocalAddr(), conn.RemoteAddr() desc := fmt.Sprintf("%s/%s->%s", la.Network(), ra, la) info := fmt.Sprintf("<%s/%s", ra.Network(), ra) if s.Redirect { if err := getConnOriginalAddr(conn, &original); err != nil { log.Println("accept", desc, "failed") conn.Close() return nil, err } else { env.Set("original", original) } } if s.Tproxy { env.Set("original", la.String()) } if original == "" { log.Println("accept", desc) } else { log.Println("accept", desc, "original", original) } 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{}) }