diff --git a/main.go b/main.go index 8634a86..34865c1 100644 --- a/main.go +++ b/main.go @@ -81,7 +81,7 @@ func main() { log.Fatal(err) } - go local.ListenAndServe() + go local.ListenAndServe(nil) } sigCh := make(chan os.Signal, 1) diff --git a/proxy/http/http.go b/proxy/http/http.go index 1a66795..c35bf78 100644 --- a/proxy/http/http.go +++ b/proxy/http/http.go @@ -6,7 +6,6 @@ package http import ( "bufio" "bytes" - "crypto/tls" "encoding/base64" "errors" "fmt" @@ -24,21 +23,16 @@ import ( // HTTP struct type HTTP struct { - dialer proxy.Dialer - addr string - user string - password string -} - -type HTTPS struct { - HTTP - tlsConfig *tls.Config + dialer proxy.Dialer + addr string + user string + password string + pretendAsWebServer bool } func init() { proxy.RegisterDialer("http", NewHTTPDialer) proxy.RegisterServer("http", NewHTTPServer) - proxy.RegisterServer("https", NewHTTPSServer) } // NewHTTP returns a http proxy. @@ -54,44 +48,21 @@ func NewHTTP(s string, dialer proxy.Dialer) (*HTTP, error) { pass, _ := u.User.Password() h := &HTTP{ - dialer: dialer, - addr: addr, - user: user, - password: pass, + dialer: dialer, + addr: addr, + user: user, + password: pass, + pretendAsWebServer: false, + } + + pretend := u.Query().Get("pretend") + if pretend != "" { + h.pretendAsWebServer = true } return h, nil } -func NewHTTPS(s string, dialer proxy.Dialer) (*HTTPS, error) { - u, _ := url.Parse(s) - // TODO: cert=&key= - certFile := u.Query().Get("cert") - keyFile := u.Query().Get("key") - - cert, err := tls.LoadX509KeyPair(certFile, keyFile) - if err != nil { - log.F("unabled load cert: %s, key %s", certFile, keyFile) - return nil, err - } - - tlsConfig := tls.Config{ - Certificates: []tls.Certificate{cert}, - } - - http, err := NewHTTP(s, dialer) - if err != nil { - return nil, err - } - - https := &HTTPS{ - HTTP: *http, - tlsConfig: &tlsConfig, - } - - return https, nil -} - // NewHTTPDialer returns a http proxy dialer. func NewHTTPDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) { return NewHTTP(s, dialer) @@ -102,55 +73,32 @@ func NewHTTPServer(s string, dialer proxy.Dialer) (proxy.Server, error) { return NewHTTP(s, dialer) } -// NewHTTPSServer returns a https proxy server -func NewHTTPSServer(s string, dialer proxy.Dialer) (proxy.Server, error) { - return NewHTTPS(s, dialer) -} - -// ListenAndServe serves tls http proxy -func (s *HTTPS) ListenAndServe() { - l, err := tls.Listen("tcp", s.addr, s.tlsConfig) - if err != nil { - log.F("failed to listen on tls %s: %v", s.addr, err) - return - } - - defer l.Close() - - for { - c, err := l.Accept() - if err != nil { - log.F("[https] failed to accept: %v", err) - continue - } - - go s.HTTP.Serve(c) - } -} - // ListenAndServe . -func (s *HTTP) ListenAndServe() { - l, err := net.Listen("tcp", s.addr) - if err != nil { - log.F("failed to listen on %s: %v", s.addr, err) - return - } - defer l.Close() - - log.F("listening TCP on %s", s.addr) - - for { - c, err := l.Accept() +func (s *HTTP) ListenAndServe(c net.Conn) { + if c == nil { + l, err := net.Listen("tcp", s.addr) if err != nil { - log.F("[http] failed to accept: %v", err) - continue + log.F("failed to listen on %s: %v", s.addr, err) + return } + defer l.Close() + log.F("listening TCP on %s", s.addr) + + for { + c, err := l.Accept() + if err != nil { + log.F("[http] failed to accept: %v", err) + continue + } + + go s.Serve(c) + } + } else { go s.Serve(c) } } - // Serve . func (s *HTTP) Serve(c net.Conn) { defer c.Close() @@ -166,8 +114,15 @@ func (s *HTTP) Serve(c net.Conn) { return } + if s.pretendAsWebServer { + fmt.Fprintf(c, "%s 404 Not Found\r\nServer: nginx\r\n\r\n", proto) + log.F("[http pretender] being accessed as web server from %s", c.RemoteAddr().String()) + return + } + if method == "CONNECT" { s.servHTTPS(method, requestURI, proto, c) + //c.Write([]byte("HTTP/1.1 405\nAllow: GET, POST, HEAD, OPTION, PATCH\nServer: vsps/1.2\nContent-Type: \n\n")) return } diff --git a/proxy/mixed/mixed.go b/proxy/mixed/mixed.go index 5780d8b..07bfad8 100644 --- a/proxy/mixed/mixed.go +++ b/proxy/mixed/mixed.go @@ -31,6 +31,8 @@ type MixedProxy struct { http *http.HTTP socks5 *socks5.SOCKS5 + + pretendAsWebServer bool } func init() { @@ -45,9 +47,16 @@ func NewMixedProxy(s string, dialer proxy.Dialer) (*MixedProxy, error) { return nil, err } + pretend := u.Query().Get("pretend") + p := &MixedProxy{ - dialer: dialer, - addr: u.Host, + dialer: dialer, + addr: u.Host, + pretendAsWebServer: false, + } + + if pretend == "true" { + p.pretendAsWebServer = true } p.http, _ = http.NewHTTP(s, dialer) @@ -62,25 +71,28 @@ func NewMixedProxyServer(s string, dialer proxy.Dialer) (proxy.Server, error) { } // ListenAndServe . -func (p *MixedProxy) ListenAndServe() { +func (p *MixedProxy) ListenAndServe(c net.Conn) { - go p.socks5.ListenAndServeUDP() + if c == nil { + go p.socks5.ListenAndServeUDP() + l, err := net.Listen("tcp", p.addr) - l, err := net.Listen("tcp", p.addr) - if err != nil { - log.F("[mixed] failed to listen on %s: %v", p.addr, err) - return - } - - log.F("[mixed] listening TCP on %s", p.addr) - - for { - c, err := l.Accept() + //l, err := net.Listen("tcp", p.addr) if err != nil { - log.F("[mixed] failed to accept: %v", err) - continue + log.F("[mixed] failed to listen on %s: %v", p.addr, err) + return } + for { + c, err := l.Accept() + if err != nil { + log.F("[mixed] failed to accept: %v", err) + continue + } + + go p.Serve(c) + } + } else { go p.Serve(c) } } @@ -98,7 +110,7 @@ func (p *MixedProxy) Serve(c net.Conn) { if p.socks5 != nil { head, err := cc.Peek(1) if err != nil { - log.F("[mixed] peek error: %s", err) + log.F("[mixed] socks5 peek error: %s", err) return } @@ -112,7 +124,7 @@ func (p *MixedProxy) Serve(c net.Conn) { if p.http != nil { head, err := cc.Peek(8) if err != nil { - log.F("[mixed] peek error: %s", err) + log.F("[mixed] http peek error: %s", err) return } diff --git a/proxy/redir/redir_linux.go b/proxy/redir/redir_linux.go index 8963486..b99ddc2 100644 --- a/proxy/redir/redir_linux.go +++ b/proxy/redir/redir_linux.go @@ -64,7 +64,7 @@ func NewRedir6Server(s string, dialer proxy.Dialer) (proxy.Server, error) { } // ListenAndServe . -func (s *RedirProxy) ListenAndServe() { +func (s *RedirProxy) ListenAndServe(_ net.Conn) { l, err := net.Listen("tcp", s.addr) if err != nil { log.F("[redir] failed to listen on %s: %v", s.addr, err) diff --git a/proxy/server.go b/proxy/server.go index aef83c9..e9ff2bc 100644 --- a/proxy/server.go +++ b/proxy/server.go @@ -2,6 +2,7 @@ package proxy import ( "errors" + "net" "net/url" "strings" @@ -11,7 +12,7 @@ import ( // Server interface type Server interface { // ListenAndServe as proxy server, use only in server mode. - ListenAndServe() + ListenAndServe(net.Conn) } // ServerCreator is a function to create proxy servers. diff --git a/proxy/socks5/socks5.go b/proxy/socks5/socks5.go index f34a8e4..8eb2912 100644 --- a/proxy/socks5/socks5.go +++ b/proxy/socks5/socks5.go @@ -76,28 +76,32 @@ func NewSocks5Server(s string, dialer proxy.Dialer) (proxy.Server, error) { } // ListenAndServe serves socks5 requests. -func (s *SOCKS5) ListenAndServe() { +func (s *SOCKS5) ListenAndServe(c net.Conn) { go s.ListenAndServeUDP() - s.ListenAndServeTCP() + s.ListenAndServeTCP(c) } // ListenAndServeTCP . -func (s *SOCKS5) ListenAndServeTCP() { - l, err := net.Listen("tcp", s.addr) - if err != nil { - log.F("[socks5] failed to listen on %s: %v", s.addr, err) - return - } - - log.F("[socks5] listening TCP on %s", s.addr) - - for { - c, err := l.Accept() +func (s *SOCKS5) ListenAndServeTCP(c net.Conn) { + if c == nil { + l, err := net.Listen("tcp", s.addr) if err != nil { - log.F("[socks5] failed to accept: %v", err) - continue + log.F("[socks5] failed to listen on %s: %v", s.addr, err) + return } + log.F("[socks5] listening TCP on %s", s.addr) + + for { + c, err := l.Accept() + if err != nil { + log.F("[socks5] failed to accept: %v", err) + continue + } + + go s.ServeTCP(c) + } + } else { go s.ServeTCP(c) } } diff --git a/proxy/ss/ss.go b/proxy/ss/ss.go index fc54b0f..75491d2 100644 --- a/proxy/ss/ss.go +++ b/proxy/ss/ss.go @@ -66,27 +66,31 @@ func NewSSServer(s string, dialer proxy.Dialer) (proxy.Server, error) { } // ListenAndServe serves ss requests. -func (s *SS) ListenAndServe() { +func (s *SS) ListenAndServe(c net.Conn) { go s.ListenAndServeUDP() - s.ListenAndServeTCP() + s.ListenAndServeTCP(c) } // ListenAndServeTCP serves tcp ss requests. -func (s *SS) ListenAndServeTCP() { - l, err := net.Listen("tcp", s.addr) - if err != nil { - log.F("[ss] failed to listen on %s: %v", s.addr, err) - return - } - - log.F("[ss] listening TCP on %s", s.addr) - - for { - c, err := l.Accept() +func (s *SS) ListenAndServeTCP(c net.Conn) { + if c == nil { + l, err := net.Listen("tcp", s.addr) if err != nil { - log.F("[ss] failed to accept: %v", err) - continue + log.F("[ss] failed to listen on %s: %v", s.addr, err) + return } + + log.F("[ss] listening TCP on %s", s.addr) + + for { + c, err := l.Accept() + if err != nil { + log.F("[ss] failed to accept: %v", err) + continue + } + go s.ServeTCP(c) + } + } else { go s.ServeTCP(c) } } diff --git a/proxy/tcptun/tcptun.go b/proxy/tcptun/tcptun.go index 2f2a6c7..5dd9adf 100644 --- a/proxy/tcptun/tcptun.go +++ b/proxy/tcptun/tcptun.go @@ -48,7 +48,7 @@ func NewTCPTunServer(s string, dialer proxy.Dialer) (proxy.Server, error) { } // ListenAndServe . -func (s *TCPTun) ListenAndServe() { +func (s *TCPTun) ListenAndServe(_ net.Conn) { l, err := net.Listen("tcp", s.addr) if err != nil { log.F("failed to listen on %s: %v", s.addr, err) diff --git a/proxy/tls/tls.go b/proxy/tls/tls.go index d4f8cab..4b19d8c 100644 --- a/proxy/tls/tls.go +++ b/proxy/tls/tls.go @@ -3,6 +3,7 @@ package tls import ( stdtls "crypto/tls" "errors" + "fmt" "net" "net/url" "strings" @@ -18,10 +19,17 @@ type TLS struct { serverName string skipVerify bool + + certFile string + keyFile string + + server proxy.Server + serverProto string } func init() { proxy.RegisterDialer("tls", NewTLSDialer) + proxy.RegisterServer("tls", NewTLSTransport) } // NewTLS returns a tls proxy. @@ -48,6 +56,8 @@ func NewTLS(s string, dialer proxy.Dialer) (*TLS, error) { addr: addr, serverName: serverName, skipVerify: false, + certFile: "", + keyFile: "", } if skipVerify == "true" { @@ -57,6 +67,100 @@ func NewTLS(s string, dialer proxy.Dialer) (*TLS, error) { return p, nil } +// NewTLSServerTransport returns a tls transport layer before the real server +func NewTLSTransport(s string, dialer proxy.Dialer) (proxy.Server, error) { + transport := strings.Split(s, ",") + + // prepare transport listener + if len(transport) != 2 { + err := fmt.Errorf("malformd listener: %s", s) + log.F(err.Error()) + return nil, err + } + + u, err := url.Parse(transport[0]) + if err != nil { + log.F("parse url err: %s", err) + return nil, err + } + + // TODO: cert=&key= + query := u.Query() + + certFile := query.Get("cert") + keyFile := query.Get("key") + + addr := u.Host + colonPos := strings.LastIndex(addr, ":") + if colonPos == -1 { + colonPos = len(addr) + } + serverName := addr[:colonPos] + + p := &TLS{ + dialer: dialer, + addr: addr, + serverName: serverName, + skipVerify: false, + certFile: certFile, + keyFile: keyFile, + serverProto: transport[1], + } + + // prepare layer 7 server + p.server, err = proxy.ServerFromURL(transport[1], dialer) + + return p, nil +} + +func (s *TLS) ListenAndServe(c net.Conn) { + // c for TCP_FAST_OPEN + + var tlsConfig *stdtls.Config + + var ticketKey [32]byte + copy(ticketKey[:], "f8710951c1f6d0d95a95eed5e99b51f1") + + if s.certFile != "" && s.keyFile != "" { + cert, err := stdtls.LoadX509KeyPair(s.certFile, s.keyFile) + if err != nil { + log.F("unabled load cert: %s, key %s", s.certFile, s.keyFile) + return + } + + tlsConfig = &stdtls.Config{ + Certificates: []stdtls.Certificate{cert}, + MinVersion: stdtls.VersionTLS12, + MaxVersion: stdtls.VersionTLS13, + SessionTicketKey: ticketKey, + Accept0RTTData: true, + } + } else { + tlsConfig = nil + } + + l, err := stdtls.Listen("tcp", s.addr, tlsConfig) + if err != nil { + log.F("failed to listen on tls %s: %v", s.addr, err) + return + } + + defer l.Close() + + log.F("listening TCP on %s with TLS", s.addr) + + for { + c, err := l.Accept() + if err != nil { + log.F("[https] failed to accept: %v", err) + continue + } + + // it's callee's response to decide process request in sync/async mode. + s.server.ListenAndServe(c) + } +} + // NewTLSDialer returns a tls proxy dialer. func NewTLSDialer(s string, dialer proxy.Dialer) (proxy.Dialer, error) { return NewTLS(s, dialer) @@ -79,6 +183,9 @@ func (s *TLS) Dial(network, addr string) (net.Conn, error) { conf := &stdtls.Config{ ServerName: s.serverName, InsecureSkipVerify: s.skipVerify, + ClientSessionCache: stdtls.NewLRUClientSessionCache(64), + MinVersion: stdtls.VersionTLS12, + MaxVersion: stdtls.VersionTLS13, } c := stdtls.Client(cc, conf) diff --git a/proxy/tproxy/tproxy_linux.go b/proxy/tproxy/tproxy_linux.go index 6398eb4..3d96600 100644 --- a/proxy/tproxy/tproxy_linux.go +++ b/proxy/tproxy/tproxy_linux.go @@ -51,7 +51,7 @@ func NewTProxyServer(s string, dialer proxy.Dialer) (proxy.Server, error) { } // ListenAndServe . -func (s *TProxy) ListenAndServe() { +func (s *TProxy) ListenAndServe(_ net.Conn) { // go s.ListenAndServeTCP() s.ListenAndServeUDP() } diff --git a/proxy/udptun/udptun.go b/proxy/udptun/udptun.go index 8fb72ff..8ce8e9f 100644 --- a/proxy/udptun/udptun.go +++ b/proxy/udptun/udptun.go @@ -50,7 +50,7 @@ func NewUDPTunServer(s string, dialer proxy.Dialer) (proxy.Server, error) { } // ListenAndServe . -func (s *UDPTun) ListenAndServe() { +func (s *UDPTun) ListenAndServe(_ net.Conn) { c, err := net.ListenPacket("udp", s.addr) if err != nil { log.F("[udptun] failed to listen on %s: %v", s.addr, err) diff --git a/proxy/uottun/uottun.go b/proxy/uottun/uottun.go index f43418c..0da69a1 100644 --- a/proxy/uottun/uottun.go +++ b/proxy/uottun/uottun.go @@ -50,7 +50,7 @@ func NewUoTTunServer(s string, dialer proxy.Dialer) (proxy.Server, error) { } // ListenAndServe . -func (s *UoTTun) ListenAndServe() { +func (s *UoTTun) ListenAndServe(_ net.Conn) { c, err := net.ListenPacket("udp", s.addr) if err != nil { log.F("[uottun] failed to listen on %s: %v", s.addr, err)