Raspberry Pi など Linux で nmap を使ったポートスキャンするときの Node-RED で JSON 出力するメモ
この記事は Node-RED Qiita Advent Calendar 2024 の 2 日目の記事です。
Raspberry Pi など Linux で nmap を使ったポートスキャンするときの Node-RED での JSON 出力するメモです。
2024/11/29 の情報で進めます。
背景
最近ようやく Raspberry Pi など Linux であれば nmap を使ったポートスキャンが便利だなということに知ることができました。
ただ、nmap はポートスキャンすると
sudo nmap -sP 192.168.1.0/24
Starting Nmap 7.93 ( https://nmap.org ) at 2024-11-29 11:21 JST
Nmap scan report for ****** (192.168.1.1)
Host is up (0.0012s latency).
MAC Address: 00:00:00:00:00:00 (Device)
Nmap scan report for 192.168.1.2
Host is up (0.25s latency).
MAC Address: 00:00:00:00:00:00 (Device)
Nmap scan report for 192.168.1.3
Host is up (0.15s latency).
MAC Address: 00:00:00:00:00:00 (Device)
Nmap scan report for 192.168.1.4
....
というテキストで来てしまい扱いにくいので Node-RED で JSON 出力したくなったのでやってみます。
nmap インストール
pi@raspberrypi:~ $ nmap
-bash: nmap: command not found
Raspberry Pi で初手で nmap がまだ使えないときは、
sudo apt-get install nmap
こちらでインストールします。
JSON に変換する JavaScript
sudo nmap -sP 192.168.1.0/24
Starting Nmap 7.93 ( https://nmap.org ) at 2024-11-29 11:21 JST
Nmap scan report for ****** (192.168.1.1)
Host is up (0.0012s latency).
MAC Address: 00:00:00:00:00:00 (Device)
Nmap scan report for 192.168.1.2
Host is up (0.25s latency).
MAC Address: 00:00:00:00:00:00 (Device)
Nmap scan report for 192.168.1.3
Host is up (0.15s latency).
MAC Address: 00:00:00:00:00:00 (Device)
Nmap scan report for 192.168.1.4
....
こちらの出力を変換します。
const result = msg.payload;
const list1 = result.split('Nmap scan report for ');
const nmapList = [];
list1.forEach(function (item) {
const o = {};
const macAddressLine = item.split('MAC Address: ')[1];
if (macAddressLine){
o.macAddress = macAddressLine.split(' (')[0];
o.deviceName = macAddressLine.split(' (')[1].split(')')[0];
o.ipAddress = item.split("\n")[0];
nmapList.push(o);
}
});
msg.payload = nmapList;
return msg;
といった JavaScript で変換できました。あんまりイレギュラーな対応を想定していないものですが、これでうまくいっています。
Node-RED に組み込んでみる

このようなフローです。 parse の中に先ほどのコードが入っています。
動かしてみると、

このようにうまく JSON 出力で返ってきます!
[
{
"macAddress": "00:00:00:00:00:00",
"deviceName": "Device01",
"ipAddress": "****** (192.168.1.1)"
},
{
"macAddress": "00:00:00:00:00:00",
"deviceName": "Device02",
"ipAddress": "192.168.1.2"
},
...
]
内容はこんな感じです。192.168.1.1 は最初に検索されるものでちょっとパースがしくじってますが、ポートスキャンしたいのは 2 以降なのでよさそうです。
最近はこの仕組みを使ってネットワーク内のポートスキャンを Node-RED でうまく調査できるようなり便利に使っています。
JSON フローも置いておきます。
[{"id":"364b3841b0d211e9","type":"exec","z":"f6623d9257dd5585","command":"sudo nmap -sP 192.168.1.0/24","addpay":"","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"","x":510,"y":300,"wires":[["0e68ce40d6433872","b31c3edbb07abd05"],[],[]]},{"id":"0e68ce40d6433872","type":"debug","z":"f6623d9257dd5585","name":"debug 32","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":840,"y":260,"wires":[]},{"id":"b31c3edbb07abd05","type":"function","z":"f6623d9257dd5585","name":"parse","func":"const result = msg.payload;\n\nconst list1 = result.split('Nmap scan report for ');\n\nconst nmapList = [];\n\nlist1.forEach(function (item) {\n const o = {};\n const macAddressLine = item.split('MAC Address: ')[1];\n if (macAddressLine){\n o.macAddress = macAddressLine.split(' (')[0];\n o.deviceName = macAddressLine.split(' (')[1].split(')')[0];\n o.ipAddress = item.split(\"\\n\")[0];\n nmapList.push(o);\n }\n \n});\n\nmsg.payload = nmapList;\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":830,"y":320,"wires":[["e29d99d26d657be3"]]},{"id":"118469b3d601f6fa","type":"inject","z":"f6623d9257dd5585","name":"start","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":250,"y":300,"wires":[["364b3841b0d211e9"]]},{"id":"e29d99d26d657be3","type":"debug","z":"f6623d9257dd5585","name":"debug 31","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1020,"y":320,"wires":[]}]