Update network configuration to work with Linksys WRT1900ACS and Cisco Catalyst 3560G.

This commit is contained in:
Patrick Fairbank
2017-07-22 00:08:55 -07:00
parent e3eb59240a
commit 0a783b3701
14 changed files with 580 additions and 740 deletions

113
access_point_config.go Normal file
View File

@@ -0,0 +1,113 @@
// Copyright 2017 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
//
// Methods for configuring a Linksys WRT1900ACS access point running OpenWRT for team SSIDs and VLANs.
package main
import (
"bytes"
"fmt"
"golang.org/x/crypto/ssh"
"os"
"sync"
"text/template"
)
var accessPointSshPort = 22
const (
red1Vlan = 10
red2Vlan = 20
red3Vlan = 30
blue1Vlan = 40
blue2Vlan = 50
blue3Vlan = 60
)
var accessPointMutex sync.Mutex
// Sets up wireless networks for the given set of teams.
func ConfigureTeamWifi(red1, red2, red3, blue1, blue2, blue3 *Team) error {
// Make sure multiple configurations aren't being set at the same time.
accessPointMutex.Lock()
defer accessPointMutex.Unlock()
config, err := generateAccessPointConfig(red1, red2, red3, blue1, blue2, blue3)
if err != nil {
return err
}
command := fmt.Sprintf("cat <<ENDCONFIG > /etc/config/wireless && wifi radio0\n%sENDCONFIG\n", config)
return runAccessPointCommand(command)
}
func generateAccessPointConfig(red1, red2, red3, blue1, blue2, blue3 *Team) (string, error) {
// Determine what new SSIDs are needed.
networks := make(map[int]*Team)
var err error
if err = addTeamNetwork(networks, red1, red1Vlan); err != nil {
return "", err
}
if err = addTeamNetwork(networks, red2, red2Vlan); err != nil {
return "", err
}
if err = addTeamNetwork(networks, red3, red3Vlan); err != nil {
return "", err
}
if err = addTeamNetwork(networks, blue1, blue1Vlan); err != nil {
return "", err
}
if err = addTeamNetwork(networks, blue2, blue2Vlan); err != nil {
return "", err
}
if err = addTeamNetwork(networks, blue3, blue3Vlan); err != nil {
return "", err
}
// Generate the config file to be uploaded to the AP.
template, err := template.ParseFiles("templates/access_point.cfg")
if err != nil {
return "", err
}
var configFile bytes.Buffer
err = template.Execute(&configFile, networks)
if err != nil {
return "", err
}
return configFile.String(), nil
}
// Verifies the validity of the given team's WPA key and adds a network for it to the list to be configured.
func addTeamNetwork(networks map[int]*Team, team *Team, vlan int) error {
if team == nil {
return nil
}
if len(team.WpaKey) < 8 || len(team.WpaKey) > 63 {
return fmt.Errorf("Invalid WPA key '%s' configured for team %d.", team.WpaKey, team.Id)
}
networks[vlan] = team
return nil
}
// Logs into the access point via SSH and runs the given shell command.
func runAccessPointCommand(command string) error {
// Open an SSH connection to the AP.
config := &ssh.ClientConfig{User: eventSettings.ApUsername,
Auth: []ssh.AuthMethod{ssh.Password(eventSettings.ApPassword)},
HostKeyCallback: ssh.InsecureIgnoreHostKey()}
conn, err := ssh.Dial("tcp", fmt.Sprintf("%s:%d", eventSettings.ApAddress, accessPointSshPort), config)
if err != nil {
return err
}
session, err := conn.NewSession()
if err != nil {
return err
}
defer session.Close()
defer conn.Close()
session.Stdout = os.Stdout
// Run the command. An error will be returned if the exit status is non-zero.
return session.Run(command)
}

BIN
access_point_config.tar.gz Normal file

Binary file not shown.

View File

