149 lines
5.2 KiB
Bash
Executable File
149 lines
5.2 KiB
Bash
Executable File
#!/usr/bin/bash
|
|
|
|
# check for nmap and jq
|
|
# check for root
|
|
|
|
starttime="$(date '+%Y-%m-%d %H:%M:%S')"
|
|
|
|
if [ -f arpscan.json ]
|
|
then
|
|
tempjson=$(jq '.ips += {} | .ips=(.ips|to_entries|map_values(.value.online=false)|from_entries)' arpscan.json)
|
|
if [ $? -ne 0 ]
|
|
then
|
|
echo "Failed to load network JSON" 1>&2
|
|
exit 1
|
|
fi
|
|
else
|
|
tempjson={}
|
|
fi
|
|
|
|
jsonescape() {
|
|
jq -Rs . < <(printf "%s" "${1}")
|
|
}
|
|
|
|
foundhost() {
|
|
tempjson=$(jq "$(jsonescape "${1}") as \$ip|.ips[\$ip].mac=$(jsonescape "${2}")|.ips[\$ip].online=true|.ips[\$ip].lastseen=$(jsonescape "${starttime}")" <<< "${tempjson}")
|
|
}
|
|
|
|
doscan() {
|
|
local nmaplog
|
|
nmaplog=$(sudo nmap -sn -n "${1}")
|
|
if [ $? -ne 0 ]
|
|
then
|
|
echo "nmap failed" 1>&2
|
|
return 1
|
|
fi
|
|
cat <<< "${nmaplog}" > "nmaplog.$(sed 's/\//\./' <<< "${1}").txt"
|
|
|
|
local parsestep
|
|
local ipaddr
|
|
parsestep=waitheader
|
|
ipaddr=
|
|
|
|
while read -r line
|
|
do
|
|
case $parsestep in
|
|
waitheader)
|
|
if [[ "${line}" != "Starting Nmap "* ]]
|
|
then
|
|
echo "Nmap start header expected, got ${line}" 1>&2
|
|
return 1
|
|
fi
|
|
parsestep=hostdata
|
|
;;
|
|
hostdata)
|
|
if [[ "${line}" == "Nmap done: "* ]]
|
|
then
|
|
parsestep=scandone
|
|
elif [[ "${line}" =~ ^Nmap\ scan\ report\ for\ (.*)$ ]]
|
|
then
|
|
ipaddr="${BASH_REMATCH[1]}"
|
|
elif [[ "${line}" =~ ^Host\ is\ up(\ \(.*\))?.$ ]]
|
|
then
|
|
continue
|
|
elif [[ "${line}" =~ ^MAC\ Address:\ ([A-F0-9:]{17}).*$ ]]
|
|
then
|
|
local macaddr
|
|
macaddr="${BASH_REMATCH[1]}"
|
|
if [[ "${ipaddr}" == "" ]]
|
|
then
|
|
echo "Found MAC without IP" 1>&2
|
|
return 1
|
|
fi
|
|
foundhost "${ipaddr}" "${macaddr}"
|
|
if [ $? -ne 0 ]
|
|
then
|
|
echo "Registering host failed" 1>&2
|
|
return 1
|
|
fi
|
|
ipaddr=
|
|
else
|
|
echo "Failed to parse: ${line}" 1>&2
|
|
return 1
|
|
fi
|
|
;;
|
|
scandone)
|
|
echo "Unexpected data after scan: ${line}" 1>&2
|
|
return 1
|
|
;;
|
|
*)
|
|
echo "Invalid parse step: ${parsestep}" 1>&2
|
|
return 1
|
|
;;
|
|
esac
|
|
done <<< "$nmaplog"
|
|
#done < nmaplog.txt
|
|
}
|
|
|
|
localifaces="$(ip -j addr | jq '[.[]|{ifname:.ifname,address:.address,addr_info:.addr_info[]}|select(.ifname!="lo")|select(.addr_info.prefixlen>=20)|select(.addr_info.family=="inet")|{ifname:.ifname,ip:.addr_info.local,prefix:.addr_info.prefixlen,mac:(.address|ascii_upcase)}]|map_values(.ip32=(.ip|split(".")|to_entries|map((.value|tonumber)*pow(256;3-.key))|add))|map_values(.subnet32=(.ip32/pow(2;32-.prefix)|floor)*pow(2;32-.prefix))|map_values(.subnet=([(.subnet32/pow(256;3)|floor%256),(.subnet32/pow(256;2)|floor%256),(.subnet32/256|floor%256),.subnet32%256]|join(".")))|map_values(del(.ip32)|del(.subnet32))')"
|
|
|
|
for i in $(seq "$(jq 'length' <<< "${localifaces}")")
|
|
do
|
|
currentiface="$(jq ".[${i}-1]" <<< "${localifaces}")"
|
|
foundhost "$(jq -r '.ip' <<< "${currentiface}")" "$(jq -r '.mac' <<< "${currentiface}")"
|
|
subnet="$(jq -r '.subnet' <<< "${currentiface}")/$(jq '.prefix' <<< "${currentiface}")"
|
|
echo "Scanning ${subnet}"
|
|
doscan "${subnet}"
|
|
if [ $? -ne 0 ]
|
|
then
|
|
echo "Scan failed" 1>&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
## make sure the MAC vendor and device/port fields exist
|
|
#tempjson="$(jq '.macvendor+={}|.devices+=[]' <<< "${tempjson}")"
|
|
if [ ! -f macvendor.json ]
|
|
then
|
|
echo '{}' > macvendor.json
|
|
fi
|
|
if [ ! -d devices ]
|
|
then
|
|
mkdir -p devices
|
|
fi
|
|
if [ ! -f devices/_example.json ]
|
|
then
|
|
cat <<EOF > devices/_example.json
|
|
{
|
|
"desc": "Description of the device",
|
|
"model": "Example Device Model",
|
|
"type": "example",
|
|
"user": "username",
|
|
"ports": [
|
|
{
|
|
"name": "port1",
|
|
"mac": "00:00:00:00:00:00"
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
fi
|
|
|
|
tempjson="$(jq '.ips=(.ips|to_entries|sort_by(.key|split(".")|to_entries|map((.value|tonumber)*pow(256;3-.key))|add)|from_entries)' <<< "${tempjson}")"
|
|
|
|
fancyjson="$(jq --slurpfile macvendor macvendor.json --slurpfile devices <(cat devices/*.json) '. as $root|$macvendor[0]|to_entries|map({key:.value[],value:.key})|from_entries as $vendors|($devices|map(.*(.ports[]|with_entries(.key|="port_"+.))))|map_values(del(.ports))|map({key:.port_mac,value:.})|from_entries as $ports|$root.ips|map_values(.port=$ports[.mac]|.vendor=$vendors[.mac[0:8]])' <<< "${tempjson}")"
|
|
|
|
jq -r '(["[?]","IP","MAC","Vendor","Model","User","Device","Port","Last seen"],(to_entries|sort_by(.key|split(".")|to_entries|map((.value|tonumber)*pow(256;3-.key))|add)|.[]|[if .value.online then "[#]" else "[ ]" end,.key,.value.mac,.value.vendor,.value.port.model,.value.port.user,.value.port.desc,.value.port.port_name,.value.lastseen]))|@tsv' <<< "${fancyjson}" | column -ts $'\t'
|
|
|
|
cat <<< "${tempjson}" > arpscan.json
|