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