Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package bettercap for openSUSE:Factory checked in at 2025-09-24 15:24:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/bettercap (Old) and /work/SRC/openSUSE:Factory/.bettercap.new.27445 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "bettercap" Wed Sep 24 15:24:18 2025 rev:5 rq:1306785 version:2.41.4 Changes: -------- --- /work/SRC/openSUSE:Factory/bettercap/bettercap.changes 2025-07-23 16:39:44.474937006 +0200 +++ /work/SRC/openSUSE:Factory/.bettercap.new.27445/bettercap.changes 2025-09-24 15:26:33.270092189 +0200 @@ -1,0 +2,23 @@ +Sat Sep 20 08:05:06 UTC 2025 - Martin Hauke <[email protected]> + +- Update to version 2.41.4: + * releasing version 2.41.4 + * hotfix: hotfix 2 for tcp.proxy + +------------------------------------------------------------------- +Wed Sep 10 19:32:44 UTC 2025 - Martin Hauke <[email protected]> + +- Update to version 2.41.4: + New Features + * Add default username and password for the API to simplify + initial setup and access control. + Fixes + * Corrected tcp.proxy onData return value handling (fixes #788) + to ensure proper flow control in TCP proxy callbacks. + * Ensured consistent behavior between HTTP and HTTPS servers. + * Enforced callback signature checks to prevent runtime errors + with invalid handlers. + Miscellaneous + * Fixed minor typos and improved wording. + +------------------------------------------------------------------- Old: ---- bettercap-2.41.1.obscpio New: ---- bettercap-2.41.4.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ bettercap.spec ++++++ --- /var/tmp/diff_new_pack.mzBIa2/_old 2025-09-24 15:26:33.982122168 +0200 +++ /var/tmp/diff_new_pack.mzBIa2/_new 2025-09-24 15:26:33.986122336 +0200 @@ -1,7 +1,7 @@ # # spec file for package bettercap # -# Copyright (c) 2025 SUSE LLC +# Copyright (c) 2025 SUSE LLC and contributors # Copyright (c) 2019-2025, Martin Hauke <[email protected]> # # All modifications and additions to the file contributed by third parties @@ -18,7 +18,7 @@ Name: bettercap -Version: 2.41.1 +Version: 2.41.4 Release: 0 Summary: Swiss army knife for network attacks and monitoring License: GPL-3.0-or-later ++++++ _service ++++++ --- /var/tmp/diff_new_pack.mzBIa2/_old 2025-09-24 15:26:34.022123852 +0200 +++ /var/tmp/diff_new_pack.mzBIa2/_new 2025-09-24 15:26:34.026124020 +0200 @@ -2,7 +2,7 @@ <service name="obs_scm" mode="manual"> <param name="url">https://github.com/bettercap/bettercap.git</param> <param name="scm">git</param> - <param name="revision">v2.41.1</param> + <param name="revision">v2.41.4</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.mzBIa2/_old 2025-09-24 15:26:34.050125031 +0200 +++ /var/tmp/diff_new_pack.mzBIa2/_new 2025-09-24 15:26:34.054125199 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/bettercap/bettercap.git</param> - <param name="changesrevision">fa7e95c42048ad4404d5f0fad6d09471bba1faa1</param></service></servicedata> + <param name="changesrevision">4ec2753fad4a26096ea5c4cc11a38baaf39a3830</param></service></servicedata> (No newline at EOF) ++++++ bettercap-2.41.1.obscpio -> bettercap-2.41.4.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/.github/workflows/build-and-deploy.yml new/bettercap-2.41.4/.github/workflows/build-and-deploy.yml --- old/bettercap-2.41.1/.github/workflows/build-and-deploy.yml 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/.github/workflows/build-and-deploy.yml 2025-08-18 19:15:44.000000000 +0200 @@ -99,7 +99,7 @@ runs-on: ubuntu-latest steps: - name: Download Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v5 with: pattern: release-artifacts-* merge-multiple: true diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/core/banner.go new/bettercap-2.41.4/core/banner.go --- old/bettercap-2.41.1/core/banner.go 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/core/banner.go 2025-08-18 19:15:44.000000000 +0200 @@ -2,7 +2,7 @@ const ( Name = "bettercap" - Version = "2.41.1" + Version = "2.41.4" Author = "Simone 'evilsocket' Margaritelli" Website = "https://bettercap.org/" ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/modules/api_rest/api_rest.go new/bettercap-2.41.4/modules/api_rest/api_rest.go --- old/bettercap-2.41.1/modules/api_rest/api_rest.go 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/modules/api_rest/api_rest.go 2025-08-18 19:15:44.000000000 +0200 @@ -90,12 +90,12 @@ "Value of the Access-Control-Allow-Origin header of the API server.")) mod.AddParam(session.NewStringParameter("api.rest.username", - "", + "user", "", "API authentication username.")) mod.AddParam(session.NewStringParameter("api.rest.password", - "", + "pass", "", "API authentication password.")) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/modules/http_server/http_server.go new/bettercap-2.41.4/modules/http_server/http_server.go --- old/bettercap-2.41.1/modules/http_server/http_server.go 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/modules/http_server/http_server.go 2025-08-18 19:15:44.000000000 +0200 @@ -31,20 +31,20 @@ mod.AddParam(session.NewStringParameter("http.server.address", session.ParamIfaceAddress, session.IPv4Validator, - "Address to bind the http server to.")) + "Address to bind the HTTP server to.")) mod.AddParam(session.NewIntParameter("http.server.port", "80", - "Port to bind the http server to.")) + "Port to bind the HTTP server to.")) mod.AddHandler(session.NewModuleHandler("http.server on", "", - "Start httpd server.", + "Start HTTP server.", func(args []string) error { return mod.Start() })) mod.AddHandler(session.NewModuleHandler("http.server off", "", - "Stop httpd server.", + "Stop HTTP server.", func(args []string) error { return mod.Stop() })) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/modules/https_server/https_server.go new/bettercap-2.41.4/modules/https_server/https_server.go --- old/bettercap-2.41.1/modules/https_server/https_server.go 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/modules/https_server/https_server.go 2025-08-18 19:15:44.000000000 +0200 @@ -35,11 +35,11 @@ mod.AddParam(session.NewStringParameter("https.server.address", session.ParamIfaceAddress, session.IPv4Validator, - "Address to bind the http server to.")) + "Address to bind the HTTPS server to.")) mod.AddParam(session.NewIntParameter("https.server.port", "443", - "Port to bind the http server to.")) + "Port to bind the HTTPS server to.")) mod.AddParam(session.NewStringParameter("https.server.certificate", "~/.bettercap-httpd.cert.pem", @@ -54,13 +54,13 @@ tls.CertConfigToModule("https.server", &mod.SessionModule, tls.DefaultLegitConfig) mod.AddHandler(session.NewModuleHandler("https.server on", "", - "Start https server.", + "Start HTTPS server.", func(args []string) error { return mod.Start() })) mod.AddHandler(session.NewModuleHandler("https.server off", "", - "Stop https server.", + "Stop HTTPS server.", func(args []string) error { return mod.Stop() })) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/modules/packet_proxy/packet_proxy_linux.go new/bettercap-2.41.4/modules/packet_proxy/packet_proxy_linux.go --- old/bettercap-2.41.1/modules/packet_proxy/packet_proxy_linux.go 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/modules/packet_proxy/packet_proxy_linux.go 2025-08-18 19:15:44.000000000 +0200 @@ -16,15 +16,13 @@ "github.com/evilsocket/islazy/fs" ) -type hookFunc func(q *nfqueue.Nfqueue, a nfqueue.Attribute) int - type PacketProxy struct { session.SessionModule chainName string rule string queue *nfqueue.Nfqueue queueNum int - queueCb hookFunc + queueCb func(q *nfqueue.Nfqueue, a nfqueue.Attribute) int pluginPath string plugin *plugin.Plugin } @@ -151,7 +149,7 @@ return } else if sym, err = mod.plugin.Lookup("OnPacket"); err != nil { return - } else if mod.queueCb, ok = sym.(hookFunc); !ok { + } else if mod.queueCb, ok = sym.(func(q *nfqueue.Nfqueue, a nfqueue.Attribute) int); !ok { return fmt.Errorf("Symbol OnPacket is not a valid callback function.") } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/modules/tcp_proxy/tcp_proxy_script.go new/bettercap-2.41.4/modules/tcp_proxy/tcp_proxy_script.go --- old/bettercap-2.41.1/modules/tcp_proxy/tcp_proxy_script.go 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/modules/tcp_proxy/tcp_proxy_script.go 2025-08-18 19:15:44.000000000 +0200 @@ -1,6 +1,7 @@ package tcp_proxy import ( + "encoding/json" "net" "strings" @@ -55,12 +56,36 @@ log.Error("error while executing onData callback: %s", err) return nil } else if ret != nil { - array, ok := ret.([]byte) - if !ok { - log.Error("error while casting exported value to array of byte: value = %+v", ret) + return toByteArray(ret) + } + } + return nil +} + +func toByteArray(ret interface{}) []byte { + // this approach is a bit hacky but it handles all cases + + // serialize ret to JSON + if jsonData, err := json.Marshal(ret); err == nil { + // attempt to deserialize as []float64 + var back2Array []float64 + if err := json.Unmarshal(jsonData, &back2Array); err == nil { + result := make([]byte, len(back2Array)) + for i, num := range back2Array { + if num >= 0 && num <= 255 { + result[i] = byte(num) + } else { + log.Error("array element at index %d is not a valid byte value %d", i, num) + return nil + } } - return array + return result + } else { + log.Error("failed to deserialize %+v to []float64: %v", ret, err) } + } else { + log.Error("failed to serialize %+v to JSON: %v", ret, err) } + return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/modules/tcp_proxy/tcp_proxy_script_test.go new/bettercap-2.41.4/modules/tcp_proxy/tcp_proxy_script_test.go --- old/bettercap-2.41.1/modules/tcp_proxy/tcp_proxy_script_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/bettercap-2.41.4/modules/tcp_proxy/tcp_proxy_script_test.go 2025-08-18 19:15:44.000000000 +0200 @@ -0,0 +1,169 @@ +package tcp_proxy + +import ( + "net" + "testing" + + "github.com/evilsocket/islazy/plugin" +) + +func TestOnData_NoReturn(t *testing.T) { + jsCode := ` + function onData(from, to, data, callback) { + // don't return anything + } + ` + + plug, err := plugin.Parse(jsCode) + if err != nil { + t.Fatalf("Failed to parse plugin: %v", err) + } + + script := &TcpProxyScript{ + Plugin: plug, + doOnData: plug.HasFunc("onData"), + } + + from := &net.TCPAddr{IP: net.ParseIP("192.168.1.1"), Port: 1234} + to := &net.TCPAddr{IP: net.ParseIP("192.168.1.2"), Port: 5678} + data := []byte("test data") + + result := script.OnData(from, to, data, nil) + if result != nil { + t.Errorf("Expected nil result when callback returns nothing, got %v", result) + } +} + +func TestOnData_ReturnsArrayOfIntegers(t *testing.T) { + jsCode := ` + function onData(from, to, data, callback) { + // Return modified data as array of integers + return [72, 101, 108, 108, 111]; // "Hello" in ASCII + } + ` + + plug, err := plugin.Parse(jsCode) + if err != nil { + t.Fatalf("Failed to parse plugin: %v", err) + } + + script := &TcpProxyScript{ + Plugin: plug, + doOnData: plug.HasFunc("onData"), + } + + from := &net.TCPAddr{IP: net.ParseIP("192.168.1.1"), Port: 1234} + to := &net.TCPAddr{IP: net.ParseIP("192.168.1.2"), Port: 5678} + data := []byte("test data") + + result := script.OnData(from, to, data, nil) + expected := []byte("Hello") + + if result == nil { + t.Fatal("Expected non-nil result when callback returns array of integers") + } + + if len(result) != len(expected) { + t.Fatalf("Expected result length %d, got %d", len(expected), len(result)) + } + + for i, b := range result { + if b != expected[i] { + t.Errorf("Expected byte at index %d to be %d, got %d", i, expected[i], b) + } + } +} + +func TestOnData_ReturnsDynamicArray(t *testing.T) { + jsCode := ` + function onData(from, to, data, callback) { + var result = []; + for (var i = 0; i < data.length; i++) { + result.push((data[i] + 1) % 256); + } + return result; + } + ` + + plug, err := plugin.Parse(jsCode) + if err != nil { + t.Fatalf("Failed to parse plugin: %v", err) + } + + script := &TcpProxyScript{ + Plugin: plug, + doOnData: plug.HasFunc("onData"), + } + + from := &net.TCPAddr{IP: net.ParseIP("192.168.1.1"), Port: 1234} + to := &net.TCPAddr{IP: net.ParseIP("192.168.1.2"), Port: 5678} + data := []byte{10, 20, 30, 40, 255} + + result := script.OnData(from, to, data, nil) + expected := []byte{11, 21, 31, 41, 0} // 255 + 1 = 256 % 256 = 0 + + if result == nil { + t.Fatal("Expected non-nil result when callback returns array of integers") + } + + if len(result) != len(expected) { + t.Fatalf("Expected result length %d, got %d", len(expected), len(result)) + } + + for i, b := range result { + if b != expected[i] { + t.Errorf("Expected byte at index %d to be %d, got %d", i, expected[i], b) + } + } +} + +func TestOnData_ReturnsMixedArray(t *testing.T) { + jsCode := ` + function charToInt(value) { + return value.charCodeAt() + } + + function onData(from, to, data) { + st_data = String.fromCharCode.apply(null, data) + if( st_data.indexOf("mysearch") != -1 ) { + payload = "mypayload"; + st_data = st_data.replace("mysearch", payload); + res_int_arr = st_data.split("").map(charToInt) // []uint16 + res_int_arr[0] = payload.length + 1; // first index is float64 and rest []uint16 + return res_int_arr; + } + return data; + } + ` + + plug, err := plugin.Parse(jsCode) + if err != nil { + t.Fatalf("Failed to parse plugin: %v", err) + } + + script := &TcpProxyScript{ + Plugin: plug, + doOnData: plug.HasFunc("onData"), + } + + from := &net.TCPAddr{IP: net.ParseIP("192.168.1.1"), Port: 1234} + to := &net.TCPAddr{IP: net.ParseIP("192.168.1.6"), Port: 5678} + data := []byte("Hello mysearch world") + + result := script.OnData(from, to, data, nil) + expected := []byte("\x0aello mypayload world") + + if result == nil { + t.Fatal("Expected non-nil result when callback returns array of integers") + } + + if len(result) != len(expected) { + t.Fatalf("Expected result length %d, got %d", len(expected), len(result)) + } + + for i, b := range result { + if b != expected[i] { + t.Errorf("Expected byte at index %d to be %d, got %d", i, expected[i], b) + } + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/modules/ticker/ticker.go new/bettercap-2.41.4/modules/ticker/ticker.go --- old/bettercap-2.41.1/modules/ticker/ticker.go 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/modules/ticker/ticker.go 2025-08-18 19:15:44.000000000 +0200 @@ -43,7 +43,7 @@ })) mod.AddHandler(session.NewModuleHandler("ticker off", "", - "Stop the maint icker.", + "Stop the main ticker.", func(args []string) error { return mod.Stop() })) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/modules/wifi/wifi.go new/bettercap-2.41.4/modules/wifi/wifi.go --- old/bettercap-2.41.1/modules/wifi/wifi.go 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/modules/wifi/wifi.go 2025-08-18 19:15:44.000000000 +0200 @@ -265,8 +265,8 @@ mod.AddHandler(probe) - channelSwitchAnnounce := session.NewModuleHandler("wifi.channel_switch_announce bssid channel ", `wifi\.channel_switch_announce ((?:[a-fA-F0-9:]{11,}))\s+((?:[0-9]+))`, - "Start a 802.11 channel hop attack, all client will be force to change the channel lead to connection down.", + channelSwitchAnnounce := session.NewModuleHandler("wifi.channel_switch_announce BSSID CHANNEL ", `wifi\.channel_switch_announce ((?:[a-fA-F0-9:]{11,}))\s+((?:[0-9]+))`, + "Start a 802.11 channel hop attack, all client will be forced to change the channel lead to connection down.", func(args []string) error { bssid, err := net.ParseMAC(args[0]) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/bettercap-2.41.1/modules/wifi/wifi_test.go new/bettercap-2.41.4/modules/wifi/wifi_test.go --- old/bettercap-2.41.1/modules/wifi/wifi_test.go 2025-07-15 11:52:58.000000000 +0200 +++ new/bettercap-2.41.4/modules/wifi/wifi_test.go 2025-08-18 19:15:44.000000000 +0200 @@ -518,37 +518,6 @@ } } -func TestWiFiModuleChannelSwitchAnnounce(t *testing.T) { - sess := createMockSession() - mod := NewWiFiModule(sess) - - // Test CSA handler - handlers := mod.Handlers() - var csaHandler session.ModuleHandler - for _, h := range handlers { - if h.Name == "wifi.channel_switch_announce bssid channel " { - csaHandler = h - break - } - } - - if csaHandler.Name == "" { - t.Fatal("CSA handler not found") - } - - // Test with valid parameters - err := csaHandler.Exec([]string{"aa:bb:cc:dd:ee:ff", "11"}) - if err == nil { - t.Error("Expected error when running CSA without running module") - } - - // Test with invalid channel - err = csaHandler.Exec([]string{"aa:bb:cc:dd:ee:ff", "999"}) - if err == nil { - t.Error("Expected error with invalid channel") - } -} - func TestWiFiModuleFakeAuth(t *testing.T) { sess := createMockSession() mod := NewWiFiModule(sess) ++++++ bettercap.obsinfo ++++++ --- /var/tmp/diff_new_pack.mzBIa2/_old 2025-09-24 15:26:35.778197787 +0200 +++ /var/tmp/diff_new_pack.mzBIa2/_new 2025-09-24 15:26:35.782197956 +0200 @@ -1,5 +1,5 @@ name: bettercap -version: 2.41.1 -mtime: 1752573178 -commit: fa7e95c42048ad4404d5f0fad6d09471bba1faa1 +version: 2.41.4 +mtime: 1755537344 +commit: 4ec2753fad4a26096ea5c4cc11a38baaf39a3830 ++++++ vendor.tar.gz ++++++
