mystab_pcap.c
最終更新:2010/1/12
001: /* 002: * mystab_pcap.c 003: * libpcap を用いた TCP パケット解析用スタブ 004: * pcap_loop で無限ループする。終了には 005: * Ctrl-C 入力か kill コマンドで SIGINT シグナルを送る。 006: */ 007: 008: #define ETHER_HEADER_SIZE (6+6+2) 009: 010: #include "mystab_pcap.h" 011: #include "apr_signal.h" 012: 013: #if defined(WIN32) || defined(WINDOWS) || defined(MSVC) 014: 015: /* 016: * ネットワークデバイスのリストの出力ユーティリティ 017: * (Windows のみ) 018: * 返り値: 019: * 成功:1 020: * 失敗:0 (errbuf にエラーメッセージが保存される) 021: */ 022: 023: int disp_devices( 024: apr_file_t *out 025: , char *errbuf 026: , int errbuf_size 027: ) { 028: pcap_if_t *alldevs = NULL; 029: pcap_if_t *d = NULL; 030: 031: /* ネットワークデバイスのリストの取得 */ 032: if (pcap_findalldevs(&alldevs, errbuf) == -1) { 033: return 0; 034: } 035: 036: if(!alldevs) { 037: snprintf(errbuf, ERR_BUF_SIZE, "No interface\n"); 038: return 0; 039: } 040: 041: /* ネットワークデバイスのリストの表示 */ 042: for(d=alldevs; d; d=d->next) { 043: apr_file_printf(out, "%s\n", d->name); 044: if (d->description) 045: apr_file_printf(out, "\tdescription: %s\n\n", d->description); 046: else 047: apr_file_printf(out, "\t(No description)\n\n"); 048: } 049: 050: pcap_freealldevs(alldevs); 051: 052: return 1; 053: } 054: #endif /* defined(WIN32) || defined(WINDOWS) || defined(MSVC) */ 055: 056: struct printer { 057: pcap_handler f; 058: int type; 059: }; 060: 061: static void ether_flame_handler(u_char *, const struct pcap_pkthdr *, const u_char *); 062: 063: static struct printer printers[] = { 064: { ether_flame_handler, DLT_EN10MB }, 065: { NULL, 0 }, 066: }; 067: 068: static char errbuf[ERR_BUF_SIZE]; 069: 070: static pcap_t *_my_pcap_init ( 071: int ac 072: , char **av 073: , my_pcap_params *params 074: , apr_file_t *astderr 075: , apr_pool_t *pool 076: ) { 077: pcap_t *pd; 078: struct bpf_program fcode; 079: bpf_u_int32 localnet, netmask; 080: 081: if (my_pcap_init(ac, av, params, astderr, pool) == 0) { 082: return NULL; 083: } 084: 085: if(!params->device){ 086: params->device = pcap_lookupdev(errbuf); 087: if(! params->device){ 088: apr_file_printf(astderr, "ERROR: pcap_lookupdev: %s\n", errbuf); 089: return NULL; 090: } 091: } 092: 093: pd = pcap_open_live(params->device, params->snaplen, params->pflag, params->to_ms, errbuf); 094: 095: if(!pd){ 096: apr_file_printf(astderr, "ERROR: pcap_open_live: %s\n", errbuf); 097: return NULL; 098: } else if(! params->filter) { 099: /* no filter */ 100: return pd; 101: } else if(pcap_lookupnet(params->device, &localnet, &netmask, errbuf) < 0){ 102: apr_file_printf(astderr, "ERROR: pcap_lookupnet: %s\n", errbuf); 103: return NULL; 104: } else if (pcap_compile(pd, &fcode, params->filter, params->Oflag, netmask) < 0) { 105: apr_file_printf(astderr, "ERROR: pcap_compile(): %s\n", pcap_geterr(pd)); 106: return NULL; 107: } else if (pcap_setfilter(pd, &fcode) < 0) { 108: apr_file_printf(astderr, "ERROR: pcap_setfilter(): %s\n", pcap_geterr(pd)); 109: return NULL; 110: } 111: 112: return pd; 113: } 114: 115: static pcap_handler lookup_printer( 116: int type 117: ) { 118: struct printer *p; 119: 120: for (p = printers; p->f; ++p) 121: if (type == p->type) 122: return p->f; 123: 124: /* not found */ 125: return NULL; 126: } 127: 128: typedef struct _ether_flame_hadler_data { 129: apr_pool_t *pool; 130: apr_file_t *out; 131: my_tcp_pkt *d; 132: } ether_flame_hadler_data; 133: 134: static void ether_flame_handler ( 135: u_char * userdata 136: , const struct pcap_pkthdr *h 137: , const u_char *p 138: ) { 139: apr_byte_t *c = NULL; 140: 141: ether_flame_hadler_data *efhd = (ether_flame_hadler_data *)userdata; 142: my_tcp_pkt *d = efhd->d; 143: 144: if (h->caplen < ETHER_HEADER_SIZE + 40) /* パケットサイズが小さい… */ 145: return; 146: 147: memset(d, 0, sizeof(my_tcp_pkt)); 148: 149: /* TCP の先頭 */ 150: 151: d->ip_header_pos = (unsigned char*)p + ETHER_HEADER_SIZE; 152: 153: /* IP ヘッダのバイト数の取得。 154: * IP パケット先頭(イーサヘッダ後)の最初のバイトの下位4ビットの値×4バイト 155: */ 156: 157: c = d->ip_header_pos; 158: d->ip_header_size = (*c & 0xF)*4; 159: 160: /* IP データグラムのバイト数の取得。 161: * IP ヘッダのバイト数も含まれる。 162: * IP パケット先頭から3バイト目と4バイト目 163: */ 164: 165: d->ip_datagram_size = *(c+2)*256 + *(c+3); 166: 167: /* 送り元IP アドレスの取得。 168: * IP パケット先頭から13〜16バイト目 169: */ 170: 171: c = d->ip_header_pos + 12; 172: snprintf(d->ip_src_addr, 16, "%d.%d.%d.%d", *c, *(c+1), *(c+2), *(c+3)); 173: 174: /* あて先IP アドレスの取得。 175: * IP パケット先頭から17〜20バイト目 176: */ 177: 178: c += 4; 179: snprintf(d->ip_dst_addr, 16, "%d.%d.%d.%d", *c, *(c+1), *(c+2), *(c+3)); 180: 181: /* TCP の先頭 */ 182: 183: d->tcp_header_pos = d->ip_header_pos + d->ip_header_size; 184: 185: /* 送り元ポート番号とあて先ポート番頭の取得。 186: * TCP パケット先頭の1〜2バイト目:送り元ポート番号 187: * TCP パケット先頭の3〜4バイト目:あて先ポート番号 188: */ 189: 190: c = d->tcp_header_pos; 191: d->tcp_src_port = *c * 256 + *(c+1); 192: d->tcp_dst_port = *(c+2) * 256 + *(c+3); 193: 194: /* TCP シーケンス番号の取得 */ 195: 196: c = d->tcp_header_pos + 4; 197: d->tcp_seq_no = *c*256*256*256+*(c+1)*256*256+*(c+2)*256+*(c+3); 198: c += 4; 199: d->tcp_ack_no = *c*256*256*256+*(c+1)*256*256+*(c+2)*256+*(c+3); 200: 201: 202: /* TCP ヘッダのバイト数の取得。 203: * TCP パケット先頭から13バイト目の上位4ビットの値×4バイト 204: */ 205: 206: c = d->tcp_header_pos + 12; 207: d->tcp_header_size = (*c >> 4) * 4; 208: 209: /* コードビットの取得 210: * TCP パケットの14バイト目の下位6ビット。 211: */ 212: { 213: unsigned char code_bits = 0; 214: c = d->tcp_header_pos + 13; 215: code_bits = *c & 0x3F; 216: d->tcp_urg_bit = code_bits>>5; 217: d->tcp_ack_bit = (code_bits>>4) & 1; 218: d->tcp_psh_bit = (code_bits>>3) & 1; 219: d->tcp_rst_bit = (code_bits>>2) & 1; 220: d->tcp_syn_bit = (code_bits>>1) & 1; 221: d->tcp_fin_bit = (code_bits) & 1; 222: } 223: 224: /* TCP ペイロードサイズ */ 225: 226: d->tcp_payload_size = d->ip_datagram_size - d->ip_header_size - d->tcp_header_size; 227: 228: 229: /* TCP ペイロードの位置 */ 230: 231: d->tcp_payload_pos = d->tcp_header_pos + d->tcp_header_size; 232: 233: my_pcap_main(efhd->pool, efhd->out, d); 234: 235: } 236: 237: static pcap_t *pd = NULL; 238: 239: /* シグナルハンドラ 240: * pcap_loop を抜ける 241: */ 242: 243: static void my_signal_handler (int x) { 244: if(0)fprintf(stderr, "SIGNAL: %d\n", x); 245: if (pd) { 246: pcap_breakloop(pd); 247: } 248: } 249: 250: int apr_my_main ( 251: int ac, 252: char **av, 253: apr_file_t * astdin, 254: apr_file_t * astdout, 255: apr_file_t * astderr, 256: apr_pool_t * pool 257: ) 258: { 259: my_pcap_params params; 260: pcap_handler printer; 261: ether_flame_hadler_data efhd; 262: my_tcp_pkt d; 263: int rv = 0; 264: 265: /* シグナル設定 */ 266: 267: apr_signal(SIGINT, my_signal_handler); 268: 269: /* libpcap パラメータのデフォルト値の設定 */ 270: 271: params.device = NULL; 272: params.snaplen = 65535; 273: params.pflag =0; 274: params.to_ms = 1000; 275: params.Oflag = 0; 276: params.cnt = -1; 277: params.filter = NULL; 278: 279: pd = _my_pcap_init(ac, av, ¶ms, astderr, pool); 280: 281: if(!pd) { 282: return 1; 283: } 284: 285: printer = lookup_printer(pcap_datalink(pd)); 286: if (!printer) { 287: apr_file_printf(astderr, "ERROR: unknown data link type\n"); 288: return 1; 289: } 290: 291: efhd.pool = pool; 292: efhd.out = astdout; 293: efhd.d = &d; 294: 295: rv = pcap_loop(pd, params.cnt, printer, (u_char*)&efhd); 296: if (rv == (-2)){ 297: apr_file_printf(astderr, "WARNING: escaped from pcap_loop.\n"); 298: } else { 299: apr_file_printf(astderr, "ERROR: pcap_loop: %s\n", pcap_geterr(pd)); 300: } 301: 302: if (pd) { 303: pcap_close(pd); 304: pd = NULL; 305: } 306: 307: my_pcap_finally(astdout); 308: 309: /* 正常終了 */ 310: return 0; 311: }
KAKU PROJECT (2009) |