josuah.net

netini

(source)

Network layer topology in red, physical connexions in grey.

What is it for?

Plotting networks is extremely useful for understanding how it works and troubleshoot problems. Particularly when you do not know the network in advance.

In theory, from an access to that place's router and switches, using arp tables and mac address tables, you can guess some of the L1/L2/L3 topology.

netini is a toolset doing this: build network graph out of simple declarative config files, and generate config files out of raw command output from routers and switches.

How to use it?

The netini-dot(1) tool generating the plots is reading a trivial .ini format from all files passed as argument:

Example for a network named sky:

[net]
name = skynet-wan-knet
ip = 92.118.99.140/30

[net]
name = skynet-lan-user
ip = 10.191.10.0/23
vlan = 10

[net]
name = skynet-lan-server
ip = 10.191.20.0/24
vlan = 20

[net]
name = skynet-lan-admin
ip = 10.191.30.0/24
vlan = 20

[host]
name = skynet-modem-knet-1
ip = 92.118.99.141

[host]
name = skynet-router-1
ip = 92.118.99.142
ip = 10.191.10.1
ip = 10.191.20.1
ip = 10.191.30.1

[host]
name = skynet-switch-1
ip = 10.191.30.2
link = skynet-router-1
link = 0c:1c:20:69:d8:d8
link = 08:4a:cf:e6:d0:08
link = e8:5b:5b:b1:5d:db
link = 5c:d2:e4:1b:1e:ee

[host]
name = skynet-switch-2
ip = 10.191.30.2
link = skynet-router-1
link = 00:c0:a3:91:9d:e2
link = 48:9d:24:c9:f8:79
link = f4:32:3d:40:c6:18
link = 84:18:26:bd:88:2d

[host]
name = skynet-workstation-1
ip = 10.191.10.1
link = 0c:1c:20:69:d8:d8

[host]
name = skynet-workstation-2
ip = 10.191.10.1
link = 08:4a:cf:e6:d0:08
...

All hosts with IPs that fit a network are linked automatically to it on the plot.

link= variables in hosts permit to build L1 links by using a hostname, a MAC address or an IP as value.

Any other detail might be added, and will be shown on the item label.

Other tools are available to generate parts of these configuration files from command output coming from local hosts or routers.

How is the matching done?

Connecting hosts to networks is done by defining a network with subnet, and adding IPs that belong to that network to the hosts. The classic IP matching algorythm does the wiring job on its own. This means that autogenerated output can

For link-layer, the link= entries of hosts bind them to other hosts.

What does it looks like in practice?

From this from arp -a (or ip neigh show on Linux, randomly generated here):

10.191.10.130 dev wlan0 lladdr 0c:1c:20:69:d8:d8 ref 1 used 0/0/0 probes 6 REACHABLE
10.191.10.65 dev wlan0 lladdr 08:4a:cf:e6:d0:08 ref 1 used 0/0/0 probes 6 REACHABLE
10.191.10.28 dev wlan0 lladdr e8:5b:5b:b1:5d:db ref 1 used 0/0/0 probes 6 REACHABLE
10.191.10.85 dev wlan0 lladdr 08:00:33:00:b7:2e ref 1 used 0/0/0 probes 6 REACHABLE
10.191.11.239 dev wlan0 lladdr 5c:d2:e4:1b:1e:ee ref 1 used 0/0/0 probes 6 REACHABLE
10.191.11.105 dev wlan0 lladdr 74:6e:e4:71:05:25 ref 1 used 0/0/0 probes 6 REACHABLE
10.191.20.36 dev wlan0 lladdr 68:d4:82:66:29:7b ref 1 used 0/0/0 probes 6 REACHABLE
10.191.20.247 dev wlan0 lladdr ac:19:9f:03:6c:f2 ref 1 used 0/0/0 probes 6 REACHABLE
10.191.20.113 dev wlan0 lladdr 00:c0:a3:91:9d:e2 ref 1 used 0/0/0 probes 6 REACHABLE
10.191.20.178 dev wlan0 lladdr 48:9d:24:c9:f8:79 ref 1 used 0/0/0 probes 6 REACHABLE
10.191.20.11 dev wlan0 lladdr f4:32:3d:40:c6:18 ref 1 used 0/0/0 probes 6 REACHABLE
10.191.20.31 dev wlan0 lladdr 84:18:26:bd:88:2d ref 1 used 0/0/0 probes 6 REACHABLE

netini-arp linux skynet turns it into this:

[host]
name = skynet-Kakao-1
ip = 10.191.10.130
mac = 0c:1c:20:69:d8:d8

