Skip to content

Commit

Permalink
Add ability to set syslog IP address via the API.
Browse files Browse the repository at this point in the history
  • Loading branch information
patfair committed Jun 29, 2024
1 parent 96dcfd8 commit e5eedda
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 4 deletions.
14 changes: 13 additions & 1 deletion radio/configuration_request_ap.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package radio
import (
"errors"
"fmt"
"regexp"
)

// ConfigurationRequest represents a JSON request to configure the radio.
Expand All @@ -26,6 +27,9 @@ type ConfigurationRequest struct {
// SSID and WPA key for each team station, keyed by alliance and number (e.g. "red1", "blue3). If a station is not
// included, its network will be disabled by setting its SSID to a placeholder.
StationConfigurations map[string]StationConfiguration `json:"stationConfigurations"`

// IP address of the syslog server to send logs to (via UDP on port 514).
SyslogIpAddress string `json:"syslogIpAddress"`
}

// StationConfiguration represents the configuration for a single team station.
Expand All @@ -42,7 +46,7 @@ var validLinksysChannels = []int{36, 40, 44, 48, 149, 153, 157, 161, 165}
// Validate checks that all parameters within the configuration request have valid values.
func (request ConfigurationRequest) Validate(radio *Radio) error {
if request.Channel == 0 && request.ChannelBandwidth == "" && len(request.StationConfigurations) == 0 &&
request.RedVlans == "" && request.BlueVlans == "" {
request.RedVlans == "" && request.BlueVlans == "" && request.SyslogIpAddress == "" {
return errors.New("empty configuration request")
}

Expand Down Expand Up @@ -117,5 +121,13 @@ func (request ConfigurationRequest) Validate(radio *Radio) error {
}
}

// Validate syslog IP address.
if request.SyslogIpAddress != "" {
match, _ := regexp.MatchString("^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$", request.SyslogIpAddress)
if !match {
return fmt.Errorf("invalid syslog IP address: %s", request.SyslogIpAddress)
}
}

return nil
}
5 changes: 5 additions & 0 deletions radio/configuration_request_ap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,9 @@ func TestConfigurationRequest_Validate(t *testing.T) {
}
err = request.Validate(linksysRadio)
assert.EqualError(t, err, "invalid WPA key length for station blue1: 17 (expecting 8-16)")

// Invalid syslog IP address.
request = ConfigurationRequest{SyslogIpAddress: "10.0.100.256"}
err = request.Validate(linksysRadio)
assert.EqualError(t, err, "invalid syslog IP address: 10.0.100.256")
}
15 changes: 15 additions & 0 deletions radio/radio_ap.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ type Radio struct {
// Map of team station names to their current status.
StationStatuses map[string]*NetworkStatus `json:"stationStatuses"`

// IP address of the syslog server to send logs to (via UDP on port 514).
SyslogIpAddress string `json:"syslogIpAddress"`

// Version of the radio software.
Version string `json:"version"`

Expand Down Expand Up @@ -182,6 +185,8 @@ func (radio *Radio) setInitialState() {
radio.ChannelBandwidth = "INVALID"
}
_ = radio.updateStationStatuses()

radio.SyslogIpAddress, _ = uciTree.GetLast("system", "@system[0]", "log_ip")
}

// configure configures the radio with the given configuration.
Expand Down Expand Up @@ -214,6 +219,16 @@ func (radio *Radio) configure(request ConfigurationRequest) error {
radio.spareVlans = Vlans102030
}
}
if request.SyslogIpAddress != "" {
uciTree.SetType("system", "@system[0]", "log_ip", uci.TypeOption, request.SyslogIpAddress)
if err := uciTree.Commit(); err != nil {
return fmt.Errorf("failed to commit system configuration: %v", err)
}
radio.SyslogIpAddress = request.SyslogIpAddress
if _, err := shell.runCommand("/etc/init.d/log", "restart"); err != nil {
return fmt.Errorf("failed to restart syslog service: %v", err)
}
}

