diff --git a/go.mod b/go.mod index 1d7fc176..e2ebc8c4 100644 --- a/go.mod +++ b/go.mod @@ -10,11 +10,11 @@ require ( github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf github.com/bettercap/recording v0.0.0-20190408083647-3ce1dcf032e3 - github.com/chifflier/nfqueue-go v0.0.0-20170228160439-61ca646babef github.com/dustin/go-humanize v1.0.1 github.com/elazarl/goproxy v0.0.0-20240726154733-8b0c20506380 github.com/elazarl/goproxy/ext v0.0.0-20210110162100-a92cc753f88e // indirect github.com/evilsocket/islazy v1.11.0 + github.com/florianl/go-nfqueue/v2 v2.0.0 github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe github.com/google/go-github v17.0.0+incompatible github.com/google/go-querystring v1.1.0 // indirect diff --git a/go.sum b/go.sum index bc002ad4..d6a3406b 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ github.com/antchfx/jsonquery v1.3.5 h1:243OSaQh02EfmASa3w3weKC9UaiD8RRzJhgfvq3q4 github.com/antchfx/jsonquery v1.3.5/go.mod h1:qH23yX2Jsj1/k378Yu/EOgPCNgJ35P9tiGOeQdt/GWc= github.com/antchfx/xpath v1.3.1 h1:PNbFuUqHwWl0xRjvUPjJ95Agbmdj2uzzIwmQKgu4oCk= github.com/antchfx/xpath v1.3.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= -github.com/bettercap/gatt v0.0.0-20210514133428-df6e615f2f67 h1:xzN6806c01hWTz8gjGsRjhOPlYj5/dNoZIR8CN9+O1c= -github.com/bettercap/gatt v0.0.0-20210514133428-df6e615f2f67/go.mod h1:oafnPgaBI4gqJiYkueCyR4dqygiWGXTGOE0gmmAVeeQ= github.com/bettercap/gatt v0.0.0-20240808115956-ec4935e8c4a0 h1:HiFUGV/7eGWG/YJAf9HcKOUmxIj+7LVzC8zD57VX1qo= github.com/bettercap/gatt v0.0.0-20240808115956-ec4935e8c4a0/go.mod h1:oafnPgaBI4gqJiYkueCyR4dqygiWGXTGOE0gmmAVeeQ= github.com/bettercap/nrf24 v0.0.0-20190219153547-aa37e6d0e0eb h1:JWAAJk4ny+bT3VrtcX+e7mcmWtWUeUM0xVcocSAUuWc= @@ -16,8 +14,6 @@ github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf h1:pwGPRc5PIp4K github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf/go.mod h1:03rWiUf60r1miMVzMEtgtkq7RdZniecZFw3/Zgvyxcs= github.com/bettercap/recording v0.0.0-20190408083647-3ce1dcf032e3 h1:pC4ZAk7UtDIbrRKzMMiIL1TVkiKlgtgcJodqKB53Rl4= github.com/bettercap/recording v0.0.0-20190408083647-3ce1dcf032e3/go.mod h1:kqVwnx6DKuOHMZcBnzsgp2Lq2JZHDtFtm92b5hxdRaM= -github.com/chifflier/nfqueue-go v0.0.0-20170228160439-61ca646babef h1:uhLIhHeIRlFbAI1mOHkz3vN23T+QdhA9MgnvnJaQyL0= -github.com/chifflier/nfqueue-go v0.0.0-20170228160439-61ca646babef/go.mod h1:xn8SYXvxzI99iSN8+Kh3wCvt2fhr27vPPf8ju9FwRS0= github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM= github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= github.com/chzyer/test v1.0.0 h1:p3BQDXSxOhOG0P9z6/hGnII4LGiEPOYBhs8asl/fC04= @@ -35,11 +31,14 @@ github.com/elazarl/goproxy/ext v0.0.0-20210110162100-a92cc753f88e h1:CQn2/8fi3km github.com/elazarl/goproxy/ext v0.0.0-20210110162100-a92cc753f88e/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/evilsocket/islazy v1.11.0 h1:B5w6uuS6ki6iDG+aH/RFeoMb8ijQh/pGabewqp2UeJ0= github.com/evilsocket/islazy v1.11.0/go.mod h1:muYH4x5MB5YRdkxnrOtrXLIBX6LySj1uFIqys94LKdo= +github.com/florianl/go-nfqueue/v2 v2.0.0 h1:NTCxS9b0GSbHkWv1a7oOvZn679fsyDkaSkRvOYpQ9Oo= +github.com/florianl/go-nfqueue/v2 v2.0.0/go.mod h1:M2tBLIj62QpwqjwV0qfcjqGOqP3qiTuXr2uSRBXH9Qk= github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe h1:8P+/htb3mwwpeGdJg69yBF/RofK7c6Fjz5Ypa/bTqbY= github.com/gobwas/glob v0.0.0-20181002190808-e7a84e9525fe/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY= @@ -58,6 +57,8 @@ github.com/hashicorp/mdns v1.0.5 h1:1M5hW1cunYeoXOqHwEb/GBDDHAFo0Yqb/uz/beC6LbE= github.com/hashicorp/mdns v1.0.5/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= github.com/inconshreveable/go-vhost v1.0.0 h1:IK4VZTlXL4l9vz2IZoiSFbYaaqUW7dXJAiPriUN5Ur8= github.com/inconshreveable/go-vhost v1.0.0/go.mod h1:aA6DnFhALT3zH0y+A39we+zbrdMC2N0X/q21e6FI0LU= +github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= +github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/go-tld v1.2.1 h1:kDKOkmXLlskqjcvNs7w5XHLep7c8WM7Xd4HQjxllVMk= github.com/jpillora/go-tld v1.2.1/go.mod h1:plzIl7xr5UWKGy7R+giuv+L/nOjrPjsoWxy/ST9OBUk= github.com/kr/binarydist v0.1.0 h1:6kAoLA9FMMnNGSehX0s1PdjbEaACznAv/W219j2uvyo= @@ -77,6 +78,10 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b h1:r12blE3QRYlW1WBiBEe007O6NrTb/P54OjR5d4WLEGk= github.com/mdlayher/dhcp6 v0.0.0-20190311162359-2a67805d7d0b/go.mod h1:p4K2+UAoap8Jzsadsxc0KG0OZjmmCthTPUyZqAVkjBY= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab h1:n8cgpHzJ5+EDyDri2s/GC7a9+qK3/YEGnBsd0uS/8PY= @@ -138,6 +143,7 @@ golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= @@ -170,6 +176,7 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -182,6 +189,7 @@ golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFK golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= diff --git a/modules/packet_proxy/packet_proxy_linux.go b/modules/packet_proxy/packet_proxy_linux.go index 4d92dbb1..9cf28023 100644 --- a/modules/packet_proxy/packet_proxy_linux.go +++ b/modules/packet_proxy/packet_proxy_linux.go @@ -2,29 +2,27 @@ package packet_proxy import ( "fmt" - "io/ioutil" - golog "log" "plugin" + "context" "strings" "syscall" + "time" "github.com/bettercap/bettercap/core" "github.com/bettercap/bettercap/session" - "github.com/chifflier/nfqueue-go/nfqueue" + nfqueue "github.com/florianl/go-nfqueue/v2" "github.com/evilsocket/islazy/fs" - "github.com/evilsocket/islazy/tui" ) type PacketProxy struct { session.SessionModule - done chan bool chainName string rule string - queue *nfqueue.Queue + queue *nfqueue.Nfqueue queueNum int - queueCb nfqueue.Callback + queueCb nfqueue.HookFunc pluginPath string plugin *plugin.Plugin } @@ -37,7 +35,6 @@ var mod *PacketProxy func NewPacketProxy(s *session.Session) *PacketProxy { mod = &PacketProxy{ SessionModule: session.NewSessionModule("packet.proxy", s), - done: make(chan bool), queue: nil, queueCb: nil, queueNum: 0, @@ -95,13 +92,12 @@ func (mod *PacketProxy) destroyQueue() { return } - mod.queue.DestroyQueue() mod.queue.Close() mod.queue = nil } func (mod *PacketProxy) runRule(enable bool) (err error) { - action := "-A" + action := "-I" if !enable { action = "-D" } @@ -118,7 +114,6 @@ func (mod *PacketProxy) runRule(enable bool) (err error) { args = append(args, []string{ "-j", "NFQUEUE", "--queue-num", fmt.Sprintf("%d", mod.queueNum), - "--queue-bypass", }...) mod.Debug("iptables %s", args) @@ -128,8 +123,6 @@ func (mod *PacketProxy) runRule(enable bool) (err error) { } func (mod *PacketProxy) Configure() (err error) { - golog.SetOutput(ioutil.Discard) - mod.destroyQueue() if err, mod.queueNum = mod.IntParam("packet.proxy.queue.num"); err != nil { @@ -142,62 +135,78 @@ func (mod *PacketProxy) Configure() (err error) { return } - if mod.pluginPath == "" { - return fmt.Errorf("The parameter %s can not be empty.", tui.Bold("packet.proxy.plugin")) - } else if !fs.Exists(mod.pluginPath) { - return fmt.Errorf("%s does not exist.", mod.pluginPath) - } - - mod.Info("loading packet proxy plugin from %s ...", mod.pluginPath) - - var ok bool - var sym plugin.Symbol - - if mod.plugin, err = plugin.Open(mod.pluginPath); err != nil { - return - } else if sym, err = mod.plugin.Lookup("OnPacket"); err != nil { - return - } else if mod.queueCb, ok = sym.(func(*nfqueue.Payload) int); !ok { - return fmt.Errorf("Symbol OnPacket is not a valid callback function.") - } - - if sym, err = mod.plugin.Lookup("OnStart"); err == nil { - var onStartCb func() int - if onStartCb, ok = sym.(func() int); !ok { - return fmt.Errorf("OnStart signature does not match expected signature: 'func() int'") - } else { - var result int - if result = onStartCb(); result != 0 { - return fmt.Errorf("OnStart returned non-zero result. result=%d", result) + if mod.pluginPath != "" { + if !fs.Exists(mod.pluginPath) { + return fmt.Errorf("%s does not exist.", mod.pluginPath) + } + + mod.Info("loading packet proxy plugin from %s ...", mod.pluginPath) + + var ok bool + var sym plugin.Symbol + + if mod.plugin, err = plugin.Open(mod.pluginPath); err != nil { + return + } else if sym, err = mod.plugin.Lookup("OnPacket"); err != nil { + return + } else if mod.queueCb, ok = sym.(func(nfqueue.Attribute) int); !ok { + return fmt.Errorf("Symbol OnPacket is not a valid callback function.") + } + + if sym, err = mod.plugin.Lookup("OnStart"); err == nil { + var onStartCb func() int + if onStartCb, ok = sym.(func() int); !ok { + return fmt.Errorf("OnStart signature does not match expected signature: 'func() int'") + } else { + var result int + if result = onStartCb(); result != 0 { + return fmt.Errorf("OnStart returned non-zero result. result=%d", result) + } } } + } else { + mod.Warning("no plugin set") } - mod.queue = new(nfqueue.Queue) - if err = mod.queue.SetCallback(dummyCallback); err != nil { - return - } else if err = mod.queue.Init(); err != nil { - return - } else if err = mod.queue.Unbind(syscall.AF_INET); err != nil { - return - } else if err = mod.queue.Bind(syscall.AF_INET); err != nil { - return - } else if err = mod.queue.CreateQueue(mod.queueNum); err != nil { - return - } else if err = mod.queue.SetMode(nfqueue.NFQNL_COPY_PACKET); err != nil { - return - } else if err = mod.runRule(true); err != nil { - return + config := nfqueue.Config { + NfQueue: uint16(mod.queueNum), + Copymode: nfqueue.NfQnlCopyPacket, + AfFamily: syscall.AF_INET, + MaxPacketLen: 0xFFFF, + MaxQueueLen: 0xFF, + WriteTimeout: 15 * time.Millisecond, } + mod.Debug("config: %+v", config) + + if err = mod.runRule(true); err != nil { + return + } else if mod.queue, err = nfqueue.Open(&config); err != nil { + return + } else if err = mod.queue.RegisterWithErrorFunc(context.Background(), dummyCallback, func(e error) int { + mod.Error("%v", e) + return -1 + }); err != nil { + return + } + return nil } // we need this because for some reason we can't directly // pass the symbol loaded from the plugin as a direct // CGO callback ... ¯\_(ツ)_/¯ -func dummyCallback(payload *nfqueue.Payload) int { - return mod.queueCb(payload) +func dummyCallback(attribute nfqueue.Attribute) int { + if mod.queueCb != nil { + return mod.queueCb(attribute) + } else { + id := *attribute.PacketID + + mod.Info("[%d] %v", id, *attribute.Payload) + + mod.queue.SetVerdict(id, nfqueue.NfAccept) + return 0 + } } func (mod *PacketProxy) Start() error { @@ -209,31 +218,24 @@ func (mod *PacketProxy) Start() error { return mod.SetRunning(true, func() { mod.Info("started on queue number %d", mod.queueNum) - - defer mod.destroyQueue() - - mod.queue.Loop() - - mod.done <- true }) } func (mod *PacketProxy) Stop() (err error) { return mod.SetRunning(false, func() { - mod.queue.StopLoop() mod.runRule(false) - var sym plugin.Symbol - if sym, err = mod.plugin.Lookup("OnStop"); err == nil { - var onStopCb func() - var ok bool - if onStopCb, ok = sym.(func()); !ok { - mod.Error("OnStop signature does not match expected signature: 'func()', unable to call OnStop.") - } else { - onStopCb() + if mod.plugin != nil { + var sym plugin.Symbol + if sym, err = mod.plugin.Lookup("OnStop"); err == nil { + var onStopCb func() + var ok bool + if onStopCb, ok = sym.(func()); !ok { + mod.Error("OnStop signature does not match expected signature: 'func()', unable to call OnStop.") + } else { + onStopCb() + } } } - - <-mod.done }) }