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) |