if radio.Type == TypeLinksys {
// Clear the state of the radio before loading teams; the Linksys AP is crash-prone otherwise.
Expand Down
13 changes: 10 additions & 3 deletions radio/radio_ap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ func TestRadio_setInitialState(t *testing.T) {

fakeTree.valuesForGet["wireless.wifi1.channel"] = "23"
fakeTree.valuesForGet["wireless.wifi1.htmode"] = "HT20"
fakeTree.valuesForGet["system.@system[0].log_ip"] = "10.20.30.40"
fakeShell.commandOutput["iwinfo ath1 info"] = "ath1\nESSID: \"1111\"\n"
fakeShell.commandOutput["iwinfo ath11 info"] = "ath11\nESSID: \"no-team-2\"\n"
fakeShell.commandOutput["iwinfo ath12 info"] = "ath12\nESSID: \"no-team-3\"\n"
Expand All @@ -142,6 +143,7 @@ func TestRadio_setInitialState(t *testing.T) {
assert.Nil(t, radio.StationStatuses["blue1"])
assert.Nil(t, radio.StationStatuses["blue2"])
assert.Equal(t, "6666", radio.StationStatuses["blue3"].Ssid)
assert.Equal(t, "10.20.30.40", radio.SyslogIpAddress)
}

func TestRadio_handleConfigurationRequestVividHosting(t *testing.T) {
Expand All @@ -154,6 +156,7 @@ func TestRadio_handleConfigurationRequestVividHosting(t *testing.T) {
fakeShell.commandOutput["cat /etc/vh_firmware"] = ""
radio := NewRadio()

fakeShell.commandOutput["/etc/init.d/log restart"] = ""
fakeShell.commandOutput["wifi reload wifi1"] = ""
fakeShell.commandOutput["iwinfo ath1 info"] = "ath1\nESSID: \"1111\"\n"
fakeShell.commandOutput["iwinfo ath11 info"] = "ath11\nESSID: \"no-team-2\"\n"
Expand All @@ -177,12 +180,14 @@ func TestRadio_handleConfigurationRequestVividHosting(t *testing.T) {
"blue2": {Ssid: "5555", WpaKey: "55555555"},
"blue3": {Ssid: "6666", WpaKey: "66666666"},
},
SyslogIpAddress: "12.34.56.78",
}
radio.ConfigurationRequestChannel <- dummyRequest2
radio.ConfigurationRequestChannel <- request
assert.Nil(t, radio.handleConfigurationRequest(dummyRequest1))
assert.Equal(t, 28, fakeTree.setCount)
assert.Equal(t, 29, fakeTree.setCount)
assert.Equal(t, fakeTree.valuesFromSet["wireless.wifi1.channel"], "5")
assert.Equal(t, fakeTree.valuesFromSet["system.@system[0].log_ip"], "12.34.56.78")
assert.Equal(t, fakeTree.valuesFromSet["wireless.@wifi-iface[1].ssid"], "1111")
assert.Equal(t, fakeTree.valuesFromSet["wireless.@wifi-iface[1].key"], "11111111")
assert.Equal(t, fakeTree.valuesFromSet["wireless.@wifi-iface[1].sae_password"], "11111111")
Expand Down Expand Up @@ -210,8 +215,9 @@ func TestRadio_handleConfigurationRequestVividHosting(t *testing.T) {
assert.Equal(t, fakeTree.valuesFromSet["wireless.@wifi-iface[9].ssid"], "no-team-9")
assert.Equal(t, fakeTree.valuesFromSet["wireless.@wifi-iface[9].key"], "no-team-9")
assert.Equal(t, fakeTree.valuesFromSet["wireless.@wifi-iface[9].sae_password"], "no-team-9")
assert.Equal(t, 9, fakeTree.commitCount)
assert.Equal(t, 8, len(fakeShell.commandsRun))
assert.Equal(t, 10, fakeTree.commitCount)
assert.Equal(t, 9, len(fakeShell.commandsRun))
assert.Contains(t, fakeShell.commandsRun, "/etc/init.d/log restart")
assert.Contains(t, fakeShell.commandsRun, "wifi reload wifi1")
assert.Contains(t, fakeShell.commandsRun, "iwinfo ath1 info")
assert.Contains(t, fakeShell.commandsRun, "iwinfo ath11 info")
Expand All @@ -220,6 +226,7 @@ func TestRadio_handleConfigurationRequestVividHosting(t *testing.T) {
assert.Contains(t, fakeShell.commandsRun, "iwinfo ath14 info")
assert.Contains(t, fakeShell.commandsRun, "iwinfo ath15 info")

assert.Equal(t, "12.34.56.78", radio.SyslogIpAddress)
assert.Equal(t, "1111", radio.StationStatuses["red1"].Ssid)
assert.Nil(t, radio.StationStatuses["red2"])
assert.Equal(t, "3333", radio.StationStatuses["red3"].Ssid)
Expand Down

0 comments on commit e5eedda

Please sign in to comment.