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でも何でもしてみて下さい。