add bypass support for handlers

This commit is contained in:
ginuerzh 2018-06-30 15:55:05 +08:00
parent c11b5ddce8
commit f292d8e76f
10 changed files with 127 additions and 57 deletions

View File

@ -146,7 +146,10 @@ func (bp *Bypass) Contains(addr string) bool {
if bp == nil { if bp == nil {
return false return false
} }
// try to strip the port
if host, _, _ := net.SplitHostPort(addr); host != "" {
addr = host
}
var matched bool var matched bool
for _, matcher := range bp.matchers { for _, matcher := range bp.matchers {
if matcher == nil { if matcher == nil {

View File

@ -5,7 +5,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"strings"
"github.com/go-log/log" "github.com/go-log/log"
) )
@ -269,13 +268,9 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
return return
} }
// NOTE: IPv6 will not work.
if strings.Contains(addr, ":") {
addr = strings.Split(addr, ":")[0]
}
if node.Bypass.Contains(addr) { if node.Bypass.Contains(addr) {
if Debug { 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()) log.Log("[route]", buf.String())
} }
return return
@ -297,6 +292,7 @@ func (c *Chain) selectRouteFor(addr string) (route *Chain, err error) {
route.Resolver = c.Resolver route.Resolver = c.Resolver
if Debug { if Debug {
buf.WriteString(addr)
log.Log("[route]", buf.String()) log.Log("[route]", buf.String())
} }
return return

View File

@ -444,12 +444,12 @@ func (r *route) serve() error {
var whitelist, blacklist *gost.Permissions var whitelist, blacklist *gost.Permissions
if node.Values.Get("whitelist") != "" { 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 return err
} }
} }
if node.Values.Get("blacklist") != "" { 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 return err
} }
} }
@ -463,6 +463,7 @@ func (r *route) serve() error {
gost.TLSConfigHandlerOption(tlsCfg), gost.TLSConfigHandlerOption(tlsCfg),
gost.WhitelistHandlerOption(whitelist), gost.WhitelistHandlerOption(whitelist),
gost.BlacklistHandlerOption(blacklist), gost.BlacklistHandlerOption(blacklist),
gost.BypassHandlerOption(parseBypass(node.Get("bypass"))),
) )
var handler gost.Handler var handler gost.Handler
switch node.Protocol { switch node.Protocol {
@ -502,9 +503,6 @@ func (r *route) serve() error {
} }
srv := &gost.Server{Listener: ln} srv := &gost.Server{Listener: ln}
srv.Init(
gost.BypassServerOption(parseBypass(node.Get("bypass"))),
)
chain.Resolver = parseResolver(node.Get("dns")) chain.Resolver = parseResolver(node.Get("dns"))
if gost.Debug { if gost.Debug {

View File

@ -24,6 +24,7 @@ type HandlerOptions struct {
TLSConfig *tls.Config TLSConfig *tls.Config
Whitelist *Permissions Whitelist *Permissions
Blacklist *Permissions Blacklist *Permissions
Bypass *Bypass
} }
// HandlerOption allows a common way to set handler options. // 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 { type autoHandler struct {
options []HandlerOption options []HandlerOption
} }

29
http.go
View File