@@ -0,0 +1,80 @@
// Copyright 2014 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
package main
import (
"github.com/stretchr/testify/assert"
"regexp"
"testing"
)
func TestConfigureAccessPoint(t *testing.T) {
radioRe := regexp.MustCompile("option device 'radio0'")
ssidRe := regexp.MustCompile("option ssid '([-\\w ]+)'")
wpaKeyRe := regexp.MustCompile("option key '([-\\w ]+)'")
vlanRe := regexp.MustCompile("option network 'vlan(\\d+)'")
// Should not configure any team SSIDs if there are no teams.
config, _ := generateAccessPointConfig(nil, nil, nil, nil, nil, nil)
assert.NotContains(t, config, "option device 'radio0'")
ssids := ssidRe.FindAllStringSubmatch(config, -1)
wpaKeys := wpaKeyRe.FindAllStringSubmatch(config, -1)
vlans := vlanRe.FindAllStringSubmatch(config, -1)
assert.Equal(t, "Cheesy Arena", ssids[0][1])
assert.Equal(t, "1234Five", wpaKeys[0][1])
assert.Equal(t, "100", vlans[0][1])
// Should configure two SSID for two teams.
config, _ = generateAccessPointConfig(&Team{Id: 254, WpaKey: "aaaaaaaa"}, nil, nil, nil, nil,
&Team{Id: 1114, WpaKey: "bbbbbbbb"})
assert.Equal(t, 2, len(radioRe.FindAllString(config, -1)))
ssids = ssidRe.FindAllStringSubmatch(config, -1)
wpaKeys = wpaKeyRe.FindAllStringSubmatch(config, -1)
vlans = vlanRe.FindAllStringSubmatch(config, -1)
assert.Equal(t, "Cheesy Arena", ssids[0][1])
assert.Equal(t, "1234Five", wpaKeys[0][1])
assert.Equal(t, "100", vlans[0][1])
assert.Equal(t, "254", ssids[1][1])
assert.Equal(t, "aaaaaaaa", wpaKeys[1][1])
assert.Equal(t, "10", vlans[1][1])
assert.Equal(t, "1114", ssids[2][1])
assert.Equal(t, "bbbbbbbb", wpaKeys[2][1])
assert.Equal(t, "60", vlans[2][1])
// Should configure all SSIDs for six teams.
config, _ = generateAccessPointConfig(&Team{Id: 1, WpaKey: "11111111"},
&Team{Id: 2, WpaKey: "22222222"}, &Team{Id: 3, WpaKey: "33333333"}, &Team{Id: 4, WpaKey: "44444444"},
&Team{Id: 5, WpaKey: "55555555"}, &Team{Id: 6, WpaKey: "66666666"})
assert.Equal(t, 6, len(radioRe.FindAllString(config, -1)))
ssids = ssidRe.FindAllStringSubmatch(config, -1)
wpaKeys = wpaKeyRe.FindAllStringSubmatch(config, -1)
vlans = vlanRe.FindAllStringSubmatch(config, -1)
assert.Equal(t, "Cheesy Arena", ssids[0][1])
assert.Equal(t, "1234Five", wpaKeys[0][1])
assert.Equal(t, "100", vlans[0][1])
assert.Equal(t, "1", ssids[1][1])
assert.Equal(t, "11111111", wpaKeys[1][1])
assert.Equal(t, "10", vlans[1][1])
assert.Equal(t, "2", ssids[2][1])
assert.Equal(t, "22222222", wpaKeys[2][1])
assert.Equal(t, "20", vlans[2][1])
assert.Equal(t, "3", ssids[3][1])
assert.Equal(t, "33333333", wpaKeys[3][1])
assert.Equal(t, "30", vlans[3][1])
assert.Equal(t, "4", ssids[4][1])
assert.Equal(t, "44444444", wpaKeys[4][1])
assert.Equal(t, "40", vlans[4][1])
assert.Equal(t, "5", ssids[5][1])
assert.Equal(t, "55555555", wpaKeys[5][1])
assert.Equal(t, "50", vlans[5][1])
assert.Equal(t, "6", ssids[6][1])
assert.Equal(t, "66666666", wpaKeys[6][1])
assert.Equal(t, "60", vlans[6][1])
// Should reject a missing WPA key.
_, err := generateAccessPointConfig(&Team{Id: 254}, nil, nil, nil, nil, nil)
if assert.NotNil(t, err) {
assert.Contains(t, err.Error(), "Invalid WPA key")
}
}

View File

@@ -1,151 +0,0 @@
// Copyright 2014 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
//
// Methods for configuring a Cisco Aironet AP1252AG access point for team SSIDs and VLANs.
package main
import (
"bufio"
"bytes"
"fmt"
"net"
"regexp"
"strconv"
"sync"
)
var aironetTelnetPort = 23
const (
red1Vlan = 11
red2Vlan = 12
red3Vlan = 13
blue1Vlan = 14
blue2Vlan = 15
blue3Vlan = 16
)
var aironetMutex sync.Mutex
// Sets up wireless networks for the given set of teams.
func ConfigureTeamWifi(red1, red2, red3, blue1, blue2, blue3 *Team) error {
// Make sure multiple configurations aren't being set at the same time.
aironetMutex.Lock()
defer aironetMutex.Unlock()
for _, team := range []*Team{red1, red2, red3, blue1, blue2, blue3} {
if team != nil && (len(team.WpaKey) < 8 || len(team.WpaKey) > 63) {
return fmt.Errorf("Invalid WPA key '%s' configured for team %d.", team.WpaKey, team.Id)
}
}
// Determine what new SSIDs are needed and build the commands to set them up.
oldSsids, err := getSsids()
if err != nil {
return err
}
addSsidsCommand := ""
associateSsidsCommand := ""
replaceSsid := func(team *Team, vlan int) {
if team == nil {
return
}
if oldSsids[strconv.Itoa(team.Id)] == vlan {
delete(oldSsids, strconv.Itoa(team.Id))
} else {
addSsidsCommand += fmt.Sprintf("dot11 ssid %d\nvlan %d\nauthentication open\nauthentication "+
"key-management wpa version 2\nmbssid guest-mode\nwpa-psk ascii %s\n", team.Id, vlan, team.WpaKey)
associateSsidsCommand += fmt.Sprintf("ssid %d\n", team.Id)
}
}
replaceSsid(red1, red1Vlan)
replaceSsid(red2, red2Vlan)
replaceSsid(red3, red3Vlan)
replaceSsid(blue1, blue1Vlan)
replaceSsid(blue2, blue2Vlan)
replaceSsid(blue3, blue3Vlan)
if len(addSsidsCommand) != 0 {
associateSsidsCommand = "interface Dot11Radio1\n" + associateSsidsCommand
}
// Build the command to remove the SSIDs that are no longer needed.
removeSsidsCommand := ""
for ssid, _ := range oldSsids {
removeSsidsCommand += fmt.Sprintf("no dot11 ssid %s\n", ssid)
}
// Build and run the overall command to do everything in a single telnet session.
command := removeSsidsCommand + addSsidsCommand + associateSsidsCommand
if len(command) > 0 {
_, err = runAironetConfigCommand(removeSsidsCommand + addSsidsCommand + associateSsidsCommand)
if err != nil {
return err
}
}
return nil
}
// Returns a map of currently-configured SSIDs to VLANs.
func getSsids() (map[string]int, error) {
// Get the entire config dump.
config, err := runAironetCommand("show running-config\n")
if err != nil {
return nil, err
}
// Parse out the SSIDs and VLANs from the config dump.
re := regexp.MustCompile("(?s)dot11 ssid (\\w+)\\s+vlan (1[1-6])")
ssidMatches := re.FindAllStringSubmatch(config, -1)
if ssidMatches == nil {
// There are probably no SSIDs currently configured.
return nil, nil
}
// Build the map of SSID to VLAN.
ssids := make(map[string]int)
for _, match := range ssidMatches {
vlan, _ := strconv.Atoi(match[2])
ssids[match[1]] = vlan
}
return ssids, nil
}
// Logs into the Aironet via Telnet and runs the given command in user exec mode. Reads the output and returns
// it as a string.
func runAironetCommand(command string) (string, error) {
// Open a Telnet connection to the AP.
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", eventSettings.ApAddress, aironetTelnetPort))
if err != nil {
return "", err
}
defer conn.Close()
// Login to the AP, send the command, and log out all at once.
writer := bufio.NewWriter(conn)
_, err = writer.WriteString(fmt.Sprintf("%s\n%s\nterminal length 0\n%sexit\n", eventSettings.ApUsername,
eventSettings.ApPassword, command))
if err != nil {
return "", err
}
err = writer.Flush()
if err != nil {
return "", err
}
// Read the response.
var reader bytes.Buffer
_, err = reader.ReadFrom(conn)
if err != nil {
return "", err
}
return reader.String(), nil
}
// Logs into the Aironet via Telnet and runs the given command in global configuration mode. Reads the output
// and returns it as a string.
func runAironetConfigCommand(command string) (string, error) {
return runAironetCommand(fmt.Sprintf("config terminal\n%send\ncopy running-config startup-config\n\n",
command))
}

