Scott O'Brien

Ramblings and resources of my online life

Finding overlaps in address space

2014-02-24 06:05:36 +0000 +0000

We have an interesting problem at my workplace, we have an MPLS VPN design for separation of security zones (e.g., staff from students.) and we don’t have MPLS support on our edge. With a L3 to the edge design though this means that while every edge switch has its own address space (per VRF), it also has a /30 uplink (once again, per VRF) back to the PE device.

While this (rightly or wrongly decided) slightly more complicated design in itself isn’t a problem, I’ve been working on programatically putting all of this data into an IPAM (IP Address Management) solution. Doing this from the devices themselves (as apposed to a spreadsheet where it was previously kept) has provided the best way moving forward, so good in fact, that my IPAM started throwing exceptions when duplicate IP addresses and overlapping spaces were attempted to be added in the system.

The following Python script uses my Cisco IOS python library to be able to identify IP address overlaps from a bunch of my saved device configs.

It works by the following:

  1. Adds all L3 interfaces addresses and secondary addresses to a list
  2. Sorts list such that larger subnets are at the front, smaller (/32’s and the such) are at the back of the list.
  3. Walks through each subnet, if the network addresses is not in the routing table, add it in, if it is, add it to a list of colliding subnets.
  4. With the list of colliding subnets (subnets that have been multiply defined, or are of overlapping size):
    1. If they are /30’s and there are only two places of definition, skip
    2. if the subnet values are not equal OR an address appears twice in the subnet.  Print it out as a colliding address (space)

You can find the script as a ghist here (note:  This assumes the devices have been picked and loaded as a Picked list of IOSDevice’s)

Automating VLAN changes for ESXi Switchports in Cisco IOS.

2014-01-29 10:51:35 +0000 +0000

6500

At the organisation I’m currently working for, we recently experienced what appears to be a common issue, VLAN’s trunked down to ESXi nodes were inconsistent.

In our DC, we’re still running the old school Cisco Catalyst switches.  If we were running a fabric, or Nexus switches we could put port profiles to action or if we lucky enough to have some equipment running Junos <3 we could be using apply-groups for this.

Being stuck with 6500’s in the DC as our L2 platform (and a VSS for the L3 MPLS PE) this is a quick little hack job to automate configuration changes across switchports in Cisco IOS based on dynamically finding ports that are matching an interface description.

In our DC, we have a bunch of switches (defined at the top of this script) and all our switchports that go to ESXi switchports that should have this template applied are matched on the interface description containing ‘ESXHOST’

This relies on the python EXScript module

  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
# This script is used for updating the VLANs that are trunked down to ESX boxes.
#  It works by logging in to each switch in the DC then looking at the interfaces that have 'ESXHOST'
#  in the description.  For each of those switchports, it will run the 'alter' commands

from Exscript.Account import Account
from Exscript.protocols import SSH2
import argparse
import getopt
import getpass
import sys

#A list of the switches to interigate.  These are the switches that have ESXi hosts in them
SWITCHES = [
    '10.0.0.2',
    '10.0.0.3',
    '10.0.0.4',
    '10.0.0.5',
    '10.0.0.7'
    ]

#Commands to execute for every switchport
vlan_commands = """
  switchport trunk allowed vlan add 5,10,15,20-25,30,40,50
  switchport trunk allowed vlan add 60,69,70,100-1000
"""

def query_yes_no(question, default="yes"):
    """Ask a yes/no question via raw_input() and return their answer.

    "question" is a string that is presented to the user.
    "default" is the presumed answer if the user just hits &lt;Enter&gt;.
        It must be "yes" (the default), "no" or None (meaning
        an answer is required of the user).

    The "answer" return value is one of "yes" or "no".
    """
    valid = {"yes":True,   "y":True,  "ye":True,
             "no":False,     "n":False}
    if default == None:
        prompt = " [y/n] "
    elif default == "yes":
        prompt = " [Y/n] "
    elif default == "no":
        prompt = " [y/N] "
    else:
        raise ValueError("invalid default answer: '%s'" % default)

    while True:
        sys.stdout.write(question + prompt)
        choice = raw_input().lower()
        if default is not None and choice == '':
            return valid[default]
        elif choice in valid:
            return valid[choice]
        else:
            sys.stdout.write("Please respond with 'yes' or 'no' "\
                             "(or 'y' or 'n').\n")

def returnInterfacesFromShowDescription(text):
    """
    Returns a LIST of interfaces from the output of 'show interface desc' from a cisco device
    """
    return [ x.split()[0] for x in text.split("\n") ]

def genUpdateConfigForInterfaces(config, interfaces):
    """
    Takes in a configuration block to run, a list of interfaces and generates the appropriate int range commands with the
    config block after
    """
    updateConfig = ""
    while len(interfaces) &gt; 0:
        updateConfig += "int range " + ",".join(interfaces[:5])
        interfaces = interfaces[5:]
        updateConfig += "\n  %s\n" % config.strip()
    return updateConfig

