add network param for sniffing

This commit is contained in:
ginuerzh
2025-08-13 21:25:35 +08:00
parent d0ff5358df
commit 52289bea6c
14 changed files with 126 additions and 112 deletions
+2 -2
View File
@@ -405,14 +405,14 @@ func (h *httpHandler) handleRequest(ctx context.Context, conn net.Conn, req *htt
conn = xnet.NewReadWriteConn(br, conn, conn) conn = xnet.NewReadWriteConn(br, conn, conn)
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
return sniffer.HandleHTTP(ctx, conn, return sniffer.HandleHTTP(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
sniffing.WithLog(log), sniffing.WithLog(log),
) )
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
return sniffer.HandleTLS(ctx, conn, return sniffer.HandleTLS(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
+4 -2
View File
@@ -206,7 +206,7 @@ func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn, opts ...han
conn = xnet.NewReadWriteConn(br, conn, conn) conn = xnet.NewReadWriteConn(br, conn, conn)
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
return sniffer.HandleHTTP(ctx, conn, return sniffer.HandleHTTP(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithBypass(h.options.Bypass), sniffing.WithBypass(h.options.Bypass),
@@ -214,7 +214,9 @@ func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn, opts ...han
sniffing.WithLog(log), sniffing.WithLog(log),
) )
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
return sniffer.HandleTLS(ctx, conn, return sniffer.HandleTLS(ctx,
ro.Network,
conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithBypass(h.options.Bypass), sniffing.WithBypass(h.options.Bypass),
+2 -2
View File
@@ -185,14 +185,14 @@ func (h *relayHandler) handleConnect(ctx context.Context, conn net.Conn, network
conn = xnet.NewReadWriteConn(br, conn, conn) conn = xnet.NewReadWriteConn(br, conn, conn)
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
return sniffer.HandleHTTP(ctx, conn, return sniffer.HandleHTTP(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
sniffing.WithLog(log), sniffing.WithLog(log),
) )
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
return sniffer.HandleTLS(ctx, conn, return sniffer.HandleTLS(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
+2 -2
View File
@@ -159,7 +159,7 @@ func (h *sniHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.
conn = xnet.NewReadWriteConn(br, conn, conn) conn = xnet.NewReadWriteConn(br, conn, conn)
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
return sniffer.HandleHTTP(ctx, conn, return sniffer.HandleHTTP(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithBypass(h.options.Bypass), sniffing.WithBypass(h.options.Bypass),
@@ -167,7 +167,7 @@ func (h *sniHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.
sniffing.WithLog(log), sniffing.WithLog(log),
) )
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
return sniffer.HandleTLS(ctx, conn, return sniffer.HandleTLS(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithBypass(h.options.Bypass), sniffing.WithBypass(h.options.Bypass),
+2 -2
View File
@@ -304,14 +304,14 @@ func (h *socks4Handler) handleConnect(ctx context.Context, conn net.Conn, req *g
conn = xnet.NewReadWriteConn(br, conn, conn) conn = xnet.NewReadWriteConn(br, conn, conn)
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
return sniffer.HandleHTTP(ctx, conn, return sniffer.HandleHTTP(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
sniffing.WithLog(log), sniffing.WithLog(log),
) )
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
return sniffer.HandleTLS(ctx, conn, return sniffer.HandleTLS(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
+2 -2
View File
@@ -123,14 +123,14 @@ func (h *socks5Handler) handleConnect(ctx context.Context, conn net.Conn, networ
conn = xnet.NewReadWriteConn(br, conn, conn) conn = xnet.NewReadWriteConn(br, conn, conn)
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
return sniffer.HandleHTTP(ctx, conn, return sniffer.HandleHTTP(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
sniffing.WithLog(log), sniffing.WithLog(log),
) )
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
return sniffer.HandleTLS(ctx, conn, return sniffer.HandleTLS(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
+2 -2
View File
@@ -210,14 +210,14 @@ func (h *ssHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.H
conn = xnet.NewReadWriteConn(br, conn, conn) conn = xnet.NewReadWriteConn(br, conn, conn)
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
return sniffer.HandleHTTP(ctx, conn, return sniffer.HandleHTTP(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
sniffing.WithLog(log), sniffing.WithLog(log),
) )
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
return sniffer.HandleTLS(ctx, conn, return sniffer.HandleTLS(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
+2 -2
View File
@@ -205,14 +205,14 @@ func (h *forwardHandler) handleDirectForward(ctx context.Context, conn *sshd_uti
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
return sniffer.HandleHTTP(ctx, xnet.NewReadWriteConn(br, conn, conn), return sniffer.HandleHTTP(ctx, "tcp", xnet.NewReadWriteConn(br, conn, conn),
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
sniffing.WithLog(log), sniffing.WithLog(log),
) )
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
return sniffer.HandleTLS(ctx, xnet.NewReadWriteConn(br, conn, conn), return sniffer.HandleTLS(ctx, "tcp", xnet.NewReadWriteConn(br, conn, conn),
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
+2
View File
@@ -125,6 +125,8 @@ func (h *tungoHandler) Handle(ctx context.Context, conn net.Conn, opts ...handle
recorder: h.recorder, recorder: h.recorder,
stats: h.stats, stats: h.stats,
ipv6: h.md.ipv6,
opts: &h.options, opts: &h.options,
} }
+4
View File
@@ -32,6 +32,8 @@ type metadata struct {
multicastGroups []netip.Addr multicastGroups []netip.Addr
ipv6 bool
tcpSendBufferSize int tcpSendBufferSize int
tcpReceiveBufferSize int tcpReceiveBufferSize int
tcpModerateReceiveBuffer bool tcpModerateReceiveBuffer bool
@@ -73,6 +75,8 @@ func (h *tungoHandler) parseMetadata(md mdata.Metadata) (err error) {
h.md.multicastGroups = append(h.md.multicastGroups, addr) h.md.multicastGroups = append(h.md.multicastGroups, addr)
} }
h.md.ipv6 = mdutil.GetBool(md, "ipv6")
h.md.tcpSendBufferSize = mdutil.GetInt(md, "tcpSendBufferSize", "tungo.tcpSendBufferSize") h.md.tcpSendBufferSize = mdutil.GetInt(md, "tcpSendBufferSize", "tungo.tcpSendBufferSize")
h.md.tcpReceiveBufferSize = mdutil.GetInt(md, "tcpReceiveBufferSize", "tungo.tcpReceiveBufferSize") h.md.tcpReceiveBufferSize = mdutil.GetInt(md, "tcpReceiveBufferSize", "tungo.tcpReceiveBufferSize")
h.md.tcpModerateReceiveBuffer = mdutil.GetBool(md, "tcpModerateReceiveBuffer", "tungo.tcpModerateReceiveBuffer") h.md.tcpModerateReceiveBuffer = mdutil.GetBool(md, "tcpModerateReceiveBuffer", "tungo.tcpModerateReceiveBuffer")
+14 -7
View File
@@ -57,6 +57,8 @@ type transportHandler struct {
stats *stats_util.HandlerStats stats *stats_util.HandlerStats
recorder recorder.RecorderObject recorder recorder.RecorderObject
ipv6 bool
opts *handler.Options opts *handler.Options
} }
@@ -111,9 +113,14 @@ func (h *transportHandler) handleTCPConn(originConn adapter.TCPConn) {
sid := xid.New().String() sid := xid.New().String()
ctx := xctx.ContextWithSid(context.Background(), xctx.Sid(sid)) ctx := xctx.ContextWithSid(context.Background(), xctx.Sid(sid))
network := "tcp"
if remoteIP.Unmap().Is6() && h.ipv6 {
network = "tcp6"
}
ro := &xrecorder.HandlerRecorderObject{ ro := &xrecorder.HandlerRecorderObject{
Service: h.opts.Service, Service: h.opts.Service,
Network: "tcp", Network: network,
RemoteAddr: remoteAddr.String(), RemoteAddr: remoteAddr.String(),
DstAddr: dstAddr.String(), DstAddr: dstAddr.String(),
Host: dstAddr.String(), Host: dstAddr.String(),
@@ -191,7 +198,7 @@ func (h *transportHandler) handleTCPConn(originConn adapter.TCPConn) {
ro.Host = address ro.Host = address
var buf bytes.Buffer var buf bytes.Buffer
cc, err = h.opts.Router.Dial(ictx.ContextWithBuffer(ctx, &buf), "tcp", address) cc, err = h.opts.Router.Dial(ictx.ContextWithBuffer(ctx, &buf), network, address)
ro.Route = buf.String() ro.Route = buf.String()
if err != nil && !h.sniffingFallback { if err != nil && !h.sniffingFallback {
return nil, err return nil, err
@@ -200,7 +207,7 @@ func (h *transportHandler) handleTCPConn(originConn adapter.TCPConn) {
if cc == nil { if cc == nil {
var buf bytes.Buffer var buf bytes.Buffer
cc, err = h.opts.Router.Dial(ictx.ContextWithBuffer(ctx, &buf), "tcp", dstAddr.String()) cc, err = h.opts.Router.Dial(ictx.ContextWithBuffer(ctx, &buf), network, dstAddr.String())
ro.Route = buf.String() ro.Route = buf.String()
ro.Host = dstAddr.String() ro.Host = dstAddr.String()
} }
@@ -221,7 +228,7 @@ func (h *transportHandler) handleTCPConn(originConn adapter.TCPConn) {
conn = xnet.NewReadWriteConn(br, conn, conn) conn = xnet.NewReadWriteConn(br, conn, conn)
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
sniffer.HandleHTTP(ctx, conn, sniffer.HandleHTTP(ctx, network, conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithBypass(h.opts.Bypass), sniffing.WithBypass(h.opts.Bypass),
@@ -230,7 +237,7 @@ func (h *transportHandler) handleTCPConn(originConn adapter.TCPConn) {
) )
return return
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
sniffer.HandleTLS(ctx, conn, sniffer.HandleTLS(ctx, network, conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithBypass(h.opts.Bypass), sniffing.WithBypass(h.opts.Bypass),
@@ -242,13 +249,13 @@ func (h *transportHandler) handleTCPConn(originConn adapter.TCPConn) {
} }
if h.opts.Bypass != nil && if h.opts.Bypass != nil &&
h.opts.Bypass.Contains(ctx, "tcp", dstAddr.String()) { h.opts.Bypass.Contains(ctx, network, dstAddr.String()) {
log.Debug("bypass: ", dstAddr) log.Debug("bypass: ", dstAddr)
return return
} }
var buf bytes.Buffer var buf bytes.Buffer
cc, err := h.opts.Router.Dial(ictx.ContextWithBuffer(ctx, &buf), "tcp", dstAddr.String()) cc, err := h.opts.Router.Dial(ictx.ContextWithBuffer(ctx, &buf), network, dstAddr.String())
ro.Route = buf.String() ro.Route = buf.String()
if err != nil { if err != nil {
log.Errorf("dial %s: %v", dstAddr.String(), err) log.Errorf("dial %s: %v", dstAddr.String(), err)
+2 -2
View File
@@ -176,14 +176,14 @@ func (h *unixHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler
conn = xnet.NewReadWriteConn(br, conn, conn) conn = xnet.NewReadWriteConn(br, conn, conn)
switch proto { switch proto {
case sniffing.ProtoHTTP: case sniffing.ProtoHTTP:
return sniffer.HandleHTTP(ctx, conn, return sniffer.HandleHTTP(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
sniffing.WithLog(log), sniffing.WithLog(log),
) )
case sniffing.ProtoTLS: case sniffing.ProtoTLS:
return sniffer.HandleTLS(ctx, conn, return sniffer.HandleTLS(ctx, "tcp", conn,
sniffing.WithDial(dial), sniffing.WithDial(dial),
sniffing.WithDialTLS(dialTLS), sniffing.WithDialTLS(dialTLS),
sniffing.WithRecorderObject(ro), sniffing.WithRecorderObject(ro),
+52 -53
View File
@@ -51,57 +51,56 @@ var (
) )
type HandleOptions struct { type HandleOptions struct {
Dial func(ctx context.Context, network, address string) (net.Conn, error) dial func(ctx context.Context, network, address string) (net.Conn, error)
httpKeepalive bool
HTTPKeepalive bool node *chain.Node
Node *chain.Node hop hop.Hop
Hop hop.Hop bypass bypass.Bypass
Bypass bypass.Bypass recorderObject *xrecorder.HandlerRecorderObject
RecorderObject *xrecorder.HandlerRecorderObject log logger.Logger
Log logger.Logger
} }
type HandleOption func(opts *HandleOptions) type HandleOption func(opts *HandleOptions)
func WithDial(dial func(ctx context.Context, network, address string) (net.Conn, error)) HandleOption { func WithDial(dial func(ctx context.Context, network, address string) (net.Conn, error)) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.Dial = dial opts.dial = dial
} }
} }
func WithHTTPKeepalive(keepalive bool) HandleOption { func WithHTTPKeepalive(keepalive bool) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.HTTPKeepalive = keepalive opts.httpKeepalive = keepalive
} }
} }
func WithNode(node *chain.Node) HandleOption { func WithNode(node *chain.Node) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.Node = node opts.node = node
} }
} }
func WithHop(hop hop.Hop) HandleOption { func WithHop(hop hop.Hop) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.Hop = hop opts.hop = hop
} }
} }
func WithBypass(bypass bypass.Bypass) HandleOption { func WithBypass(bypass bypass.Bypass) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.Bypass = bypass opts.bypass = bypass
} }
} }
func WithRecorderObject(ro *xrecorder.HandlerRecorderObject) HandleOption { func WithRecorderObject(ro *xrecorder.HandlerRecorderObject) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.RecorderObject = ro opts.recorderObject = ro
} }
} }
func WithLog(log logger.Logger) HandleOption { func WithLog(log logger.Logger) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.Log = log opts.log = log
} }
} }
@@ -141,12 +140,12 @@ func (h *Sniffer) HandleHTTP(ctx context.Context, conn net.Conn, opts ...HandleO
return err return err
} }
if ho.Log.IsLevelEnabled(logger.TraceLevel) { if ho.log.IsLevelEnabled(logger.TraceLevel) {
dump, _ := httputil.DumpRequest(req, false) dump, _ := httputil.DumpRequest(req, false)
ho.Log.Trace(string(dump)) ho.log.Trace(string(dump))
} }
ro := ho.RecorderObject ro := ho.recorderObject
ro.HTTP = &xrecorder.HTTPRecorderObject{ ro.HTTP = &xrecorder.HTTPRecorderObject{
Host: req.Host, Host: req.Host,
Proto: req.Proto, Proto: req.Proto,
@@ -176,8 +175,8 @@ func (h *Sniffer) HandleHTTP(ctx context.Context, conn net.Conn, opts ...HandleO
} }
defer cc.Close() defer cc.Close()
ho.Log = ho.Log.WithFields(map[string]any{"src": cc.LocalAddr().String(), "dst": cc.RemoteAddr().String()}) ho.log = ho.log.WithFields(map[string]any{"src": cc.LocalAddr().String(), "dst": cc.RemoteAddr().String()})
log := ho.Log log := ho.log
log.Debugf("connected to node %s(%s)", node.Name, node.Addr) log.Debugf("connected to node %s(%s)", node.Name, node.Addr)
ro.SrcAddr = cc.LocalAddr().String() ro.SrcAddr = cc.LocalAddr().String()
@@ -212,17 +211,17 @@ func (h *Sniffer) HandleHTTP(ctx context.Context, conn net.Conn, opts ...HandleO
} }
func (h *Sniffer) dial(ctx context.Context, conn net.Conn, req *http.Request, ho *HandleOptions) (node *chain.Node, cc net.Conn, err error) { func (h *Sniffer) dial(ctx context.Context, conn net.Conn, req *http.Request, ho *HandleOptions) (node *chain.Node, cc net.Conn, err error) {
dial := ho.Dial dial := ho.dial
if dial == nil { if dial == nil {
dial = (&net.Dialer{}).DialContext dial = (&net.Dialer{}).DialContext
} }
if node = ho.Node; node != nil { if node = ho.node; node != nil {
cc, err = dial(ctx, "tcp", node.Addr) cc, err = dial(ctx, "tcp", node.Addr)
return return
} }
ro := ho.RecorderObject ro := ho.recorderObject
res := &http.Response{ res := &http.Response{
ProtoMajor: req.ProtoMajor, ProtoMajor: req.ProtoMajor,
@@ -237,13 +236,13 @@ func (h *Sniffer) dial(ctx context.Context, conn net.Conn, req *http.Request, ho
host = net.JoinHostPort(strings.Trim(host, "[]"), "80") host = net.JoinHostPort(strings.Trim(host, "[]"), "80")
} }
ro.Host = host ro.Host = host
ho.Log = ho.Log.WithFields(map[string]any{ ho.log = ho.log.WithFields(map[string]any{
"host": host, "host": host,
}) })
if ho.Bypass != nil && if ho.bypass != nil &&
ho.Bypass.Contains(ctx, "tcp", host, bypass.WithPathOption(req.RequestURI)) { ho.bypass.Contains(ctx, "tcp", host, bypass.WithPathOption(req.RequestURI)) {
ho.Log.Debugf("bypass: %s %s", host, req.RequestURI) ho.log.Debugf("bypass: %s %s", host, req.RequestURI)
res.StatusCode = http.StatusForbidden res.StatusCode = http.StatusForbidden
ro.HTTP.StatusCode = res.StatusCode ro.HTTP.StatusCode = res.StatusCode
res.Write(conn) res.Write(conn)
@@ -252,13 +251,13 @@ func (h *Sniffer) dial(ctx context.Context, conn net.Conn, req *http.Request, ho
} }
node = &chain.Node{} node = &chain.Node{}
if ho.Hop != nil { if ho.hop != nil {
var clientIP net.IP var clientIP net.IP
if clientAddr, _ := net.ResolveTCPAddr("tcp", ro.ClientAddr); clientAddr != nil { if clientAddr, _ := net.ResolveTCPAddr("tcp", ro.ClientAddr); clientAddr != nil {
clientIP = clientAddr.IP clientIP = clientAddr.IP
} }
node = ho.Hop.Select(ctx, node = ho.hop.Select(ctx,
hop.ClientIPSelectOption(clientIP), hop.ClientIPSelectOption(clientIP),
hop.ProtocolSelectOption(sniffing.ProtoHTTP), hop.ProtocolSelectOption(sniffing.ProtoHTTP),
hop.HostSelectOption(host), hop.HostSelectOption(host),
@@ -269,7 +268,7 @@ func (h *Sniffer) dial(ctx context.Context, conn net.Conn, req *http.Request, ho
) )
} }
if node == nil { if node == nil {
ho.Log.Warnf("node for %s not found", host) ho.log.Warnf("node for %s not found", host)
res.StatusCode = http.StatusBadGateway res.StatusCode = http.StatusBadGateway
ro.HTTP.StatusCode = res.StatusCode ro.HTTP.StatusCode = res.StatusCode
res.Write(conn) res.Write(conn)
@@ -283,11 +282,11 @@ func (h *Sniffer) dial(ctx context.Context, conn net.Conn, req *http.Request, ho
} }
ro.Host = node.Addr ro.Host = node.Addr
ho.Log = ho.Log.WithFields(map[string]any{ ho.log = ho.log.WithFields(map[string]any{
"node": node.Name, "node": node.Name,
"dst": node.Addr, "dst": node.Addr,
}) })
ho.Log.Debugf("find node for host %s -> %s(%s)", host, node.Name, node.Addr) ho.log.Debugf("find node for host %s -> %s(%s)", host, node.Name, node.Addr)
cc, err = dial(ctx, "tcp", node.Addr) cc, err = dial(ctx, "tcp", node.Addr)
if err != nil { if err != nil {
@@ -296,7 +295,7 @@ func (h *Sniffer) dial(ctx context.Context, conn net.Conn, req *http.Request, ho
if marker := node.Marker(); marker != nil { if marker := node.Marker(); marker != nil {
marker.Mark() marker.Mark()
} }
ho.Log.Warnf("connect to node %s(%s) failed: %v", node.Name, node.Addr, err) ho.log.Warnf("connect to node %s(%s) failed: %v", node.Name, node.Addr, err)
res.Write(conn) res.Write(conn)
return return
} }
@@ -332,8 +331,8 @@ func (h *Sniffer) serveH2(ctx context.Context, conn net.Conn, ho *HandleOptions)
return errors.New("h2: invalid client preface") return errors.New("h2: invalid client preface")
} }
ro := ho.RecorderObject ro := ho.recorderObject
log := ho.Log log := ho.log
ro.Time = time.Time{} ro.Time = time.Time{}
@@ -370,9 +369,9 @@ func (h *Sniffer) serveH2(ctx context.Context, conn net.Conn, ho *HandleOptions)
func (h *Sniffer) httpRoundTrip(ctx context.Context, rw, cc io.ReadWriteCloser, node *chain.Node, req *http.Request, pStats stats.Stats, ho *HandleOptions) (close bool, err error) { func (h *Sniffer) httpRoundTrip(ctx context.Context, rw, cc io.ReadWriteCloser, node *chain.Node, req *http.Request, pStats stats.Stats, ho *HandleOptions) (close bool, err error) {
close = true close = true
log := ho.Log log := ho.log
ro := &xrecorder.HandlerRecorderObject{} ro := &xrecorder.HandlerRecorderObject{}
*ro = *ho.RecorderObject *ro = *ho.recorderObject
ro.Time = time.Now() ro.Time = time.Now()
log.Infof("%s <-> %s", ro.RemoteAddr, req.Host) log.Infof("%s <-> %s", ro.RemoteAddr, req.Host)
@@ -540,7 +539,7 @@ func (h *Sniffer) httpRoundTrip(ctx context.Context, rw, cc io.ReadWriteCloser,
resp.ProtoMinor = req.ProtoMinor resp.ProtoMinor = req.ProtoMinor
} }
if !ho.HTTPKeepalive { if !ho.httpKeepalive {
resp.Header.Set("Connection", "close") resp.Header.Set("Connection", "close")
} }
@@ -790,7 +789,7 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
return err return err
} }
ro := ho.RecorderObject ro := ho.recorderObject
ro.TLS = &xrecorder.TLSRecorderObject{ ro.TLS = &xrecorder.TLSRecorderObject{
ServerName: clientHello.ServerName, ServerName: clientHello.ServerName,
ClientHello: hex.EncodeToString(buf.Bytes()), ClientHello: hex.EncodeToString(buf.Bytes()),
@@ -808,7 +807,7 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
} }
ro.Host = host ro.Host = host
if ho.Bypass != nil && ho.Bypass.Contains(ctx, "tcp", host) { if ho.bypass != nil && ho.bypass.Contains(ctx, "tcp", host) {
return xbypass.ErrBypass return xbypass.ErrBypass
} }
} }
@@ -818,9 +817,9 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
return err return err
} }
defer cc.Close() defer cc.Close()
ho.Node = node ho.node = node
log := ho.Log.WithFields(map[string]any{"src": cc.LocalAddr().String(), "dst": cc.RemoteAddr().String()}) log := ho.log.WithFields(map[string]any{"src": cc.LocalAddr().String(), "dst": cc.RemoteAddr().String()})
log.Debugf("connected to node %s(%s)", node.Name, node.Addr) log.Debugf("connected to node %s(%s)", node.Name, node.Addr)
ro.SrcAddr = cc.LocalAddr().String() ro.SrcAddr = cc.LocalAddr().String()
@@ -874,26 +873,26 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
} }
func (h *Sniffer) dialTLS(ctx context.Context, host string, ho *HandleOptions) (node *chain.Node, cc net.Conn, err error) { func (h *Sniffer) dialTLS(ctx context.Context, host string, ho *HandleOptions) (node *chain.Node, cc net.Conn, err error) {
dial := ho.Dial dial := ho.dial
if dial == nil { if dial == nil {
dial = (&net.Dialer{}).DialContext dial = (&net.Dialer{}).DialContext
} }
if node = ho.Node; node != nil { if node = ho.node; node != nil {
cc, err = dial(ctx, "tcp", node.Addr) cc, err = dial(ctx, "tcp", node.Addr)
return return
} }
node = &chain.Node{} node = &chain.Node{}
ro := ho.RecorderObject ro := ho.recorderObject
if ho.Hop != nil { if ho.hop != nil {
var clientIP net.IP var clientIP net.IP
if clientAddr, _ := net.ResolveTCPAddr("tcp", ro.ClientAddr); clientAddr != nil { if clientAddr, _ := net.ResolveTCPAddr("tcp", ro.ClientAddr); clientAddr != nil {
clientIP = clientAddr.IP clientIP = clientAddr.IP
} }
node = ho.Hop.Select(ctx, node = ho.hop.Select(ctx,
hop.ClientIPSelectOption(clientIP), hop.ClientIPSelectOption(clientIP),
hop.HostSelectOption(host), hop.HostSelectOption(host),
hop.ProtocolSelectOption(sniffing.ProtoTLS), hop.ProtocolSelectOption(sniffing.ProtoTLS),
@@ -923,12 +922,12 @@ func (h *Sniffer) dialTLS(ctx context.Context, host string, ho *HandleOptions) (
} }
ro.Host = addr ro.Host = addr
ho.Log = ho.Log.WithFields(map[string]any{ ho.log = ho.log.WithFields(map[string]any{
"host": host, "host": host,
"node": node.Name, "node": node.Name,
"dst": fmt.Sprintf("%s/%s", addr, ro.Network), "dst": fmt.Sprintf("%s/%s", addr, ro.Network),
}) })
ho.Log.Debugf("find node for host %s -> %s(%s)", host, node.Name, addr) ho.log.Debugf("find node for host %s -> %s(%s)", host, node.Name, addr)
cc, err = dial(ctx, ro.Network, addr) cc, err = dial(ctx, ro.Network, addr)
if err != nil { if err != nil {
@@ -937,7 +936,7 @@ func (h *Sniffer) dialTLS(ctx context.Context, host string, ho *HandleOptions) (
if marker := node.Marker(); marker != nil { if marker := node.Marker(); marker != nil {
marker.Mark() marker.Mark()
} }
ho.Log.Warnf("connect to node %s(%s) failed: %v", node.Name, node.Addr, err) ho.log.Warnf("connect to node %s(%s) failed: %v", node.Name, node.Addr, err)
return return
} }
@@ -962,8 +961,8 @@ func (h *Sniffer) dialTLS(ctx context.Context, host string, ho *HandleOptions) (
} }
func (h *Sniffer) terminateTLS(ctx context.Context, conn, cc net.Conn, clientHello *dissector.ClientHelloInfo, ho *HandleOptions) error { func (h *Sniffer) terminateTLS(ctx context.Context, conn, cc net.Conn, clientHello *dissector.ClientHelloInfo, ho *HandleOptions) error {
ro := ho.RecorderObject ro := ho.recorderObject
log := ho.Log log := ho.log
nextProtos := clientHello.SupportedProtos nextProtos := clientHello.SupportedProtos
if h.NegotiatedProtocol != "" { if h.NegotiatedProtocol != "" {
@@ -1063,7 +1062,7 @@ func (h *Sniffer) terminateTLS(ctx context.Context, conn, cc net.Conn, clientHel
return clientConn, nil return clientConn, nil
}), }),
WithHTTPKeepalive(true), WithHTTPKeepalive(true),
WithNode(ho.Node), WithNode(ho.node),
WithRecorderObject(ro), WithRecorderObject(ro),
WithLog(log), WithLog(log),
} }
+34 -34
View File
@@ -54,43 +54,43 @@ var (
) )
type HandleOptions struct { type HandleOptions struct {
Dial func(ctx context.Context, network, address string) (net.Conn, error) dial func(ctx context.Context, network, address string) (net.Conn, error)
DialTLS func(ctx context.Context, network, address string, cfg *tls.Config) (net.Conn, error) dialTLS func(ctx context.Context, network, address string, cfg *tls.Config) (net.Conn, error)
Bypass bypass.Bypass bypass bypass.Bypass
RecorderObject *xrecorder.HandlerRecorderObject recorderObject *xrecorder.HandlerRecorderObject
Log logger.Logger log logger.Logger
} }
type HandleOption func(opts *HandleOptions) type HandleOption func(opts *HandleOptions)
func WithDial(dial func(ctx context.Context, network, address string) (net.Conn, error)) HandleOption { func WithDial(dial func(ctx context.Context, network, address string) (net.Conn, error)) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.Dial = dial opts.dial = dial
} }
} }
func WithDialTLS(dialTLS func(ctx context.Context, network, address string, cfg *tls.Config) (net.Conn, error)) HandleOption { func WithDialTLS(dialTLS func(ctx context.Context, network, address string, cfg *tls.Config) (net.Conn, error)) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.DialTLS = dialTLS opts.dialTLS = dialTLS
} }
} }
func WithBypass(bypass bypass.Bypass) HandleOption { func WithBypass(bypass bypass.Bypass) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.Bypass = bypass opts.bypass = bypass
} }
} }
func WithRecorderObject(ro *xrecorder.HandlerRecorderObject) HandleOption { func WithRecorderObject(ro *xrecorder.HandlerRecorderObject) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.RecorderObject = ro opts.recorderObject = ro
} }
} }
func WithLog(log logger.Logger) HandleOption { func WithLog(log logger.Logger) HandleOption {
return func(opts *HandleOptions) { return func(opts *HandleOptions) {
opts.Log = log opts.log = log
} }
} }
@@ -111,7 +111,7 @@ type Sniffer struct {
ReadTimeout time.Duration ReadTimeout time.Duration
} }
func (h *Sniffer) HandleHTTP(ctx context.Context, conn net.Conn, opts ...HandleOption) error { func (h *Sniffer) HandleHTTP(ctx context.Context, network string, conn net.Conn, opts ...HandleOption) error {
var ho HandleOptions var ho HandleOptions
for _, opt := range opts { for _, opt := range opts {
opt(&ho) opt(&ho)
@@ -130,13 +130,13 @@ func (h *Sniffer) HandleHTTP(ctx context.Context, conn net.Conn, opts ...HandleO
return err return err
} }
log := ho.Log log := ho.log
if log.IsLevelEnabled(logger.TraceLevel) { if log.IsLevelEnabled(logger.TraceLevel) {
dump, _ := httputil.DumpRequest(req, false) dump, _ := httputil.DumpRequest(req, false)
log.Trace(string(dump)) log.Trace(string(dump))
} }
ro := ho.RecorderObject ro := ho.recorderObject
ro.HTTP = &xrecorder.HTTPRecorderObject{ ro.HTTP = &xrecorder.HTTPRecorderObject{
Host: req.Host, Host: req.Host,
Proto: req.Proto, Proto: req.Proto,
@@ -156,7 +156,7 @@ func (h *Sniffer) HandleHTTP(ctx context.Context, conn net.Conn, opts ...HandleO
// http/2 // http/2
if req.Method == "PRI" && len(req.Header) == 0 && req.URL.Path == "*" && req.Proto == "HTTP/2.0" { if req.Method == "PRI" && len(req.Header) == 0 && req.URL.Path == "*" && req.Proto == "HTTP/2.0" {
return h.serveH2(ctx, xnet.NewReadWriteConn(br, conn, conn), &ho) return h.serveH2(ctx, network, xnet.NewReadWriteConn(br, conn, conn), &ho)
} }
host := req.Host host := req.Host
@@ -170,16 +170,16 @@ func (h *Sniffer) HandleHTTP(ctx context.Context, conn net.Conn, opts ...HandleO
"host": host, "host": host,
}) })
if ho.Bypass != nil && ho.Bypass.Contains(ctx, "tcp", host) { if ho.bypass != nil && ho.bypass.Contains(ctx, network, host) {
return xbypass.ErrBypass return xbypass.ErrBypass
} }
} }
dial := ho.Dial dial := ho.dial
if dial == nil { if dial == nil {
dial = (&net.Dialer{}).DialContext dial = (&net.Dialer{}).DialContext
} }
cc, err := dial(ctx, "tcp", host) cc, err := dial(ctx, network, host)
if err != nil { if err != nil {
return err return err
} }
@@ -218,7 +218,7 @@ func (h *Sniffer) HandleHTTP(ctx context.Context, conn net.Conn, opts ...HandleO
} }
} }
func (h *Sniffer) serveH2(ctx context.Context, conn net.Conn, ho *HandleOptions) error { func (h *Sniffer) serveH2(ctx context.Context, network string, conn net.Conn, ho *HandleOptions) error {
const expectedBody = "SM\r\n\r\n" const expectedBody = "SM\r\n\r\n"
buf := make([]byte, len(expectedBody)) buf := make([]byte, len(expectedBody))
@@ -230,14 +230,14 @@ func (h *Sniffer) serveH2(ctx context.Context, conn net.Conn, ho *HandleOptions)
return errors.New("h2: invalid client preface") return errors.New("h2: invalid client preface")
} }
ro := ho.RecorderObject ro := ho.recorderObject
log := ho.Log log := ho.log
ro.Time = time.Time{} ro.Time = time.Time{}
tr := &http2.Transport{ tr := &http2.Transport{
DialTLSContext: func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { DialTLSContext: func(ctx context.Context, nw, addr string, cfg *tls.Config) (net.Conn, error) {
if dial := ho.DialTLS; dial != nil { if dial := ho.dialTLS; dial != nil {
return dial(ctx, network, addr, cfg) return dial(ctx, network, addr, cfg)
} }
@@ -564,7 +564,7 @@ func (h *Sniffer) copyWebsocketFrame(w io.Writer, r io.Reader, buf *bytes.Buffer
return nil return nil
} }
func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOption) error { func (h *Sniffer) HandleTLS(ctx context.Context, network string, conn net.Conn, opts ...HandleOption) error {
var ho HandleOptions var ho HandleOptions
for _, opt := range opts { for _, opt := range opts {
opt(&ho) opt(&ho)
@@ -580,9 +580,9 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
return err return err
} }
log := ho.Log log := ho.log
ro := ho.RecorderObject ro := ho.recorderObject
ro.TLS = &xrecorder.TLSRecorderObject{ ro.TLS = &xrecorder.TLSRecorderObject{
ServerName: clientHello.ServerName, ServerName: clientHello.ServerName,
ClientHello: hex.EncodeToString(buf.Bytes()), ClientHello: hex.EncodeToString(buf.Bytes()),
@@ -600,16 +600,16 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
} }
ro.Host = host ro.Host = host
if ho.Bypass != nil && ho.Bypass.Contains(ctx, "tcp", host) { if ho.bypass != nil && ho.bypass.Contains(ctx, network, host) {
return xbypass.ErrBypass return xbypass.ErrBypass
} }
} }
dial := ho.Dial dial := ho.dial
if dial == nil { if dial == nil {
dial = (&net.Dialer{}).DialContext dial = (&net.Dialer{}).DialContext
} }
cc, err := dial(ctx, "tcp", host) cc, err := dial(ctx, network, host)
if err != nil { if err != nil {
return err return err
} }
@@ -624,8 +624,8 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
if host == "" { if host == "" {
host = ro.Host host = ro.Host
} }
if h.MitmBypass == nil || !h.MitmBypass.Contains(ctx, "tcp", host) { if h.MitmBypass == nil || !h.MitmBypass.Contains(ctx, network, host) {
return h.terminateTLS(ctx, xnet.NewReadWriteConn(io.MultiReader(buf, conn), conn, conn), cc, clientHello, &ho) return h.terminateTLS(ctx, network, xnet.NewReadWriteConn(io.MultiReader(buf, conn), conn, conn), cc, clientHello, &ho)
} }
} }
@@ -666,9 +666,9 @@ func (h *Sniffer) HandleTLS(ctx context.Context, conn net.Conn, opts ...HandleOp
return err return err
} }
func (h *Sniffer) terminateTLS(ctx context.Context, conn, cc net.Conn, clientHello *dissector.ClientHelloInfo, ho *HandleOptions) error { func (h *Sniffer) terminateTLS(ctx context.Context, network string, conn, cc net.Conn, clientHello *dissector.ClientHelloInfo, ho *HandleOptions) error {
ro := ho.RecorderObject ro := ho.recorderObject
log := ho.Log log := ho.log
nextProtos := clientHello.SupportedProtos nextProtos := clientHello.SupportedProtos
if h.NegotiatedProtocol != "" { if h.NegotiatedProtocol != "" {
@@ -773,7 +773,7 @@ func (h *Sniffer) terminateTLS(ctx context.Context, conn, cc net.Conn, clientHel
WithRecorderObject(ro), WithRecorderObject(ro),
WithLog(log), WithLog(log),
} }
return h.HandleHTTP(ctx, serverConn, opts...) return h.HandleHTTP(ctx, network, serverConn, opts...)
} }
type h2Handler struct { type h2Handler struct {