add network for bypass

This commit is contained in:
ginuerzh 2023-09-30 17:51:55 +08:00
parent ea585fc25d
commit 836cf6eade
24 changed files with 92 additions and 160 deletions

View File

@ -232,7 +232,7 @@ func (bp *localBypass) parsePatterns(r io.Reader) (patterns []string, err error)
return
}
func (bp *localBypass) Contains(ctx context.Context, addr string) bool {
func (bp *localBypass) Contains(ctx context.Context, network, addr string, opts ...bypass.Option) bool {
if addr == "" || bp == nil {
return false
}

View File

@ -10,8 +10,8 @@ import (
"github.com/go-gost/core/bypass"
"github.com/go-gost/core/logger"
"github.com/go-gost/plugin/bypass/proto"
auth_util "github.com/go-gost/x/internal/util/auth"
"github.com/go-gost/x/internal/plugin"
auth_util "github.com/go-gost/x/internal/util/auth"
"google.golang.org/grpc"
)
@ -47,14 +47,21 @@ func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) bypass.Bypas
return p
}
func (p *grpcPlugin) Contains(ctx context.Context, addr string) bool {
func (p *grpcPlugin) Contains(ctx context.Context, network, addr string, opts ...bypass.Option) bool {
if p.client == nil {
return true
}
var options bypass.Options
for _, opt := range opts {
opt(&options)
}
r, err := p.client.Bypass(ctx,
&proto.BypassRequest{
Network: network,
Addr: addr,
Host: options.Host,
Client: string(auth_util.IDFromContext(ctx)),
})
if err != nil {
@ -72,7 +79,9 @@ func (p *grpcPlugin) Close() error {
}
type httpPluginRequest struct {
Network string `json:"network"`
Addr string `json:"addr"`
Host string `json:"host"`
Client string `json:"client"`
}
@ -105,13 +114,20 @@ func NewHTTPPlugin(name string, url string, opts ...plugin.Option) bypass.Bypass
}
}
func (p *httpPlugin) Contains(ctx context.Context, addr string) (ok bool) {
func (p *httpPlugin) Contains(ctx context.Context, network, addr string, opts ...bypass.Option) (ok bool) {
if p.client == nil {
return
}
var options bypass.Options
for _, opt := range opts {
opt(&options)
}
rb := httpPluginRequest{
Network: network,
Addr: addr,
Host: options.Host,
Client: string(auth_util.IDFromContext(ctx)),
}
v, err := json.Marshal(&rb)

View File

@ -79,14 +79,23 @@ func (c *Chain) Name() string {
return c.name
}
func (c *Chain) Route(ctx context.Context, network, address string) chain.Route {
func (c *Chain) Route(ctx context.Context, network, address string, opts ...chain.RouteOption) chain.Route {
if c == nil || len(c.hops) == 0 {
return nil
}
var options chain.RouteOptions
for _, opt := range opts {
opt(&options)
}
rt := NewRoute(ChainRouteOption(c))
for _, h := range c.hops {
node := h.Select(ctx, hop.AddrSelectOption(address))
node := h.Select(ctx,
hop.NetworkSelectOption(network),
hop.AddrSelectOption(address),
hop.HostSelectOption(options.Host),
)
if node == nil {
return rt
}
@ -117,9 +126,9 @@ func (p *chainGroup) WithSelector(s selector.Selector[chain.Chainer]) *chainGrou
return p
}
func (p *chainGroup) Route(ctx context.Context, network, address string) chain.Route {
func (p *chainGroup) Route(ctx context.Context, network, address string, opts ...chain.RouteOption) chain.Route {
if chain := p.next(ctx); chain != nil {
return chain.Route(ctx, network, address)
return chain.Route(ctx, network, address, opts...)
}
return nil
}

4
go.mod
View File

@ -7,10 +7,10 @@ require (
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/gin-contrib/cors v1.3.1
github.com/gin-gonic/gin v1.9.1
github.com/go-gost/core v0.0.0-20230928130125-b0bd45c1b862
github.com/go-gost/core v0.0.0-20230930094840-bf3b76a27306
github.com/go-gost/gosocks4 v0.0.1
github.com/go-gost/gosocks5 v0.4.0
github.com/go-gost/plugin v0.0.0-20230928130211-8bc0679b5c15
github.com/go-gost/plugin v0.0.0-20230930094933-bc86458bf2fb
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451
github.com/go-redis/redis/v8 v8.11.5

4
go.sum
View File

@ -102,12 +102,16 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gost/core v0.0.0-20230928130125-b0bd45c1b862 h1:hbCHyfYE96WZefTBitiL35FCYxHCgEWpS+W/5oCyEXk=
github.com/go-gost/core v0.0.0-20230928130125-b0bd45c1b862/go.mod h1:ndkgWVYRLwupVaFFWv8ML1Nr8tD3xhHK245PLpUDg4E=
github.com/go-gost/core v0.0.0-20230930094840-bf3b76a27306 h1:+5jZhk7GTofLvcxwUQrthj1Vwyk73h3B7ux0gJ3BeQ0=
github.com/go-gost/core v0.0.0-20230930094840-bf3b76a27306/go.mod h1:ndkgWVYRLwupVaFFWv8ML1Nr8tD3xhHK245PLpUDg4E=
github.com/go-gost/gosocks4 v0.0.1 h1:+k1sec8HlELuQV7rWftIkmy8UijzUt2I6t+iMPlGB2s=
github.com/go-gost/gosocks4 v0.0.1/go.mod h1:3B6L47HbU/qugDg4JnoFPHgJXE43Inz8Bah1QaN9qCc=
github.com/go-gost/gosocks5 v0.4.0 h1:EIrOEkpJez4gwHrMa33frA+hHXJyevjp47thpMQsJzI=
github.com/go-gost/gosocks5 v0.4.0/go.mod h1:1G6I7HP7VFVxveGkoK8mnprnJqSqJjdcASKsdUn4Pp4=
github.com/go-gost/plugin v0.0.0-20230928130211-8bc0679b5c15 h1:SKPbGuJUBKhh4qE2G5juT4PNMrzYH86itiY3TGwvYcs=
github.com/go-gost/plugin v0.0.0-20230928130211-8bc0679b5c15/go.mod h1:mM/RLNsVy2nz5PiOijuqLYR3LhMzyQ9Kh/p0rXybJoo=
github.com/go-gost/plugin v0.0.0-20230930094933-bc86458bf2fb h1:pJP1zrNLyKPsDQhL+ITyP2uCaS4Kax9T4ap2dZF3QaM=
github.com/go-gost/plugin v0.0.0-20230930094933-bc86458bf2fb/go.mod h1:mM/RLNsVy2nz5PiOijuqLYR3LhMzyQ9Kh/p0rXybJoo=
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7 h1:qAG1OyjvdA5h221CfFSS3J359V3d2E7dJWyP29QoDSI=
github.com/go-gost/relay v0.4.1-0.20230916134211-828f314ddfe7/go.mod h1:lcX+23LCQ3khIeASBo+tJ/WbwXFO32/N5YN6ucuYTG8=
github.com/go-gost/tls-dissector v0.0.2-0.20220408131628-aac992c27451 h1:xj8gUZGYO3nb5+6Bjw9+tsFkA9sYynrOvDvvC4uDV2I=

View File

@ -199,7 +199,7 @@ func (h *dnsHandler) request(ctx context.Context, msg []byte, log logger.Logger)
}
if h.options.Bypass != nil && mq.Question[0].Qclass == dns.ClassINET {
if h.options.Bypass.Contains(context.Background(), strings.Trim(mq.Question[0].Name, ".")) {
if h.options.Bypass.Contains(context.Background(), "udp", strings.Trim(mq.Question[0].Name, ".")) {
log.Debug("bypass: ", mq.Question[0].Name)
mr = (&dns.Msg{}).SetReply(&mq)
b := bufpool.Get(h.md.bufferSize)

View File

@ -154,7 +154,7 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
}
ctx = auth_util.ContextWithID(ctx, auth_util.ID(id))
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, addr) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, network, addr) {
resp.StatusCode = http.StatusForbidden
if log.IsLevelEnabled(logger.TraceLevel) {

View File

@ -155,7 +155,7 @@ func (h *http2Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req
}
ctx = auth_util.ContextWithID(ctx, auth_util.ID(id))
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, addr) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, "tcp", addr) {
w.WriteHeader(http.StatusForbidden)
log.Debug("bypass: ", addr)
return nil

View File

@ -10,8 +10,8 @@ import (
"time"
"github.com/go-gost/core/chain"
"github.com/go-gost/core/hop"
"github.com/go-gost/core/handler"
"github.com/go-gost/core/hop"
"github.com/go-gost/core/logger"
md "github.com/go-gost/core/metadata"
sx "github.com/go-gost/x/internal/util/selector"
@ -106,7 +106,7 @@ func (h *http3Handler) roundTrip(ctx context.Context, w http.ResponseWriter, req
w.Header().Set(k, h.md.header.Get(k))
}
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, addr) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, "udp", addr) {
w.WriteHeader(http.StatusForbidden)
log.Debug("bypass: ", addr)
return nil

View File

@ -122,7 +122,7 @@ func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn, opts ...han
log.Debugf("%s >> %s", conn.RemoteAddr(), dstAddr)
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, dstAddr.String()) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, dstAddr.Network(), dstAddr.String()) {
log.Debug("bypass: ", dstAddr)
return nil
}
@ -163,7 +163,7 @@ func (h *redirectHandler) handleHTTP(ctx context.Context, rw io.ReadWriter, radd
"host": host,
})
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, host) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, "tcp", host) {
log.Debug("bypass: ", host)
return nil
}
@ -232,7 +232,7 @@ func (h *redirectHandler) handleHTTPS(ctx context.Context, rw io.ReadWriter, rad
"host": host,
})
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, host) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, "tcp", host) {
log.Debug("bypass: ", host)
return nil
}

