forked from Team254/cheesy-arena
-
Notifications
You must be signed in to change notification settings - Fork 0
/
aironet.go
151 lines (133 loc) · 4.19 KB
/
aironet.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright 2014 Team 254. All Rights Reserved.
// Author: [email protected] (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))
}