Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #! /usr/local/bin/pike
- array switches = ({ "mdfswitch2",
- "cab1switch1", "cab1switch2", "cab1switch3", "cab1switch4", "cab1switch5",
- "cab2switch1", "cab3switch1", "cab4switch1", "cab4switch2", "cab5switch1",
- "idf4eswitch3", "idf4eswitch4", "idf4eswitch5",
- "idf4wswitch3", "idf4wswitch4", "idf4wswitch5",
- "idf5eswitch3", "idf5eswitch4", "idf5eswitch5",
- "idf5wswitch3", "idf5wswitch4", "idf5wswitch5"
- });
- array ip = ({}), mac = ({}), bridgeport = ({}), switchport = ({}), all = ({});
- int main(int argc, array(string) argv) {
- object s = Sql.Sql("mysql://localhost/switchinfo");
- setup();
- s->query("update ip set current=0");
- foreach (ip, mapping m)
- {
- s->query("replace into ip (switchname,portdescription,portname,vlan,hostname,ip,mac,macsonport,current) "
- "values(%s,%s,%s,%d,%s,%s,%s,%d,%d)",
- m->switchname, m->portdescription||"", m->portname||"",
- m->vlan,
- m->hostname, m->ip, m->dot1dTpFdbAddress, m->macsonport, 1);
- };
- s->query("update mac set current=0");
- foreach (mac, mapping m)
- {
- s->query("replace into mac (switchname,portdescription,portname,vlan,mac,macsonport,current) "
- "values(%s,%s,%s,%d,%s,%d,%d)",
- m->switchname, m->portdescription||"", m->portname||"",
- m->vlan, m->dot1dTpFdbAddress, m->macsonport, 1);
- };
- }
- /* inherit .portlist; */
- array setup()
- {
- mixed rv;
- array tds = ({ });
- array ip2 = ({ });
- /* Pull SNMP tables from all switches in parallel */
- foreach (switches, string oneswitch)
- {
- tds += ({ Thread.Thread(fetch_switch, oneswitch) });
- }
- /* Collect results */
- foreach (tds, Thread t)
- {
- rv = t->wait();
- ip += rv->ip;
- mac += rv->mac;
- bridgeport += rv->bridgeport;
- switchport += rv->switchport;
- all += rv->all;
- write("]");
- }
- /* done. */
- write("\n");
- /* For each IP we found, try and determine which port it's plugged
- into */
- foreach(Array.sort_array(Array.uniq(ip->ipNetToMediaNetAddress),Array.dwim_sort_func), string oneip)
- {
- mixed m;
- int uniqs;
- /* Look up name */
- mixed hostname = System.gethostbyaddr(oneip);
- if (hostname)
- hostname = hostname[0];
- else
- hostname = "";
- /* Get a list of all MACs associated with the IP */
- array matches = findmatches(ip,
- ([ "ipNetToMediaNetAddress":oneip ])
- );
- uniqs = sizeof(Array.uniq(matches->ipNetToMediaPhysAddress));
- if (uniqs > 1)
- {
- /* Trouble. Same IP seen with different macs on different
- * switches. NATting or routing is probably taking place. If
- * one of the macs maps to only one IP and the rest map to
- * multiple IPs, pick the single MAC.
- */
- /* First get a list of the macs seen on this IP */
- mixed macs = Array.uniq(matches->ipNetToMediaPhysAddress);
- /* Now find all IP objects matching the macs we are interested
- * in, and extract the mac associated with that IP. We'll end
- * up with an array of same macs as we started with, but with
- * more dupes.
- */
- macs = findmatches(ip, ([ "ipNetToMediaPhysAddress":macs ]))
- ->ipNetToMediaPhysAddress;
- macs = arraycount(macs);
- string least;
- /* Find the mac with the least other IPs assigned to it */
- foreach(macs; string key; int count)
- {
- if (key == "00:00:00:00:00:00")
- continue;
- if (!least || count < macs[least])
- least = key;
- }
- /* filter our previous matches array to only include the mac we decided on */
- matches = findmatches(matches,
- ([ "ipNetToMediaPhysAddress":least ])
- );
- uniqs = sizeof(Array.uniq(matches->ipNetToMediaPhysAddress));
- write ("Multiple MACs for %s %s; using %s (%d)\n", oneip, hostname, least, macs[least]);
- }
- if (uniqs == 1)
- {
- /* Good, Only one MAC; now find the port with the least
- number of MACs sharing it. */
- mapping least;
- array macs = findmatches(mac,
- ([ "dot1dTpFdbAddress":matches[0]->ipNetToMediaPhysAddress ])
- );
- foreach(macs, mapping match)
- {
- if (!least || (match->macsonport > 0 && match->macsonport < least->macsonport))
- least = match;
- }
- if (!least)
- {
- /* No ports routing this MAC? */
- write("Couldn't find any ports forwarding IP %s %s(%s)\n",
- oneip, hostname, matches[0]->ipNetToMediaPhysAddress);
- continue;
- }
- m = copy_value(least);
- m->ip = oneip;
- m->secondpass = 1;
- m->table = "ip";
- if (hostname)
- m->hostname = hostname;
- ip2 += ({ m });
- all += ({ m });
- } else
- {
- throw("shouldn't get here");
- }
- }
- ip = ip2;
- return all;
- }
- mixed fetch_switch(string switchname)
- {
- array ip, mac, bridgeport, switchport, switchportX;
- write("[");
- ip = snmptable(switchname, "ipNetToMediaTable");
- ip = ip[*] + ([ "table":"ip" ]);
- foreach(ip, mixed m)
- m->ipNetToMediaPhysAddress = fixmac(m->ipNetToMediaPhysAddress);
- mac = snmptable(switchname, "dot1dTpFdbTable", (["allvlans":1]) );
- mac = mac[*] + ([ "table":"mac" ]);
- foreach(mac, mixed m)
- m->dot1dTpFdbAddress = fixmac(m->dot1dTpFdbAddress);
- bridgeport = snmptable(switchname, "dot1dBasePortTable", (["allvlans":1]));
- bridgeport = bridgeport[*] + ([ "table":"bridgeport" ]);
- switchport = snmptable(switchname, "ifTable");
- switchportX = snmptable(switchname, "ifXTable");
- /* merge iftable and ifxtable */
- switchport = switchport[*] + switchportX[*];
- switchport = switchport[*] + ([ "table":"switchport" ]);
- foreach(switchport, mixed m)
- m->ifPhysAddress = fixmac(m->ifPhysAddress);
- /* Copy the physical port's name to each bridge port */
- foreach(bridgeport, mixed m)
- {
- mixed sport = findmatches(switchport,
- ([ "ifIndex":m->dot1dBasePortIfIndex ])
- );
- if (sizeof(sport) == 0)
- {
- ttyprintf("Cannot find the physical port for bridge port %s on %s\n",
- m->dot1dBasePortIfIndex, switchname);
- continue;
- }
- if (sizeof(sport) > 1)
- {
- ttyprintf("Too many physical ports for bridge port %s on %s?\n",
- m->dot1dBasePortIfIndex, switchname);
- continue;
- }
- sport = sport[0];
- m->portdescription = sport->ifDescr;
- m->portname = sport->ifName;
- }
- /* Copy the port name and the number of other MACs on the port to
- each MAC */
- foreach(mac, mixed m)
- {
- array matches;
- /* search bridgeport first */
- matches = findmatches(bridgeport,
- ([ "dot1dBasePort":m->dot1dTpFdbPort ])
- );
- if (sizeof(matches))
- {
- m->portname = matches[0]->portname;
- m->portdescription = matches[0]->portdescription;
- m->macsonport = sizeof(findmatches(mac, ([ "dot1dTpFdbPort":m->dot1dTpFdbPort ])));
- continue;
- }
- /* no matches - try switchport */
- matches = findmatches(switchport,
- ([ "ifIndex":m->dot1dTpFdbPort ])
- );
- if (sizeof(matches))
- {
- m->portname = matches[0]->ifName;
- m->portdescription = matches[0]->ifDescr;
- m->macsonport = sizeof(findmatches(mac, ([ "dot1dTpFdbPort":m->dot1dTpFdbPort ])));
- continue;
- }
- }
- /* Find out which port each known IP is visible on */
- foreach(ip, mixed m)
- {
- array matches = findmatches(mac,
- ([ "dot1dTpFdbAddress":m->ipNetToMediaPhysAddress ])
- );
- if (sizeof(matches) == 1)
- {
- m->portname = matches[0]->portname;
- m->portdescription = matches[0]->portdescription;
- m->macsonport = matches[0]->macsonport;
- }
- }
- write("%s ", switchname);
- return ([ "ip":ip, "mac":mac,
- "switchport":switchport, "bridgeport":bridgeport,
- "all":ip + mac + switchport + bridgeport ]);
- }
- array(mapping) snmptable(string|array switchname, string tablename, void|mixed options)
- {
- if (!options)
- options=([ ]);
- if (arrayp(switchname))
- {
- array rv = ({ });
- array tds = ({ });
- foreach (switchname, string onehost)
- {
- tds += ({ Thread.Thread(snmptable, onehost, tablename, options) });
- }
- foreach (tds, Thread t)
- {
- rv += t->wait();
- write(".%s", switchname);
- }
- write ("\n");
- return rv;
- }
- if (options->allvlans)
- {
- m_delete(options, "allvlans");
- array rv = ({ });
- /* Need to fetch a list of vlans known by this switch, and iterate
- our table fetch over all of them */
- mixed vlans=snmptable(switchname, "vtpVlanTable");
- /* No vlans? just do a regular pull */
- if (sizeof(vlans) == 0)
- return snmptable(switchname, tablename, options);
- foreach (vlans->index, mixed vlan)
- {
- /* just extract the final component of the vlan oid */
- vlan=(int)((vlan/".")[-1]);
- /* ignore fake vlans */
- if (vlan >= 1000)
- continue;
- /* fetch this vlan's table and tack it onto the rest */
- rv += snmptable(switchname, tablename, options + ([ "vlan":vlan ]));
- write("v%d",vlan);
- }
- return rv;
- }
- string community = "-c public";
- if (options->vlan)
- community += "@" + (string)options->vlan;
- string cmd = sprintf("snmptable -m +BRIDGE-MIB:CISCO-VTP-MIB -v2c -Ox -Ci -CB -Cf '\t' %s %s %s", community, switchname, tablename);
- mixed result = Process.popen(cmd);
- result /= "\n";
- result = result[1..] - ({ "" });
- result[*] /= "\t";
- if (sizeof(result) < 2)
- return ({ });
- array headers = result[0];
- array rows = result[1..];
- array(mapping) table = mkmapping(headers, rows[*]);
- table = table[*] + ([ "switchname":switchname ]);
- table = table[*] + ([ "vlan":(options->vlan||1) ]);
- return table;
- }
- /* converts mac addresses into "aa:bb:cc:dd:ee:ff" format */
- string fixmac(string s)
- {
- array vals;
- /* Extract runs of hex chars */
- vals = Array.flatten(array_sscanf(s, "%{%*s%[a-fA-F0-9]%}")) - ({""});
- /* pad with zeros */
- vals = map(vals, lambda(string v) { return sprintf("%02s", v); } );
- return lower_case(vals * ":");
- }
- /* given an array of mappings 'input', return all entries that match the
- * mappings in 'searches':
- *
- * ([ "*":"value1" ]) will match any input element with any value==value1
- *
- * ([ "key1": ({"value1","value2"}) ]) will match any input element with
- * key1==value1 or key1==value2
- */
- array findmatches(array input, mapping searches)
- {
- return filter(input, lambda(mixed m)
- {
- foreach (searches; string key; string value)
- {
- // write("M:%O\nK:%O\nV:%O\n", m, key, value);
- if (key)
- {
- if (key == "*")
- {
- if (search(values(m), value)== -1)
- return 0;
- } else if (!arrayp(value))
- {
- /* Just searching for one thing */
- // write("M:%O\nK:%O\n", m, key);
- if (m[key] != value)
- return 0;
- } else
- {
- // write("V:%O\nm[key]:%O\n",value,m[key]);
- /* Search value is an array; match if any element matches */
- if (search(value, m[key]) == -1)
- return 0;
- }
- } else
- {
- /* Not even a mapping? */
- throw("what is this");
- if (search(m, value) == 0)
- return 0;
- }
- }
- return 1;
- });
- }
- /* Take an array of duplicated lines, and return a mapping of
- * element:count
- */
- mapping arraycount(array a)
- {
- mapping rv = ([ ]);
- foreach (a, mixed line)
- {
- rv[line] = Array.count(a,line);
- }
- return rv;
- }
- int istty = !!Stdio.stdin->tcgetattr();
- void ttyprintf(string format, mixed ... args)
- {
- if (istty)
- write(format, @args);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement