1 /*
2 * Copyright (C) 2001 Marco Ziech (mmz@gmx.net)
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18 #include "common/setup_before.h"
19 #include <stdio.h>
20 #include <pcap.h>
21 #include <errno.h>
22 #include <netinet/in.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include "compat/strerror.h"
26 #include "compat/getopt.h"
27 #include "common/init_protocol.h"
28 #include "common/bnet_protocol.h"
29 #include "common/udp_protocol.h"
30 #include "common/packet.h"
31 #include "common/eventlog.h"
32 #include "common/hexdump.h"
33 #include "common/list.h"
34 #include "common/version.h"
35 #include "common/util.h"
36 #include "common/setup_after.h"
37
38 /* FIXME: everywhere: add checks for NULL pointers */
39
40 char *filename = NULL;
41 pcap_t *pc;
42 char ebuf[PCAP_ERRBUF_SIZE];
43
44
45 int bnpcap_dodebug = 0;
46 int bnpcap_beverbose = 0;
47
48 unsigned int listen_port = 6112;
49
50 /********************* CONNECTIONS ********************/
51
52 typedef enum {
53 tcp_state_none,
54 tcp_state_syn,
55 tcp_state_ack,
56 tcp_state_ok
57 } t_tcp_state;
58
59 typedef struct {
60 /* It's IPV4 */
61 unsigned int ip;
62 unsigned short port;
63 } t_bnpcap_addr;
64
65 /* To track connections ... */
66 typedef struct {
67 t_bnpcap_addr client;
68 t_bnpcap_addr server;
69 t_packet_class class;
70 t_tcp_state tcpstate;
71 int incomplete;
72 int clientoff;
73 t_packet *clientpkt;
74 int serveroff;
75 t_packet *serverpkt;
76 t_list * packets;
77 } t_bnpcap_conn;
78
79 typedef struct {
80 t_packet_dir dir;
81 struct timeval tv;
82 unsigned int id;
83 t_packet *p;
84 } t_bnpcap_packet;
85
86 t_list * conns;
87 t_list * udppackets;
88
89 struct timeval packettime;
90
91 static unsigned int current_packet_id = 1;
92
93 /*********************** HEADERS **********************/
94
95 /* FIXME: don't assume that's always true */
96 typedef unsigned char u8;
97 typedef unsigned short u16;
98 typedef unsigned int u32;
99
100 /************************** TCP ***********************/
101
102 typedef struct {
103 u16 sport;
104 u16 dport;
105 u32 seqno;
106 u32 ackno;
107 u16 stuff; /* Data offset, various flags */
108 u16 window;
109 u16 checksum;
110 u16 urgp; /* Urgent Pointer (if URG flag set) */
111 /* options */
112 } t_tcp_header_raw;
113
114 typedef struct {
115 unsigned short sport;
116 unsigned short dport;
117 unsigned int seqno;
118 unsigned int ackno;
119 unsigned char doffset;
120 unsigned short flags;
121 #define TCP_URG 0x20 /* Urgent pointer field significant */
122 #define TCP_ACK 0x10 /* Acknowlegdement field significant */
123 #define TCP_PSH 0x08 /* Push function */
124 #define TCP_RST 0x04 /* Reset connection */
125 #define TCP_SYN 0x02 /* Synchronize sequence numbers */
126 #define TCP_FIN 0x01 /* No more data from sender (finish) */
127 unsigned short window;
128 unsigned short checksum;
129 unsigned short urgp;
130 /* options */
131 } t_tcp_header;
132
133 /******************************** UDP ************************/
134
135 typedef struct {
136 u16 sport;
137 u16 dport;
138 u16 len;
139 u16 checksum;
140 } t_ip_udp_header_raw;
141
142 typedef struct {
143 unsigned short sport;
144 unsigned short dport;
145 unsigned short len;
146 unsigned short checksum;
147 } t_ip_udp_header;
148
149 /******************************** IP *************************/
150
151 typedef struct {
152 u8 versionihl;
153 u8 tos;
154 u16 len;
155 u16 id;
156 u16 flagsoffset;
157 u8 ttl;
158 u8 protocol;
159 u16 checksum;
160 u32 src;
161 u32 dst;
162 /* options */
163 } t_ip_header_raw;
164
165 typedef struct {
166 unsigned char version;
167 unsigned char ihl;
168 unsigned char tos;
169 unsigned short len;
170 unsigned short id;
171 unsigned char flags;
172 #define IP_DF 0x02 /* 1 == Don't fragment */
173 #define IP_MF 0x01 /* 1 == More fragments */
174 unsigned short offset;
175 unsigned char ttl;
176 unsigned char protocol;
177 unsigned short checksum;
178 unsigned int src;
179 unsigned int dst;
180 /* options */
181 } t_ip_header;
182
183 /******************************* ETHERNET *****************************/
184
185 typedef struct {
186 u8 dst[6]; /* Ethernet hardware address */
187 u8 src[6]; /* Ethernet hardware address */
188 u16 type; /* Ethernet_II: protocol type */
189 /* FIXME: Ethernet [802.2|802.3|SNAP]: maybe something else (eg. length) */
190 } t_ether_raw;
191
192 /************************************************************************/
193 /************************* CONNECTION FUNCTIONS *************************/
194
bnpcap_conn_new(t_bnpcap_addr const * s,t_bnpcap_addr const * d)195 static t_bnpcap_conn * bnpcap_conn_new(t_bnpcap_addr const *s, t_bnpcap_addr const *d)
196 {
197 t_bnpcap_conn * c;
198
199 c = (t_bnpcap_conn *) malloc(sizeof(t_bnpcap_conn)); /* avoid warning */
200 if (!c) {
201 eventlog(eventlog_level_error,__FUNCTION__,"malloc failed: %s",pstrerror(errno));
202 return NULL;
203 }
204 if (d->port==listen_port || d->port==6200) { /* FIXME: That's dirty: We assume the server is on port 6112 */
205 memcpy(&c->client,s,sizeof(t_bnpcap_addr));
206 memcpy(&c->server,d,sizeof(t_bnpcap_addr));
207 } else {
208 memcpy(&c->client,d,sizeof(t_bnpcap_addr));
209 memcpy(&c->server,s,sizeof(t_bnpcap_addr));
210 }
211 c->class = packet_class_init;
212 c->packets = list_create();
213 c->incomplete = 0;
214 c->tcpstate = tcp_state_none;
215 c->clientoff = 0;
216 c->clientpkt = NULL;
217 c->serveroff = 0;
218 c->serverpkt = NULL;
219 return c;
220 }
221
bnpcap_conn_set_class(t_bnpcap_conn * c,t_packet_class class)222 static void bnpcap_conn_set_class(t_bnpcap_conn *c, t_packet_class class)
223 {
224 c->class = class;
225 }
226
bnpcap_conn_get_class(t_bnpcap_conn * c)227 static t_packet_class bnpcap_conn_get_class(t_bnpcap_conn *c)
228 {
229 return c->class;
230 }
231
bnpcap_conn_find(t_bnpcap_addr const * s,t_bnpcap_addr const * d)232 static t_bnpcap_conn * bnpcap_conn_find(t_bnpcap_addr const *s, t_bnpcap_addr const *d)
233 {
234 t_elem * curr;
235
236 LIST_TRAVERSE(conns,curr) {
237 t_bnpcap_conn *c;
238
239 c = elem_get_data(curr);
240 if (((c->client.ip==s->ip)&&(c->client.port==s->port))&&
241 ((c->server.ip==d->ip)&&(c->server.port==d->port))) {
242 return c;
243 } else if (((c->client.ip==d->ip)&&(c->client.port==d->port))&&
244 ((c->server.ip==s->ip)&&(c->server.port==s->port))) {
245 return c;
246 }
247 }
248 return NULL;
249 }
250
bnpcap_conn_get_dir(t_bnpcap_conn const * c,t_bnpcap_addr const * s,t_bnpcap_addr const * d)251 static t_packet_dir bnpcap_conn_get_dir(t_bnpcap_conn const * c, t_bnpcap_addr const *s, t_bnpcap_addr const *d)
252 {
253 if (((c->client.ip==s->ip)&&(c->client.port==s->port))&&
254 ((c->server.ip==d->ip)&&(c->server.port==d->port)))
255 return packet_dir_from_client;
256 else
257 return packet_dir_from_server;
258 }
259
bnpcap_conn_add_packet(t_bnpcap_conn * c,t_bnpcap_packet * bp)260 static int bnpcap_conn_add_packet(t_bnpcap_conn *c, t_bnpcap_packet *bp) {
261 eventlog(eventlog_level_debug,__FUNCTION__,"id=%u ",bp->id);
262 list_append_data(c->packets,bp);
263 packet_add_ref(bp->p);
264 return 0;
265 }
266
bnpcap_conn_packet(unsigned int sip,unsigned short sport,unsigned int dip,unsigned short dport,unsigned char const * data,unsigned int len)267 static int bnpcap_conn_packet(unsigned int sip, unsigned short sport, unsigned int dip, unsigned short dport, unsigned char const * data, unsigned int len)
268 {
269 t_bnpcap_addr s;
270 t_bnpcap_addr d;
271 t_bnpcap_conn *c;
272 t_bnpcap_packet *bp;
273
274 s.ip = sip;
275 s.port = sport;
276 d.ip = dip;
277 d.port = dport;
278
279 if ((c = bnpcap_conn_find(&s,&d))) {
280 eventlog(eventlog_level_debug,__FUNCTION__,"adding packet to existing connection");
281 if (c->tcpstate==tcp_state_ack) {
282 c->tcpstate = tcp_state_ok;
283 } else if (c->tcpstate==tcp_state_syn) {
284 c->incomplete = 1; /* ACK missing */
285 c->tcpstate = tcp_state_ok;
286 }
287 } else {
288 eventlog(eventlog_level_debug,__FUNCTION__,"adding packet to incomplete connection");
289 c = bnpcap_conn_new(&s,&d);
290 bnpcap_conn_set_class(c,packet_class_raw); /* we don't know the init sequence */
291 c->incomplete = 1;
292 c->tcpstate = tcp_state_ok;
293 list_append_data(conns,c);
294 }
295 if (c->tcpstate!=tcp_state_ok) {
296 eventlog(eventlog_level_warn,__FUNCTION__,"connection got packet in wrong state!");
297 }
298 if (bnpcap_conn_get_class(c) == packet_class_init) {
299 if (len>1) {
300 eventlog(eventlog_level_warn,__FUNCTION__,"init packet larger than 1 byte");
301 }
302 switch (data[0]) {
303 case CLIENT_INITCONN_CLASS_BNET:
304 bnpcap_conn_set_class(c,packet_class_bnet);
305 break;
306 case CLIENT_INITCONN_CLASS_FILE:
307 bnpcap_conn_set_class(c,packet_class_file);
308 break;
309 case 0xf7: // W3 matchmaking hack
310 eventlog(eventlog_level_info,__FUNCTION__,"matchmaking packet");
311 bnpcap_conn_set_class(c,packet_class_bnet);
312 break;
313 default:
314 bnpcap_conn_set_class(c,packet_class_raw);
315 }
316 } else {
317 t_packet *p;
318 unsigned int off;
319 unsigned char const *datap = data;
320 int always_complete = 0;
321
322
323 if (bnpcap_conn_get_class(c) == packet_class_raw)
324 always_complete = 1; /* There is no size field */
325 if (bnpcap_conn_get_class(c) == packet_class_file)
326 always_complete = 1; /* Size field isn't always there */
327
328 if (always_complete) {
329 /* packet is always complete */
330 eventlog(eventlog_level_debug,__FUNCTION__,"packet is always complete (class=%d)",bnpcap_conn_get_class(c));
331 bp = (t_bnpcap_packet *) malloc(sizeof(t_bnpcap_packet)); /* avoid warning */
332 if (!bp) {
333 eventlog(eventlog_level_error,__FUNCTION__,"malloc failed: %s",pstrerror(errno));
334 return -1;
335 }
336 bp->dir = bnpcap_conn_get_dir(c,&s,&d);
337 bp->p = packet_create(bnpcap_conn_get_class(c));
338 bp->id = current_packet_id++;
339 if (!bp->p) {
340 eventlog(eventlog_level_error,__FUNCTION__,"packet_create failed");
341 return -1;
342 }
343 memcpy(&bp->tv,&packettime,sizeof(struct timeval));
344 packet_set_size(bp->p,len);
345 memcpy(packet_get_raw_data(bp->p,0),data,len);
346 bnpcap_conn_add_packet(c,bp);
347 if ((packet_get_class(bp->p)==packet_class_file)&&(packet_get_type(bp->p)==SERVER_FILE_REPLY)) {
348 eventlog(eventlog_level_debug,__FUNCTION__,"file transfer initiated (setting to raw)");
349 bnpcap_conn_set_class(c,packet_class_raw);
350 }
351 } else {
352 /* read out saved state */
353 if (bnpcap_conn_get_dir(c,&s,&d)==packet_dir_from_client) {
354 p = c->clientpkt;
355 off = c->clientoff;
356 } else {
357 p = c->serverpkt;
358 off = c->serveroff;
359 }
360 while ((datap-data)<(signed)len) {
361 if (!p) {
362 eventlog(eventlog_level_debug,__FUNCTION__,"creating new packet");
363 p = packet_create(bnpcap_conn_get_class(c));
364 if (!p) {
365 eventlog(eventlog_level_error,__FUNCTION__,"packet_create failed");
366 return -1;
367 }
368 packet_set_size(p,packet_get_header_size(p)); /* set it to the minimum for now */
369 off = 0;
370 }
371 if (off < packet_get_header_size(p)) {
372 unsigned int l = (packet_get_header_size(p)-off);
373 /* (len-(datap-data)) : remaining bytes in buffer */
374 if ((len-(datap-data)) < l)
375 l = (len-(datap-data));
376 eventlog(eventlog_level_debug,__FUNCTION__,"filling up header (adding %d to %d to get %d)",l,off,packet_get_header_size(p));
377 memcpy(packet_get_raw_data(p,off),datap,l);
378 datap = datap + l;
379 off = off + l;
380 } else {
381 unsigned int l = (packet_get_size(p)-off);
382 if ((len-(datap-data)) < l)
383 l = (len-(datap-data));
384 eventlog(eventlog_level_debug,__FUNCTION__,"filling up packet (0x%04x:%s) (adding %d to %d to get %d)",packet_get_type(p),packet_get_type_str(p,bnpcap_conn_get_dir(c,&s,&d)),l,off,packet_get_size(p));
385 memcpy(packet_get_raw_data(p,off),datap,l);
386 datap = datap + l;
387 off = off + l;
388 }
389 if ((off>=packet_get_header_size(p))&&(off>=packet_get_size(p))) {
390 /* packet is complete */
391 eventlog(eventlog_level_debug,__FUNCTION__,"packet is complete");
392 bp = (t_bnpcap_packet *) malloc(sizeof(t_bnpcap_packet)); /* avoid warning */
393 if (!bp) {
394 eventlog(eventlog_level_error,__FUNCTION__,"malloc failed: %s",pstrerror(errno));
395 return -1;
396 }
397 if ((off != packet_get_size(p))&&(bnpcap_dodebug)) {
398 eventlog(eventlog_level_warn,__FUNCTION__,"packet size differs (%d != %d) (offset=0x%04x)",off,packet_get_size(p),datap-data);
399 hexdump(stderr,data,len);
400 /* memcpy(packet_get_raw_data(p,0),data,packet_get_size(p)); */
401 }
402 bp->dir = bnpcap_conn_get_dir(c,&s,&d);
403 bp->p = p;
404 bp->id = current_packet_id++;
405 memcpy(&bp->tv,&packettime,sizeof(struct timeval));
406 bnpcap_conn_add_packet(c,bp);
407 if (packet_get_size(p)==0)
408 datap = data + len; /* if size is invalid, drop the rest of the stream packet */
409 p = NULL;
410 off = 0;
411 }
412 } /* while */
413 /* write back saved state */
414 if ((off>0)&&(bnpcap_dodebug)) {
415 eventlog(eventlog_level_debug,__FUNCTION__,"saving %d bytes in packet buffer (p=0x%08lx)",off,(long)p);
416 }
417 if (bnpcap_conn_get_dir(c,&s,&d)==packet_dir_from_client) {
418 c->clientpkt = p;
419 c->clientoff = off;
420 } else {
421 c->serverpkt = p;
422 c->serveroff = off;
423 }
424 } /* !always_complete */
425 return 0;
426 }
427 return 0;
428 }
429
430
431 /************************************************************************/
432 /******************************** LAYERS ********************************/
433
434 /********************************* TCP **********************************/
435
bnpcap_tcp2tcp(t_tcp_header * d,t_tcp_header_raw const * s)436 static int bnpcap_tcp2tcp(t_tcp_header * d, t_tcp_header_raw const * s)
437 {
438 d->sport = htons(s->sport);
439 d->dport = htons(s->dport);
440 d->seqno = htonl(s->seqno);
441 d->ackno = htonl(s->ackno);
442 d->doffset = (htons(s->stuff) & 0xF000) >> 12;
443 d->flags = (htons(s->stuff) & 0x0FFF);
444 d->window = htons(s->window);
445 d->checksum = htons(s->checksum);
446 d->urgp = htons(s->urgp);
447 return 0;
448 }
449
bnpcap_process_tcp(t_ip_header const * ip,unsigned char const * data,unsigned int len)450 static int bnpcap_process_tcp(t_ip_header const * ip, unsigned char const *data, unsigned int len)
451 {
452 t_tcp_header_raw const *raw;
453 t_tcp_header h;
454
455 raw = (t_tcp_header_raw const *) data; /* avoid warning */
456 bnpcap_tcp2tcp(&h,raw);
457 if (h.doffset < 5) {
458 eventlog(eventlog_level_warn,__FUNCTION__,"tcp header too small (%u 32-bit words)",h.doffset);
459 return 1;
460 } else {
461 char fstr[32] = "";
462
463 if (h.flags & TCP_URG)
464 strcat(fstr,"U");
465 if (h.flags & TCP_ACK)
466 strcat(fstr,"A");
467 if (h.flags & TCP_PSH)
468 strcat(fstr,"P");
469 if (h.flags & TCP_RST)
470 strcat(fstr,"R");
471 if (h.flags & TCP_SYN)
472 strcat(fstr,"S");
473 if (h.flags & TCP_FIN)
474 strcat(fstr,"F");
475 eventlog(eventlog_level_debug,__FUNCTION__,"tcp: sport=%u dport=%u seqno=0x%08x ackno=0x%08x window=0x%08x len=%d (%s)",h.sport,h.dport,h.seqno,h.ackno,h.window,((signed)len-(h.doffset*4)),fstr);
476 if (((signed)len-(h.doffset*4))<=0) {
477 eventlog(eventlog_level_info,__FUNCTION__,"empty packet (%d)",((signed)len-(h.doffset*4)));
478 /* handle sync packets */
479 if (h.flags & TCP_SYN) {
480 t_bnpcap_addr s,d;
481
482 s.ip=ip->src; s.port=h.sport;
483 d.ip=ip->dst; d.port=h.dport;
484 if (h.flags & TCP_ACK) {
485 t_bnpcap_conn *c = bnpcap_conn_find(&s,&d);
486
487 if (c) {
488 if (c->tcpstate==tcp_state_syn)
489 c->tcpstate=tcp_state_ack;
490 }
491 } else {
492 if (!bnpcap_conn_find(&s,&d)) {
493 t_bnpcap_conn *c;
494
495 c = bnpcap_conn_new(&s,&d);
496 c->tcpstate = tcp_state_syn;
497 list_append_data(conns,c);
498 eventlog(eventlog_level_debug,__FUNCTION__,"created new connection with SYN");
499 } else {
500 eventlog(eventlog_level_debug,__FUNCTION__,"got SYN in connection");
501 }
502 }
503 }
504 } else if (((h.sport!=listen_port)&&(h.dport!=listen_port)) && ((h.sport!=6200)&&(h.dport!=6200))) {
505 eventlog(eventlog_level_info,__FUNCTION__,"other packet (%d)",((signed)len-(h.doffset*4)));
506 } else {
507 eventlog(eventlog_level_info,__FUNCTION__,"valid packet (%d)",((signed)len-(h.doffset*4)));
508 bnpcap_conn_packet(ip->src,h.sport,ip->dst,h.dport,data+(h.doffset*4),len-(h.doffset*4));
509 }
510 return 0;
511 }
512 }
513
514 /************************************ UDP ********************************/
515
bnpcap_udp2udp(t_ip_udp_header * d,t_ip_udp_header_raw const * s)516 static int bnpcap_udp2udp(t_ip_udp_header *d, t_ip_udp_header_raw const *s)
517 {
518 d->sport = ntohs(s->sport);
519 d->dport = ntohs(s->dport);
520 d->len = ntohs(s->len);
521 d->checksum = ntohs(s->checksum);
522 return 0;
523 }
524
bnpcap_process_udp(unsigned char const * data,unsigned int len)525 static int bnpcap_process_udp(unsigned char const *data, unsigned int len)
526 {
527 t_ip_udp_header_raw const *raw;
528 t_ip_udp_header h;
529 t_bnpcap_packet *bp;
530
531 raw = (t_ip_udp_header_raw const *) data; /* avoid warning */
532 bnpcap_udp2udp(&h,raw);
533
534 bp = (t_bnpcap_packet *) malloc(sizeof(t_bnpcap_packet)); /* avoid warning */
535 if (!bp) {
536 eventlog(eventlog_level_error,__FUNCTION__,"malloc failed: %s",pstrerror(errno));
537 return -1;
538 }
539 if (h.dport==listen_port || h.dport==6200) {
540 bp->dir = packet_dir_from_client;
541 } else {
542 bp->dir = packet_dir_from_server;
543 }
544 eventlog(eventlog_level_debug,__FUNCTION__,"sport=%u dport=%u len=%u(%d)",h.sport,h.dport,h.len,len);
545 bp->id = current_packet_id++;
546 memcpy(&bp->tv,&packettime,sizeof(struct timeval));
547 bp->p = packet_create(packet_class_udp);
548 if (!bp->p) {
549 eventlog(eventlog_level_error,__FUNCTION__,"packet_create failed");
550 return -1;
551 }
552 packet_set_size(bp->p,h.len-sizeof(t_ip_udp_header_raw));
553 memcpy(packet_get_raw_data(bp->p,0),data+sizeof(t_ip_udp_header_raw),h.len-sizeof(t_ip_udp_header_raw));
554 eventlog(eventlog_level_error,__FUNCTION__,"id=%u ",bp->id);
555 list_append_data(udppackets,bp);
556 return 0;
557 }
558
559 /************************************ IP *********************************/
560
bnpcap_ip2ip(t_ip_header * d,t_ip_header_raw const * s)561 static int bnpcap_ip2ip(t_ip_header * d, t_ip_header_raw const * s)
562 {
563 d->version = ((s->versionihl & 0xf0) >> 4);
564 d->ihl = s->versionihl & 0x0f;
565 d->tos = s->tos;
566 d->len = ntohs(s->len);
567 d->id = ntohs(s->id);
568 d->offset = ntohl(s->flagsoffset);
569 d->flags = ((d->offset & 0xE000)>>13);
570 d->offset = ((d->offset & 0x1FFF));
571 d->ttl = s->ttl;
572 d->protocol = s->protocol;
573 d->checksum = ntohs(s->checksum);
574 d->src = ntohl(s->src);
575 d->dst = ntohl(s->dst);
576 return 0;
577 }
578
579
bnpcap_process_ip(unsigned char const * data,unsigned int len)580 static int bnpcap_process_ip(unsigned char const *data, unsigned int len)
581 {
582 /* FIXME: handle IP fragmentation */
583 /* FIXME: use identification field to pass the datagram in the right order */
584 t_ip_header_raw const *raw;
585 t_ip_header h;
586
587 raw = (t_ip_header_raw const *) data; /* avoid warning */
588 bnpcap_ip2ip(&h,raw);
589 if (h.version != 4) {
590 eventlog(eventlog_level_warn,__FUNCTION__,"ip version %u not supported (ihl=%u, raw=0x%02x)",h.version,h.ihl,raw->versionihl);
591 return 1;
592 } else if (h.ihl < 5) {
593 /* an IP header must be at least 5 words */
594 eventlog(eventlog_level_warn,__FUNCTION__,"ip header to small (%u 32-bit words)",h.ihl);
595 return 1;
596 } else if (h.len > len) {
597 eventlog(eventlog_level_warn,__FUNCTION__,"ip len larger than packet (%d > %d)",h.len,len);
598 return 1;
599 } else {
600 char fstr[32] = "";
601
602 if (h.flags & IP_DF)
603 strcat(fstr,"D");
604 if (h.flags & IP_MF)
605 strcat(fstr,"M");
606 eventlog(eventlog_level_debug,__FUNCTION__,"ip: len=%u(%u) src=%08x dst=%08x protocol=%u offset=0x%08x id=0x%08x (%s)",h.len,len,h.src,h.dst,h.protocol,h.offset,h.id,fstr);
607 if (h.protocol==6) {
608 /* This is TCP */
609 return bnpcap_process_tcp(&h,data+(h.ihl*4),h.len-(h.ihl*4));
610 } else if (h.protocol==17) {
611 /* This is UDP */
612 return bnpcap_process_udp(data+(h.ihl*4),h.len-(h.ihl*4));
613 }
614 }
615 return 0;
616 }
617
618 /************************************* ETHERNET ******************************/
619
bnpcap_process_ether(unsigned char const * data,unsigned int len)620 static int bnpcap_process_ether(unsigned char const *data, unsigned int len)
621 { /* Well, first parse the ethernet header (I hope you use Ethernet_II :) ... */
622 t_ether_raw const *raw;
623
624 raw = (t_ether_raw const *) data; /* avoid warning */
625 if (ntohs(raw->type)==0x0800) {
626 /* This is IP */
627 return bnpcap_process_ip(data+sizeof(t_ether_raw),len-sizeof(t_ether_raw));
628 } else {
629 eventlog(eventlog_level_warn,__FUNCTION__,"unsupported protocol 0x%04x",ntohs(raw->type));
630 return 1;
631 }
632 }
633
634 /* If you want to use other hardware protocols like PPP add them here ... */
635
636 /**************************** PACKET/PCAP *********************************/
637
bnpcap_process_packet(u_char * private,const struct pcap_pkthdr * p,u_char const * data)638 static void bnpcap_process_packet(u_char * private, const struct pcap_pkthdr * p, u_char const * data)
639 {
640 unsigned int pl = p->len;
641
642 if(private) private = NULL; // hack to eliminate compiler warning
643
644 memcpy(&packettime,&p->ts,sizeof(struct timeval));
645 eventlog(eventlog_level_debug,__FUNCTION__,"packet: len=%d caplen=%d",p->len,p->caplen);
646 /* FIXME: check if it's ethernet */
647 bnpcap_process_ether(data,pl);
648 }
649
650 /**************************************************************************/
651
bnpcap_usage(void)652 static void bnpcap_usage(void) {
653 printf("BNPCAP - A tool to convert pcap battle.net dumps to a human-readable format.\n");
654 printf("Version " PVPGN_VERSION " --- Copyright (c) 2001 Marco Ziech (mmz@gmx.net)\n");
655 printf("This software makes use of libpcap.\n\n");
656 printf("Usage: bnpcap [-d] [-v] [-p PORT] <pcap-filename>\n");
657 printf(" -d Print out debugging information\n");
658 printf(" -v Be more verbose\n");
659 printf(" -p PORT Specify port to process (Default: 6112)\n\n");
660 }
661
662 /******************************* MAIN *************************************/
663
main(int argc,char ** argv)664 int main (int argc, char **argv) {
665 t_elem * currconn;
666 t_elem * currudp;
667 int c;
668
669 while ((c=getopt(argc,argv,"dvp:"))!=-1) {
670 switch (c) {
671 case 'p':
672 str_to_uint(optarg, &listen_port);
673 break;
674 case 'd':
675 bnpcap_dodebug = 1;
676 break;
677 case 'v':
678 bnpcap_beverbose = 1;
679 break;
680 case '?':
681 printf("unrecognized option '%c'\n",optopt);
682 break;
683 default:
684 printf("getopt returned \'%c\'\n",c);
685 }
686 }
687
688 if (optind < argc) {
689 filename = argv[optind];
690 } else {
691 bnpcap_usage();
692 return 1;
693 }
694
695 pc = pcap_open_offline(filename,ebuf);
696 if (!pc) {
697 fprintf(stderr,"pcap_open_offline: %s\n",ebuf);
698 return -1;
699 }
700
701 eventlog_set(stderr);
702 eventlog_clear_level();
703 if (bnpcap_dodebug)
704 eventlog_add_level("debug");
705 if (bnpcap_beverbose||bnpcap_dodebug)
706 eventlog_add_level("info");
707 eventlog_add_level("warn");
708 eventlog_add_level("error");
709 eventlog_add_level("fatal");
710
711 conns = list_create();
712 udppackets = list_create();
713 pcap_dispatch(pc,0,bnpcap_process_packet,NULL);
714
715 printf("### This packet dump was created by bnpcap.\n");
716 LIST_TRAVERSE(conns,currconn) {
717 t_bnpcap_conn *c;
718 char cstr[64];
719 char sstr[64];
720 t_elem * currpacket;
721
722 c = elem_get_data(currconn);
723 snprintf(cstr,64,"%u.%u.%u.%u:%u",((c->client.ip & 0xFF000000)>>24),((c->client.ip & 0x00FF0000)>>16),((c->client.ip & 0x0000FF00)>>8),((c->client.ip & 0x000000FF)),c->client.port);
724 snprintf(sstr,64,"%u.%u.%u.%u:%u",((c->server.ip & 0xFF000000)>>24),((c->server.ip & 0x00FF0000)>>16),((c->server.ip & 0x0000FF00)>>8),((c->server.ip & 0x000000FF)),c->server.port);
725 printf("## %s connection: client=%s server=%s\n",(c->incomplete?"incomplete":"complete"),cstr,sstr);
726 LIST_TRAVERSE(c->packets,currpacket) {
727 t_bnpcap_packet * bp;
728
729 bp = elem_get_data(currpacket);
730 printf("# %u packet from %s: type=0x%04x(%s) length=%d class=%s\n",bp->id/*bp->tv.tv_sec*/,(bp->dir==packet_dir_from_client?"client":"server"),packet_get_type(bp->p),packet_get_type_str(bp->p,bp->dir),packet_get_size(bp->p),packet_get_class_str(bp->p));
731 hexdump(stdout,packet_get_raw_data(bp->p,0),packet_get_size(bp->p));
732 printf("\n");
733 }
734 }
735 printf("## udp packets\n");
736 LIST_TRAVERSE(udppackets,currudp) {
737 t_bnpcap_packet *bp;
738
739 bp = elem_get_data(currudp);
740 printf("# %u packet from %s: type=0x%04x(%s) length=%d class=%s\n",bp->id/*bp->tv.tv_sec*/,(bp->dir==packet_dir_from_client?"client":"server"),packet_get_type(bp->p),packet_get_type_str(bp->p,bp->dir),packet_get_size(bp->p),packet_get_class_str(bp->p));
741 hexdump(stdout,packet_get_raw_data(bp->p,0),packet_get_size(bp->p));
742 printf("\n");
743 }
744 pcap_close(pc);
745 return 0;
746 }
747