ncat で snmpget のリクエストをエミュレートする

## ncat

`ncat` コマンドを利用すると、簡易的な TCP/UDP クライアントの操作をコマンドラインから行うことができます。

```console
$ nc example.com 80 <<EOF
GET / HTTP/1.1
Host: example.com
Connection: close

EOF
```

実行例

```console
$ nc example.com 80 <<EOF
GET / HTTP/1.1
Host: example.com
Connection: close

EOF
HTTP/1.1 200 OK
Accept-Ranges: bytes
Age: 469158
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
Date: Mon, 21 Oct 2024 13:03:13 GMT
Etag: "3147526947"
Expires: Mon, 28 Oct 2024 13:03:13 GMT
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Server: ECAcc (lac/55C3)
Vary: Accept-Encoding
X-Cache: HIT
Content-Length: 1256
Connection: close

<!doctype html>
<html>
<head>
...
</head>

<body>
<div>
    <h1>Example Domain</h1>
    <p>This domain is for use in illustrative examples in documents. You may use this
    domain in literature without prior coordination or asking for permission.</p>
    <p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
```

また、サーバとして実行することもできます。

```console
# nc --listen 0.0.0.0 8080
```

この状態で 8080 ポートにブラウザアクセスすると接続があった旨が表示されるので、以下を入力します。

```console
HTTP/1.0 200 OK
<html>
  <body>
    <h1>Hello, world!</h1>
  </body>
</html>

```

最後は改行を入れてください。ブラウザに「Hello, world!」と表示されます。

クローズは `^D` です。

## 161/udp への接続

`nc` を用いて 161/udp の疎通確認ができます。これは非常に有用だと思います。

```console
$ echo | nc -u -v 127.0.0.1 161
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:161.
Ncat: 1 bytes sent, 0 bytes received in 0.02 seconds.
```

snmpd が停止していたりする (ポートが開いていない) と、「Connection Refused」となります。

```console
$ systemctl stop snmpd
$ echo | nc -u -v 127.0.0.1 161
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:161.
Ncat: Connection refused.
```

## snmpget のリクエストをシミュレート

結論から言うとうまくいきませんでした。以下のような結果となりました。

```console
$ cat ./byte.bin | nc -u -v 127.0.0.1 161
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:161.
Ncat: 43 bytes sent, 0 bytes received in 0.14 seconds.
```

「0 bytes received」となってしまい、応答が返ってきませんでした。

## 試したこと1

`tcpdump` コマンドによって pcap ファイルを作成

```console
$ tcpdump -i lo udp port 161 -w snmp_request.pcap
```

```console
$ snmpget -v 2c -c public 127.0.0.1 1.3.6.1.2.1.1.1.0
```

取得したパケットキャプチャファイルを Wireshark で開き、 「Export Packet Bytes...」でファイルに出力。

cat で標準出力に渡す形で実行。

```console
$ cat ./byte.bin | nc -u -v 127.0.0.1 161
```

## 試したこと2

「copy as C String」という形で Wireshark から C言語形式でデータを取得。 `ncat` コマンドに流し込み。

```console
$ printf "0)\x02\x01\x0x04\x06public\xa0\x1c\x02\x04$h\x95\xf8\x02\x01\x00\x02\x01\x000\x\x06\x01\x02\x01\x01\x01\x00\x05\x00" | nc -u -v 127.0.0.1 161
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:161.
Ncat: 43 bytes sent, 0 bytes received in 0.01 seconds.
```

## 試したこと3

「試したこと2」で取得したバイナリデータを c 言語で出力するようにし、その出力を `ncat` に流し込み。

```console
$ gcc -std=c99 -o out out.c; ./out | nc -v -u 127.0.0.1 161
Ncat: Version 7.50 ( https://nmap.org/ncat )
Ncat: Connected to 127.0.0.1:161.
Ncat: 37 bytes sent, 0 bytes received in 0.07 seconds.
```

```out.c
#include <stdio.h>

int main() {
    // Define the raw SNMP packet as a byte array
    unsigned char snmp_packet[] = {
        0x30, 0x02, 0x01, 0x00, 0x04, 0x06, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 
        0xa0, 0x1c, 0x02, 0x04, 0x24, 0x68, 0x95, 0xf8, 0x02, 0x01, 0x00, 0x02, 
        0x01, 0x00, 0x30, 0x0a, 0x06, 0x01, 0x02, 0x01, 0x01, 0x01, 0x00, 0x05, 0x00
    };

    int length = sizeof(snmp_packet) / sizeof(snmp_packet[0]);

    // Write the binary data to standard output
    fwrite(snmp_packet, sizeof(unsigned char), length, stdout);

    return 0;
}
```