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 リファレンスガイド (Man Page)

ただ、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 に組み込んでみる

node-red-nmap-json-parse_00.png

このようなフローです。 parse の中に先ほどのコードが入っています。

動かしてみると、

node-red-nmap-json-parse_01.png

このようにうまく 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":[]}]