From fa182eca763e651afd38d45941ae1f1025563907 Mon Sep 17 00:00:00 2001 From: jdl Date: Sun, 14 Jun 2026 08:15:00 +0200 Subject: [PATCH] Audit changes --- hub/api/api.go | 2 +- hub/api/db/sanitize-validate.go | 2 +- hub/api/db/written.go | 6 ++---- hub/api/migrations/2024-11-30-init.sql | 3 ++- hub/cookie.go | 2 +- hub/handler.go | 1 + peer/control/ping.go | 8 ++++++-- peer/device.go | 2 +- peer/hub_poller.go | 2 +- peer/on_multicast.go | 2 +- peer/on_ping.go | 4 +++- peer/on_tick.go | 7 +++++++ peer/remote.go | 3 ++- 13 files changed, 29 insertions(+), 15 deletions(-) diff --git a/hub/api/api.go b/hub/api/api.go index 7c6ac0d..03d3e1f 100644 --- a/hub/api/api.go +++ b/hub/api/api.go @@ -27,7 +27,7 @@ type API struct { } func New(dbPath string) (*API, error) { - sqlDB, err := sql.Open("sqlite3", dbPath+"?_journal=WAL") + sqlDB, err := sql.Open("sqlite3", dbPath+"?_journal=WAL&_foreign_keys=on") if err != nil { return nil, err } diff --git a/hub/api/db/sanitize-validate.go b/hub/api/db/sanitize-validate.go index 6ca1d65..929c357 100644 --- a/hub/api/db/sanitize-validate.go +++ b/hub/api/db/sanitize-validate.go @@ -92,7 +92,7 @@ func Peer_Validate(p *Peer) error { return errs.ErrInvalidPort } - if len(p.Name) == 0 { + if len(p.Name) == 0 || len(p.Name) > 63 { return errs.ErrInvalidPeerName } for _, c := range p.Name { diff --git a/hub/api/db/written.go b/hub/api/db/written.go index da3d4c9..0546e3c 100644 --- a/hub/api/db/written.go +++ b/hub/api/db/written.go @@ -1,7 +1,5 @@ package db -import "database/sql" - func Peer_ListAll(tx TX, networkID int64) ([]*Peer, error) { const query = Peer_SelectQuery + ` WHERE NetworkID=? ORDER BY PeerIP ASC` return Peer_List(tx, query, networkID) @@ -14,8 +12,8 @@ func Peer_GetByAPIKey(tx TX, apiKey string) (*Peer, error) { apiKey) } -func Network_HasPeers(db *sql.DB, networkID int64) (exists bool, err error) { +func Network_HasPeers(tx TX, networkID int64) (exists bool, err error) { const query = "SELECT EXISTS(SELECT 1 FROM peers WHERE NetworkID=?)" - err = db.QueryRow(query, networkID).Scan(&exists) + err = tx.QueryRow(query, networkID).Scan(&exists) return exists, err } diff --git a/hub/api/migrations/2024-11-30-init.sql b/hub/api/migrations/2024-11-30-init.sql index bce964b..3c6bc03 100644 --- a/hub/api/migrations/2024-11-30-init.sql +++ b/hub/api/migrations/2024-11-30-init.sql @@ -21,5 +21,6 @@ CREATE TABLE peers ( WGPubKey BLOB NOT NULL, SignPubKey BLOB NOT NULL, UNIQUE(NetworkID, Name), - PRIMARY KEY(NetworkID, PeerIP) + PRIMARY KEY(NetworkID, PeerIP), + FOREIGN KEY(NetworkID) REFERENCES networks(NetworkID) ) WITHOUT ROWID; diff --git a/hub/cookie.go b/hub/cookie.go index e56b970..c2bacc9 100644 --- a/hub/cookie.go +++ b/hub/cookie.go @@ -19,7 +19,7 @@ func (a *App) setCookie(w http.ResponseWriter, name, value string) { Secure: !a.insecure, SameSite: http.SameSiteStrictMode, HttpOnly: true, - MaxAge: 86400 * 21, + MaxAge: 86400 * 365 * 10, }) } diff --git a/hub/handler.go b/hub/handler.go index cfae8ba..b772da1 100644 --- a/hub/handler.go +++ b/hub/handler.go @@ -18,6 +18,7 @@ func (app *App) handlePub(pattern string, fn handlerFunc) { s := app.api.Session_Get(sessionID) if r.Method == http.MethodPost { + r.Body = http.MaxBytesReader(w, r.Body, 128*1024) r.ParseMultipartForm(64 * 1024) } else { r.ParseForm() diff --git a/peer/control/ping.go b/peer/control/ping.go index 7ea0bf5..ebde243 100644 --- a/peer/control/ping.go +++ b/peer/control/ping.go @@ -65,14 +65,18 @@ func Unmarshal(buf [Size]byte) (Ping, error) { p := Ping{ PingTS: int64(binary.BigEndian.Uint64(buf[1:9])), } - if addr := netip.AddrFrom4([4]byte(buf[9:13])); !addr.IsUnspecified() { + + if addr := netip.AddrFrom4([4]byte(buf[9:13])); !addr.IsUnspecified() && addr.Is4() { p.SrcV4 = netip.AddrPortFrom(addr, binary.BigEndian.Uint16(buf[13:15])) } - if addr := netip.AddrFrom16([16]byte(buf[15:31])); !addr.IsUnspecified() { + + if addr := netip.AddrFrom16([16]byte(buf[15:31])); !addr.IsUnspecified() && addr.Is6() { p.SrcV6 = netip.AddrPortFrom(addr, binary.BigEndian.Uint16(buf[31:33])) } + if addr := netip.AddrFrom16([16]byte(buf[33:49])).Unmap(); !addr.IsUnspecified() { p.Dst = netip.AddrPortFrom(addr, binary.BigEndian.Uint16(buf[49:51])) } + return p, nil } diff --git a/peer/device.go b/peer/device.go index 9be7061..2699346 100644 --- a/peer/device.go +++ b/peer/device.go @@ -61,7 +61,7 @@ func (a *App) devPromote(p *Peer) { if ep.IsValid() { log.Printf("PROMOTED: %s - %s @ %s", p.Name, p.VPNIP.String(), p.WGEndpoint().String()) } else { - log.Printf("PROMOTED: %s - %s (no IP)", p.Name, p.VPNIP.String()) + log.Printf("DIRECT: %s - %s (waiting for handshake)", p.Name, p.VPNIP.String()) } devRetry(p.VPNIP, "Promote", func() error { return a.dev.Promote(p.PubKey(), p.VPNIP) }) p.State = StateDirect diff --git a/peer/hub_poller.go b/peer/hub_poller.go index 2138e86..f638408 100644 --- a/peer/hub_poller.go +++ b/peer/hub_poller.go @@ -89,7 +89,7 @@ func (hp *HubPoller) poll() { return } - body, err := io.ReadAll(resp.Body) + body, err := io.ReadAll(io.LimitReader(resp.Body, 128*1024)) if err != nil { log.Printf("[HubPoller] read body: %v", err) return diff --git a/peer/on_multicast.go b/peer/on_multicast.go index 404d5a9..e2ac44b 100644 --- a/peer/on_multicast.go +++ b/peer/on_multicast.go @@ -15,7 +15,7 @@ func (a *App) onMulticastDiscovery(pkt multicast.Packet) { vpnIP := netip.AddrFrom4(octets) peer, ok := a.peersByIP[vpnIP] - if !ok { + if !ok || peer.IsPublic { return } diff --git a/peer/on_ping.go b/peer/on_ping.go index 8df01eb..9dc8264 100644 --- a/peer/on_ping.go +++ b/peer/on_ping.go @@ -58,10 +58,12 @@ func (a *App) onPing(e PingEvent) { peer.UpdateEndpoints(e.ping.SrcV4, e.ping.SrcV6) } +var cgnatPrefix = netip.MustParsePrefix("100.64.0.0/10") + func addrIsRoutable(addrPort netip.AddrPort) bool { if addrPort.Port() == 0 { return false } addr := addrPort.Addr() - return addr.IsGlobalUnicast() && !addr.IsPrivate() + return addr.IsGlobalUnicast() && !addr.IsPrivate() && !cgnatPrefix.Contains(addr) } diff --git a/peer/on_tick.go b/peer/on_tick.go index c1c30c3..465620d 100644 --- a/peer/on_tick.go +++ b/peer/on_tick.go @@ -39,6 +39,7 @@ func (a *App) onTick() { case StateRelayed: // If we have an ep to probe, add it. if ep := p.PreferredEndpoint(); ep.IsValid() { + p.ProbeStart = time.Now() a.devAddProbe(p, ep) } @@ -50,6 +51,12 @@ func (a *App) onTick() { } else if ep := p.PreferredEndpoint(); ep.IsValid() && ep != p.WGEndpoint() { // Update the probe address if it's changed. a.devAddProbe(p, ep) + } else if time.Since(p.ProbeStart) > 8*wginterface.ProbeKeepalive { + // Give up probing if we haven't been able to handshake. + p.EndpointV4 = netip.AddrPort{} + p.EndpointV6 = netip.AddrPort{} + p.EndpointLAN = netip.AddrPort{} + a.devAddPeer(p) } case StateDirect: diff --git a/peer/remote.go b/peer/remote.go index 444a8be..b0961ca 100644 --- a/peer/remote.go +++ b/peer/remote.go @@ -27,8 +27,9 @@ type Peer struct { EndpointV4 netip.AddrPort // Reported IPv4 endpoint. EndpointV6 netip.AddrPort // Reported IPv6 endpoint. EndpointLAN netip.AddrPort // Discovered via multicast. - EndpointWG netip.AddrPort // Current wireguard port. + EndpointWG netip.AddrPort // Current wireguard endpoint. RTT time.Duration // Round-trip time. + ProbeStart time.Time // When we started probing. State PeerState // Current routing state; updated on each devXxx call. Role control.Role // Role in relation to the local application. SignPubKey [32]byte // nacl/sign public key for verifying multicast beacons.