mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 13:46:44 -04:00
167 lines
4.8 KiB
Go
167 lines
4.8 KiB
Go
// Copyright 2014 Team 254. All Rights Reserved.
|
|
// Author: pat@patfairbank.com (Patrick Fairbank)
|
|
//
|
|
// Methods for configuring a Cisco Switch 3500-series switch for team VLANs.
|
|
|
|
package network
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"github.com/Team254/cheesy-arena-lite/model"
|
|
"net"
|
|
"regexp"
|
|
"strconv"
|
|
"sync"
|
|
)
|
|
|
|
const switchTelnetPort = 23
|
|
|
|
const (
|
|
red1Vlan = 10
|
|
red2Vlan = 20
|
|
red3Vlan = 30
|
|
blue1Vlan = 40
|
|
blue2Vlan = 50
|
|
blue3Vlan = 60
|
|
)
|
|
|
|
type Switch struct {
|
|
address string
|
|
port int
|
|
password string
|
|
mutex sync.Mutex
|
|
}
|
|
|
|
var ServerIpAddress = "10.0.100.5" // The DS will try to connect to this address only.
|
|
|
|
func NewSwitch(address, password string) *Switch {
|
|
return &Switch{address: address, port: switchTelnetPort, password: password}
|
|
}
|
|
|
|
// Sets up wired networks for the given set of teams.
|
|
func (sw *Switch) ConfigureTeamEthernet(teams [6]*model.Team) error {
|
|
// Make sure multiple configurations aren't being set at the same time.
|
|
sw.mutex.Lock()
|
|
defer sw.mutex.Unlock()
|
|
|
|
// Determine what new team VLANs are needed and build the commands to set them up.
|
|
oldTeamVlans, err := sw.getTeamVlans()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
addTeamVlansCommand := ""
|
|
replaceTeamVlan := func(team *model.Team, vlan int) {
|
|
if team == nil {
|
|
return
|
|
}
|
|
if oldTeamVlans[team.Id] == vlan {
|
|
delete(oldTeamVlans, team.Id)
|
|
} else {
|
|
addTeamVlansCommand += fmt.Sprintf(
|
|
"ip dhcp excluded-address 10.%d.%d.1 10.%d.%d.100\n"+
|
|
"no ip dhcp pool dhcp%d\n"+
|
|
"ip dhcp pool dhcp%d\n"+
|
|
"network 10.%d.%d.0 255.255.255.0\n"+
|
|
"default-router 10.%d.%d.61\n"+
|
|
"lease 7\n"+
|
|
"no access-list 1%d\n"+
|
|
"access-list 1%d permit ip 10.%d.%d.0 0.0.0.255 host %s\n"+
|
|
"access-list 1%d permit udp any eq bootpc any eq bootps\n"+
|
|
"interface Vlan%d\nip address 10.%d.%d.61 255.255.255.0\n",
|
|
team.Id/100, team.Id%100, team.Id/100, team.Id%100, vlan, vlan, team.Id/100, team.Id%100, team.Id/100,
|
|
team.Id%100, vlan, vlan, team.Id/100, team.Id%100, ServerIpAddress, vlan, vlan, team.Id/100,
|
|
team.Id%100)
|
|
}
|
|
}
|
|
replaceTeamVlan(teams[0], red1Vlan)
|
|
replaceTeamVlan(teams[1], red2Vlan)
|
|
replaceTeamVlan(teams[2], red3Vlan)
|
|
replaceTeamVlan(teams[3], blue1Vlan)
|
|
replaceTeamVlan(teams[4], blue2Vlan)
|
|
replaceTeamVlan(teams[5], blue3Vlan)
|
|
|
|
// Build the command to remove the team VLANs that are no longer needed.
|
|
removeTeamVlansCommand := ""
|
|
for _, vlan := range oldTeamVlans {
|
|
removeTeamVlansCommand += fmt.Sprintf("interface Vlan%d\nno ip address\nno access-list 1%d\n", vlan, vlan)
|
|
}
|
|
|
|
// Build and run the overall command to do everything in a single telnet session.
|
|
command := removeTeamVlansCommand + addTeamVlansCommand
|
|
if len(command) > 0 {
|
|
_, err = sw.runConfigCommand(removeTeamVlansCommand + addTeamVlansCommand)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Returns a map of currently-configured teams to VLANs.
|
|
func (sw *Switch) getTeamVlans() (map[int]int, error) {
|
|
// Get the entire config dump.
|
|
config, err := sw.runCommand("show running-config\n")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Parse out the team IDs and VLANs from the config dump.
|
|
re := regexp.MustCompile("(?s)interface Vlan(\\d\\d)\\s+ip address 10\\.(\\d+)\\.(\\d+)\\.61")
|
|
teamVlanMatches := re.FindAllStringSubmatch(config, -1)
|
|
if teamVlanMatches == nil {
|
|
// There are probably no teams currently configured.
|
|
return nil, nil
|
|
}
|
|
|
|
// Build the map of team to VLAN.
|
|
teamVlans := make(map[int]int)
|
|
for _, match := range teamVlanMatches {
|
|
team100s, _ := strconv.Atoi(match[2])
|
|
team1s, _ := strconv.Atoi(match[3])
|
|
team := int(team100s)*100 + team1s
|
|
vlan, _ := strconv.Atoi(match[1])
|
|
teamVlans[team] = vlan
|
|
}
|
|
return teamVlans, nil
|
|
}
|
|
|
|
// 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 (sw *Switch) runCommand(command string) (string, error) {
|
|
// Open a Telnet connection to the switch.
|
|
conn, err := net.Dial("tcp", fmt.Sprintf("%s:%d", sw.address, sw.port))
|
|
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\nenable\n%s\nterminal length 0\n%sexit\n", sw.password, sw.password,
|
|
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 switch via Telnet and runs the given command in global configuration mode. Reads the output
|
|
// and returns it as a string.
|
|
func (sw *Switch) runConfigCommand(command string) (string, error) {
|
|
return sw.runCommand(fmt.Sprintf("config terminal\n%send\ncopy running-config startup-config\n\n", command))
|
|
}
|