Files
cheesy-arena-lite/aironet.go
2014-09-06 22:25:12 -07:00

152 lines
4.2 KiB
Go

// 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))
}