mystab_pcap.c

最終更新:2010/1/12

mystab_pcap.c

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, &params, 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: }
Copyright (C) KAKU PROJECT (2009)KAKU PROJECT (2009)