この記事は 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":[]}]