View File

@@ -1,77 +0,0 @@
// Copyright 2014 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
package main
import (
"bytes"
"fmt"
"github.com/stretchr/testify/assert"
"net"
"testing"
"time"
)
func TestConfigureAironet(t *testing.T) {
aironetTelnetPort = 9023
eventSettings = &EventSettings{ApAddress: "127.0.0.1", ApUsername: "user", ApPassword: "password"}
var command string
// Should do nothing if current configuration is blank.
mockTelnet(t, aironetTelnetPort, "", &command)
assert.Nil(t, ConfigureTeamWifi(nil, nil, nil, nil, nil, nil))
assert.Equal(t, "", command)
// Should remove any existing teams but not other SSIDs.
aironetTelnetPort += 1
mockTelnet(t, aironetTelnetPort,
"dot11 ssid 1\nvlan 1\ndot11 ssid 254\nvlan 12\ndot11 ssid Cheesy Arena\nvlan 17\n", &command)
assert.Nil(t, ConfigureTeamWifi(nil, nil, nil, nil, nil, nil))
assert.Equal(t, "user\npassword\nterminal length 0\nconfig terminal\nno dot11 ssid 254\nend\n"+
"copy running-config startup-config\n\nexit\n", command)
// Should configure new teams and leave existing ones alone if still needed.
aironetTelnetPort += 1
mockTelnet(t, aironetTelnetPort, "dot11 ssid 254\nvlan 11\n", &command)
assert.Nil(t, ConfigureTeamWifi(&Team{Id: 254, WpaKey: "aaaaaaaa"}, nil, nil, nil, nil,
&Team{Id: 1114, WpaKey: "bbbbbbbb"}))
assert.Equal(t, "user\npassword\nterminal length 0\nconfig terminal\ndot11 ssid 1114\nvlan 16\n"+
"authentication open\nauthentication key-management wpa version 2\nmbssid guest-mode\nwpa-psk ascii "+
"bbbbbbbb\ninterface Dot11Radio1\nssid 1114\nend\ncopy running-config startup-config\n\nexit\n",
command)
// Should reject a missing WPA key.
aironetTelnetPort += 1
mockTelnet(t, aironetTelnetPort, "", &command)
err := ConfigureTeamWifi(&Team{Id: 254}, nil, nil, nil, nil, nil)
if assert.NotNil(t, err) {
assert.Contains(t, err.Error(), "Invalid WPA key")
}
}
func mockTelnet(t *testing.T, port int, response string, command *string) {
go func() {
// Fake the first connection which should just get the configuration.
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
assert.Nil(t, err)
defer ln.Close()
conn, err := ln.Accept()
assert.Nil(t, err)
conn.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
var reader bytes.Buffer
reader.ReadFrom(conn)
assert.Contains(t, reader.String(), "terminal length 0\nshow running-config\nexit\n")
conn.Write([]byte(response))
conn.Close()
// Fake the second connection which should configure stuff.
conn2, err := ln.Accept()
assert.Nil(t, err)
conn2.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
var reader2 bytes.Buffer
reader2.ReadFrom(conn2)
*command = reader2.String()
conn2.Close()
}()
time.Sleep(100 * time.Millisecond) // Give it some time to open the socket.
}