[host]
name = skynet-Kakao-2
ip = 10.191.10.65
mac = 0c:1c:20:69:d8:d9

[host]
name = skynet-LgElectronics-1
ip = 10.191.10.28
mac = e8:5b:5b:b1:5d:db

[host]
name = skynet-BauschAndLomb-1
ip = 10.191.10.85
mac = 08:00:33:00:b7:2e

[host]
name = skynet-IntelOrate-1
ip = 10.191.11.239
mac = 5c:d2:e4:1b:1e:ee

[host]
name = skynet-AsiaVitalMponents-1
ip = 10.191.11.105
mac = 74:6e:e4:71:05:25

[host]
name = skynet-ShenzhenGongjinElectronics-1
ip = 10.191.20.36
mac = 68:d4:82:66:29:7b

[host]
name = skynet-SungrowPowerSupply-1
ip = 10.191.20.247
mac = ac:19:9f:03:6c:f2

[host]
name = skynet-DualEnterprises-1
ip = 10.191.20.113
mac = 00:c0:a3:91:9d:e2

[host]
name = skynet-BlackberryRts-1
ip = 10.191.20.178
mac = 48:9d:24:c9:f8:79

[host]
name = skynet-SichuanTianyiKangheMmunications-1
ip = 10.191.20.11
mac = f4:32:3d:40:c6:18

[host]
name = skynet-Osram-1
ip = 10.191.20.31
mac = 84:18:26:bd:88:2d

netini-dot turns it into this:

graph G {
	{ "skynet-Kakao-1" [shape=rectangle; label="skynet-Kakao-1\nip 10.191.10.130\nmac 0c:1c:20:69:d8:d8\n"] }
	{ "skynet-GuangdongOppoMobileTelecommunications-1" [shape=rectangle; label="skynet-GuangdongOppoMobileTelecommunications-1\nip 10.191.10.65\nmac 08:4a:cf:e6:d0:08\n"] }
	{ "skynet-LgElectronics-1" [shape=rectangle; label="skynet-LgElectronics-1\nip 10.191.10.28\nmac e8:5b:5b:b1:5d:db\n"] }
	{ "skynet-BauschAndLomb-1" [shape=rectangle; label="skynet-BauschAndLomb-1\nip 10.191.10.85\nmac 08:00:33:00:b7:2e\n"] }
	{ "skynet-IntelOrate-1" [shape=rectangle; label="skynet-IntelOrate-1\nip 10.191.11.239\nmac 5c:d2:e4:1b:1e:ee\n"] }
	{ "skynet-AsiaVitalMponents-1" [shape=rectangle; label="skynet-AsiaVitalMponents-1\nip 10.191.11.105\nmac 74:6e:e4:71:05:25\n"] }
	{ "skynet-ShenzhenGongjinElectronics-1" [shape=rectangle; label="skynet-ShenzhenGongjinElectronics-1\nip 10.191.20.36\nmac 68:d4:82:66:29:7b\n"] }
	{ "skynet-SungrowPowerSupply-1" [shape=rectangle; label="skynet-SungrowPowerSupply-1\nip 10.191.20.247\nmac ac:19:9f:03:6c:f2\n"] }
	{ "skynet-DualEnterprises-1" [shape=rectangle; label="skynet-DualEnterprises-1\nip 10.191.20.113\nmac 00:c0:a3:91:9d:e2\n"] }
	{ "skynet-BlackberryRts-1" [shape=rectangle; label="skynet-BlackberryRts-1\nip 10.191.20.178\nmac 48:9d:24:c9:f8:79\n"] }
	{ "skynet-SichuanTianyiKangheMmunications-1" [shape=rectangle; label="skynet-SichuanTianyiKangheMmunications-1\nip 10.191.20.11\nmac f4:32:3d:40:c6:18\n"] }
	{ "skynet-Osram-1" [shape=rectangle; label="skynet-Osram-1\nip 10.191.20.31\nmac 84:18:26:bd:88:2d\n"] }
}

Finally plotted by graphviz.

Note that extra data can be added at each step, and netini-merge lets one have manual entries that override the autogenerated ones.

How did you get these device brand names out of numbers?

Each MAC address has its 6 first bytes ("OUI") associated to a manufacturer, so the netini-oui tool downloads the definition a [oui.csv(http://standards-oui.ieee.org/oui/oui.csv) from IANA to resolve the OUI identifiers.

The heuristics comes from a WireShark python script.

More features?

Mail me your suggestions as a request or as a patch.