?? bnpcap.c
字號:
/* * Copyright (C) 2001 Marco Ziech (mmz@gmx.net) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include "common/setup_before.h"#include <stdio.h>#include <pcap.h>#include <errno.h>#include <netinet/in.h>#include <string.h>#include <stdlib.h>#include "compat/strerror.h"#include "compat/getopt.h"#include "common/init_protocol.h"#include "common/bnet_protocol.h"#include "common/udp_protocol.h"#include "common/packet.h"#include "common/eventlog.h"#include "common/hexdump.h"#include "common/list.h"#include "common/version.h"#include "common/util.h"#include "common/setup_after.h"/* FIXME: everywhere: add checks for NULL pointers */char *filename = NULL;pcap_t *pc;char ebuf[PCAP_ERRBUF_SIZE];int bnpcap_dodebug = 0;int bnpcap_beverbose = 0;unsigned int listen_port = 6112;/********************* CONNECTIONS ********************/typedef enum { tcp_state_none, tcp_state_syn, tcp_state_ack, tcp_state_ok} t_tcp_state;typedef struct { /* It's IPV4 */ unsigned int ip; unsigned short port;} t_bnpcap_addr;/* To track connections ... */typedef struct { t_bnpcap_addr client; t_bnpcap_addr server; t_packet_class class; t_tcp_state tcpstate; int incomplete; int clientoff; t_packet *clientpkt; int serveroff; t_packet *serverpkt; t_list * packets;} t_bnpcap_conn;typedef struct { t_packet_dir dir; struct timeval tv; unsigned int id; t_packet *p;} t_bnpcap_packet;t_list * conns;t_list * udppackets;struct timeval packettime;static unsigned int current_packet_id = 1;/*********************** HEADERS **********************//* FIXME: don't assume that's always true */typedef unsigned char u8;typedef unsigned short u16;typedef unsigned int u32;/************************** TCP ***********************/typedef struct { u16 sport; u16 dport; u32 seqno; u32 ackno; u16 stuff; /* Data offset, various flags */ u16 window; u16 checksum; u16 urgp; /* Urgent Pointer (if URG flag set) */ /* options */} t_tcp_header_raw;typedef struct { unsigned short sport; unsigned short dport; unsigned int seqno; unsigned int ackno; unsigned char doffset; unsigned short flags;#define TCP_URG 0x20 /* Urgent pointer field significant */#define TCP_ACK 0x10 /* Acknowlegdement field significant */#define TCP_PSH 0x08 /* Push function */#define TCP_RST 0x04 /* Reset connection */#define TCP_SYN 0x02 /* Synchronize sequence numbers */#define TCP_FIN 0x01 /* No more data from sender (finish) */ unsigned short window; unsigned short checksum; unsigned short urgp; /* options */} t_tcp_header;/******************************** UDP ************************/typedef struct { u16 sport; u16 dport; u16 len; u16 checksum;} t_ip_udp_header_raw;typedef struct { unsigned short sport; unsigned short dport; unsigned short len; unsigned short checksum;} t_ip_udp_header;/******************************** IP *************************/typedef struct { u8 versionihl; u8 tos; u16 len; u16 id; u16 flagsoffset; u8 ttl; u8 protocol; u16 checksum; u32 src; u32 dst; /* options */} t_ip_header_raw;typedef struct { unsigned char version; unsigned char ihl; unsigned char tos; unsigned short len; unsigned short id; unsigned char flags;#define IP_DF 0x02 /* 1 == Don't fragment */#define IP_MF 0x01 /* 1 == More fragments */ unsigned short offset; unsigned char ttl; unsigned char protocol; unsigned short checksum; unsigned int src; unsigned int dst; /* options */} t_ip_header;/******************************* ETHERNET *****************************/typedef struct { u8 dst[6]; /* Ethernet hardware address */ u8 src[6]; /* Ethernet hardware address */ u16 type; /* Ethernet_II: protocol type */ /* FIXME: Ethernet [802.2|802.3|SNAP]: maybe something else (eg. length) */} t_ether_raw;/************************************************************************//************************* CONNECTION FUNCTIONS *************************/static t_bnpcap_conn * bnpcap_conn_new(t_bnpcap_addr const *s, t_bnpcap_addr const *d){ t_bnpcap_conn * c; c = (t_bnpcap_conn *) malloc(sizeof(t_bnpcap_conn)); /* avoid warning */ if (!c) { eventlog(eventlog_level_error,__FUNCTION__,"malloc failed: %s",pstrerror(errno)); return NULL; } if (d->port==listen_port || d->port==6200) { /* FIXME: That's dirty: We assume the server is on port 6112 */ memcpy(&c->client,s,sizeof(t_bnpcap_addr)); memcpy(&c->server,d,sizeof(t_bnpcap_addr)); } else { memcpy(&c->client,d,sizeof(t_bnpcap_addr)); memcpy(&c->server,s,sizeof(t_bnpcap_addr)); } c->class = packet_class_init; c->packets = list_create(); c->incomplete = 0; c->tcpstate = tcp_state_none; c->clientoff = 0; c->clientpkt = NULL; c->serveroff = 0; c->serverpkt = NULL; return c;}static void bnpcap_conn_set_class(t_bnpcap_conn *c, t_packet_class class){ c->class = class;}static t_packet_class bnpcap_conn_get_class(t_bnpcap_conn *c){ return c->class;}static t_bnpcap_conn * bnpcap_conn_find(t_bnpcap_addr const *s, t_bnpcap_addr const *d){ t_elem * curr; LIST_TRAVERSE(conns,curr) { t_bnpcap_conn *c; c = elem_get_data(curr); if (((c->client.ip==s->ip)&&(c->client.port==s->port))&& ((c->server.ip==d->ip)&&(c->server.port==d->port))) { return c; } else if (((c->client.ip==d->ip)&&(c->client.port==d->port))&& ((c->server.ip==s->ip)&&(c->server.port==s->port))) { return c; } } return NULL;}static t_packet_dir bnpcap_conn_get_dir(t_bnpcap_conn const * c, t_bnpcap_addr const *s, t_bnpcap_addr const *d){ if (((c->client.ip==s->ip)&&(c->client.port==s->port))&& ((c->server.ip==d->ip)&&(c->server.port==d->port))) return packet_dir_from_client; else return packet_dir_from_server;}static int bnpcap_conn_add_packet(t_bnpcap_conn *c, t_bnpcap_packet *bp) { eventlog(eventlog_level_debug,__FUNCTION__,"id=%u ",bp->id); list_append_data(c->packets,bp); packet_add_ref(bp->p); return 0;}static int bnpcap_conn_packet(unsigned int sip, unsigned short sport, unsigned int dip, unsigned short dport, unsigned char const * data, unsigned int len){ t_bnpcap_addr s; t_bnpcap_addr d; t_bnpcap_conn *c; t_bnpcap_packet *bp; s.ip = sip; s.port = sport; d.ip = dip; d.port = dport; if ((c = bnpcap_conn_find(&s,&d))) { eventlog(eventlog_level_debug,__FUNCTION__,"adding packet to existing connection"); if (c->tcpstate==tcp_state_ack) { c->tcpstate = tcp_state_ok; } else if (c->tcpstate==tcp_state_syn) { c->incomplete = 1; /* ACK missing */ c->tcpstate = tcp_state_ok; } } else { eventlog(eventlog_level_debug,__FUNCTION__,"adding packet to incomplete connection"); c = bnpcap_conn_new(&s,&d); bnpcap_conn_set_class(c,packet_class_raw); /* we don't know the init sequence */ c->incomplete = 1; c->tcpstate = tcp_state_ok; list_append_data(conns,c); } if (c->tcpstate!=tcp_state_ok) { eventlog(eventlog_level_warn,__FUNCTION__,"connection got packet in wrong state!"); } if (bnpcap_conn_get_class(c) == packet_class_init) { if (len>1) { eventlog(eventlog_level_warn,__FUNCTION__,"init packet larger than 1 byte"); } switch (data[0]) { case CLIENT_INITCONN_CLASS_BNET: bnpcap_conn_set_class(c,packet_class_bnet); break; case CLIENT_INITCONN_CLASS_FILE: bnpcap_conn_set_class(c,packet_class_file); break; case 0xf7: // W3 matchmaking hack eventlog(eventlog_level_info,__FUNCTION__,"matchmaking packet"); bnpcap_conn_set_class(c,packet_class_bnet); break; default: bnpcap_conn_set_class(c,packet_class_raw); } } else { t_packet *p; unsigned int off; unsigned char const *datap = data; int always_complete = 0; if (bnpcap_conn_get_class(c) == packet_class_raw) always_complete = 1; /* There is no size field */ if (bnpcap_conn_get_class(c) == packet_class_file) always_complete = 1; /* Size field isn't always there */ if (always_complete) { /* packet is always complete */ eventlog(eventlog_level_debug,__FUNCTION__,"packet is always complete (class=%d)",bnpcap_conn_get_class(c)); bp = (t_bnpcap_packet *) malloc(sizeof(t_bnpcap_packet)); /* avoid warning */ if (!bp) { eventlog(eventlog_level_error,__FUNCTION__,"malloc failed: %s",pstrerror(errno)); return -1; } bp->dir = bnpcap_conn_get_dir(c,&s,&d); bp->p = packet_create(bnpcap_conn_get_class(c)); bp->id = current_packet_id++; if (!bp->p) { eventlog(eventlog_level_error,__FUNCTION__,"packet_create failed"); return -1; } memcpy(&bp->tv,&packettime,sizeof(struct timeval)); packet_set_size(bp->p,len); memcpy(packet_get_raw_data(bp->p,0),data,len); bnpcap_conn_add_packet(c,bp); if ((packet_get_class(bp->p)==packet_class_file)&&(packet_get_type(bp->p)==SERVER_FILE_REPLY)) { eventlog(eventlog_level_debug,__FUNCTION__,"file transfer initiated (setting to raw)"); bnpcap_conn_set_class(c,packet_class_raw); } } else { /* read out saved state */ if (bnpcap_conn_get_dir(c,&s,&d)==packet_dir_from_client) { p = c->clientpkt; off = c->clientoff; } else { p = c->serverpkt; off = c->serveroff; } while ((datap-data)<(signed)len) { if (!p) { eventlog(eventlog_level_debug,__FUNCTION__,"creating new packet"); p = packet_create(bnpcap_conn_get_class(c)); if (!p) { eventlog(eventlog_level_error,__FUNCTION__,"packet_create failed"); return -1; } packet_set_size(p,packet_get_header_size(p)); /* set it to the minimum for now */ off = 0; } if (off < packet_get_header_size(p)) { unsigned int l = (packet_get_header_size(p)-off); /* (len-(datap-data)) : remaining bytes in buffer */ if ((len-(datap-data)) < l)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -