Skip to content

Commit 00189a0

Browse files
authored
0.3.15 #patch (#348)
## v0.3.15 Fixes * Address APNS memory consumption bug * Ping API call was broken * Undo shadowports mitigation as it breaks sitevpn use cases Improvements * API performance refactoring with the event bus & notifications channel * Improved packet_logs performance with cached interface name lookups
1 parent 0a1d86a commit 00189a0

File tree

18 files changed

+445
-121
lines changed

18 files changed

+445
-121
lines changed

RELEASE-NOTES.md

+12
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
# Secure Programmable Router (SPR) Release Notes
2+
3+
## v0.3.15
4+
5+
Fixes
6+
* Address APNS memory consumption bug
7+
* Ping API call was broken
8+
* Undo shadowports mitigation as it breaks sitevpn use cases
9+
10+
Improvements
11+
* API performance refactoring with the event bus & notifications channel
12+
* Improved packet_logs performance with cached interface name lookups
13+
214
## v0.3.14
315
Fixes
416
* Fix deadlock in API with Devices mutex

api/code/alerts.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ func AlertsRunEventListener() {
812812
doStore := func(ch <-chan Alert) {
813813
defer wg.Done()
814814
for message := range ch {
815-
sprbus.Publish(message.Topic, message.Info)
815+
SprbusPublish(message.Topic, message.Info)
816816
}
817817
}
818818

api/code/api.go

+35-11
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ var SuperdSocketPath = TEST_PREFIX + "/state/plugins/superd/socket"
5656
// NOTE .Fire will dial, print to stdout/stderr if sprbus not started
5757
var log = sprbus.NewLog("log:api")
5858

59+
var gSprbusClient *sprbus.Client
60+
5961
type InfluxConfig struct {
6062
URL string
6163
Org string
@@ -289,7 +291,7 @@ func getInfo(w http.ResponseWriter, r *http.Request) {
289291

290292
go func() {
291293
defer stdin.Close()
292-
io.WriteString(stdin, string(output))
294+
io.WriteString(stdin, strings.Replace(string(output), "0 user,", "0 users,", 1))
293295
}()
294296

295297
data, err = cmd.Output()
@@ -1162,7 +1164,7 @@ func saveDevicesJson(devices map[string]DeviceEntry) {
11621164
scrubbed_devices := convertDevicesPublic(devices)
11631165
savePublicDevicesJson(scrubbed_devices)
11641166

1165-
sprbus.Publish("devices:save", scrubbed_devices)
1167+
SprbusPublish("devices:save", scrubbed_devices)
11661168
}
11671169

11681170
func getDevicesJson() map[string]DeviceEntry {
@@ -1325,7 +1327,6 @@ func checkDeviceExpiries(devices map[string]DeviceEntry) {
13251327
lastTime, err := time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", entry.DHCPLastTime)
13261328
if err != nil {
13271329
// Handle error
1328-
log.Printf("Error parsing time: %v", err)
13291330
return
13301331
}
13311332

@@ -1410,7 +1411,7 @@ func deleteDeviceLocked(devices map[string]DeviceEntry, identity string) {
14101411
}
14111412

14121413
//notify the bus
1413-
sprbus.Publish("device:delete", scrubDevice(val))
1414+
SprbusPublish("device:delete", scrubDevice(val))
14141415

14151416
}
14161417

@@ -1648,7 +1649,7 @@ func updateDevice(w http.ResponseWriter, r *http.Request, dev DeviceEntry, ident
16481649
val.PSKEntry.Psk = "**"
16491650
}
16501651

1651-
sprbus.Publish("device:update", scrubDevice(val))
1652+
SprbusPublish("device:update", scrubDevice(val))
16521653

16531654
w.Header().Set("Content-Type", "application/json")
16541655
json.NewEncoder(w).Encode(val)
@@ -1706,7 +1707,7 @@ func updateDevice(w http.ResponseWriter, r *http.Request, dev DeviceEntry, ident
17061707
devices[identity] = dev
17071708
saveDevicesJson(devices)
17081709

1709-
sprbus.Publish("device:save", scrubDevice(dev))
1710+
SprbusPublish("device:save", scrubDevice(dev))
17101711

17111712
if pskModified {
17121713
//psks updated -- update hostapd
@@ -2152,7 +2153,7 @@ func reportPSKAuthFailure(w http.ResponseWriter, r *http.Request) {
21522153
return
21532154
}
21542155

2155-
sprbus.Publish("wifi:auth:fail", pskf)
2156+
SprbusPublish("wifi:auth:fail", pskf)
21562157

21572158
if pskf.MAC == "" || (pskf.Type != "sae" && pskf.Type != "wpa") || (pskf.Reason != "noentry" && pskf.Reason != "mismatch") {
21582159
http.Error(w, "malformed data", 400)
@@ -2177,7 +2178,7 @@ func reportPSKAuthSuccess(w http.ResponseWriter, r *http.Request) {
21772178
return
21782179
}
21792180

2180-
sprbus.Publish("wifi:auth:success", pska)
2181+
SprbusPublish("wifi:auth:success", pska)
21812182

21822183
if pska.Iface == "" || pska.Event != "AP-STA-CONNECTED" || pska.MAC == "" {
21832184
http.Error(w, "malformed data", 400)
@@ -2243,7 +2244,7 @@ func reportDisconnect(w http.ResponseWriter, r *http.Request) {
22432244
return
22442245
}
22452246

2246-
sprbus.Publish("wifi:station:disconnect", event)
2247+
SprbusPublish("wifi:station:disconnect", event)
22472248

22482249
if event.Iface == "" || event.Event != "AP-STA-DISCONNECTED" || event.MAC == "" {
22492250
http.Error(w, "malformed data", 400)
@@ -2708,14 +2709,26 @@ func logRequest(handler http.Handler) http.Handler {
27082709
logs["remoteaddr"] = r.RemoteAddr
27092710
logs["method"] = r.Method
27102711
logs["path"] = r.URL.Path
2711-
sprbus.Publish("log:www:access", logs)
2712+
SprbusPublish("log:www:access", logs)
27122713

27132714
handler.ServeHTTP(w, r)
27142715
})
27152716
}
27162717

27172718
var ServerEventSock = TEST_PREFIX + "/state/api/eventbus.sock"
27182719

2720+
// SprbusPublish() using default socket, make sure bytes are json
2721+
func SprbusPublish(topic string, bytes interface{}) error {
2722+
value, err := json.Marshal(bytes)
2723+
2724+
if err != nil {
2725+
return err
2726+
}
2727+
2728+
_, err = gSprbusClient.Publish(topic, string(value))
2729+
return err
2730+
}
2731+
27192732
func startEventBus() {
27202733
// make sure the client dont connect to the prev socket
27212734
os.Remove(ServerEventSock)
@@ -2730,6 +2743,16 @@ func startEventBus() {
27302743
// not reached
27312744
}
27322745

2746+
func registerEventClient() {
2747+
//tbd, sprbus needs an update to allow Publish from server
2748+
// as pub/service are private and theres no method.
2749+
client, err := sprbus.NewClient(ServerEventSock)
2750+
if err != nil {
2751+
log.Fatal(err)
2752+
}
2753+
gSprbusClient = client
2754+
}
2755+
27332756
func main() {
27342757

27352758
//update auth API
@@ -2743,6 +2766,7 @@ func main() {
27432766

27442767
// start eventbus
27452768
go startEventBus()
2769+
registerEventClient()
27462770

27472771
unix_dhcpd_router := mux.NewRouter().StrictSlash(true)
27482772
unix_wifid_router := mux.NewRouter().StrictSlash(true)
@@ -2772,7 +2796,7 @@ func main() {
27722796
external_router_setup.HandleFunc("/hostapd/restart", restartWifi).Methods("PUT")
27732797
external_router_setup.HandleFunc("/hostapd/restart_setup", restartSetupWifi).Methods("PUT")
27742798

2775-
external_router_setup.HandleFunc("/hostapd/calcChannel", hostapdChannelCalc).Methods("PUT")
2799+
external_router_setup.HandleFunc("/hostapd/calcChannel", hostapdChannelCalc).Methods("PUT")
27762800
external_router_setup.HandleFunc("/link/config", updateLinkConfig).Methods("PUT")
27772801

27782802
external_router_setup.HandleFunc("/iw/{command:.*}", iwCommand).Methods("GET")

api/code/auth.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import (
2020
"github.com/golang-jwt/jwt/v5"
2121
"github.com/gorilla/mux"
2222
"github.com/pquerna/otp/totp"
23-
"github.com/spr-networks/sprbus"
2423
)
2524

2625
var AuthUsersFile = TEST_PREFIX + "/configs/auth/auth_users.json"
@@ -257,7 +256,7 @@ func Authenticate(authenticatedNext *mux.Router, publicNext *mux.Router, setupMo
257256
//NOTE: tokens dont check JWT OTP
258257

259258
if authorizedToken(r, token) {
260-
sprbus.Publish("auth:success", map[string]string{"type": "token", "name": tokenName, "reason": "api"})
259+
SprbusPublish("auth:success", map[string]string{"type": "token", "name": tokenName, "reason": "api"})
261260
authenticatedNext.ServeHTTP(w, r)
262261
return
263262
} else {
@@ -280,7 +279,7 @@ func Authenticate(authenticatedNext *mux.Router, publicNext *mux.Router, setupMo
280279
reason = "invalid or missing JWT OTP"
281280
redirect_validate = true
282281
} else {
283-
sprbus.Publish("auth:success", map[string]string{"type": "user", "username": username, "reason": "api"})
282+
SprbusPublish("auth:success", map[string]string{"type": "user", "username": username, "reason": "api"})
284283

285284
authenticatedNext.ServeHTTP(w, r)
286285
return
@@ -301,7 +300,7 @@ func Authenticate(authenticatedNext *mux.Router, publicNext *mux.Router, setupMo
301300
}
302301

303302
if authenticatedNext.Match(r, &matchInfo) || setupMode.Match(r, &matchInfo) {
304-
sprbus.Publish("auth:failure", map[string]string{"reason": reason, "type": failType, "name": tokenName + username})
303+
SprbusPublish("auth:failure", map[string]string{"reason": reason, "type": failType, "name": tokenName + username})
305304

306305
if redirect_validate {
307306
http.Redirect(w, r, "/auth/validate", 302)
@@ -317,7 +316,7 @@ func Authenticate(authenticatedNext *mux.Router, publicNext *mux.Router, setupMo
317316
}
318317
}
319318

320-
sprbus.Publish("auth:failure", map[string]string{"reason": "unknown route, no credentials", "type": failType, "name": tokenName + username})
319+
SprbusPublish("auth:failure", map[string]string{"reason": "unknown route, no credentials", "type": failType, "name": tokenName + username})
321320
if redirect_validate {
322321
http.Redirect(w, r, "/auth/validate", 302)
323322
} else {

api/code/dhcp.go

+3-5
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import (
2525
"strings"
2626
"sync"
2727
"time"
28-
29-
"github.com/spr-networks/sprbus"
3028
)
3129

3230
var gDHCPConfigPath = TEST_PREFIX + "/configs/base/dhcp.json"
@@ -332,7 +330,7 @@ func dhcpRequest(w http.ResponseWriter, r *http.Request) {
332330
return
333331
}
334332

335-
sprbus.Publish("dhcp:request", dhcp)
333+
SprbusPublish("dhcp:request", dhcp)
336334

337335
if dhcp.MAC == "" || dhcp.Iface == "" {
338336
http.Error(w, "need MAC and Iface to dhcp", 400)
@@ -379,7 +377,7 @@ func dhcpRequest(w http.ResponseWriter, r *http.Request) {
379377

380378
response := DHCPResponse{dhcp.MAC, IP, Router, getLANIP(), LeaseTime}
381379

382-
sprbus.Publish("dhcp:response", response)
380+
SprbusPublish("dhcp:response", response)
383381

384382
w.Header().Set("Content-Type", "application/json")
385383
json.NewEncoder(w).Encode(response)
@@ -620,7 +618,7 @@ func wireguardUpdate(w http.ResponseWriter, r *http.Request) {
620618
Devicesmtx.Lock()
621619
defer Devicesmtx.Unlock()
622620

623-
sprbus.Publish("wg:update", wg)
621+
SprbusPublish("wg:update", wg)
624622

625623
devices := getDevicesJson()
626624
val, exists := lookupWGDevice(&devices, wg.PublicKey, wg.IP)

api/code/firewall.go

+4-8
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,6 @@ import (
2323
"github.com/gorilla/mux"
2424
)
2525

26-
import (
27-
"github.com/spr-networks/sprbus"
28-
)
29-
3026
var FWmtx sync.Mutex
3127

3228
type BaseRule struct {
@@ -1130,7 +1126,7 @@ func refreshDeviceTags(dev DeviceEntry) {
11301126
applyEndpointRules(dev)
11311127
FWmtx.Unlock()
11321128
}()
1133-
sprbus.Publish("device:tags:update", scrubDevice(dev))
1129+
SprbusPublish("device:tags:update", scrubDevice(dev))
11341130
}
11351131

11361132
func refreshDeviceGroupsAndPolicy(dev DeviceEntry) {
@@ -1182,7 +1178,7 @@ func refreshDeviceGroupsAndPolicy(dev DeviceEntry) {
11821178
populateVmapEntries(ipv4, dev.MAC, ifname, "")
11831179
}
11841180

1185-
sprbus.Publish("device:groups:update", scrubDevice(dev))
1181+
SprbusPublish("device:groups:update", scrubDevice(dev))
11861182
}
11871183

11881184
func applyPingRules() {
@@ -2734,7 +2730,7 @@ func notifyVpnActivity(new_vpn_peers []string, endpoints []string) {
27342730
RemoteEndpoint: endpoints[i],
27352731
Status: "online",
27362732
}
2737-
sprbus.Publish("device:vpn:online", notification)
2733+
SprbusPublish("device:vpn:online", notification)
27382734
}
27392735
}
27402736

@@ -2747,7 +2743,7 @@ func notifyVpnActivity(new_vpn_peers []string, endpoints []string) {
27472743
RemoteEndpoint: gPreviousEndpoints[i],
27482744
Status: "offline",
27492745
}
2750-
sprbus.Publish("device:vpn:offline", notification)
2746+
SprbusPublish("device:vpn:offline", notification)
27512747
//recommended hardening against shadow port attacks
27522748
//https://petsymposium.org/popets/2024/popets-2024-0070.pdf
27532749
clearConntrackSrcIP(peer)

api/code/interfaces.go

+41-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import (
88
"crypto/rand"
99
"encoding/json"
1010
"fmt"
11+
"golang.org/x/net/icmp"
12+
"golang.org/x/net/ipv4"
13+
"syscall"
1114
"io/ioutil"
1215
"math/big"
1316
"net"
@@ -898,24 +901,55 @@ func pingTest(w http.ResponseWriter, r *http.Request) {
898901
return
899902
}
900903

901-
network := "ip4:icmp"
902-
if ipAddr.IP.To4() == nil {
903-
network = "ip6:ipv6-icmp"
904-
}
905904

906905
result := []string{}
907906

908907
for i := 0; i < 4; i++ {
909908
start := time.Now()
910909

911-
conn, err := net.ListenPacket(network, ief.Name)
910+
fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP)
912911
if err != nil {
913-
http.Error(w, "Failed to listen on interface", 400)
912+
http.Error(w, "Error creating raw socket: %v\n", 400)
913+
return
914+
}
915+
defer syscall.Close(fd)
916+
917+
if err := syscall.BindToDevice(fd, ief.Name); err != nil {
918+
http.Error(w, "Error binding to interface", 400)
919+
return
920+
}
921+
922+
f := os.NewFile(uintptr(fd), "")
923+
conn, err := net.FilePacketConn(f)
924+
if err != nil {
925+
http.Error(w, "Error creating ICMP connection", 400)
914926
return
915927
}
916928
defer conn.Close()
917929

918-
_, err = conn.WriteTo([]byte{}, ipAddr)
930+
err = syscall.BindToDevice(fd, ief.Name)
931+
if err != nil {
932+
http.Error(w, "Failed to listen on interface", 400)
933+
return
934+
}
935+
936+
msg := icmp.Message{
937+
Type: ipv4.ICMPTypeEcho,
938+
Code: 0,
939+
Body: &icmp.Echo{
940+
ID: 1,
941+
Seq: i,
942+
Data: []byte("HELLO"),
943+
},
944+
}
945+
946+
msgBytes, err := msg.Marshal(nil)
947+
if err != nil {
948+
http.Error(w, "Failed to marshal ping", 400)
949+
return
950+
}
951+
952+
_, err = conn.WriteTo(msgBytes, ipAddr)
919953
if err != nil {
920954
continue
921955
}

0 commit comments

Comments
 (0)