@ -116,6 +116,13 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
return 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) { if !Can("tcp", req.Host, h.options.Whitelist, h.options.Blacklist) {
log.Logf("[http] Unauthorized to tcp connect to %s", req.Host) log.Logf("[http] Unauthorized to tcp connect to %s", req.Host)
b := []byte("HTTP/1.1 403 Forbidden\r\n" + b := []byte("HTTP/1.1 403 Forbidden\r\n" +
@ -127,6 +134,17 @@ func (h *httpHandler) handleRequest(conn net.Conn, req *http.Request) {
return 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")) u, p, _ := basicProxyAuth(req.Header.Get("Proxy-Authorization"))
if Debug && (u != "" || p != "") { if Debug && (u != "" || p != "") {
log.Logf("[http] %s - %s : Authorization: '%s' '%s'", conn.RemoteAddr(), req.Host, 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-Authorization")
// req.Header.Del("Proxy-Connection") // 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) route, err := h.options.Chain.selectRouteFor(req.Host)
if err != nil { if err != nil {
log.Logf("[http] %s -> %s : %s", conn.RemoteAddr(), req.Host, err) 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 host := req.Host
if !strings.Contains(host, ":") { if _, port, _ := net.SplitHostPort(host); port == "" {
host += ":80" host = net.JoinHostPort(req.Host, "80")
} }
cc, err := route.Dial(host) cc, err := route.Dial(host)

View File

@ -296,6 +296,12 @@ func (h *http2Handler) roundTrip(w http.ResponseWriter, r *http.Request) {
return 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")) u, p, _ := basicProxyAuth(r.Header.Get("Proxy-Authorization"))
if Debug && (u != "" || p != "") { if Debug && (u != "" || p != "") {
log.Logf("[http] %s - %s : Authorization: '%s' '%s'", r.RemoteAddr, target, u, p) log.Logf("[http] %s - %s : Authorization: '%s' '%s'", r.RemoteAddr, target, u, p)

View File

@ -71,9 +71,8 @@ func (s *Server) Serve(h Handler, opts ...ServerOption) error {
} }
tempDelay = 0 tempDelay = 0
ip := extractIP(conn.RemoteAddr()) if s.options.Bypass.Contains(conn.RemoteAddr().String()) {
if s.options.Bypass.Contains(ip.String()) { log.Log("[bypass]", conn.RemoteAddr())
log.Log("bypass", ip.String())
conn.Close() conn.Close()
continue continue
} }
@ -151,16 +150,3 @@ func transport(rw1, rw2 io.ReadWriter) error {
} }
return err 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
}

27
sni.go
View File

@ -33,13 +33,16 @@ func (c *sniConnector) Connect(conn net.Conn, addr string) (net.Conn, error) {
} }
type sniHandler struct { type sniHandler struct {
options []HandlerOption options *HandlerOptions
} }
// SNIHandler creates a server Handler for SNI proxy server. // SNIHandler creates a server Handler for SNI proxy server.
func SNIHandler(opts ...HandlerOption) Handler { func SNIHandler(opts ...HandlerOption) Handler {
h := &sniHandler{ h := &sniHandler{
options: opts, options: &HandlerOptions{},
}
for _, opt := range opts {
opt(h.options)
} }
return h return h
} }
@ -66,7 +69,8 @@ func (h *sniHandler) Handle(conn net.Conn) {
if !req.URL.IsAbs() { if !req.URL.IsAbs() {
req.URL.Scheme = "http" // make sure that the URL is absolute 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 return
} }
@ -76,19 +80,20 @@ func (h *sniHandler) Handle(conn net.Conn) {
return return
} }
options := &HandlerOptions{} addr := net.JoinHostPort(host, "443")
for _, opt := range h.options {
opt(options)
}
if !Can("tcp", host, options.Whitelist, options.Blacklist) { if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) {
log.Logf("[sni] Unauthorized to tcp connect to %s", host) log.Logf("[sni] Unauthorized to tcp connect to %s", addr)
return
}
if h.options.Bypass.Contains(addr) {
log.Log("[sni] [bypass]", addr)
return return
} }
cc, err := options.Chain.Dial(host + ":443") cc, err := h.options.Chain.Dial(addr)
if err != nil { if err != nil {
log.Logf("[sni] %s -> %s : %s", conn.RemoteAddr(), host, err) log.Logf("[sni] %s -> %s : %s", conn.RemoteAddr(), addr, err)
return return
} }
defer cc.Close() defer cc.Close()

View File

@ -419,6 +419,15 @@ func (h *socks5Handler) handleConnect(conn net.Conn, req *gosocks5.Request) {
} }
return 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) cc, err := h.options.Chain.Dial(addr)
if err != nil { if err != nil {
@ -716,6 +725,10 @@ func (h *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
if err != nil { if err != nil {
continue // drop silently 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 { if _, err := peer.WriteToUDP(dgram.Data, raddr); err != nil {
errc <- err errc <- err
return return
@ -738,6 +751,10 @@ func (h *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
if clientAddr == nil { if clientAddr == nil {
continue continue
} }
if h.options.Bypass.Contains(raddr.String()) {
log.Log("[socks5-udp] [bypass] read from", raddr)
continue // bypass
}
buf := bytes.Buffer{} buf := bytes.Buffer{}
dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(0, 0, toSocksAddr(raddr)), b[:n]) dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(0, 0, toSocksAddr(raddr)), b[:n])
dgram.Write(&buf) dgram.Write(&buf)
@ -785,6 +802,11 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error
if clientAddr == nil { if clientAddr == nil {
clientAddr = addr 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)) dgram.Header.Rsv = uint16(len(dgram.Data))
if err := dgram.Write(cc); err != nil { if err := dgram.Write(cc); err != nil {
errc <- err errc <- err
@ -809,6 +831,11 @@ func (h *socks5Handler) tunnelClientUDP(uc *net.UDPConn, cc net.Conn) (err error
if clientAddr == nil { if clientAddr == nil {
continue 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 dgram.Header.Rsv = 0
buf := bytes.Buffer{} buf := bytes.Buffer{}
@ -903,6 +930,10 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, uc *net.UDPConn) (err error
errc <- err errc <- err
return return
} }
if h.options.Bypass.Contains(addr.String()) {
log.Log("[udp-tun] [bypass] read from", addr)
continue // bypass
}
// pipe from peer to tunnel // pipe from peer to tunnel
dgram := gosocks5.NewUDPDatagram( dgram := gosocks5.NewUDPDatagram(
@ -932,6 +963,10 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, uc *net.UDPConn) (err error
if err != nil { if err != nil {
continue // drop silently 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 { if _, err := uc.WriteToUDP(dgram.Data, addr); err != nil {
log.Logf("[udp-tun] %s -> %s : %s", cc.RemoteAddr(), addr, err) log.Logf("[udp-tun] %s -> %s : %s", cc.RemoteAddr(), addr, err)
errc <- 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) { if !Can("tcp", addr, h.options.Whitelist, h.options.Blacklist) {
log.Logf("[socks4-connect] Unauthorized to tcp connect to %s", addr) 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) rep.Write(conn)
if Debug { if Debug {
log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep) log.Logf("[socks4-connect] %s <- %s\n%s", conn.RemoteAddr(), req.Addr, rep)

29
ss.go
View File

@ -140,6 +140,11 @@ func (h *shadowHandler) Handle(conn net.Conn) {
return return
} }
if h.options.Bypass.Contains(addr) {
log.Logf("[ss] [bypass] %s", addr)
return
}
cc, err := h.options.Chain.Dial(addr) cc, err := h.options.Chain.Dial(addr)
if err != nil { if err != nil {
log.Logf("[ss] %s -> %s : %s", conn.RemoteAddr(), addr, err) log.Logf("[ss] %s -> %s : %s", conn.RemoteAddr(), addr, err)
@ -353,11 +358,11 @@ func (h *shadowUDPdHandler) Handle(conn net.Conn) {
defer cc.Close() defer cc.Close()
log.Logf("[ssu] %s <-> %s", conn.RemoteAddr(), conn.LocalAddr()) 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()) 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) errc := make(chan error, 1)
go func() { go func() {
for { for {
@ -374,14 +379,18 @@ func transportUDP(sc net.Conn, cc net.PacketConn) error {
errc <- err errc <- err
return return
} }
//if Debug { if Debug {
// log.Logf("[ssu] %s >>> %s length: %d", sc.RemoteAddr(), dgram.Header.Addr.String(), len(dgram.Data)) 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()) addr, err := net.ResolveUDPAddr("udp", dgram.Header.Addr.String())
if err != nil { if err != nil {
errc <- err errc <- err
return 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 { if _, err := cc.WriteTo(dgram.Data, addr); err != nil {
errc <- err errc <- err
return return
@ -397,9 +406,13 @@ func transportUDP(sc net.Conn, cc net.PacketConn) error {
errc <- err errc <- err
return return
} }
//if Debug { if Debug {
// log.Logf("[ssu] %s <<< %s length: %d", sc.RemoteAddr(), addr, n) 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]) dgram := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(0, 0, toSocksAddr(addr)), b[:n])
buf := bytes.Buffer{} buf := bytes.Buffer{}
dgram.Write(&buf) dgram.Write(&buf)