diff --git a/bypass.go b/bypass.go index 6608fb5..fdeaa13 100644 --- a/bypass.go +++ b/bypass.go @@ -146,7 +146,10 @@ func (bp *Bypass) Contains(addr string) bool { if bp == nil { return false } - + // try to strip the port + if host, _, _ := net.SplitHostPort(addr); host != "" { + addr = host + } var matched bool for _, matcher := range bp.matchers { if matcher == nil { diff --git a/chain.go b/chain.go index 1e553db..45831e3 100644 --- a/chain.go +++ b/chain.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "net" - "strings" "github.com/go-log/log" ) @@ -269,13 +268,9 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) { return } - // NOTE: IPv6 will not work. - if strings.Contains(addr, ":") { - addr = strings.Split(addr, ":")[0] - } if node.Bypass.Contains(addr) { if Debug { - buf.WriteString(fmt.Sprintf("[%d@bypass: %s]", node.ID, addr)) + buf.WriteString(fmt.Sprintf("[bypass]%s -> %s", node.String(), addr)) log.Log("[route]", buf.String()) } return @@ -297,6 +292,7 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) { route.Resolver = c.Resolver if Debug { + buf.WriteString(addr) log.Log("[route]", buf.String()) } return diff --git a/cmd/gost/main.go b/cmd/gost/main.go index df91498..4cdaf1b 100644 --- a/cmd/gost/main.go +++ b/cmd/gost/main.go @@ -444,12 +444,12 @@ func (r *route) serve() error { var whitelist, blacklist *gost.Permissions if node.Values.Get("whitelist") != "" { - if whitelist, err = gost.ParsePermissions(node.Values.Get("whitelist")); err != nil { + if whitelist, err = gost.ParsePermissions(node.Get("whitelist")); err != nil { return err } } if node.Values.Get("blacklist") != "" { - if blacklist, err = gost.ParsePermissions(node.Values.Get("blacklist")); err != nil { + if blacklist, err = gost.ParsePermissions(node.Get("blacklist")); err != nil { return err } } @@ -463,6 +463,7 @@ func (r *route) serve() error { gost.TLSConfigHandlerOption(tlsCfg), gost.WhitelistHandlerOption(whitelist), gost.BlacklistHandlerOption(blacklist), + gost.BypassHandlerOption(parseBypass(node.Get("bypass"))), ) var handler gost.Handler switch node.Protocol { @@ -502,9 +503,6 @@ func (r *route) serve() error { } srv := &gost.Server{Listener: ln} - srv.Init( - gost.BypassServerOption(parseBypass(node.Get("bypass"))), - ) chain.Resolver = parseResolver(node.Get("dns")) if gost.Debug { diff --git a/handler.go b/handler.go index 515e355..f0802e7 100644 --- a/handler.go +++ b/handler.go @@ -24,6 +24,7 @@ type HandlerOptions struct { TLSConfig *tls.Config Whitelist *Permissions Blacklist *Permissions + Bypass *Bypass } // HandlerOption allows a common way to set handler options. @@ -71,6 +72,13 @@ func BlacklistHandlerOption(blacklist *Permissions) HandlerOption { } } +// BypassHandlerOption sets the bypass option of HandlerOptions. +func BypassHandlerOption(bypass *Bypass) HandlerOption { + return func(opts *HandlerOptions) { + opts.Bypass = bypass + } +} + type autoHandler struct { options []HandlerOption } diff --git a/http.go b/http.go index ccd8bea..c7f226f 100644 --- a/http.go +++ b/http.go @@ -116,6 +116,13 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) { return } + // try to get the actual host. + if v := req.Header.Get("Gost-Target"); v != "" { + if host, err := decodeServerName(v); err == nil { + req.Host = host + } + } + if !Can("tcp", req.Host, h.options.Whitelist, h.options.Blacklist) { log.Logf("[http] Unauthorized to tcp connect to %s", req.Host) b := []byte("HTTP/1.1 403 Forbidden\r\n" + @@ -127,6 +134,17 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) { return } + if h.options.Bypass.Contains(req.Host) { + log.Logf("[http] [bypass] %s", req.Host) + b := []byte("HTTP/1.1 403 Forbidden\r\n" + + "Proxy-Agent: gost/" + Version + "\r\n\r\n") + conn.Write(b) + if Debug { + log.Logf("[http] %s <- %s\n%s", conn.RemoteAddr(), req.Host, string(b)) + } + return + } + u, p, _ := basicProxyAuth(req.Header.Get("Proxy-Authorization")) if Debug && (u != "" || p != "") { log.Logf("[http] %s - %s : Authorization: '%s' '%s'", conn.RemoteAddr(), req.Host, u, p) @@ -143,13 +161,6 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) { req.Header.Del("Proxy-Authorization") // req.Header.Del("Proxy-Connection") - // try to get the actual host. - if v := req.Header.Get("Gost-Target"); v != "" { - if host, err := decodeServerName(v); err == nil { - req.Host = host - } - } - route, err := h.options.Chain.selectRouteFor(req.Host) if err != nil { log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), req.Host, err) @@ -163,8 +174,8 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) { } host := req.Host - if !strings.Contains(host, ":") { - host += ":80" + if _, port, _ := net.SplitHostPort(host); port == "" { + host = net.JoinHostPort(req.Host, "80") } cc, err := route.Dial(host) diff --git a/http2.go b/http2.go index 340d471..f3cef57 100644 --- a/http2.go +++ b/http2.go @@ -296,6 +296,12 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) { return } + if h.options.Bypass.Contains(target) { + log.Logf("[http2] [bypass] %s", target) + w.WriteHeader(http.StatusForbidden) + return + } + u, p, _ := basicProxyAuth(r.Header.Get("Proxy-Authorization")) if Debug && (u != "" || p != "") { log.Logf("[http] %s - %s : Authorization: '%s' '%s'", r.RemoteAddr, target, u, p) diff --git a/server.go b/server.go index ea3ca75..29c1212 100644 --- a/server.go +++ b/server.go @@ -71,9 +71,8 @@ func (s *Server) Serve(h Handler, opts ...ServerOption) error { } tempDelay = 0 - ip := extractIP(conn.RemoteAddr()) - if s.options.Bypass.Contains(ip.String()) { - log.Log("bypass", ip.String()) + if s.options.Bypass.Contains(conn.RemoteAddr().String()) { + log.Log("[bypass]", conn.RemoteAddr()) conn.Close() continue } @@ -151,16 +150,3 @@ func transport(rw1, rw2 io.ReadWriter) error { } return err } - -func extractIP(addr net.Addr) net.IP { - switch v := addr.(type) { - case *net.IPAddr: - return v.IP - case *net.TCPAddr: - return v.IP - case *net.UDPAddr: - return v.IP - default: - } - return net.IPv4zero -} diff --git a/sni.go b/sni.go index 0cc6719..321737f 100644 --- a/sni.go +++ b/sni.go @@ -33,13 +33,16 @@ func (c *sniConnector) Connect(conn net.Conn, addr string) (net.Conn, error) { } type sniHandler struct { - options []HandlerOption + options *HandlerOptions } // SNIHandler creates a server Handler for SNI proxy server. func SNIHandler(opts ...HandlerOption) Handler { h := &sniHandler{ - options: opts, + options: &HandlerOptions{}, + } + for _, opt := range opts { + opt(h.options) } return h } @@ -66,7 +69,8 @@ func (h *sniHandler) Handle(conn net.Conn) { if !req.URL.IsAbs() { req.URL.Scheme = "http" // make sure that the URL is absolute } - HTTPHandler(h.options...).(*httpHandler).handleRequest(conn, req) + handler := &httpHandler{options: h.options} + handler.handleRequest(conn, req) return } @@ -76,19 +80,20 @@ func (h *sniHandler) Handle(conn net.Conn) { return } - options := &HandlerOptions{} - for _, opt := range h.options { - opt(options) - } + addr := net.JoinHostPort(host, "443") - if !Can("tcp", host, options.Whitelist, options.Blacklist) { - log.Logf("[sni] Unauthorized to tcp connect to %s", host) + if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) { + log.Logf("[sni] Unauthorized to tcp connect to %s", addr) + return + } + if h.options.Bypass.Contains(addr) { + log.Log("[sni] [bypass]", addr) return } - cc, err := options.Chain.Dial(host + ":443") + cc, err := h.options.Chain.Dial(addr) if err != nil { - log.Logf("[sni] %s -> %s : %s", conn.RemoteAddr(), host, err) + log.Logf("[sni] %s -> %s : %s", conn.RemoteAddr(), addr, err) return } defer cc.Close() diff --git a/socks.go b/socks.go index 35e7800..177e24c 100644 --- a/socks.go +++ b/socks.go @@ -419,6 +419,15 @@ func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) { } return } + if h.options.Bypass.Contains(addr) { + log.Logf("[socks5-connect] [bypass] %s", addr) + rep := gosocks5.NewReply(gosocks5.NotAllowed, nil) + rep.Write(conn) + if Debug { + log.Logf("[socks5-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep) + } + return + } cc, err := h.options.Chain.Dial(addr) if err != nil { @@ -716,6 +725,10 @@ func (h *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) { if err != nil { continue // drop silently } + if h.options.Bypass.Contains(raddr.String()) { + log.Log("[socks5-udp] [bypass] write to", raddr) + continue // bypass + } if _, err := peer.WriteToUDP(dgram.Data, raddr); err != nil { errc <- err return @@ -738,6 +751,10 @@ func (h *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) { if clientAddr == nil { continue } + if h.options.Bypass.Contains(raddr.String()) { + log.Log("[socks5-udp] [bypass] read from", raddr) + continue // bypass + } buf := bytes.Buffer{} dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(0, 0, toSocksAddr(raddr)), b[:n]) dgram.Write(&buf) @@ -785,6 +802,11 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error if clientAddr == nil { clientAddr = addr } + raddr := dgram.Header.Addr.String() + if h.options.Bypass.Contains(raddr) { + log.Log("[udp-tun] [bypass] write to", raddr) + continue // bypass + } dgram.Header.Rsv = uint16(len(dgram.Data)) if err := dgram.Write(cc); err != nil { errc <- err @@ -809,6 +831,11 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error if clientAddr == nil { continue } + raddr := dgram.Header.Addr.String() + if h.options.Bypass.Contains(raddr) { + log.Log("[udp-tun] [bypass] read from", raddr) + continue // bypass + } dgram.Header.Rsv = 0 buf := bytes.Buffer{} @@ -903,6 +930,10 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, uc *net.UDPConn) (err error errc <- err return } + if h.options.Bypass.Contains(addr.String()) { + log.Log("[udp-tun] [bypass] read from", addr) + continue // bypass + } // pipe from peer to tunnel dgram := gosocks5.NewUDPDatagram( @@ -932,6 +963,10 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, uc *net.UDPConn) (err error if err != nil { continue // drop silently } + if h.options.Bypass.Contains(addr.String()) { + log.Log("[udp-tun] [bypass] write to", addr) + continue // bypass + } if _, err := uc.WriteToUDP(dgram.Data, addr); err != nil { log.Logf("[udp-tun] %s -> %s : %s", cc.RemoteAddr(), addr, err) errc <- err @@ -1116,7 +1151,16 @@ func (h *socks4Handler) handleConnect(conn net.Conn, req *gosocks4.Request) { if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) { log.Logf("[socks4-connect] Unauthorized to tcp connect to %s", addr) - rep := gosocks5.NewReply(gosocks4.Rejected, nil) + rep := gosocks4.NewReply(gosocks4.Rejected, nil) + rep.Write(conn) + if Debug { + log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep) + } + return + } + if h.options.Bypass.Contains(addr) { + log.Log("[socks4-connect] [bypass]", addr) + rep := gosocks4.NewReply(gosocks4.Rejected, nil) rep.Write(conn) if Debug { log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep) diff --git a/ss.go b/ss.go index e180cb6..6bfc694 100644 --- a/ss.go +++ b/ss.go @@ -140,6 +140,11 @@ func (h *shadowHandler) Handle(conn net.Conn) { return } + if h.options.Bypass.Contains(addr) { + log.Logf("[ss] [bypass] %s", addr) + return + } + cc, err := h.options.Chain.Dial(addr) if err != nil { log.Logf("[ss] %s -> %s : %s", conn.RemoteAddr(), addr, err) @@ -353,11 +358,11 @@ func (h *shadowUDPdHandler) Handle(conn net.Conn) { defer cc.Close() log.Logf("[ssu] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr()) - transportUDP(conn, cc) + h.transportUDP(conn, cc) log.Logf("[ssu] %s >-< %s", conn.RemoteAddr(), conn.LocalAddr()) } -func transportUDP(sc net.Conn, cc net.PacketConn) error { +func (h *shadowUDPdHandler) transportUDP(sc net.Conn, cc net.PacketConn) error { errc := make(chan error, 1) go func() { for { @@ -374,14 +379,18 @@ func transportUDP(sc net.Conn, cc net.PacketConn) error { errc <- err return } - //if Debug { - // log.Logf("[ssu] %s >>> %s length: %d", sc.RemoteAddr(), dgram.Header.Addr.String(), len(dgram.Data)) - //} + if Debug { + log.Logf("[ssu] %s >>> %s length: %d", sc.RemoteAddr(), dgram.Header.Addr.String(), len(dgram.Data)) + } addr, err := net.ResolveUDPAddr("udp", dgram.Header.Addr.String()) if err != nil { errc <- err return } + if h.options.Bypass.Contains(addr.String()) { + log.Log("[ssu] [bypass] write to", addr) + continue // bypass + } if _, err := cc.WriteTo(dgram.Data, addr); err != nil { errc <- err return @@ -397,9 +406,13 @@ func transportUDP(sc net.Conn, cc net.PacketConn) error { errc <- err return } - //if Debug { - // log.Logf("[ssu] %s <<< %s length: %d", sc.RemoteAddr(), addr, n) - //} + if Debug { + log.Logf("[ssu] %s <<< %s length: %d", sc.RemoteAddr(), addr, n) + } + if h.options.Bypass.Contains(addr.String()) { + log.Log("[ssu] [bypass] read from", addr) + continue // bypass + } dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(0, 0, toSocksAddr(addr)), b[:n]) buf := bytes.Buffer{} dgram.Write(&buf)