add bypass support for handlers
This commit is contained in:
parent
c11b5ddce8
commit
f292d8e76f
@ -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 {
|
||||
|
8
chain.go
8
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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
29
http.go
29
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)
|
||||
|
6
http2.go
6
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)
|
||||
|
18
server.go
18
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
|
||||
}
|
||||
|
27
sni.go
27
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()
|
||||
|
46
socks.go
46
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)
|
||||
|
29
ss.go
29
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)
|
||||
|
Loading…
Reference in New Issue
Block a user