一汁三菜

自分が楽しいと思うこと、マラソン、旅行、その他日々の記録をしたい。

C言語で100行以内でパケットモニタを書く

netfilterは、Linuxのパケットフィルタです。これを使うとネットワークを使って色々と遊ぶ事ができます。

libnetfilterの強力さをアピールする為に、パケットモニタを書いてみました。読みやすさの為にエラー処理を徹底的に省いていますが、特に読みづらくしたりする事なく、57行で書けています。

論より証拠。以下がソースコードです。

#include <stdio.h>
#include <netinet/in.h>
#include <linux/netfilter.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#define QUEUE_ID 2

static void print(const char *buf, int len)
{
  int i;
  for(i = 0; i < len; ++i) {
    printf("%02X ", (unsigned char)buf[i]);
    if(i % 0x10 == 0)
      printf("\n");
  }
  printf("\n");
}

int dump(struct nfq_q_handle *qh, struct nfgenmsg *msg, struct nfq_data *nfdata, void *data)
{
  struct nfqnl_msg_packet_hdr *header;
  char *payload;
  int len;

  header = nfq_get_msg_packet_hdr(nfdata);
  len = nfq_get_payload(nfdata, (char **)&payload);
  print(payload, len);

  return nfq_set_verdict(qh, ntohl(header->packet_id), NF_ACCEPT, 0, NULL);
}

int main(void)
{
  struct nfq_handle *nfqh;
  struct nfq_q_handle *nfqqh;
  char buf[0x10000];
  int len, fd;

  nfqh = nfq_open();

  nfq_unbind_pf(nfqh, PF_INET);
  nfq_bind_pf(nfqh, PF_INET);

  nfqqh = nfq_create_queue(nfqh, QUEUE_ID, dump, NULL);

  nfq_set_mode(nfqqh, NFQNL_COPY_PACKET, sizeof(buf));

  fd = nfq_fd(nfqh);
  while((len = read(fd, buf, sizeof(buf))) >= 0) {
    nfq_handle_packet(nfqh, buf, len);
  }

  nfq_unbind_pf(nfqh, PF_INET);
  nfq_close(nfqh);

  return 0;
}

コンパイル

Ubuntu Linuxでは、libnetfilter-queue-devパッケージが必要です。他に必要なパッケージは自動的にインストールされると思います。

コンパイル時にはlibnetfilter_queueをリンクするのをお忘れなく。

$ gcc pktmon.c -lnetfilter_queue

実行

Linux 2.6.14以降が必要です。
iptablesを使っているので、前準備をしておきましょう。

# iptables -A INPUT -j NFQUEUE --queue-num 2
# ./pktmon
    • queue-numに指定する値は、ソースコード中のQUEUE_IDに指定した値と同じ値にします。

後はpingでも何でもしてみて下さい。

一手間かける

iptablesを日常的に使われている人ならば、iptablesに各種オプションを与える事もできるでしょう。例えば133.11.0.0/16からのパケットだけをモニタリングしたいなら、

# iptables -A INPUT -s 133.11.0.0/16 -j NFQUEUE --queue-num 2
# ./pktmon

とすれば良いでしょう。

後処理

試してみた後は、後片付けをしましょう。

# iptables -D INPUT -j NFQUEUE --queue-num 2

まとめ

iptablesは単体でも優秀なツールですが、プログラムから利用するとさらにその便利さを享受できます。

ただしnetfilterのAPIはあまり洗練されていないので、時々謎の挙動に悩むことがあります。ご注意下さい。またマニュアルの整備がされていないので、困った時はLinuxカーネルソースコードに潜って挙動を確認する必要があります。くれぐれも深入りにはご注意を。