Network Mapper v1.0 instructions
Almquist Shell Script written for POSIX systems like OpenWRT, Linux and WSL2/WSLg
---------------------------------------
Dependencies
---------------------------------------
This was written in the Almquist Shell (ASH) scripting language for OpenWRT devices, but has been tested to run on Ubuntu on WSLg (which runs Bourne Again Shell, or Bash).
Further information on the Almquist Shell can be found at:
https://en.wikipedia.org/wiki/Almquist_shell
https://www.in-ulm.de/~mascheck/various/ash/
The graphical front-end that you see in yuor browser is rendered by the D3 Javascript Visualizer by Mike Bostock and Observable, Inc., which you can grab here:
https://d3js.org/d3.v7.js
or in minified form here:
https://d3js.org/d3.v7.min.js
Well, okay, it also relies on the fact that that your device (computer, router, whatever) has its TCP/IP stack installed, obviously. But aside from needing TCP/IP, the Almquist Shell and D3... yeah, this is all self-contained!
---------------------------------------
Installation
---------------------------------------
On OpenWRT, place networkmap.sh, update_all.sh, get_ipv6.sh and get_dhcp.sh in /www/cgi-bin/ and your networkmap.js, networkmap.json and networkmap.html in /www/. Keep this readme file safe.
In the archive:
├── readme.txt (this very file)
├── d3.v7.js
├── d3.v7.min.js
├── networkmap.js
├── networkmap.json
├── networkmap.html
└── /cgi-bin/
├── networkmap.sh
├── update_all.sh
├── get_dhcp.sh
└── get_ipv6.sh
Folder Structure of involved files:
user-provided/generated, with their target locations:
/etc/
└── config
└── dhcp
/tmp/
├── dhcp.leases
└── hosts
└── odhcpd
Provided by this package, with their target locations:
/www/
├── d3.v7.js
├── d3.v7.min.js
├── networkmap.js
├── networkmap.json
├── networkmap.html
└── /cgi-bin/
├── networkmap.sh
├── update_all.sh
├── get_dhcp.sh
└── get_ipv6.sh
I've also included two tools, get_dhcp.sh and get_ipv6.sh to help with determining addresses. Unless you made it yourself, networkmap.json won't exist yet, as it has to be compiled from your network information. Don't panic if networkmap.json isn't initially compiled, either, as the section below will detail how to generate or make your own!
---------------------------------------
How to run this prorgam
---------------------------------------
Step 1:
ensure you have a copy of your router's /tmp/dhcp.leases file at YOUR computer's /tmp/dhcp.leases
You may also need:
/tmp/hosts/odhcpd
/tmp/ipv6list
/tmp/mac_ipv4_map
/tmp/mac_ipv6_map
as well as the output of:
ip neigh show
ip -6 neigh show
and for wifi clients/repeater stations and information:
iw dev phy0-ap0 station dump
iw dev phy1-ap0 station dump
NOTE: Your router's wifi interface may be named differently depending on your hardware and software (OpenWRT version, drivers, and so on), such as wlan0, or radio0.
These instrucitons also assume you have iw and wpad available instead of hostapd_cli. I'm sure hostapd_cli works just fine but I have not tested it with that, as i have wpad and iw instead.
This program's shell script (networkmap.sh) should be run in /www/cgi-bin/ on OpenWRT, with chmod of +x (executable) from terminal/ssh. It can also run elsewhere on linux machines, just ensure that /etc/config/dhcp and /tmp/dhcp.leases exist.
Step 2:
run this program:
sh +x networkmapper.sh > /www/networkmap.json
Step 3:
if it complains about no networkmap.json file (or generates an empty one), don't panic! just make a networkmap.json file with these contents as an example:
```
{
"links": [
{ "source": "YourRouter", "target": "YourRepeaterRouter1" },
{ "source": "YourRepeaterRouter1", "target": "Device0OnRepeater1" },
{ "source": "YourRepeaterRouter1", "target": "Device1OnRepeater1" },
{ "source": "YourRouter", "target": "YourRepeaterRouter2" },
{ "source": "YourRepeaterRouter2", "target": "Device0OnRepeater2" },
{ "source": "YourRepeaterRouter2", "target": "Device1OnRepeater2" },
{ "source": "YourRouter", "target": "YourLaptop" },
{ "source": "YourRouter", "target": "YourPC" },
{ "source": "YourRouter", "target": "YourTablet" },
{ "source": "YourRouter", "target": "YourTV" },
{ "source": "YourRouter", "target": "YourGameConsole" },
{ "source": "YourRouter", "target": "YourLegacyConsole" },
{ "source": "YourRouter", "target": "YourPhone" },
{ "source": "YourRouter", "target": "YourNetPrinter" },
{ "source": "YourRouter", "target": "YourNetCam" },
{ "source": "YourRouter", "target": "YourRaspberryPi" },
{ "source": "YourRouter", "target": "YourVM" },
{ "source": "YourRouter", "target": "YourModem" }
],
"nodes": [
{ "id": "YourRouter", "ip": "192.168.1.1", "type": "router", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:55", "ipv6": "fe80:abcd:1234" },
{ "id": "YourRepeaterRouter1", "ip": "192.168.1.2", "type": "router", "connection": "wifi", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:56", "ipv6": ["2001:1970::4
fe80::feed:face:dead:beef::4
fd38:i5ee:cafe::4"] },
{ "id": "YourRepeaterRouter2", "ip": "192.168.1.3", "type": "switch", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:57", "ipv6": ["2001:1970::5
fe80::feed:face:dead:beef::5
fd38:i5ee:cafe::5"] },
{ "id": "Device0OnRepeater1", "ip": "192.168.1.100", "type": "pc", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:58", "ipv6": ["2001:1970::6
fe80::feed:face:dead:beef::6
fd38:i5ee:cafe::6"] },
{ "id": "Device1OnRepeater1", "ip": "192.168.1.101", "type": "pc", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:59", "ipv6": ["2001:1970::7
fe80::feed:face:dead:beef::7
fd38:i5ee:cafe::7"] },
{ "id": "Device0OnRepeater2", "ip": "192.168.1.200", "type": "pc", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:45:55", "ipv6": ["2001:1970::8
fe80::feed:face:dead:beef::8
fd38:i5ee:cafe::8"] },
{ "id": "Device1OnRepeater2", "ip": "192.168.1.201", "type": "pc", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:46:55", "ipv6": ["2001:1970::9
fe80::feed:face:dead:beef::9
fd38:i5ee:cafe::9"] },
{ "id": "YourPC", "ip": "192.168.1.11", "type": "pc", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:47:55", "ipv6": ["2001:1970::3
fe80::feed:face:dead:beef::3
fd38:i5ee:cafe::3"] },
{ "id": "YourTablet", "ip": "192.168.1.12", "type": "tablet", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:48:55", "ipv6": ["2001:1970::10
fe80::feed:face:dead:beef::10
fd38:i5ee:cafe::10"] },
{ "id": "YourTV", "ip": "192.168.1.13", "type": "tv", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:49:55", "ipv6": ["2001:1970::11
fe80::feed:face:dead:beef::11
fd38:i5ee:cafe::11"] },
{ "id": "YourGameConsole", "ip": "192.168.1.14", "type": "console", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:41:55", "ipv6": ["2001:1970::12
fe80::feed:face:dead:beef::12
fd38:i5ee:cafe::12"] },
{ "id": "YourPhone", "ip": "192.168.1.15", "type": "phone", "connection": "wifi", "online": true, "lastSeen": 0, "mac": "00:11:22:33:42:55", "ipv6": ["2001:1970::13
fe80::feed:face:dead:beef::13
fd38:i5ee:cafe::13"] },
{ "id": "YourNetCam", "ip": "192.168.1.16", "type": "camera", "connection": "wifi", "online": true, "lastSeen": 0, "mac": "00:11:22:33:43:55", "ipv6": ["2001:1970::14
fe80::feed:face:dead:beef::14
fd38:i5ee:cafe::14"] },
{ "id": "YourNetPrinter", "ip": "192.168.1.17", "type": "printer", "connection": "wifi", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:55", "ipv6": "" },
{ "id": "YourRaspberryPi", "ip": "192.168.1.18", "type": "iot", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "AA:BB:CC:DD:EE:FF", "ipv6": ["2001:1970::2
fe80::feed:face:dead:beef::2
fd38:i5ee:cafe::2"] },
{ "id": "YourLaptop", "ip": "192.168.1.19", "type": "pc", "connection": "wifi", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:51", "ipv6": ["2001:1970::15
fe80::feed:face:dead:beef::15
fd38:i5ee:cafe::15"] },
{ "id": "YourLegacyConsole", "ip": "192.168.1.20", "type": "console", "connection": "wifi-b", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:52", "ipv6": ["2001:1970::16
fe80::feed:face:dead:beef::16
fd38:i5ee:cafe::16"] },
{ "id": "YourVM", "ip": "192.168.1.99", "type": "vm", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:53", "ipv6": ["2001:1970::17
fe80::feed:face:dead:beef::17
fd38:i5ee:cafe::17"] },
{ "id": "YourModem", "ip": "192.168.100.1", "type": "modem", "connection": "ethernet", "online": true, "lastSeen": 0, "mac": "00:11:22:33:44:54", "ipv6": ["2001:1970::1
fe80::feed:face:dead:beef::1
fd38:i5ee:cafe::1"] }
]
}
```
the IPv6 addresses must be seperated via
, otherwise the addresses will be on a single line.
instead of this:
"ipv6":["2001:1970:aaaa:bbbb:54eb:cccc:dddd:1234","fe80::1234:5678:fe08:90ab","fd38:1234:5678:0:90ab:cdef:abcd:ab12","2001:1970:dead:beef:cafe:1234:5678:abcd"]
write them like THIS:
"ipv6": ["2001:1970::1"
fe80::feed:face:dead:beef
fd38:i5ee:cafe::1"]
NOTE: YOU really should change these values (names, IP addresses, and so on) to match whatever items are in your router's DHCP configuration. OpenWRT stores these in /etc/config/dhcp in all the cases i've seen.
You can daisy-chain things along like Router -> Repeater -> Device by telling them their relationship in the links section.
This version does not really implement auto-detection of MAC and IPv6 addresses yet.
Step 4:
Inspect networkmap.html to ensure both networkmap.js and d3.v7.js (or d3.v7.min.js) are present in the header, such as via
```