View File

@ -75,7 +75,7 @@ func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn, opts ...han
log.Debugf("%s >> %s", conn.RemoteAddr(), dstAddr)
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, dstAddr.String()) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, dstAddr.Network(), dstAddr.String()) {
log.Debug("bypass: ", dstAddr)
return nil
}

View File

@ -44,7 +44,7 @@ func (h *relayHandler) handleConnect(ctx context.Context, conn net.Conn, network
return
}
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, address) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, network, address) {
log.Debug("bypass: ", address)
resp.Status = relay.StatusForbidden
_, err = resp.WriteTo(conn)
@ -131,7 +131,7 @@ func (h *relayHandler) handleConnectTunnel(ctx context.Context, conn net.Conn, n
host, sp, _ := net.SplitHostPort(address)
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, address) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, network, address) {
log.Debug("bypass: ", address)
resp.Status = relay.StatusForbidden
_, err := resp.WriteTo(conn)

View File

@ -115,7 +115,7 @@ func (h *sniHandler) handleHTTP(ctx context.Context, rw io.ReadWriter, raddr net
"host": host,
})
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, host) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, "tcp", host) {
log.Debug("bypass: ", host)
return nil
}
@ -183,7 +183,7 @@ func (h *sniHandler) handleHTTPS(ctx context.Context, rw io.ReadWriter, raddr ne
})
log.Debugf("%s >> %s", raddr, host)
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, host) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, "tcp", host) {
log.Debug("bypass: ", host)
return nil
}

