diff --git a/pkg/config/visitor.go b/pkg/config/visitor.go index f3552b32..11959eca 100644 --- a/pkg/config/visitor.go +++ b/pkg/config/visitor.go @@ -23,7 +23,6 @@ import ( "gopkg.in/ini.v1" ) - // Visitor var ( visitorConfTypeMap = map[string]reflect.Type{ @@ -64,7 +63,6 @@ type XTCPVisitorConf struct { BaseVisitorConf `ini:",extends" json:"inline"` } - // DefaultVisitorConf creates a empty VisitorConf object by visitorType. // If visitorType doesn't exist, return nil. func DefaultVisitorConf(visitorType string) VisitorConf { diff --git a/pkg/config/visitor_test.go b/pkg/config/visitor_test.go index 98b2f097..ce200ed0 100644 --- a/pkg/config/visitor_test.go +++ b/pkg/config/visitor_test.go @@ -19,8 +19,8 @@ import ( "github.com/fatedier/frp/pkg/consts" - "gopkg.in/ini.v1" "github.com/stretchr/testify/assert" + "gopkg.in/ini.v1" ) const testVisitorPrefix = "test." diff --git a/test/e2e/e2e.crt b/test/e2e/e2e.crt new file mode 100644 index 00000000..894a776a --- /dev/null +++ b/test/e2e/e2e.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGDCCAgCgAwIBAgIJAP/5mYzCo9TZMA0GCSqGSIb3DQEBBQUAMBkxFzAVBgNV +BAMMDmV4YW1wbGUuY2EuY29tMB4XDTIxMDEyNzA4MDUyNFoXDTMxMDEyNTA4MDUy +NFowVTELMAkGA1UEBhMCWFgxEDAOBgNVBAgMB0RFRkFVTFQxEDAOBgNVBAcMB0RF +RkFVTFQxEDAOBgNVBAoMB0RFRkFVTFQxEDAOBgNVBAMMB2UyZS5jb20wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHzTaYcphSLOsV/PEWkv0XK2+hriyj ++GegXct3H7K6KxWoHMSAjmSpdGgm2/D7r4hAtAid9WpAZXExG++LGR5G/wFDMAia +FZiE+GwU20fGRsBhJVItIHVf/KwYSPBFHKCuqV0kY9Mkw1GOYZ9N33eaI4ouCSc6 +QphOgF7jRaaycXUaOLIHAYK/+QlEHi+qj5CzVqshI0YkWHY30Mvf1FmgdkCidJUC +R8OLsnc8/OJMjb+7s7rL7vdKBoRau1G1vdRwH26Xk3dq5K5BTwtCYiXjR8JmDQMS +4VoTg9BzGujd7IhTG3BVWNHo93FkmUfLaBEAdLVctBdC9J0sQviwBIV7AgMBAAGj +JzAlMCMGA1UdEQQcMBqCCWxvY2FsaG9zdIcEfwAAAYIHZTJlLmNvbTANBgkqhkiG +9w0BAQUFAAOCAQEA1blvgPF2Ey1sflkqKKJBzq8Vvh4UnHrsY1v01zAZHe6iJvTL +UfkBSiU4eYE5EAOHPCilLjmG1sqdnCeXdglOqYZB0SOrBsIYhqKbfn+IlfQCS34l +i8xDVzRFzotrzTiPk3HpSk2i6JMwGUegBhVxqYlvRyw3Od0UA18xVvxaFrHPczSl +iRx8dMchvfNpqD4PgbUeAUO+sQEB3xZlPDetYG6uk47teKaQ4ZCT/cTSeuhvoPZ0 +477E+r1KWe/kI9zeHNQ+L1GsZuwQYFGFfDpSBs8PLtyciZtPvjsZEzJrmpoq1JXT +KqkdBTZ4qElFMleV59Qtc9SRVsPbRHwT0O/cLQ== +-----END CERTIFICATE----- diff --git a/test/e2e/e2e.key b/test/e2e/e2e.key new file mode 100644 index 00000000..8ae43c66 --- /dev/null +++ b/test/e2e/e2e.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAx802mHKYUizrFfzxFpL9Fytvoa4so/hnoF3Ldx+yuisVqBzE +gI5kqXRoJtvw+6+IQLQInfVqQGVxMRvvixkeRv8BQzAImhWYhPhsFNtHxkbAYSVS +LSB1X/ysGEjwRRygrqldJGPTJMNRjmGfTd93miOKLgknOkKYToBe40WmsnF1Gjiy +BwGCv/kJRB4vqo+Qs1arISNGJFh2N9DL39RZoHZAonSVAkfDi7J3PPziTI2/u7O6 +y+73SgaEWrtRtb3UcB9ul5N3auSuQU8LQmIl40fCZg0DEuFaE4PQcxro3eyIUxtw +VVjR6PdxZJlHy2gRAHS1XLQXQvSdLEL4sASFewIDAQABAoIBAF/PnYWfNkH5vkXO +BMJhfDJXJvHuNwPuQ6sYL1CRh8BUls8F9Ij9P3IvGx6/S6E1vG3ip1sv62K0AoKd +NdKLGgTLlgxlBUr2XiwtgI7D1HhVRz2OiwiOzxpXbSM8HtPVdYwsNTkVEZRIgVx4 +nc7XAWCN+F45D3GVq7nBPz9XECfy/Aanrq4bwqGDjvw0vIRiy/M8gnJdL+1g0K1b +Cp6JkYexV5v9pnCtvYRJYqKrRxxZU90JRSb8/wNtuLeaIM/aAoUzPkUj+1owglL8 +HXUeeHsAK527gZxubYAQOCP9NGZeMEE9vAyQDxpQ+wTC5i5zhT4xkH4F/P1aYQES +fdVl86ECgYEA/NE3KgKBm5nUHOZwtZ+YiAmEkbMWXrkpYCRzQPbcMMMphMZQT4Pd +aSdtzv1qRu95qnsY/cFceyOLbiNRF+uwYJwn2PmPW7jsUQG5vHsFn12edcWxnz6k +sRRfU8HiVYoaipQD06aMUCZYKQJV4jfvcqKpVwj9b3fiN8/oDgx2AWsCgYEAylEj +Tznw54mrOFYOLbLlwwpYbVuUHWFi9WjLGLVfOHQY03CCH+PMIFPnaYRAS3SqUL8s +e5AQvNdez7HyPfGeUtXmTaEPgA8YRHTcmtfIuNn/jxjwbpcaGQn6kzB/TYdte4Pb +CXwS3Yt1LqUgC1EqkUUpszn+O6d2mnnrq1aawDECgYEAh0tvOgwdUCgCW3T23DuM +ZUCysUYlsotkmQ7ontt8+pt2nJeEYwkudBelrB/xwARoF9PIjAPuefeLpmVAAI0g +1pK6wGLNVUihLri9rSAo4iA3rM8fPxlHCXzdhvU7Kou9qGuNoLaAYGQkyc12KJnG +ipKCDRHCjuSZK0UX6mzAugECgYEAxYgw1GK67iXBEZEb6Mx5flO0gJlgZMs35mn5 +mddD8AeSUabQtbghDhM9pw0kBUgUHiB5mu7PGMGi5WBVJtuofDIx2Ot/CcYzKGt9 +FIXIiYr29M0huqg3J+lRSLKaKKUoZOcZTgphFQPbVr6MKeCGki2YCFCAA9h+eVa+ +nZxCHZECgYBJjNqhR9pc+56Mor6oBGnRbBCQn2naNuPx4AoZ8JWXU8Q8GRoI5son +F7MGeuVwLDFvyQOAiDxqyrHM+PCPLcMBdfH8rMt7GQpBsSSA09WYtQ9Sj97QhbTy +Zrq8EtPvRBmeGfZd8BDGVGunVZnNi3NaOV0fCOK6yQEtJN0J9BREbw== +-----END RSA PRIVATE KEY----- diff --git a/test/e2e/framework/mockservers.go b/test/e2e/framework/mockservers.go index 3598aac1..fc4bbdef 100644 --- a/test/e2e/framework/mockservers.go +++ b/test/e2e/framework/mockservers.go @@ -9,21 +9,34 @@ import ( ) const ( - TCPEchoServerPort = "TCPEchoServerPort" - UDPEchoServerPort = "UDPEchoServerPort" - UDSEchoServerAddr = "UDSEchoServerAddr" + TCPEchoServerPort = "TCPEchoServerPort" + UDPEchoServerPort = "UDPEchoServerPort" + UDSEchoServerAddr = "UDSEchoServerAddr" + HTTPEchoServerPort = "HTTPEchoServerPort" + HTTPSEchoServerPort = "HTTPSEchoServerPort" + WSEchoServerPort = "WSEchoServerPort" + WSSEchoServerPort = "WSSEchoServerPort" ) type MockServers struct { - tcpEchoServer *echoserver.Server - udpEchoServer *echoserver.Server - udsEchoServer *echoserver.Server + tcpEchoServer *echoserver.Server + udpEchoServer *echoserver.Server + udsEchoServer *echoserver.Server + httpEchoServer *echoserver.Server + httpsEchoServer *echoserver.Server + wsEchoServer *echoserver.Server + wssEchoServer *echoserver.Server } func NewMockServers(portAllocator *port.Allocator) *MockServers { s := &MockServers{} tcpPort := portAllocator.Get() udpPort := portAllocator.Get() + httpPort := portAllocator.Get() + httpsPort := portAllocator.Get() + wsPort := portAllocator.Get() + wssPort := portAllocator.Get() + s.tcpEchoServer = echoserver.New(echoserver.Options{ Type: echoserver.TCP, BindAddr: "127.0.0.1", @@ -45,6 +58,34 @@ func NewMockServers(portAllocator *port.Allocator) *MockServers { BindAddr: udsAddr, RepeatNum: 1, }) + + s.httpEchoServer = echoserver.New(echoserver.Options{ + Type: echoserver.HTTP, + BindAddr: "127.0.0.1", + BindPort: int32(httpPort), + RepeatNum: 1, + }) + + s.httpsEchoServer = echoserver.New(echoserver.Options{ + Type: echoserver.HTTPS, + BindAddr: "127.0.0.1", + BindPort: int32(httpsPort), + RepeatNum: 1, + }) + + s.wsEchoServer = echoserver.New(echoserver.Options{ + Type: echoserver.WS, + BindAddr: "127.0.0.1", + BindPort: int32(wsPort), + RepeatNum: 1, + }) + s.wssEchoServer = echoserver.New(echoserver.Options{ + Type: echoserver.WSS, + BindAddr: "127.0.0.1", + BindPort: int32(wssPort), + RepeatNum: 1, + }) + return s } @@ -58,6 +99,18 @@ func (m *MockServers) Run() error { if err := m.udsEchoServer.Run(); err != nil { return err } + if err := m.httpEchoServer.Run(); err != nil { + return err + } + if err := m.httpsEchoServer.Run(); err != nil { + return err + } + if err := m.wsEchoServer.Run(); err != nil { + return err + } + if err := m.wssEchoServer.Run(); err != nil { + return err + } return nil } @@ -65,6 +118,10 @@ func (m *MockServers) Close() { m.tcpEchoServer.Close() m.udpEchoServer.Close() m.udsEchoServer.Close() + m.httpEchoServer.Close() + m.httpsEchoServer.Close() + m.wsEchoServer.Close() + m.wssEchoServer.Close() os.Remove(m.udsEchoServer.GetOptions().BindAddr) } @@ -73,6 +130,10 @@ func (m *MockServers) GetTemplateParams() map[string]interface{} { ret[TCPEchoServerPort] = m.tcpEchoServer.GetOptions().BindPort ret[UDPEchoServerPort] = m.udpEchoServer.GetOptions().BindPort ret[UDSEchoServerAddr] = m.udsEchoServer.GetOptions().BindAddr + ret[HTTPEchoServerPort] = m.httpEchoServer.GetOptions().BindPort + ret[HTTPSEchoServerPort] = m.httpsEchoServer.GetOptions().BindPort + ret[WSEchoServerPort] = m.wsEchoServer.GetOptions().BindPort + ret[WSSEchoServerPort] = m.wssEchoServer.GetOptions().BindPort return ret } diff --git a/test/e2e/mock/echoserver/echoserver.go b/test/e2e/mock/echoserver/echoserver.go index 09a20954..b5358ce4 100644 --- a/test/e2e/mock/echoserver/echoserver.go +++ b/test/e2e/mock/echoserver/echoserver.go @@ -1,19 +1,27 @@ package echoserver import ( + "encoding/json" "fmt" "net" + "net/http" "strings" fnet "github.com/fatedier/frp/pkg/util/net" + + "github.com/gorilla/websocket" ) type ServerType string const ( - TCP ServerType = "tcp" - UDP ServerType = "udp" - Unix ServerType = "unix" + TCP ServerType = "tcp" + UDP ServerType = "udp" + Unix ServerType = "unix" + HTTP ServerType = "http" + HTTPS ServerType = "https" + WS ServerType = "ws" + WSS ServerType = "wss" ) type Options struct { @@ -27,7 +35,11 @@ type Options struct { type Server struct { opt Options - l net.Listener + l net.Listener + httpServer *http.Server + httpsServer *http.Server + wsServer *http.Server + wssServer *http.Server } func New(opt Options) *Server { @@ -50,19 +62,53 @@ func (s *Server) GetOptions() Options { } func (s *Server) Run() error { - if err := s.initListener(); err != nil { + if err := s.init(); err != nil { return err } - go func() { - for { - c, err := s.l.Accept() - if err != nil { - return + switch s.opt.Type { + case TCP, UDP, Unix: + go func() { + for { + c, err := s.l.Accept() + if err != nil { + return + } + go s.handle(c) } - go s.handle(c) - } - }() + }() + case HTTP: + go func() { + err := s.httpServer.ListenAndServe() + if err != nil { + fmt.Printf("echo http server exited error: %v\n", err) + } + }() + case HTTPS: + go func() { + err := s.httpsServer.ListenAndServeTLS("e2e.crt", "e2e.key") + if err != nil { + fmt.Printf("echo https server exited error: %v\n", err) + } + }() + case WS: + go func() { + err := s.wsServer.ListenAndServe() + if err != nil { + fmt.Printf("echo ws server exited error: %v\n", err) + } + }() + case WSS: + go func() { + err := s.wssServer.ListenAndServeTLS("e2e.crt", "e2e.key") + if err != nil { + fmt.Printf("echo wss server exited error: %v\n", err) + } + }() + default: + return fmt.Errorf("unknown server type: %s", s.opt.Type) + } + return nil } @@ -70,10 +116,22 @@ func (s *Server) Close() error { if s.l != nil { return s.l.Close() } + if s.httpServer != nil { + s.httpServer.Close() + } + if s.httpsServer != nil { + s.httpsServer.Close() + } + if s.wsServer != nil { + s.wsServer.Close() + } + if s.wssServer != nil { + s.wssServer.Close() + } return nil } -func (s *Server) initListener() (err error) { +func (s *Server) init() (err error) { switch s.opt.Type { case TCP: s.l, err = net.Listen("tcp", fmt.Sprintf("%s:%d", s.opt.BindAddr, s.opt.BindPort)) @@ -81,6 +139,30 @@ func (s *Server) initListener() (err error) { s.l, err = fnet.ListenUDP(s.opt.BindAddr, int(s.opt.BindPort)) case Unix: s.l, err = net.Listen("unix", s.opt.BindAddr) + case HTTP: + s.httpServer = &http.Server{ + Addr: fmt.Sprintf("%s:%d", s.opt.BindAddr, s.opt.BindPort), + Handler: http.HandlerFunc(echo), + } + fmt.Println("http echo server listen port", s.opt.BindPort) + case HTTPS: + s.httpsServer = &http.Server{ + Addr: fmt.Sprintf("%s:%d", s.opt.BindAddr, s.opt.BindPort), + Handler: http.HandlerFunc(echo), + } + fmt.Println("https echo server listen port", s.opt.BindPort) + case WS: + s.wsServer = &http.Server{ + Addr: fmt.Sprintf("%s:%d", s.opt.BindAddr, s.opt.BindPort), + Handler: http.HandlerFunc(ws), + } + fmt.Println("ws echo server listen port", s.opt.BindPort) + case WSS: + s.wssServer = &http.Server{ + Addr: fmt.Sprintf("%s:%d", s.opt.BindAddr, s.opt.BindPort), + Handler: http.HandlerFunc(ws), + } + fmt.Println("wss echo server listen port", s.opt.BindPort) default: return fmt.Errorf("unknown server type: %s", s.opt.Type) } @@ -109,3 +191,51 @@ func (s *Server) handle(c net.Conn) { c.Write([]byte(response)) } } + +func echo(w http.ResponseWriter, r *http.Request) { + rh := make(map[string]string) + for key, _ := range r.Header { + rh[key] = r.Header.Get(key) + } + rh["Host"] = r.Host + rh["Path"] = r.URL.Path + + data, err := json.Marshal(rh) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusOK) + w.Write(data) + return +} + +var ( + upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + } +) + +func ws(w http.ResponseWriter, r *http.Request) { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + if _, ok := err.(websocket.HandshakeError); !ok { + fmt.Println(err) + } + return + } + + go func() { + for { + _, data, err := conn.ReadMessage() + if err != nil { + fmt.Printf("reading message error: %v\n", err) + } + if err = conn.WriteMessage(websocket.TextMessage, data); err != nil { + fmt.Printf("writing message error: %v\n", err) + } + } + }() +}