- Add basic Ethernet ,IP, TCP and UDP dissector (IPv4 suite only)

- Add test script
- Add SIGINT (CTRL+C) handler to print statistics before quitting
This commit is contained in:
Babak Farrokhi 2014-08-01 21:34:21 +04:30
parent 97b57d0055
commit d18f1a8533
3 changed files with 255 additions and 4 deletions

View File

@ -5,5 +5,8 @@ FLAGS=-m32 -march=corei7 -mfpmath=sse -O3 #-g
sipcap: sipcap.c Makefile
$(CC) $(FLAGS) $(INC) $(LIB) sipcap.c -o sipcap
test: sipcap testrun.sh
/bin/sh testrun.sh
clean:
\/bin/rm -f sipcap

View File

@ -1,17 +1,58 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <getopt.h>
#include <signal.h>
#include <pcap.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#define SIPCAP_VERSION 1.2
#define ETHER_TYPE_IP (0x0800)
#define ETHER_TYPE_8021Q (0x8100)
/* tcpdump header (ether.h) defines ETHER_HDRLEN) */
#ifndef ETHER_HDRLEN
#define ETHER_HDRLEN 14
#endif
#define UDP_HDRLEN 8
#define MAX_PAYLOAD_LEN 5000
// Global Structs
/*
* Structure of an internet header, naked of options.
*
* Stolen from tcpdump source (thanks tcpdump people)
*
* We declare ip_len and ip_off to be short, rather than u_short
* pragmatically since otherwise unsigned comparisons can result
* against negative integers quite easily, and fail in subtle ways.
*/
struct my_ip {
u_int8_t ip_vhl; /* header length, version */
#define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4)
#define IP_HL(ip) ((ip)->ip_vhl & 0x0f)
u_int8_t ip_tos; /* type of service */
u_int16_t ip_len; /* total length */
u_int16_t ip_id; /* identification */
u_int16_t ip_off; /* fragment offset field */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_int16_t ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
// Global Vars
int pkt_count = 0;
static int pkt_count = 0;
int live_pcap = 0;
int offline_pcap = 0;
int has_expression = 0;
@ -37,6 +78,7 @@ void error(char *msg) {
exit(1);
}
void parse_options(int argc, char *argv[]) {
// TODO: Add "-c" option that stops after capturing n packets
@ -78,10 +120,205 @@ void parse_options(int argc, char *argv[]) {
if (!live_pcap && !offline_pcap) help(1);
}
void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {
u_char* handle_UDP
(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
packet)
{
const struct udphdr* udp;
// we do actual packet processing here
const u_char *payload_data;
u_short payload_len;
char payload_str[MAX_PAYLOAD_LEN];
udp = (struct udphdr*) packet;
fprintf(stdout, "\tsport: %hu dport: %hu\n", ntohs(udp->uh_sport), ntohs(udp-> uh_dport));
payload_len = ntohs(udp->uh_ulen) - UDP_HDRLEN;
if (payload_len <= 0) return NULL;
payload_data = packet + UDP_HDRLEN;
(void)strncpy(payload_str, (const char*)payload_data, payload_len);
/*
Now I have UDP payload as an string here and need to parse it
*/
// printf("\n\n%s\n\n", payload_str);
return NULL;
}
u_char* handle_TCP
(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
packet, u_int tcplen)
{
const struct tcphdr* tcp;
const u_char *payload_data;
u_short payload_len;
u_int hlen;
char payload_str[MAX_PAYLOAD_LEN];
tcp = (struct tcphdr*) packet;
fprintf(stdout, "\tsport: %hu dport: %hu\n", ntohs(tcp->th_sport), ntohs(tcp-> th_dport));
hlen = (tcp->th_off * 4);
payload_len = tcplen - hlen;
if (payload_len <= 0) return NULL;
payload_data = packet + hlen;
(void)strncpy(payload_str, (const char*)payload_data, payload_len);
/*
Damn! I have TCP payload here too! Now need to write a parser.
*/
// printf("\n\n%s\n\n", payload_str);
return NULL;
}
u_char* handle_IP
(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
packet)
{
const struct my_ip* ip;
u_int length = pkthdr->len;
u_int hlen,off,version;
int i;
int len;
/* jump pass the ethernet header */
ip = (struct my_ip*)(packet + sizeof(struct ether_header));
length -= sizeof(struct ether_header);
/* check to see we have a packet of valid length */
if (length < sizeof(struct my_ip))
{
fprintf(stderr, "!");
return NULL;
}
len = ntohs(ip->ip_len);
hlen = IP_HL(ip); /* header length */
version = IP_V(ip);/* ip version */
/* check version */
if(version != 4)
{
fprintf(stdout,"Unknown version %d\n",version);
return NULL;
}
/* check header length */
if(hlen < 5 )
{
fprintf(stdout,"bad-hlen %d \n",hlen);
}
/* see if we have as much packet as we should */
if(length < len)
printf("\ntruncated IP - %d bytes missing\n",len - length);
/* Check to see if we have the first fragment */
off = ntohs(ip->ip_off);
if((off & 0x1fff) == 0 )/* aka no 1's in first 13 bits */
{/* print SOURCE DESTINATION hlen version len offset */
switch (ip->ip_p) {
case 1:
fprintf(stdout, "ICMP");
break;
case 6:
fprintf(stdout, "TCP");
break;
case 17:
fprintf(stdout, "UDP");
break;
case 41:
fprintf(stdout, "IPv6");
break;
case 47:
fprintf(stdout, "GRE");
break;
case 50:
fprintf(stdout, "ESP");
break;
default:
fprintf(stdout, "UNKNOWN (%d)", ip->ip_p);
break;
}
fprintf(stdout,":\t%s\t%s",
inet_ntoa(ip->ip_src),
inet_ntoa(ip->ip_dst));
fprintf(stdout,"\tlen= %3d hlen = %3d", len, hlen);
switch (ip->ip_p) {
case 6:
handle_TCP(args, pkthdr, packet + sizeof(struct ether_header) + (hlen * 4), len - (hlen * 4));
break;
case 17:
handle_UDP(args, pkthdr, packet + sizeof(struct ether_header) + (hlen * 4));
break;
default:
fprintf(stdout, "\n");
break;
}
}
return NULL;
}
u_int16_t handle_ethernet
(u_char *args,const struct pcap_pkthdr* pkthdr,const u_char*
packet)
{
u_int caplen = pkthdr->caplen;
u_int length = pkthdr->len;
struct ether_header *eptr; /* net/ethernet.h */
u_short ether_type;
if (caplen < ETHER_HDRLEN)
{
// Bad Packet Captured - Try capturing full packet (or increase snaplen)
fprintf(stderr,"!");
return -1;
}
/* lets start with the ether header... */
eptr = (struct ether_header *) packet;
ether_type = ntohs(eptr->ether_type);
return ether_type;
}
void process_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
pkt_count++;
u_int16_t type = handle_ethernet(args, header, packet);
if (type != ETHERTYPE_IP) return;
handle_IP(args, header, packet);
}
void print_stat()
{
printf("finished processing %d packets\n", pkt_count);
}
void intHandler(int dummy) {
printf("\n");
print_stat();
exit(0);
}
int main(int argc, char *argv[])
@ -92,6 +329,8 @@ int main(int argc, char *argv[])
struct bpf_program fp;
bpf_u_int32 devnet, devmask;
signal(SIGINT, intHandler);
parse_options(argc, argv);
if (live_pcap) {
@ -115,7 +354,10 @@ int main(int argc, char *argv[])
if (pcap == NULL) error(errbuf);
pcap_loop(pcap, -1, &process_packet, NULL);
printf("finished processing %d packets\n", pkt_count);
pcap_close(pcap);
print_stat();
exit(0);
}

6
sipcap/testrun.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/sh
for i in `find ~/pcapfarm/*.pcap`; do
echo "Processing ${i}"
./sipcap -f ${i} | grep UNK
done