View File

@ -123,7 +123,7 @@ func (h *socks4Handler) handleConnect(ctx context.Context, conn net.Conn, req *g
})
log.Debugf("%s >> %s", conn.RemoteAddr(), addr)
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, addr) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, "tcp", addr) {
resp := gosocks4.NewReply(gosocks4.Rejected, nil)
log.Trace(resp)
log.Debug("bypass: ", addr)

View File

@ -19,7 +19,7 @@ func (h *socks5Handler) handleConnect(ctx context.Context, conn net.Conn, networ
})
log.Debugf("%s >> %s", conn.RemoteAddr(), address)
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, address) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, network, address) {
resp := gosocks5.NewReply(gosocks5.NotAllowed, nil)
log.Trace(resp)
log.Debug("bypass: ", address)

View File

@ -1,99 +0,0 @@
package v5
import (
"context"
"crypto/tls"
"net"
"github.com/go-gost/core/auth"
"github.com/go-gost/core/logger"
"github.com/go-gost/gosocks5"
auth_util "github.com/go-gost/x/internal/util/auth"
"github.com/go-gost/x/internal/util/socks"
)
type serverSelector struct {
methods []uint8
Authenticator auth.Authenticator
TLSConfig *tls.Config
logger logger.Logger
noTLS bool
}
func (selector *serverSelector) Methods() []uint8 {
return selector.methods
}
func (s *serverSelector) Select(methods ...uint8) (method uint8) {
s.logger.Debugf("%d %d %v", gosocks5.Ver5, len(methods), methods)
method = gosocks5.MethodNoAuth
for _, m := range methods {
if m == socks.MethodTLS && !s.noTLS {
method = m
break
}
}
// when Authenticator is set, auth is mandatory
if s.Authenticator != nil {
if method == gosocks5.MethodNoAuth {
method = gosocks5.MethodUserPass
}
if method == socks.MethodTLS && !s.noTLS {
method = socks.MethodTLSAuth
}
}
return
}
func (s *serverSelector) OnSelected(method uint8, conn net.Conn) (string, net.Conn, error) {
s.logger.Debugf("%d %d", gosocks5.Ver5, method)
switch method {
case socks.MethodTLS:
conn = tls.Server(conn, s.TLSConfig)
return "", conn, nil
case gosocks5.MethodUserPass, socks.MethodTLSAuth:
if method == socks.MethodTLSAuth {
conn = tls.Server(conn, s.TLSConfig)
}
req, err := gosocks5.ReadUserPassRequest(conn)
if err != nil {
s.logger.Error(err)
return "", nil, err
}
s.logger.Trace(req)
var id string
if s.Authenticator != nil {
var ok bool
ctx := auth_util.ContextWithClientAddr(context.Background(), auth_util.ClientAddr(conn.RemoteAddr().String()))
id, ok = s.Authenticator.Authenticate(ctx, req.Username, req.Password)
if !ok {
resp := gosocks5.NewUserPassResponse(gosocks5.UserPassVer, gosocks5.Failure)
if err := resp.Write(conn); err != nil {
s.logger.Error(err)
return "", nil, err
}
s.logger.Info(resp)
return "", nil, gosocks5.ErrAuthFailure
}
}
resp := gosocks5.NewUserPassResponse(gosocks5.UserPassVer, gosocks5.Succeeded)
s.logger.Trace(resp)
if err := resp.Write(conn); err != nil {
s.logger.Error(err)
return "", nil, err
}
return id, conn, nil
case gosocks5.MethodNoAcceptable:
return "", nil, gosocks5.ErrBadMethod
default:
return "", nil, gosocks5.ErrBadFormat
}
}

View File

@ -101,7 +101,7 @@ func (h *ssHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.H
log.Debugf("%s >> %s", conn.RemoteAddr(), addr)
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, addr.String()) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, "tcp", addr.String()) {
log.Debug("bypass: ", addr.String())
return nil
}

