Rework of entire locking system
Locking on the Device instance is now much more fined-grained, seperating out the fields into "resources" st. most common interactions only require a small number.
This commit is contained in:
parent
1e42b14022
commit
029410b118
10 changed files with 386 additions and 239 deletions
154
src/uapi.go
154
src/uapi.go
|
|
@ -25,32 +25,51 @@ func (s *IPCError) ErrorCode() int64 {
|
|||
|
||||
func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
|
||||
// create lines
|
||||
device.log.Debug.Println("UAPI: Processing get operation")
|
||||
|
||||
device.mutex.RLock()
|
||||
device.net.mutex.RLock()
|
||||
// create lines
|
||||
|
||||
lines := make([]string, 0, 100)
|
||||
send := func(line string) {
|
||||
lines = append(lines, line)
|
||||
}
|
||||
|
||||
if !device.privateKey.IsZero() {
|
||||
send("private_key=" + device.privateKey.ToHex())
|
||||
}
|
||||
func() {
|
||||
|
||||
if device.net.port != 0 {
|
||||
send(fmt.Sprintf("listen_port=%d", device.net.port))
|
||||
}
|
||||
// lock required resources
|
||||
|
||||
if device.net.fwmark != 0 {
|
||||
send(fmt.Sprintf("fwmark=%d", device.net.fwmark))
|
||||
}
|
||||
device.net.mutex.RLock()
|
||||
defer device.net.mutex.RUnlock()
|
||||
|
||||
for _, peer := range device.peers {
|
||||
func() {
|
||||
device.noise.mutex.RLock()
|
||||
defer device.noise.mutex.RUnlock()
|
||||
|
||||
device.routing.mutex.RLock()
|
||||
defer device.routing.mutex.RUnlock()
|
||||
|
||||
device.peers.mutex.Lock()
|
||||
defer device.peers.mutex.Unlock()
|
||||
|
||||
// serialize device related values
|
||||
|
||||
if !device.noise.privateKey.IsZero() {
|
||||
send("private_key=" + device.noise.privateKey.ToHex())
|
||||
}
|
||||
|
||||
if device.net.port != 0 {
|
||||
send(fmt.Sprintf("listen_port=%d", device.net.port))
|
||||
}
|
||||
|
||||
if device.net.fwmark != 0 {
|
||||
send(fmt.Sprintf("fwmark=%d", device.net.fwmark))
|
||||
}
|
||||
|
||||
// serialize each peer state
|
||||
|
||||
for _, peer := range device.peers.keyMap {
|
||||
peer.mutex.RLock()
|
||||
defer peer.mutex.RUnlock()
|
||||
|
||||
send("public_key=" + peer.handshake.remoteStatic.ToHex())
|
||||
send("preshared_key=" + peer.handshake.presharedKey.ToHex())
|
||||
if peer.endpoint != nil {
|
||||
|
|
@ -69,16 +88,14 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
atomic.LoadUint64(&peer.persistentKeepaliveInterval),
|
||||
))
|
||||
|
||||
for _, ip := range device.routingTable.AllowedIPs(peer) {
|
||||
for _, ip := range device.routing.table.AllowedIPs(peer) {
|
||||
send("allowed_ip=" + ip.String())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
device.net.mutex.RUnlock()
|
||||
device.mutex.RUnlock()
|
||||
}
|
||||
}()
|
||||
|
||||
// send lines
|
||||
// send lines (does not require resource locks)
|
||||
|
||||
for _, line := range lines {
|
||||
_, err := socket.WriteString(line + "\n")
|
||||
|
|
@ -94,7 +111,6 @@ func ipcGetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
|
||||
func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
||||
scanner := bufio.NewScanner(socket)
|
||||
logInfo := device.log.Info
|
||||
logError := device.log.Error
|
||||
logDebug := device.log.Debug
|
||||
|
||||
|
|
@ -130,6 +146,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
logError.Println("Failed to set private_key:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
logDebug.Println("UAPI: Updating device private key")
|
||||
device.SetPrivateKey(sk)
|
||||
|
||||
case "listen_port":
|
||||
|
|
@ -144,6 +161,8 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
|
||||
// update port and rebind
|
||||
|
||||
logDebug.Println("UAPI: Updating listen port")
|
||||
|
||||
device.net.mutex.Lock()
|
||||
device.net.port = uint16(port)
|
||||
device.net.mutex.Unlock()
|
||||
|
|
@ -170,6 +189,8 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
|
||||
logDebug.Println("UAPI: Updating fwmark")
|
||||
|
||||
device.net.mutex.Lock()
|
||||
device.net.fwmark = uint32(fwmark)
|
||||
device.net.mutex.Unlock()
|
||||
|
|
@ -181,6 +202,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
|
||||
case "public_key":
|
||||
// switch to peer configuration
|
||||
logDebug.Println("UAPI: Transition to peer configuration")
|
||||
deviceConfig = false
|
||||
|
||||
case "replace_peers":
|
||||
|
|
@ -188,6 +210,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
logError.Println("Failed to set replace_peers, invalid value:", value)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
logDebug.Println("UAPI: Removing all peers")
|
||||
device.RemoveAllPeers()
|
||||
|
||||
default:
|
||||
|
|
@ -203,43 +226,41 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
switch key {
|
||||
|
||||
case "public_key":
|
||||
var pubKey NoisePublicKey
|
||||
err := pubKey.FromHex(value)
|
||||
var publicKey NoisePublicKey
|
||||
err := publicKey.FromHex(value)
|
||||
if err != nil {
|
||||
logError.Println("Failed to get peer by public_key:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
|
||||
// check if public key of peer equal to device
|
||||
// ignore peer with public key of device
|
||||
|
||||
device.mutex.RLock()
|
||||
if device.publicKey.Equals(pubKey) {
|
||||
|
||||
// create dummy instance (not added to device)
|
||||
device.noise.mutex.RLock()
|
||||
equals := device.noise.publicKey.Equals(publicKey)
|
||||
device.noise.mutex.RUnlock()
|
||||
|
||||
if equals {
|
||||
peer = &Peer{}
|
||||
dummy = true
|
||||
device.mutex.RUnlock()
|
||||
logInfo.Println("Ignoring peer with public key of device")
|
||||
|
||||
} else {
|
||||
|
||||
// find peer referenced
|
||||
|
||||
peer, _ = device.peers[pubKey]
|
||||
device.mutex.RUnlock()
|
||||
if peer == nil {
|
||||
peer, err = device.NewPeer(pubKey)
|
||||
if err != nil {
|
||||
logError.Println("Failed to create new peer:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
}
|
||||
peer.timer.handshakeDeadline.Reset(RekeyAttemptTime)
|
||||
dummy = false
|
||||
|
||||
}
|
||||
|
||||
// find peer referenced
|
||||
|
||||
peer = device.LookupPeer(publicKey)
|
||||
|
||||
if peer == nil {
|
||||
peer, err = device.NewPeer(publicKey)
|
||||
if err != nil {
|
||||
logError.Println("Failed to create new peer:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
logDebug.Println("UAPI: Created new peer:", peer.String())
|
||||
}
|
||||
|
||||
peer.mutex.Lock()
|
||||
peer.timer.handshakeDeadline.Reset(RekeyAttemptTime)
|
||||
peer.mutex.Unlock()
|
||||
|
||||
case "remove":
|
||||
|
||||
// remove currently selected peer from device
|
||||
|
|
@ -249,7 +270,7 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
if !dummy {
|
||||
logDebug.Println("Removing", peer.String())
|
||||
logDebug.Println("UAPI: Removing peer:", peer.String())
|
||||
device.RemovePeer(peer.handshake.remoteStatic)
|
||||
}
|
||||
peer = &Peer{}
|
||||
|
|
@ -259,9 +280,12 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
|
||||
// update PSK
|
||||
|
||||
peer.mutex.Lock()
|
||||
logDebug.Println("UAPI: Updating pre-shared key for peer:", peer.String())
|
||||
|
||||
peer.handshake.mutex.Lock()
|
||||
err := peer.handshake.presharedKey.FromHex(value)
|
||||
peer.mutex.Unlock()
|
||||
peer.handshake.mutex.Unlock()
|
||||
|
||||
if err != nil {
|
||||
logError.Println("Failed to set preshared_key:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
|
|
@ -271,6 +295,8 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
|
||||
// set endpoint destination
|
||||
|
||||
logDebug.Println("UAPI: Updating endpoint for peer:", peer.String())
|
||||
|
||||
err := func() error {
|
||||
peer.mutex.Lock()
|
||||
defer peer.mutex.Unlock()
|
||||
|
|
@ -292,6 +318,8 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
|
||||
// update keep-alive interval
|
||||
|
||||
logDebug.Println("UAPI: Updating persistent_keepalive_interval for peer:", peer.String())
|
||||
|
||||
secs, err := strconv.ParseUint(value, 10, 16)
|
||||
if err != nil {
|
||||
logError.Println("Failed to set persistent_keepalive_interval:", err)
|
||||
|
|
@ -316,25 +344,41 @@ func ipcSetOperation(device *Device, socket *bufio.ReadWriter) *IPCError {
|
|||
}
|
||||
|
||||
case "replace_allowed_ips":
|
||||
|
||||
logDebug.Println("UAPI: Removing all allowed IPs for peer:", peer.String())
|
||||
|
||||
if value != "true" {
|
||||
logError.Println("Failed to set replace_allowed_ips, invalid value:", value)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
if !dummy {
|
||||
device.routingTable.RemovePeer(peer)
|
||||
|
||||
if dummy {
|
||||
continue
|
||||
}
|
||||
|
||||
device.routing.mutex.Lock()
|
||||
device.routing.table.RemovePeer(peer)
|
||||
device.routing.mutex.Unlock()
|
||||
|
||||
case "allowed_ip":
|
||||
|
||||
logDebug.Println("UAPI: Adding allowed_ip to peer:", peer.String())
|
||||
|
||||
_, network, err := net.ParseCIDR(value)
|
||||
if err != nil {
|
||||
logError.Println("Failed to set allowed_ip:", err)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
}
|
||||
ones, _ := network.Mask.Size()
|
||||
if !dummy {
|
||||
device.routingTable.Insert(network.IP, uint(ones), peer)
|
||||
|
||||
if dummy {
|
||||
continue
|
||||
}
|
||||
|
||||
ones, _ := network.Mask.Size()
|
||||
device.routing.mutex.Lock()
|
||||
device.routing.table.Insert(network.IP, uint(ones), peer)
|
||||
device.routing.mutex.Unlock()
|
||||
|
||||
default:
|
||||
logError.Println("Invalid UAPI key (peer configuration):", key)
|
||||
return &IPCError{Code: ipcErrorInvalid}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue