Audit changes

This commit is contained in:
jdl
2026-06-14 06:17:35 +02:00
parent cc21bee798
commit 52ea1a8d42
5 changed files with 42 additions and 9 deletions

View File

@@ -169,11 +169,25 @@ func (a *API) sweepSessions() {
} }
func (a *API) Network_Create(n *Network) error { func (a *API) Network_Create(n *Network) error {
a.lock.Lock()
defer a.lock.Unlock()
n.NetworkID = idgen.NextID(0) n.NetworkID = idgen.NextID(0)
return errs.DB(db.Network_Insert(a.db, n)) return errs.DB(db.Network_Insert(a.db, n))
} }
func (a *API) Network_Delete(n *Network) error { func (a *API) Network_Delete(n *Network) error {
a.lock.Lock()
defer a.lock.Unlock()
exists, err := db.Network_HasPeers(a.db, n.NetworkID)
if err != nil {
return errs.DB(err)
}
if exists {
return errs.Conflict.WithMsg("Delete all peers before deleting network.")
}
return errs.DB(db.Network_Delete(a.db, n.NetworkID)) return errs.DB(db.Network_Delete(a.db, n.NetworkID))
} }
@@ -189,6 +203,9 @@ func (a *API) Network_List() ([]*Network, error) {
} }
func (a *API) Peer_CreateNew(p *Peer) error { func (a *API) Peer_CreateNew(p *Peer) error {
a.lock.Lock()
defer a.lock.Unlock()
p.WGPubKey = []byte{} p.WGPubKey = []byte{}
p.SignPubKey = []byte{} p.SignPubKey = []byte{}
p.APIKey = idgen.NewToken() p.APIKey = idgen.NewToken()
@@ -217,6 +234,9 @@ func (a *API) Peer_Init(peer *Peer, args m.PeerInitArgs) error {
} }
func (a *API) Peer_Delete(networkID int64, peerIP byte) error { func (a *API) Peer_Delete(networkID int64, peerIP byte) error {
a.lock.Lock()
defer a.lock.Unlock()
return errs.DB(db.Peer_Delete(a.db, networkID, peerIP)) return errs.DB(db.Peer_Delete(a.db, networkID, peerIP))
} }

View File

@@ -1,5 +1,7 @@
package db package db
import "database/sql"
func Peer_ListAll(tx TX, networkID int64) ([]*Peer, error) { func Peer_ListAll(tx TX, networkID int64) ([]*Peer, error) {
const query = Peer_SelectQuery + ` WHERE NetworkID=? ORDER BY PeerIP ASC` const query = Peer_SelectQuery + ` WHERE NetworkID=? ORDER BY PeerIP ASC`
return Peer_List(tx, query, networkID) return Peer_List(tx, query, networkID)
@@ -11,3 +13,9 @@ func Peer_GetByAPIKey(tx TX, apiKey string) (*Peer, error) {
Peer_SelectQuery+` WHERE APIKey=?`, Peer_SelectQuery+` WHERE APIKey=?`,
apiKey) apiKey)
} }
func Network_HasPeers(db *sql.DB, networkID int64) (exists bool, err error) {
const query = "SELECT EXISTS(SELECT 1 FROM peers WHERE NetworkID=?)"
err = db.QueryRow(query, networkID).Scan(&exists)
return exists, err
}

View File

@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"log" "log"
"math/rand/v2" "math/rand/v2"
"net"
"net/http" "net/http"
"time" "time"
"vppn/hub/api" "vppn/hub/api"
@@ -28,11 +29,12 @@ func (a *App) _signin(s *api.Session, w http.ResponseWriter, r *http.Request) er
} }
func (a *App) _signinSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error { func (a *App) _signinSubmit(s *api.Session, w http.ResponseWriter, r *http.Request) error {
if !a.signInLock.TryLock(r.RemoteAddr) { host, _, _ := net.SplitHostPort(r.RemoteAddr)
if !a.signInLock.TryLock(host) {
time.Sleep(time.Duration(rand.Int64N(int64(4 * time.Second)))) time.Sleep(time.Duration(rand.Int64N(int64(4 * time.Second))))
return errs.ErrNotAuthorized return errs.ErrNotAuthorized
} }
defer a.signInLock.Unlock(r.RemoteAddr) defer a.signInLock.Unlock(host)
var pwd string var pwd string
err := webutil.NewFormScanner(r.Form). err := webutil.NewFormScanner(r.Form).
@@ -244,7 +246,7 @@ func (a *App) _adminPasswordSubmit(s *api.Session, w http.ResponseWriter, r *htt
return err return err
} }
if len(newPwd) < 8 { if len(newPwd) < 8 || len(newPwd) > 72 {
return errs.ErrInvalidPassword return errs.ErrInvalidPassword
} }
@@ -342,9 +344,10 @@ func (a *App) peersList(networkID int64) (peers []m.Peer, err error) {
} }
wgKey, err := wgtypes.NewKey(p.WGPubKey) wgKey, err := wgtypes.NewKey(p.WGPubKey)
if err != nil { if err != nil {
log.Printf("Bad WG key in DB for peer %v", p) log.Printf("Bad WG key in DB for peer %d/%d", p.NetworkID, p.PeerIP)
continue // malformed key; skip rather than serve garbage continue // malformed key; skip rather than serve garbage
} }
var signKey [32]byte var signKey [32]byte
copy(signKey[:], p.SignPubKey) copy(signKey[:], p.SignPubKey)
peers = append(peers, m.Peer{ peers = append(peers, m.Peer{

View File

@@ -9,6 +9,7 @@ import (
"net/http" "net/http"
"net/netip" "net/netip"
"os" "os"
"time"
"golang.org/x/crypto/nacl/sign" "golang.org/x/crypto/nacl/sign"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes" "golang.zx2c4.com/wireguard/wgctrl/wgtypes"
@@ -93,7 +94,7 @@ func initFromHub(hubURL, apiKey string, privKey wgtypes.Key) (LocalState, error)
req.SetBasicAuth("", apiKey) req.SetBasicAuth("", apiKey)
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req) resp, err := (&http.Client{Timeout: time.Minute}).Do(req)
if err != nil { if err != nil {
return LocalState{}, fmt.Errorf("hub init: %w", err) return LocalState{}, fmt.Errorf("hub init: %w", err)
} }

View File

@@ -63,13 +63,14 @@ func receiver(selfVPNIP netip.Addr, limiters []*ratelimiter.Limiter, ch chan<- P
continue continue
} }
if err := limiters[packet.PeerIP].Limit(); err != nil { // Slightly cheaper than limiting.
log.Printf("Rate limited packet from peer IP %d.", packet.PeerIP) age := time.Since(time.Unix(packet.Timestamp, 0))
if age > maxPacketAge || age < -maxPacketAge {
continue continue
} }
age := time.Since(time.Unix(packet.Timestamp, 0)) if err := limiters[packet.PeerIP].Limit(); err != nil {
if age > maxPacketAge || age < -maxPacketAge { log.Printf("Rate limited packet from peer IP %d.", packet.PeerIP)
continue continue
} }