View File

@ -135,7 +135,7 @@ func (h *ssuHandler) relayPacket(pc1, pc2 net.PacketConn, log logger.Logger) (er
return err
}
if h.options.Bypass != nil && h.options.Bypass.Contains(context.Background(), addr.String()) {
if h.options.Bypass != nil && h.options.Bypass.Contains(context.Background(), addr.Network(), addr.String()) {
log.Warn("bypass: ", addr)
return nil
}
@ -167,7 +167,7 @@ func (h *ssuHandler) relayPacket(pc1, pc2 net.PacketConn, log logger.Logger) (er
return err
}
if h.options.Bypass != nil && h.options.Bypass.Contains(context.Background(), raddr.String()) {
if h.options.Bypass != nil && h.options.Bypass.Contains(context.Background(), raddr.Network(), raddr.String()) {
log.Warn("bypass: ", raddr)
return nil
}

View File

@ -92,7 +92,7 @@ func (h *forwardHandler) handleDirectForward(ctx context.Context, conn *sshd_uti
log.Debugf("%s >> %s", conn.RemoteAddr(), targetAddr)
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, targetAddr) {
if h.options.Bypass != nil && h.options.Bypass.Contains(ctx, "tcp", targetAddr) {
log.Debugf("bypass %s", targetAddr)
return nil
}

View File

@ -139,7 +139,7 @@ func (p *chainHop) Select(ctx context.Context, opts ...hop.SelectOption) *chain.
// hop level bypass
if p.options.bypass != nil &&
p.options.bypass.Contains(ctx, options.Addr) {
p.options.bypass.Contains(ctx, options.Network, options.Addr, bypass.WithHostOpton(options.Host)) {
return nil
}
@ -186,7 +186,7 @@ func (p *chainHop) Select(ctx context.Context, opts ...hop.SelectOption) *chain.
}
// node level bypass
if node.Options().Bypass != nil &&
node.Options().Bypass.Contains(ctx, options.Addr) {
node.Options().Bypass.Contains(ctx, options.Network, options.Addr, bypass.WithHostOpton(options.Host)) {
continue
}

View File

@ -26,7 +26,7 @@ type grpcPlugin struct {
}
// NewGRPCPlugin creates a Hop plugin based on gRPC.
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) hop.Hop{
func NewGRPCPlugin(name string, addr string, opts ...plugin.Option) hop.Hop {
var options plugin.Options
for _, opt := range opts {
opt(&options)
@ -64,6 +64,7 @@ func (p *grpcPlugin) Select(ctx context.Context, opts ...hop.SelectOption) *chai
r, err := p.client.Select(ctx,
&proto.SelectRequest{
Network: options.Network,
Addr: options.Addr,
Host: options.Host,
Client: string(auth_util.IDFromContext(ctx)),
@ -118,7 +119,7 @@ type httpPlugin struct {
}
// NewHTTPPlugin creates an Hop plugin based on HTTP.
func NewHTTPPlugin(name string, url string, opts ...plugin.Option) hop.Hop{
func NewHTTPPlugin(name string, url string, opts ...plugin.Option) hop.Hop {
var options plugin.Options
for _, opt := range opts {
opt(&options)
@ -147,6 +148,7 @@ func (p *httpPlugin) Select(ctx context.Context, opts ...hop.SelectOption) *chai
}
rb := httpPluginRequest{
Network: options.Network,
Addr: options.Addr,
Host: options.Host,
Client: string(auth_util.IDFromContext(ctx)),

View File

@ -58,7 +58,7 @@ func (r *Relay) Run() (err error) {
return err
}
if r.bypass != nil && r.bypass.Contains(context.Background(), raddr.String()) {
if r.bypass != nil && r.bypass.Contains(context.Background(), "udp", raddr.String()) {
if r.logger != nil {
r.logger.Warn("bypass: ", raddr)
}
@ -96,7 +96,7 @@ func (r *Relay) Run() (err error) {
return err
}
if r.bypass != nil && r.bypass.Contains(context.Background(), raddr.String()) {
if r.bypass != nil && r.bypass.Contains(context.Background(), "udp", raddr.String()) {
if r.logger != nil {
r.logger.Warn("bypass: ", raddr)
}

View File

@ -30,10 +30,10 @@ type bypassWrapper struct {
r *bypassRegistry
}
func (w *bypassWrapper) Contains(ctx context.Context, addr string) bool {
func (w *bypassWrapper) Contains(ctx context.Context, network, addr string, opts ...bypass.Option) bool {
bp := w.r.get(w.name)
if bp == nil {
return false
}
return bp.Contains(ctx, addr)
return bp.Contains(ctx, network, addr, opts...)
}

View File

@ -55,10 +55,10 @@ func (w *chainWrapper) Metadata() metadata.Metadata {
return nil
}
func (w *chainWrapper) Route(ctx context.Context, network, address string) chain.Route {
func (w *chainWrapper) Route(ctx context.Context, network, address string, opts ...chain.RouteOption) chain.Route {
v := w.r.get(w.name)
if v == nil {
return nil
}
return v.Route(ctx, network, address)
return v.Route(ctx, network, address, opts...)
}