View File

@@ -1,316 +0,0 @@
! Baseline configuration for the Cisco Aironet AP1252AG access point. Load this into the AP prior to
! configuring Cheesy Arena to connect to it. Default user/pass is cheesyarena/1234Five.
!
version 15.2
no service pad
service timestamps debug datetime msec
service timestamps log datetime msec
service password-encryption
!
hostname ChezyAP
!
logging rate-limit console 9
!
aaa new-model
!
!
aaa authentication login default local
aaa authorization exec default local
!
!
!
!
!
aaa session-id common
!
!
dot11 syslog
dot11 vlan-name Blue1 vlan 14
dot11 vlan-name Blue2 vlan 15
dot11 vlan-name Blue3 vlan 16
dot11 vlan-name CheesyArena vlan 2
dot11 vlan-name Red1 vlan 11
dot11 vlan-name Red2 vlan 12
dot11 vlan-name Red3 vlan 13
!
dot11 ssid 1
vlan 11
authentication open
authentication key-management wpa version 2
mbssid guest-mode
wpa-psk ascii 7 0257550A5A575E701D
!
dot11 ssid 2
vlan 12
authentication open
authentication key-management wpa version 2
mbssid guest-mode
wpa-psk ascii 7 06545D731E1C5B4B57
!
dot11 ssid 3
vlan 13
authentication open
authentication key-management wpa version 2
mbssid guest-mode
wpa-psk ascii 7 115A4A564441585F57
!
dot11 ssid 4
vlan 14
authentication open
authentication key-management wpa version 2
mbssid guest-mode
wpa-psk ascii 7 101A5D4D5143465F58
!
dot11 ssid 5
vlan 15
authentication open
authentication key-management wpa version 2
mbssid guest-mode
wpa-psk ascii 7 00514653510E5E535A
!
dot11 ssid 6
vlan 16
authentication open
authentication key-management wpa version 2
mbssid guest-mode
wpa-psk ascii 7 1441445D5A527C7D72
!
dot11 ssid Cheesy Arena
vlan 2
authentication open
authentication key-management wpa version 2
guest-mode
wpa-psk ascii 7 144640585822233D21
!
crypto pki token default removal timeout 0
!
!
username cheesyarena privilege 15 password 7 040A59555B0745580C
!
!
bridge irb
!
!
interface Dot11Radio0
no ip address
no ip route-cache
!
encryption mode ciphers aes-ccm tkip
!
encryption vlan 2 mode ciphers aes-ccm tkip
!
ssid Cheesy Arena
!
antenna gain 0
station-role root
no dot11 extension aironet
bridge-group 1
bridge-group 1 subscriber-loop-control
bridge-group 1 spanning-disabled
bridge-group 1 block-unknown-source
no bridge-group 1 source-learning
no bridge-group 1 unicast-flooding
!
interface Dot11Radio0.2
encapsulation dot1Q 2
no ip route-cache
bridge-group 2
bridge-group 2 subscriber-loop-control
bridge-group 2 spanning-disabled
bridge-group 2 block-unknown-source
no bridge-group 2 source-learning
no bridge-group 2 unicast-flooding
!
interface Dot11Radio1
no ip address
no ip route-cache
!
encryption mode ciphers aes-ccm tkip
!
encryption vlan 11 mode ciphers aes-ccm tkip
!
encryption vlan 12 mode ciphers aes-ccm tkip
!
encryption vlan 13 mode ciphers aes-ccm tkip
!
encryption vlan 14 mode ciphers aes-ccm tkip
!
encryption vlan 15 mode ciphers aes-ccm tkip
!
encryption vlan 16 mode ciphers aes-ccm tkip
!
ssid 1
!
ssid 2
!
ssid 3
!
ssid 4
!
ssid 5
!
ssid 6
!
antenna gain 0
dfs band 3 block
mbssid
channel width 40-above
channel dfs
station-role root
no dot11 extension aironet
bridge-group 1
bridge-group 1 subscriber-loop-control
bridge-group 1 spanning-disabled
bridge-group 1 block-unknown-source
no bridge-group 1 source-learning
no bridge-group 1 unicast-flooding
!
interface Dot11Radio1.11
encapsulation dot1Q 11
no ip route-cache
bridge-group 11
bridge-group 11 subscriber-loop-control
bridge-group 11 spanning-disabled
bridge-group 11 block-unknown-source
no bridge-group 11 source-learning
no bridge-group 11 unicast-flooding
!
interface Dot11Radio1.12
encapsulation dot1Q 12
no ip route-cache
bridge-group 12
bridge-group 12 subscriber-loop-control
bridge-group 12 spanning-disabled
bridge-group 12 block-unknown-source
no bridge-group 12 source-learning
no bridge-group 12 unicast-flooding
!
interface Dot11Radio1.13
encapsulation dot1Q 13
no ip route-cache
bridge-group 13
bridge-group 13 subscriber-loop-control
bridge-group 13 spanning-disabled
bridge-group 13 block-unknown-source
no bridge-group 13 source-learning
no bridge-group 13 unicast-flooding
!
interface Dot11Radio1.14
encapsulation dot1Q 14
no ip route-cache
bridge-group 14
bridge-group 14 subscriber-loop-control
bridge-group 14 spanning-disabled
bridge-group 14 block-unknown-source
no bridge-group 14 source-learning
no bridge-group 14 unicast-flooding
!
interface Dot11Radio1.15
encapsulation dot1Q 15
no ip route-cache
bridge-group 15
bridge-group 15 subscriber-loop-control
bridge-group 15 spanning-disabled
bridge-group 15 block-unknown-source
no bridge-group 15 source-learning
no bridge-group 15 unicast-flooding
!
interface Dot11Radio1.16
encapsulation dot1Q 16
no ip route-cache
bridge-group 16
bridge-group 16 subscriber-loop-control
bridge-group 16 spanning-disabled
bridge-group 16 block-unknown-source
no bridge-group 16 source-learning
no bridge-group 16 unicast-flooding
!
interface GigabitEthernet0
no ip address
no ip route-cache
duplex auto
speed auto
bridge-group 1
bridge-group 1 spanning-disabled
no bridge-group 1 source-learning
!
interface GigabitEthernet0.2
encapsulation dot1Q 2
no ip route-cache
bridge-group 2
bridge-group 2 spanning-disabled
no bridge-group 2 source-learning
!
interface GigabitEthernet0.11
encapsulation dot1Q 11
ip access-group 100 in
no ip route-cache
bridge-group 11
bridge-group 11 spanning-disabled
no bridge-group 11 source-learning
!
interface GigabitEthernet0.12
encapsulation dot1Q 12
ip access-group 100 in
no ip route-cache
bridge-group 12
bridge-group 12 spanning-disabled
no bridge-group 12 source-learning
!
interface GigabitEthernet0.13
encapsulation dot1Q 13
ip access-group 100 in
no ip route-cache
bridge-group 13
bridge-group 13 spanning-disabled
no bridge-group 13 source-learning
!
interface GigabitEthernet0.14
encapsulation dot1Q 14
ip access-group 100 in
no ip route-cache
bridge-group 14
bridge-group 14 spanning-disabled
no bridge-group 14 source-learning
!
interface GigabitEthernet0.15
encapsulation dot1Q 15
ip access-group 100 in
no ip route-cache
bridge-group 15
bridge-group 15 spanning-disabled
no bridge-group 15 source-learning
!
interface GigabitEthernet0.16
encapsulation dot1Q 16
ip access-group 100 in
ip access-group 101 out
no ip route-cache
bridge-group 16
bridge-group 16 spanning-disabled
no bridge-group 16 source-learning
!
interface BVI1
ip address 10.0.0.60 255.0.0.0
no ip route-cache
!
ip default-gateway 10.0.0.1
ip http server
ip http authentication aaa
no ip http secure-server
ip http help-path http://www.cisco.com/warp/public/779/smbiz/prodconfig/help/eag
access-list 100 deny udp any any eq 1120
access-list 100 permit ip any any
access-list 101 deny tcp any any eq 1750
access-list 101 permit ip any any
!
bridge 1 route ip
!
!
!
line con 0
line vty 0 4
transport input all
!
sntp server 216.66.0.142
end