def updateSwitchportsWithDescription(switch, description, username, password, commands):
    """
    Function is used to log into a switch, find all switchports that CONTAINS the description
    with each of the said switchports, it will then execute the given commands.

    switch:  Device to log into
    description:  Search string to try and find in the switchport description
    username:  Username to log into the switch with
    password:  The password to log into the switch with
    commands:  A list of commands that should be executed
    """

    print "Working with switch: %s" % switch

    #establish a SSH connection to the host
    conn = SSH2()
    account = Account(username, password)
    conn.connect(switch)
    conn.login(account)

    #Do some pre-setup
    conn.execute('')

    #Make sure we're in super user mode
    conn.execute('enable')
    conn.execute('terminal length 0')

    #find all ports that have ESXHOST (or whatever is set in description) in the description
    conn.execute('show int desc | i %s' % description)
    ports = conn.response.strip()

    print "Ports are:"
    print ports
    portsList = returnInterfacesFromShowDescription(ports)[1:-1]

    #go into config mode and get ready to run the update commands
    #Generate a list of the update commands that should be ran
    updateCommands = genUpdateConfigForInterfaces(commands, portsList).split("\n")
    conn.execute('conf t')
    print conn.response.strip()
    print "! About to execute the following commands."
    for line in updateCommands:
        print "! " + line

    if query_yes_no('Execute Commands?', default="no"):
        #Run the set of commands given
        for command in updateCommands:
            conn.execute(command)
            print conn.response

        #Exit out of config mode
        conn.execute("exit")
        conn.execute("exit")
        print conn.response
        print

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="DC ESX VLAN Utility")
    parser.add_argument('--user', help='The username that should be used to log into the switches with')

    args = parser.parse_args()
    if args.user:
        username = args.user
    else:
        username = getpass.getuser()

    password = getpass.getpass()

    # Generate a list of commands
    for switch in SWITCHES:
        updateSwitchportsWithDescription(switch, 'ESXHOST', username, password, vlan_commands)

throttling guest internet on Apple Airport Extreme

2013-12-18 13:09:03 +0000 +0000

I’ve been happily running my Apple Airport Extreme as m home router for the past few years (since my debian router died, and I’ve been too lazy to replace it).  One of the cool features was the ability to create a guest network (SSID) to access the internet without being able to access your trusted network.  One feature I wanted was the ability to throttle the speed guests can access the internet at.  While I couldn’t do this with the Airport Extreme alone, Add a Juniper SRX100 into the mix that the awesome Cooper Lees gave me into the mix and problem solved.

apple-airport-extreme-base-station_1

SRX100, signed by the #1 Juniper Engineer

SRX100, signed by the #1 Juniper Engineer

AirPort Utility

AirPort Utility-2

In not so many words, performing these actions will do a number of things.  The gig ethernet switch on the back of the airport will be bridged with the WAN port.  Any traffic from your normal SSID(s) and switchports will be sent out the WAN port untagged.  Traffic from your guest network will be sent .1q tagged with vlan 1003.

I popped this into fe-0/0/1 on my SRX100 and the following config works the magic.

  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
    fe-0/0/1 {
        unit 0 {
            family ethernet-switching {
                port-mode trunk;
                vlan {
                    members vlan-guest;
                }
                native-vlan-id 3;
            }
        }
    }

    vlan {
        unit 0 {
            family inet {
                address 10.0.1.1/24;
            }
        }
        unit 1003 {
            family inet {
                filter {
                    input limit_guest_upload;
                    output limit_guest_download;
                }
                address 10.0.2.1/24;
            }
        }
    }

[system services]
        dhcp {
            pool 10.0.1.0/24 {
                address-range low 10.0.1.2 high 10.0.1.199;
                router {
                    10.0.1.1;
                }
            }
            pool 10.0.2.0/24 {
                address-range low 10.0.2.2 high 10.0.2.254;
                router {
                    10.0.2.1;
                }
            }
            propagate-settings fe-0/0/0.0;
        }

[security]
    nat {
        source {
            rule-set private-to-internet {
                from zone [ guest trust ];
                to zone untrust;
                rule source-nat-rule {
                    match {
                        source-address 0.0.0.0/0;
                    }
                    then {
                        source-nat {
                            interface;
                        }
                    }
                }
            }
        }
    }
    policies {
        from-zone trust to-zone untrust {
            policy trust-to-untrust {
                match {
                    source-address any;
                    destination-address any;
                    application any;
                }
                then {
                    permit;
                }
            }
        }
        from-zone guest to-zone untrust {
            policy guest-to-internet {
                description "Allows guest access to internet";
                match {
                    source-address any;
                    destination-address any;
                    application any;
                }
                then {
                    permit;
                }
            }
        }
    }

[security zones]
        security-zone guest {
            host-inbound-traffic {
                system-services {
                    dns;
                    ping;
                    traceroute;
                }
            }
            interfaces {
                vlan.1003;
            }
        }

firewall {
    policer guest-shaping {
        if-exceeding {
            bandwidth-limit 500k;
            burst-size-limit 300k;
        }
        then discard;
    }
    filter limit_guest_download {
        term guest-shaping {
            then {
                policer guest-shaping;
                accept;
            }
        }
    }
    filter limit_guest_upload {
        term guest-shaping {
            then {
                policer guest-shaping;
                accept;
            }
        }
    }
}
vlans {
    vlan-guest {
        vlan-id 1003;
        l3-interface vlan.1003;
    }
    vlan-trust {
        vlan-id 3;
        l3-interface vlan.0;
    }
}

And there you have it! A really simple way of limiting the bandwidth of guest users on your network using the power of Junos with an Airport Extreme!

 

Throttled Speed

What is Anycast?

2013-04-09 12:15:31 +0000 +0000

I’ve never found a really simple video on what exactly Anycast is with a basic examples when exploring the concepts.  I decided to lab it up and figured this might help some of you starting out with the concepts.  Any comments feel free to let me know!

Config Attached for IOS lab HERE.