View File

@@ -495,8 +495,8 @@ func TestSetupNetwork(t *testing.T) {
// Verify the setup ran by checking the log for the expected failure messages.
eventSettings.NetworkSecurityEnabled = true
aironetTelnetPort = 10023
catalystTelnetPort = 10023
accessPointSshPort = 10022
switchTelnetPort = 10023
mainArena.LoadMatch(&Match{Type: "test"})
var writer bytes.Buffer
log.SetOutput(&writer)

View File

@@ -1,39 +0,0 @@
// Copyright 2014 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
package main
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestConfigureCatalyst(t *testing.T) {
catalystTelnetPort = 9050
eventSettings = &EventSettings{SwitchAddress: "127.0.0.1", SwitchPassword: "password"}
var command string
// Should do nothing if current configuration is blank.
mockTelnet(t, catalystTelnetPort, "", &command)
assert.Nil(t, ConfigureTeamEthernet(nil, nil, nil, nil, nil, nil))
assert.Equal(t, "", command)
// Should remove any existing teams but not other SSIDs.
catalystTelnetPort += 1
mockTelnet(t, catalystTelnetPort,
"interface Vlan2\nip address 10.0.100.2\ninterface Vlan15\nip address 10.2.54.61\n", &command)
assert.Nil(t, ConfigureTeamEthernet(nil, nil, nil, nil, nil, nil))
assert.Equal(t, "password\nenable\npassword\nterminal length 0\nconfig terminal\ninterface Vlan15\nno ip"+
" address\nno access-list 115\nend\ncopy running-config startup-config\n\nexit\n", command)
// Should configure new teams and leave existing ones alone if still needed.
catalystTelnetPort += 1
mockTelnet(t, catalystTelnetPort, "interface Vlan15\nip address 10.2.54.61\n", &command)
assert.Nil(t, ConfigureTeamEthernet(nil, &Team{Id: 1114}, nil, nil, &Team{Id: 254}, nil))
assert.Equal(t, "password\nenable\npassword\nterminal length 0\nconfig terminal\n"+
"ip dhcp excluded-address 10.11.14.1 10.11.14.100\nno ip dhcp pool dhcp12\nip dhcp pool dhcp12\n"+
"network 10.11.14.0 255.255.255.0\ndefault-router 10.11.14.61\nlease 7\nno access-list 112\n"+
"access-list 112 permit ip 10.11.14.0 0.0.0.255 host 10.0.100.5\n"+
"access-list 112 permit udp any eq bootpc any eq bootps\ninterface Vlan12\n"+
"ip address 10.11.14.61 255.255.255.0\nend\ncopy running-config startup-config\n\nexit\n", command)
}

View File

@@ -154,10 +154,12 @@ func TestListenForDriverStations(t *testing.T) {
defer db.Close()
eventSettings, _ = db.GetEventSettings()
oldAddress := driverStationTcpListenAddress
driverStationTcpListenAddress = "127.0.0.1"
go ListenForDriverStations()
mainArena.Setup()
time.Sleep(time.Millisecond * 10)
driverStationTcpListenAddress = oldAddress // Put it back to avoid affecting other tests.
// Connect with an invalid initial packet.
tcpConn, err := net.Dial("tcp", "127.0.0.1:1750")

View File

@@ -1,7 +1,7 @@
// Copyright 2014 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
//
// Methods for configuring a Cisco Catalyst 3750 switch for team VLANs.
// Methods for configuring a Cisco Switch 3500-series switch for team VLANs.
package main
@@ -15,15 +15,15 @@ import (
"sync"
)
var catalystTelnetPort = 23
var switchTelnetPort = 23
var catalystMutex sync.Mutex
var switchMutex sync.Mutex
// Sets up wired networks for the given set of teams.
func ConfigureTeamEthernet(red1, red2, red3, blue1, blue2, blue3 *Team) error {
// Make sure multiple configurations aren't being set at the same time.
catalystMutex.Lock()
defer catalystMutex.Unlock()
switchMutex.Lock()
defer switchMutex.Unlock()
// Determine what new team VLANs are needed and build the commands to set them up.
oldTeamVlans, err := getTeamVlans()
@@ -70,7 +70,7 @@ func ConfigureTeamEthernet(red1, red2, red3, blue1, blue2, blue3 *Team) error {
// Build and run the overall command to do everything in a single telnet session.
command := removeTeamVlansCommand + addTeamVlansCommand
if len(command) > 0 {
_, err = runCatalystConfigCommand(removeTeamVlansCommand + addTeamVlansCommand)
_, err = runSwitchConfigCommand(removeTeamVlansCommand + addTeamVlansCommand)
if err != nil {
return err
}
@@ -82,7 +82,7 @@ func ConfigureTeamEthernet(red1, red2, red3, blue1, blue2, blue3 *Team) error {
// Returns a map of currently-configured teams to VLANs.
func getTeamVlans() (map[int]int, error) {
// Get the entire config dump.
config, err := runCatalystCommand("show running-config\n")
config, err := runSwitchCommand("show running-config\n")
if err != nil {
return nil, err
}
@@ -107,11 +107,11 @@ func getTeamVlans() (map[int]int, error) {
return teamVlans, nil
}
// Logs into the Catalyst via Telnet and runs the given command in user exec mode. Reads the output and
// Logs into the switch via Telnet and runs the given command in user exec mode. Reads the output and
// returns it as a string.
func runCatalystCommand(command string) (string, error) {
func runSwitchCommand(command string) (string, error) {
// Open a Telnet connection to the switch.
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", eventSettings.SwitchAddress, catalystTelnetPort))
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", eventSettings.SwitchAddress, switchTelnetPort))
if err != nil {
return "", err
}
@@ -138,9 +138,9 @@ func runCatalystCommand(command string) (string, error) {
return reader.String(), nil
}
// Logs into the Catalyst via Telnet and runs the given command in global configuration mode. Reads the output
// Logs into the switch via Telnet and runs the given command in global configuration mode. Reads the output
// and returns it as a string.
func runCatalystConfigCommand(command string) (string, error) {
return runCatalystCommand(fmt.Sprintf("config terminal\n%send\ncopy running-config startup-config\n\n",
func runSwitchConfigCommand(command string) (string, error) {
return runSwitchCommand(fmt.Sprintf("config terminal\n%send\ncopy running-config startup-config\n\n",
command))
}

View File

@@ -1,186 +1,299 @@
! Baseline configuration for the Catalyst 3500-series switch. Load this into the switch prior to configuring
! Cheesy Arena to connect to it. Default password is 1234Five.
!
version 12.1
version 12.2
no service pad
service timestamps debug uptime
service timestamps log uptime
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname ChezySwitch
!
boot-start-marker
boot-end-marker
!
enable secret 5 $1$kKSW$fCMwnMdYvXui1TulfyYHN/
!
ip subnet-zero
!
!
no aaa new-model
system mtu routing 1500
ip routing
ip dhcp excluded-address 10.0.100.1 10.0.100.100
!
ip dhcp pool dhcppool
network 10.0.100.0 255.255.255.0
default-router 10.0.100.1
domain-name team254.com
dns-server 8.8.8.8 8.8.4.4
lease 7
!
!
!
!
!
!
!
!
spanning-tree mode pvst
spanning-tree portfast default
spanning-tree extend system-id
!
vlan internal allocation policy ascending
!
!
!
!
interface FastEthernet0/1
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/2
switchport access vlan 11
switchport mode access
!
interface FastEthernet0/3
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/4
switchport access vlan 12
switchport mode access
!
interface FastEthernet0/5
switchport mode access
!
interface FastEthernet0/6
switchport access vlan 13
switchport mode access
!
interface FastEthernet0/7
switchport mode access
!
interface FastEthernet0/8
switchport access vlan 14
switchport mode access
!
interface FastEthernet0/9
switchport trunk encapsulation dot1q
switchport mode trunk
!
interface FastEthernet0/10
switchport access vlan 15
switchport mode access
!
interface FastEthernet0/11
switchport trunk encapsulation dot1q
switchport mode trunk
!
interface FastEthernet0/12
switchport access vlan 16
switchport mode access
!
interface FastEthernet0/13
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/14
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/15
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/16
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/17
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/18
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/19
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/20
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/21
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/22
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/23
switchport access vlan 2
switchport mode access
!
interface FastEthernet0/24
switchport access vlan 2
switchport mode access
!
interface GigabitEthernet0/1
switchport trunk encapsulation dot1q
switchport mode trunk
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/2
switchport access vlan 2
switchport trunk encapsulation dot1q
switchport trunk native vlan 100
switchport mode trunk
!
interface GigabitEthernet0/3
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/4
switchport mode access
!
interface GigabitEthernet0/5
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/6
switchport access vlan 10
switchport mode access
!
interface GigabitEthernet0/7
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/8
switchport access vlan 20
switchport mode access
!
interface GigabitEthernet0/9
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/10
switchport access vlan 30
switchport mode access
!
interface GigabitEthernet0/11
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/12
switchport access vlan 40
switchport mode access
!
interface GigabitEthernet0/13
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/14
switchport access vlan 50
switchport mode access
!
interface GigabitEthernet0/15
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/16
switchport access vlan 60
switchport mode access
!
interface GigabitEthernet0/17
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/18
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/19
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/20
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/21
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/22
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/23
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/24
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/25
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/26
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/27
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/28
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/29
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/30
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/31
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/32
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/33
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/34
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/35
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/36
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/37
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/38
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/39
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/40
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/41
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/42
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/43
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/44
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/45
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/46
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/47
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/48
switchport access vlan 100
switchport mode access
!
interface GigabitEthernet0/49
!
interface GigabitEthernet0/50
!
interface GigabitEthernet0/51
!
interface GigabitEthernet0/52
!
interface Vlan1
ip address 10.0.0.61 255.255.255.0
!
interface Vlan2
interface Vlan10
ip address 10.0.1.61 255.255.255.0
ip access-group 110 in
!
interface Vlan20
ip address 10.0.2.61 255.255.255.0
ip access-group 120 in
!
interface Vlan30
ip address 10.0.3.61 255.255.255.0
ip access-group 130 in
!
interface Vlan40
ip address 10.0.4.61 255.255.255.0
ip access-group 140 in
!
interface Vlan50
ip address 10.0.5.61 255.255.255.0
ip access-group 150 in
!
interface Vlan60
ip address 10.0.6.61 255.255.255.0
ip access-group 160 in
!
interface Vlan100
ip address 10.0.100.2 255.255.255.0
!
interface Vlan11
ip address 10.0.1.61 255.255.255.0
ip access-group 111 in
!
interface Vlan12
ip address 10.0.2.61 255.255.255.0
ip access-group 112 in
!
interface Vlan13
ip address 10.0.3.61 255.255.255.0
ip access-group 113 in
!
interface Vlan14
ip address 10.0.4.61 255.255.255.0
ip access-group 114 in
!
interface Vlan15
ip address 10.0.5.61 255.255.255.0
ip access-group 115 in
!
interface Vlan16
ip address 10.0.6.61 255.255.255.0
ip access-group 116 in
!
ip classless
ip http server
no ip http server
no ip http secure-server
!
access-list 111 permit ip 10.0.1.0 0.0.0.255 host 10.0.100.5
access-list 111 permit udp any eq bootpc any eq bootps
access-list 112 permit ip 10.0.2.0 0.0.0.255 host 10.0.100.5
access-list 112 permit udp any eq bootpc any eq bootps
access-list 113 permit ip 10.0.3.0 0.0.0.255 host 10.0.100.5
access-list 113 permit udp any eq bootpc any eq bootps
access-list 114 permit ip 10.0.4.0 0.0.0.255 host 10.0.100.5
access-list 114 permit udp any eq bootpc any eq bootps
access-list 115 permit ip 10.0.5.0 0.0.0.255 host 10.0.100.5
access-list 115 permit udp any eq bootpc any eq bootps
access-list 116 permit ip 10.0.6.0 0.0.0.255 host 10.0.100.5
access-list 116 permit udp any eq bootpc any eq bootps
!
access-list 110 permit ip 10.0.1.0 0.0.0.255 host 10.0.100.5
access-list 110 permit udp any eq bootpc any eq bootps
access-list 120 permit ip 10.0.2.0 0.0.0.255 host 10.0.100.5
access-list 120 permit udp any eq bootpc any eq bootps
access-list 130 permit ip 10.0.3.0 0.0.0.255 host 10.0.100.5
access-list 130 permit udp any eq bootpc any eq bootps
access-list 140 permit ip 10.0.4.0 0.0.0.255 host 10.0.100.5
access-list 140 permit udp any eq bootpc any eq bootps
access-list 150 permit ip 10.0.5.0 0.0.0.255 host 10.0.100.5
access-list 150 permit udp any eq bootpc any eq bootps
access-list 160 permit ip 10.0.6.0 0.0.0.255 host 10.0.100.5
access-list 160 permit udp any eq bootpc any eq bootps
!
snmp-server community 1234Five RO
!
!
line con 0
exec-timeout 0 0
line vty 0 4
@@ -190,5 +303,4 @@ line vty 5 15
password 1234Five
login
!
!
end

70
switch_config_test.go Normal file
View File

@@ -0,0 +1,70 @@
// Copyright 2014 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
package main
import (
"bytes"
"fmt"
"github.com/stretchr/testify/assert"
"net"
"testing"
"time"
)
func TestConfigureSwitch(t *testing.T) {
switchTelnetPort = 9050
eventSettings = &EventSettings{SwitchAddress: "127.0.0.1", SwitchPassword: "password"}
var command string
// Should do nothing if current configuration is blank.
mockTelnet(t, switchTelnetPort, "", &command)
assert.Nil(t, ConfigureTeamEthernet(nil, nil, nil, nil, nil, nil))
assert.Equal(t, "", command)
// Should remove any existing teams but not other SSIDs.
switchTelnetPort += 1
mockTelnet(t, switchTelnetPort,
"interface Vlan100\nip address 10.0.100.2\ninterface Vlan50\nip address 10.2.54.61\n", &command)
assert.Nil(t, ConfigureTeamEthernet(nil, nil, nil, nil, nil, nil))
assert.Equal(t, "password\nenable\npassword\nterminal length 0\nconfig terminal\ninterface Vlan50\nno ip"+
" address\nno access-list 150\nend\ncopy running-config startup-config\n\nexit\n", command)
// Should configure new teams and leave existing ones alone if still needed.
switchTelnetPort += 1
mockTelnet(t, switchTelnetPort, "interface Vlan50\nip address 10.2.54.61\n", &command)
assert.Nil(t, ConfigureTeamEthernet(nil, &Team{Id: 1114}, nil, nil, &Team{Id: 254}, nil))
assert.Equal(t, "password\nenable\npassword\nterminal length 0\nconfig terminal\n"+
"ip dhcp excluded-address 10.11.14.1 10.11.14.100\nno ip dhcp pool dhcp20\nip dhcp pool dhcp20\n"+
"network 10.11.14.0 255.255.255.0\ndefault-router 10.11.14.61\nlease 7\nno access-list 120\n"+
"access-list 120 permit ip 10.11.14.0 0.0.0.255 host 10.0.100.5\n"+
"access-list 120 permit udp any eq bootpc any eq bootps\ninterface Vlan20\n"+
"ip address 10.11.14.61 255.255.255.0\nend\ncopy running-config startup-config\n\nexit\n", command)
}
func mockTelnet(t *testing.T, port int, response string, command *string) {
go func() {
// Fake the first connection which should just get the configuration.
ln, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
assert.Nil(t, err)
defer ln.Close()
conn, err := ln.Accept()
assert.Nil(t, err)
conn.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
var reader bytes.Buffer
reader.ReadFrom(conn)
assert.Contains(t, reader.String(), "terminal length 0\nshow running-config\nexit\n")
conn.Write([]byte(response))
conn.Close()
// Fake the second connection which should configure stuff.
conn2, err := ln.Accept()
assert.Nil(t, err)
conn2.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
var reader2 bytes.Buffer
reader2.ReadFrom(conn2)
*command = reader2.String()
conn2.Close()
}()
time.Sleep(100 * time.Millisecond) // Give it some time to open the socket.
}

View File

@@ -0,0 +1,46 @@
config wifi-device 'radio1'
option type 'mac80211'
option channel '11'
option hwmode '11g'
option path 'soc/soc:pcie-controller/pci0000:00/0000:00:02.0/0000:02:00.0'
option htmode 'HT20'
option disabled '0'
option txpower '20'
option country 'US'
config wifi-iface
option device 'radio1'
option mode 'ap'
option hidden '1'
option encryption 'psk2+ccmp'
option network 'vlan100'
option ssid 'Cheesy Arena'
option key '1234Five'
option macaddr '62:38:e0:12:6b:17'
config wifi-device 'radio0'
option type 'mac80211'
option hwmode '11a'
option path 'soc/soc:pcie-controller/pci0000:00/0000:00:01.0/0000:01:00.0'
option txpower '23'
option channel '157'
option country 'US'
option htmode 'HT20'
option basic_rates '6500,7200'
option short_gi_20 '0'
{{range $vlan, $team := .}}
config wifi-iface
option device 'radio0'
option mode 'ap'
option isolate '0'
option bgscan '0'
option wds '0'
option maxassoc '1'
option hidden '1'
option network 'vlan{{$vlan}}'
option encryption 'psk2+ccmp'
option ssid '{{$team.Id}}'
option key '{{$team.WpaKey}}'
option disabled '0'
{{end}}

View File

@@ -160,7 +160,7 @@
</fieldset>
<fieldset>
<legend>Networking</legend>
<p>Enable this setting if you have a Cisco Aironet AP1252AG access point and Catalyst 3500-series
<p>Enable this setting if you have a Linksys WRT1900ACS access point and Catalyst 3500-series
switch available, for isolating each team to its own SSID and VLAN.</p>
<div class="form-group">
<label class="col-lg-7 control-label">Enable advanced network security</label>