How can I create a .csv file? In this .csv I want to write information of the packets.
This is my code: https://www.tcpdump.org/sniffex.c
I want to write into my file .csv some prints, for example the ip, tcp, etc.
This is my previous question: How can i create a file .csv?
#define APP_NAME "sniffex"
#define APP_DESC "Sniffer example using libpcap"
#define APP_COPYRIGHT "Copyright (c) 2005 The Tcpdump Group"
#define APP_DISCLAIMER "THERE IS ABSOLUTELY NO WARRANTY FOR THIS PROGRAM."
#include <pcap.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* default snap length (maximum bytes per packet to capture) */
#define SNAP_LEN 1518
/* ethernet headers are always exactly 14 bytes [1] */
#define SIZE_ETHERNET 14
/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN 6
FILE *f = fopen("test", "w");
/* Ethernet header */
struct sniff_ethernet {
u_char ether_dhost[ETHER_ADDR_LEN]; /* destination host address */
u_char ether_shost[ETHER_ADDR_LEN]; /* source host address */
u_short ether_type; /* IP? ARP? RARP? etc */
};
/* IP header */
struct sniff_ip {
u_char ip_vhl; /* version << 4 | header length >> 2 */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)
/* TCP header */
typedef u_int tcp_seq;
struct sniff_tcp {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
u_char th_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
u_char th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
u_short th_win; /* window */
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
};
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
void
print_payload(const u_char *payload, int len);
void
print_hex_ascii_line(const u_char *payload, int len, int offset);
void
print_app_banner(void);
void
print_app_usage(void);
/*
* app name/banner
*/
void
print_app_banner(void)
{
printf("%s - %s\n", APP_NAME, APP_DESC);
printf("%s\n", APP_COPYRIGHT);
printf("%s\n", APP_DISCLAIMER);
printf("\n");
return;
}
/*
* print help text
*/
void
print_app_usage(void)
{
printf("Usage: %s [interface]\n", APP_NAME);
printf("\n");
printf("Options:\n");
printf(" interface Listen on <interface> for packets.\n");
printf("\n");
return;
}
/*
* print data in rows of 16 bytes: offset hex ascii
*
* 00000 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1..
*/
void
print_hex_ascii_line(const u_char *payload, int len, int offset)
{
int i;
int gap;
const u_char *ch;
/* offset */
printf("%05d ", offset);
/* hex */
ch = payload;
for(i = 0; i < len; i++) {
printf("%02x ", *ch);
ch++;
/* print extra space after 8th byte for visual aid */
if (i == 7)
printf(" ");
}
/* print space to handle line less than 8 bytes */
if (len < 8)
printf(" ");
/* fill hex gap with spaces if not full line */
if (len < 16) {
gap = 16 - len;
for (i = 0; i < gap; i++) {
printf(" ");
}
}
printf(" ");
/* ascii (if printable) */
ch = payload;
for(i = 0; i < len; i++) {
if (isprint(*ch))
printf("%c", *ch);
else
printf(".");
ch++;
}
printf("\n");
return;
}
/*
* print packet payload data (avoid printing binary data)
*/
void
print_payload(const u_char *payload, int len)
{
int len_rem = len;
int line_width = 16; /* number of bytes per line */
int line_len;
int offset = 0; /* zero-based offset counter */
const u_char *ch = payload;
if (len <= 0)
return;
/* data fits on one line */
if (len <= line_width) {
print_hex_ascii_line(ch, len, offset);
return;
}
/* data spans multiple lines */
for ( ;; ) {
/* compute current line length */
line_len = line_width % len_rem;
/* print line */
print_hex_ascii_line(ch, line_len, offset);
/* compute total remaining */
len_rem = len_rem - line_len;
/* shift pointer to remaining bytes to print */
ch = ch + line_len;
/* add offset */
offset = offset + line_width;
/* check if we have line width chars or less */
if (len_rem <= line_width) {
/* print last line and get out */
print_hex_ascii_line(ch, len_rem, offset);
break;
}
}
return;
}
/*
* dissect/print packet
*/
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
static int count = 1; /* packet counter */
/* declare pointers to packet headers */
const struct sniff_ethernet *ethernet; /* The ethernet header [1] */
const struct sniff_ip *ip; /* The IP header */
const struct sniff_tcp *tcp; /* The TCP header */
const char *payload; /* Packet payload */
int size_ip;
int size_tcp;
int size_payload;
printf("\nPacket number %d:\n", count);
count++;
/* define ethernet header */
ethernet = (struct sniff_ethernet*)(packet);
/* define/compute ip header offset */
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
size_ip = IP_HL(ip)*4;
if (size_ip < 20) {
printf(" * Invalid IP header length: %u bytes\n", size_ip);
return;
}
/* print source and destination IP addresses */
printf(" From: %s\n", inet_ntoa(ip->ip_src));
printf(" To: %s\n", inet_ntoa(ip->ip_dst));
/* determine protocol */
switch(ip->ip_p) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
break;
case IPPROTO_UDP:
printf(" Protocol: UDP\n");
return;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
return;
case IPPROTO_IP:
printf(" Protocol: IP\n");
return;
default:
printf(" Protocol: unknown\n");
return;
}
/*
* OK, this packet is TCP.
*/
/* define/compute tcp header offset */
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
size_tcp = TH_OFF(tcp)*4;
if (size_tcp < 20) {
printf(" * Invalid TCP header length: %u bytes\n", size_tcp);
return;
}
printf(" Src port: %d\n", ntohs(tcp->th_sport));
printf(" Dst port: %d\n", ntohs(tcp->th_dport));
/* define/compute tcp payload (segment) offset */
payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);
/* compute tcp payload (segment) size */
size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);
/*
* Print payload data; it might be binary, so don't just
* treat it as a string.
*/
if (size_payload > 0) {
printf(" Payload (%d bytes):\n", size_payload);
print_payload(payload, size_payload);
}
return;
}
int main(int argc, char **argv)
{
char *dev = NULL; /* capture device name */
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */
char filter_exp[] = "ip"; /* filter expression [3] */
struct bpf_program fp; /* compiled filter program (expression) */
bpf_u_int32 mask; /* subnet mask */
bpf_u_int32 net; /* ip */
int num_packets = 10; /* number of packets to capture */
print_app_banner();
/* check for capture device name on command-line */
if (argc == 2) {
dev = argv[1];
}
else if (argc > 2) {
fprintf(stderr, "error: unrecognized command-line options\n\n");
print_app_usage();
exit(EXIT_FAILURE);
}
else {
/* find a capture device if not specified on command-line */
dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n",
errbuf);
exit(EXIT_FAILURE);
}
}
/* get network number and mask associated with capture device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
dev, errbuf);
net = 0;
mask = 0;
}
/* print capture info */
printf("Device: %s\n", dev);
printf("Number of packets: %d\n", num_packets);
printf("Filter expression: %s\n", filter_exp);
/* open capture device */
handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
exit(EXIT_FAILURE);
}
/* make sure we're capturing on an Ethernet device [2] */
if (pcap_datalink(handle) != DLT_EN10MB) {
fprintf(stderr, "%s is not an Ethernet\n", dev);
exit(EXIT_FAILURE);
}
/* compile the filter expression */
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* apply the compiled filter */
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* now we can set our callback function */
pcap_loop(handle, num_packets, got_packet, NULL);
/* cleanup */
pcap_freecode(&fp);
pcap_close(handle);
printf("\nCapture complete.\n");
return 0;
}
I was following this steps but just get for one packet, I want to write rows for every packet
typedef struct CsvRow
{
char ipLocal[32];
char ipRemote[32];
...
struct csvRow* next;
} Csvrow;
CsvRow* first;
CsvRow* last;
// collecting
CsvRow* newLine = malloc(sizeof(CsvRow));
newLine->next = NULL;
if (last == NULL)
{
first = last = newLine;
}
else
{
last->next = newLine;
}
// then when you are gathering information just add that in last
strcpy(last->ipLocal, "someip");
..
// at the end of your main function do
FILE* fp = fopen("test.csv", "w");
if (fp == NULL)
{
fprintf(stderr, "file access denied");
abort();
}
for (CsvRow* p = first; p != NULL; p = p->next)
{
fprintf(fp, "%s,%s\n", p->ipLocal, p->ipRemote);
}
fclose(fp);
// free memory
CsvRow* q = first;
while (q != NULL)
{
CsvRow* next = q->next;
free(q);
q = next;
}
the got_packet is a callback so every time that function is called you should create a new CsvRow struct and add it to your list, inside of got_packet fill the struct. then at program end (before return 0), open the file and write your list starting with first
e.g.
typedef struct {
char from[32];
char to[32];
.. and whatever else you want to put in
} CsvRow;
CsvRow* first = NULL;
CsvRow* last = NULL;
void got_packet( .. )
{
CsvRow* newLine = malloc(sizeof(CsvRow));
newLine->next = NULL;
if (last == NULL)
{
first = last = newLine;
}
else
{
last->next = newLine;
last = newLine; // new last
}
strcpy(last->from, inet_ntoa(ip->ip_src));
strcpy(last->to, inet_ntoa(ip->ip_dst));
... and fill in whatever else you want to store
}
then at the end of main()
FILE *fp = fopen("yourfile","w");
for (CsvRow* p = first; p != NULL; p=p->next)
{
fprintf(fp,"%s,%s", p->from, p->to );
}
fclose(fp);
Related
How i can create a file .csv?, i want to create only a file, because i want to declare outside the main() my File. as well i have a functions, and de main() function.
my is this: https://www.tcpdump.org/sniffex.c i want to write in my file .csv some prints, for example the ip, tcp, etc.
#define APP_NAME "sniffex"
#define APP_DESC "Sniffer example using libpcap"
#define APP_COPYRIGHT "Copyright (c) 2005 The Tcpdump Group"
#define APP_DISCLAIMER "THERE IS ABSOLUTELY NO WARRANTY FOR THIS PROGRAM."
#include <pcap.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* default snap length (maximum bytes per packet to capture) */
#define SNAP_LEN 1518
/* ethernet headers are always exactly 14 bytes [1] */
#define SIZE_ETHERNET 14
/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN 6
FILE *f = fopen("test", "w");
/* Ethernet header */
struct sniff_ethernet {
u_char ether_dhost[ETHER_ADDR_LEN]; /* destination host address */
u_char ether_shost[ETHER_ADDR_LEN]; /* source host address */
u_short ether_type; /* IP? ARP? RARP? etc */
};
/* IP header */
struct sniff_ip {
u_char ip_vhl; /* version << 4 | header length >> 2 */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)
/* TCP header */
typedef u_int tcp_seq;
struct sniff_tcp {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
u_char th_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
u_char th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
u_short th_win; /* window */
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
};
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
void
print_payload(const u_char *payload, int len);
void
print_hex_ascii_line(const u_char *payload, int len, int offset);
void
print_app_banner(void);
void
print_app_usage(void);
/*
* app name/banner
*/
void
print_app_banner(void)
{
printf("%s - %s\n", APP_NAME, APP_DESC);
printf("%s\n", APP_COPYRIGHT);
printf("%s\n", APP_DISCLAIMER);
printf("\n");
return;
}
/*
* print help text
*/
void
print_app_usage(void)
{
printf("Usage: %s [interface]\n", APP_NAME);
printf("\n");
printf("Options:\n");
printf(" interface Listen on <interface> for packets.\n");
printf("\n");
return;
}
/*
* print data in rows of 16 bytes: offset hex ascii
*
* 00000 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1..
*/
void
print_hex_ascii_line(const u_char *payload, int len, int offset)
{
int i;
int gap;
const u_char *ch;
/* offset */
printf("%05d ", offset);
/* hex */
ch = payload;
for(i = 0; i < len; i++) {
printf("%02x ", *ch);
ch++;
/* print extra space after 8th byte for visual aid */
if (i == 7)
printf(" ");
}
/* print space to handle line less than 8 bytes */
if (len < 8)
printf(" ");
/* fill hex gap with spaces if not full line */
if (len < 16) {
gap = 16 - len;
for (i = 0; i < gap; i++) {
printf(" ");
}
}
printf(" ");
/* ascii (if printable) */
ch = payload;
for(i = 0; i < len; i++) {
if (isprint(*ch))
printf("%c", *ch);
else
printf(".");
ch++;
}
printf("\n");
return;
}
/*
* print packet payload data (avoid printing binary data)
*/
void
print_payload(const u_char *payload, int len)
{
int len_rem = len;
int line_width = 16; /* number of bytes per line */
int line_len;
int offset = 0; /* zero-based offset counter */
const u_char *ch = payload;
if (len <= 0)
return;
/* data fits on one line */
if (len <= line_width) {
print_hex_ascii_line(ch, len, offset);
return;
}
/* data spans multiple lines */
for ( ;; ) {
/* compute current line length */
line_len = line_width % len_rem;
/* print line */
print_hex_ascii_line(ch, line_len, offset);
/* compute total remaining */
len_rem = len_rem - line_len;
/* shift pointer to remaining bytes to print */
ch = ch + line_len;
/* add offset */
offset = offset + line_width;
/* check if we have line width chars or less */
if (len_rem <= line_width) {
/* print last line and get out */
print_hex_ascii_line(ch, len_rem, offset);
break;
}
}
return;
}
/*
* dissect/print packet
*/
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
static int count = 1; /* packet counter */
/* declare pointers to packet headers */
const struct sniff_ethernet *ethernet; /* The ethernet header [1] */
const struct sniff_ip *ip; /* The IP header */
const struct sniff_tcp *tcp; /* The TCP header */
const char *payload; /* Packet payload */
int size_ip;
int size_tcp;
int size_payload;
printf("\nPacket number %d:\n", count);
count++;
/* define ethernet header */
ethernet = (struct sniff_ethernet*)(packet);
/* define/compute ip header offset */
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
size_ip = IP_HL(ip)*4;
if (size_ip < 20) {
printf(" * Invalid IP header length: %u bytes\n", size_ip);
return;
}
/* print source and destination IP addresses */
printf(" From: %s\n", inet_ntoa(ip->ip_src));
printf(" To: %s\n", inet_ntoa(ip->ip_dst));
/* determine protocol */
switch(ip->ip_p) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
break;
case IPPROTO_UDP:
printf(" Protocol: UDP\n");
return;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
return;
case IPPROTO_IP:
printf(" Protocol: IP\n");
return;
default:
printf(" Protocol: unknown\n");
return;
}
/*
* OK, this packet is TCP.
*/
/* define/compute tcp header offset */
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
size_tcp = TH_OFF(tcp)*4;
if (size_tcp < 20) {
printf(" * Invalid TCP header length: %u bytes\n", size_tcp);
return;
}
printf(" Src port: %d\n", ntohs(tcp->th_sport));
printf(" Dst port: %d\n", ntohs(tcp->th_dport));
/* define/compute tcp payload (segment) offset */
payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);
/* compute tcp payload (segment) size */
size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);
/*
* Print payload data; it might be binary, so don't just
* treat it as a string.
*/
if (size_payload > 0) {
printf(" Payload (%d bytes):\n", size_payload);
print_payload(payload, size_payload);
}
return;
}
int main(int argc, char **argv)
{
char *dev = NULL; /* capture device name */
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */
char filter_exp[] = "ip"; /* filter expression [3] */
struct bpf_program fp; /* compiled filter program (expression) */
bpf_u_int32 mask; /* subnet mask */
bpf_u_int32 net; /* ip */
int num_packets = 10; /* number of packets to capture */
print_app_banner();
/* check for capture device name on command-line */
if (argc == 2) {
dev = argv[1];
}
else if (argc > 2) {
fprintf(stderr, "error: unrecognized command-line options\n\n");
print_app_usage();
exit(EXIT_FAILURE);
}
else {
/* find a capture device if not specified on command-line */
dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n",
errbuf);
exit(EXIT_FAILURE);
}
}
/* get network number and mask associated with capture device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
dev, errbuf);
net = 0;
mask = 0;
}
/* print capture info */
printf("Device: %s\n", dev);
printf("Number of packets: %d\n", num_packets);
printf("Filter expression: %s\n", filter_exp);
/* open capture device */
handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
exit(EXIT_FAILURE);
}
/* make sure we're capturing on an Ethernet device [2] */
if (pcap_datalink(handle) != DLT_EN10MB) {
fprintf(stderr, "%s is not an Ethernet\n", dev);
exit(EXIT_FAILURE);
}
/* compile the filter expression */
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* apply the compiled filter */
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* now we can set our callback function */
pcap_loop(handle, num_packets, got_packet, NULL);
/* cleanup */
pcap_freecode(&fp);
pcap_close(handle);
printf("\nCapture complete.\n");
return 0;
}
but i got this error:
error: initializer element is not constant
FILE *f = fopen("test", "w");
If you want to write the results in a file, move
FILE *f = fopen("test", "w");
into your main() function (also check return value since the function can fail), if you want the file format to be csv then you should add the extension .csv so that other people know it has that format e.g. "test.csv" instead of "test". pass the file pointer to all the functions where you need to write to the csv-file.
Now to serialize the contents that you have collected and since the format of a csv-file is row based you need to collect the information before you write it (easier that way). So decide on a structure that will contain all the information you want to put in a row in the csv-file and fill that structure, have a linked list of these structures that you create as you are gathering information, then once you are done collecting, go through the list and write one row to the csv-file per structure.
E.g.
typedef struct CsvRow
{
char ipLocal[32];
char ipRemote[32];
...
struct csvRow* next;
} Csvrow;
CsvRow* first;
CsvRow* last;
// collecting
CsvRow* newLine = malloc(sizeof(CsvRow));
newLine->next = NULL;
if (last == NULL)
{
first = last = newLine;
}
else
{
last->next = newLine;
last = newLine;
}
// then when you are gathering information just add that in last
strcpy(last->ipLocal, "someip");
..
// at the end of your main function do
FILE* fp = fopen("test.csv", "w");
if (fp == NULL)
{
fprintf(stderr, "file access denied");
abort();
}
for (CsvRow* p = first; p != NULL; p = p->next)
{
fprintf(fp, "%s,%s\n", p->ipLocal, p->ipRemote);
}
fclose(fp);
// free memory
CsvRow* q = first;
while (q != NULL)
{
CsvRow* next = q->next;
free(q);
q = next;
}
You need to split the line into opening the file, and declaring the variable, the declaration can stay where it is:
FILE *f;
The open must occur in your main() function:
main()
{
f = fopen("test.csv", "w");
...
Then you can use that in your code anywwhere:
fprintf(f,"some stuff");
And remember to close the file when your program finishes (this would be at the end of your main() function...
fclose(f);
I'm writing a program to get certain pieces of information from the headers in a pcap. I'm not sure if I did this right. It works with all of my professor's tests, however, there are hidden tests that I need to be aware of. It's the TCP flags I'm not sure about. It works in index 47, but don't know why, should be 46. (Ethernet Header(14) + IPv4 header(20) + 13th byte in TCP header (13) -1 (to account for arrays starting at 0) = 46). Is it a fluke that it works on spot 47?
Here's my code:
#include <pcap/pcap.h>
#include <stdlib.h>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
/*
* Most of this file is the background functionality to open a capture file or to
* open an inteface for a live capture. You can ignore all this unless you are
* interested in an example of how pcap works.
*
* To use the file, simply insert your code in the "Put your code here" section and
* create a Makefile for compilation.
*/
/* Maximum time that the OS will buffer packets before giving them to your program. */
#define MAX_BUFFER_TIME_MS (300)
/* Maximum time the program will wait for a packet during live capture.
* Measured in MAX_BUFFER_TIME_MS units. Program closes when it expires. */
#define MAX_IDLE_TIME 100 /* 100*MAX_BUFFER_TIME_MS idle time at most */
/* Function that creates the structures necessary to perform a packet capture and
* determines capture source depending on arguments. Function will terminate the
* program on error, so return value always valid. */
pcap_t* setup_capture(int argc, char *argv[], char *use_file);
/* Cleanup the state of the capture. */
void cleanup_capture(pcap_t *handle);
/* Check for abnormal conditions during capture.
* 1 returned if a packet is ready, 0 if a packet is not available.
* Terminates program if an unrecoverable error occurs. */
char valid_capture(int return_value, pcap_t *pcap_handle, char use_file);
int main(int argc, char *argv[]) {
pcap_t *pcap_handle = NULL; /* Handle for PCAP library */
struct pcap_pkthdr *packet_hdr = NULL; /* Packet header from PCAP */
const u_char *packet_data = NULL; /* Packet data from PCAP */
int ret = 0; /* Return value from library calls */
char use_file = 0; /* Flag to use file or live capture */
/* Setup the capture and get the valid handle. */
pcap_handle = setup_capture(argc, argv, &use_file);
/* Loop through all the packets in the trace file.
* ret will equal -2 when the trace file ends.
* ret will never equal -2 for a live capture. */
ret = pcap_next_ex(pcap_handle, &packet_hdr, &packet_data);
struct ether_header
{
u_int8_t ether_dhost[6]; /* destination eth addr */
u_int8_t ether_shost[6]; /* source ether addr */
u_int16_t ether_type; /* packet type ID field */
};
struct ether_header *eptr;
char src[INET_ADDRSTRLEN];
char dst[INET_ADDRSTRLEN];
char src6[INET6_ADDRSTRLEN];
char dst6[INET6_ADDRSTRLEN];
while( ret != -2 ) {
if( valid_capture(ret, pcap_handle, use_file) ){
eptr = (struct ether_header *) packet_data;
fprintf(stdout,"%s -> ",ether_ntoa((const struct ether_addr *)&eptr->ether_shost));
fprintf(stdout,"%s \n",ether_ntoa((const struct ether_addr *)&eptr->ether_dhost));
if(packet_data[12] == 0x08 && packet_data[13] == 0x00)
{
printf(" [IPv4] ");
fprintf(stdout,"%s -> ", inet_ntop(AF_INET,(const void *)packet_data+26,src,INET_ADDRSTRLEN));
fprintf(stdout,"%s\n", inet_ntop(AF_INET,(const void *)packet_data+30,dst,INET_ADDRSTRLEN));
if(packet_data[23] == 0x06)
{
printf(" [TCP] %d -> ",packet_data[34]*256+packet_data[35]);
printf("%d ",packet_data[36]*256+packet_data[37]);
// printf("%02X ",packet_data[47]); //print out value of flag;
if(packet_data[47] & (1!=0))
printf("FIN \n");
else if((packet_data[47] == 0x02 || packet_data[47] == 0x12) & (2!=0))
printf("SYN \n");
else{
printf("\n");
}
}
else if(packet_data[23] == 0x11)
{
printf(" [UDP] %d -> ",packet_data[34]*256+packet_data[35]);
printf("%d \n",packet_data[36]*256+packet_data[37]);
}
else{
printf(" [%d] \n",packet_data[23]);
}
}
else if(packet_data[12] == 0x86 && packet_data[13] == 0xdd)
{
printf(" [IPv6] ");
printf("%s -> ", inet_ntop(AF_INET6, (const void *)packet_data+22, src6, INET6_ADDRSTRLEN));
printf("%s \n", inet_ntop(AF_INET6, (const void *)packet_data+38, dst6, INET6_ADDRSTRLEN));
if(packet_data[20] == 0x06)
{
printf(" [TCP] %d -> ",packet_data[54]*256+packet_data[55]);
printf("%d ",packet_data[56]*256+packet_data[57]);
// printf("%02X ",packet_data[67]); //print out value of flag
if(packet_data[67] & (1!=0))
printf("FIN \n");
else if((packet_data[67] == 0x02 || packet_data[67] == 0x12) & (2!=0))
printf("SYN \n");
else{
printf("\n");
}
}
else if(packet_data[20] == 0x11)
{
printf(" [UDP] %d -> ",packet_data[54]*256+packet_data[55]);
printf("%d \n",packet_data[56]*256+packet_data[57]);
}
else{
printf(" [%d] \n",packet_data[20]);
}
} else {
fprintf(stdout," [%d] \n",ntohs(eptr->ether_type));
}
}
/* Get the next packet */
ret = pcap_next_ex(pcap_handle, &packet_hdr, &packet_data);
}
cleanup_capture(pcap_handle);
return 0;
}
pcap_t* setup_capture(int argc, char *argv[], char *use_file) {
char *trace_file = NULL; /* Trace file to process */
pcap_t *pcap_handle = NULL; /* Handle for PCAP library to return */
char pcap_buff[PCAP_ERRBUF_SIZE]; /* Error buffer used by pcap functions */
char *dev_name = NULL; /* Device name for live capture */
/* Check command line arguments */
if( argc > 2 ) {
fprintf(stderr, "Usage: %s [trace_file]\n", argv[0]);
exit(-1);
}
else if( argc > 1 ){
*use_file = 1;
trace_file = argv[1];
}
else {
*use_file = 0;
}
/* Open the trace file, if appropriate */
if( *use_file ){
pcap_handle = pcap_open_offline(trace_file, pcap_buff);
if( pcap_handle == NULL ){
fprintf(stderr, "Error opening trace file \"%s\": %s\n", trace_file, pcap_buff);
exit(-1);
}
}
/* Lookup and open the default device if trace file not used */
else{
dev_name = pcap_lookupdev(pcap_buff);
if( dev_name == NULL ){
fprintf(stderr, "Error finding default capture device: %s\n", pcap_buff);
exit(-1);
}
/* Use buffer length as indication of warning, per pcap_open_live(3). */
pcap_buff[0] = 0;
pcap_handle = pcap_open_live(dev_name, BUFSIZ, 1, MAX_BUFFER_TIME_MS, pcap_buff);
if( pcap_handle == NULL ){
fprintf(stderr, "Error opening capture device %s: %s\n", dev_name, pcap_buff);
exit(-1);
}
if( pcap_buff[0] != 0 ) {
printf("Warning: %s\n", pcap_buff);
}
printf("Capturing on interface '%s'\n", dev_name);
}
return pcap_handle;
}
void cleanup_capture(pcap_t *handle) {
/* Close the trace file or device */
pcap_close(handle);
}
char valid_capture(int return_value, pcap_t *pcap_handle, char use_file) {
static int idle_count = 0; /* Count of idle periods with no packets */
char ret = 0; /* Return value, invalid by default */
/* A general error occurred */
if( return_value == -1 ) {
pcap_perror(pcap_handle, "Error processing packet:");
cleanup_capture(pcap_handle);
exit(-1);
}
/* Timeout occured for a live packet capture */
else if( (return_value == 0) && (use_file == 0) ){
if( ++idle_count >= MAX_IDLE_TIME ){
printf("Timeout waiting for additional packets on interface\n");
cleanup_capture(pcap_handle);
exit(0);
}
}
/* Unexpected/unknown return value */
else if( return_value != 1 ) {
fprintf(stderr, "Unexpected return value (%i) from pcap_next_ex()\n", return_value);
cleanup_capture(pcap_handle);
exit(-1);
}
/* Normal operation, packet arrived */
else{
idle_count = 0;
ret = 1;
}
return ret;
}
Here's a few sample print outs: (the left is the professors results, the right is mine, I have extra printout to see what's in that spot in the array). Thanks
0:0:86:5:80:da -> 0:60:97:7:69:ea 0:0:86:5:80:da -> 0:60:97:7:69:ea
[IPv6] 3ffe:507:0:1:200:86ff:fe05:80da -> 3ffe:501:410:0:2c0:dfff:fe47:33e [IPv6] 3ffe:507:0:1:200:86ff:fe05:80da -> 3ffe:501:410:0:2c0:dfff:fe47:33e
[TCP] 1022 -> 22 SYN | [TCP] 1022 -> 22 02 SYN
0:60:97:7:69:ea -> 0:0:86:5:80:da 0:60:97:7:69:ea -> 0:0:86:5:80:da
[IPv6] 3ffe:501:410:0:2c0:dfff:fe47:33e -> 3ffe:507:0:1:200:86ff:fe05:80da [IPv6] 3ffe:501:410:0:2c0:dfff:fe47:33e -> 3ffe:507:0:1:200:86ff:fe05:80da
[TCP] 22 -> 1022 SYN | [TCP] 22 -> 1022 12 SYN
Here's how you can locate the TCP flags:
If we assume that we are talking about Ethernet, the Ethernet frame header will be 14 bytes: a 6 byte destination followed by a 6 byte source and then a 2 byte ether type (for 802.3/SNAP/Ethernet II, which is most likely)
If the Ethertype at offset 12/13 from the start of the frame contains 0x0800, you are looking at TCP/IP.
if(frame[12]==0x08 && frame[13]==0x00) { /* IP packet inside */ }
Assuming that you have an IP Ethertype, the next byte will contain two nibble sized fields: The IP version number (likely 0x40 for you) and then the IP header length (likely 0x05). Putting those nibbles together, you would have 0x45 sitting in that field. It is very important to check that field. You could mask off the upper nibble like so:
ihl = frame[14]&0x0f;
to grab the IP header length field. This number will tell you where to find the next protocol layer's header. Typically you will have a 5 here (20 byte header), but if there are IP options, this number will be larger. Let's take this number and calculate from here:
embedded_protocol_header = frame[ihl * 4];
Next, you should verify that you actually have a TCP packet. This can be verified by examining byte offset 9 in the IP header:
ip_header_start = frame[14];
embedded_protocol = ip_header_start[9];
if(embedded_protocol == 6) { tcp_header = embedded_protocol_header; }
Now that we know it is TCP, we can grab the TCP flags. These will be at offset 13 in the TCP header:
tcp_flags = tcp_header[13];
To examine the SYN/ACK bits, you can mask everything else off:
synack = tcp_flags & 0x3f;
You can now check to see if it's a SYN ACK:
if(synack == 0x12) { /* SYN and ACK were set */
You may wonder about the 0x3f mask above. The reason for it is that the two high order bits in the TCP flags are used for ECN if the system supports ECN. If it is supported, ECN negotiation occurs during the 3 way handshake in these bits and the two low order bits in the TOS byte of the IP header (differentiated services byte). Rather than dealing with all of the possible cases, the simplest thing is to turn those bits off completely and check to see if you still have SYN and ACK.
I'm trying to improve my C/network knowledge implementing a ARP spoofing tool with Pcap library.
I'm stuck with sniffing arp packets. I can detect the ARP type in the ethertype field of Ethernet frame. But when I "read" the ARP packet, all values are 0 (null) but hardware addr(MAC) & protocol address(ip) are very weird 8 byte number repeated (like 20e54ef12:20e54ef12:20e54ef12...). I just can't figure it out.
Here is what I've done so far :
packet_struct.h (the different structures used for eth, arp, ip...)
#ifndef DEF_PACKET_STRUCT
#define DEF_PACKET_STRUCT
#include <sys/types.h>
#define BUFF_SIZE 1518
#define ETH_SIZE 14
#define ARP_SIZE 28
/* in bytes */
#define ETH_ADDR_SIZE 6
#define IP_ADDR_SIZE 4
typedef struct pkt_eth {
unsigned char dest[ETH_ADDR_SIZE];
unsigned char src[ETH_ADDR_SIZE];
unsigned short type;
} pkt_eth;
#define ETHERTYPE_ARP 0x0806
#define ARP_REQUEST 1
#define ARP_REPLY 2
typedef struct pkt_arp {
unsigned short htype;/* hardware type => ethernet , etc */
unsigned short ptype; /*protocol type => ipv4 or ipv6 */
unsigned char hard_addr_len; /* usually 6 bytes for ethernet */
unsigned char proto_addr_len; /*usually 8 bytes for ipv4 */
unsigned short opcode; /* type of arp */
unsigned char hard_addr_send[ETH_ADDR_SIZE];
unsigned char proto_addr_send[IP_ADDR_SIZE];
unsigned char hard_addr_dest[ETH_ADDR_SIZE];
unsigned char proto_addr_dest[IP_ADDR_SIZE];
} pkt_arp;
#define ETHERTYPE_IP 0x0800
typedef struct pkt_ip {
unsigned char vhl;
unsigned char tos;
unsigned short len;
unsigned short id;
unsigned short off;
unsigned char ttl;
unsigned char proto;
unsigned short crc;
unsigned int addr_src;
unsigned int addr_dest;
} pkt_ip;
#endif
packet_print.c (utilities to print packet information )
#include "packet_struct.h"
#include <stdio.h>
#include <stdlib.h>
char * to_addr(unsigned char * addr, int length) {
int i = 0;
char string[length];
for(i=0; i< length; i++)
sprintf(string,"%02x:",addr[i]);
return string;
}
void print_pkt_eth(pkt_eth * eth) {
int i = 0;
fprintf(stdout,"Ethernet Layer \n");
fprintf(stdout,"\tSource:\t");
for(i=0;i<ETH_ADDR_SIZE;i++)
fprintf(stdout,"%02x:",eth->src[i]);
//fprintf(stdout,"%s",to_addr(eth->src,ETH_ADDR_SIZE));
fprintf(stdout,"\n\tDest:\t");
for(i=0;i<ETH_ADDR_SIZE;i++)
fprintf(stdout,"%02X:",eth->dest[i]);
if(ntohs(eth->type) == ETHERTYPE_IP)
fprintf(stdout,"\n\tType:\t IPv4");
else if(ntohs(eth->type) == ETHERTYPE_ARP)
fprintf(stdout,"\n\tType:\t ARP");
printf("\n");
}
void print_pkt_arp(pkt_arp * arp) {
int op = 0;
int i = 0;
printf("ARP Layer \n");
printf("\tHardware type:\t%02d\n",arp->htype);
printf("\tProtocol type:\t%02d\n",arp->ptype);
printf("\tHardware addresses length:\t%01d\n",arp->hard_addr_len);
printf("\tProtocol addresses length:\t%01d\n",arp->proto_addr_len);
op = ntohs(arp->opcode);
printf("\tOperation code:\t%01u\n",op);
printf("\tHardware sender:\t");
for(i=0;i<ETH_ADDR_SIZE;i++)
printf("%02x:",arp->hard_addr_send);
printf("\n\tSoftware sender:\t");
for(i=0;i<IP_ADDR_SIZE;i++)
printf("%02x:",arp->proto_addr_send);
printf("\n");
}
void print_pkt_ip(pkt_ip * ip) {
}
sniffer.c ( the tool itself )
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h> // for addresses translation
#include<errno.h>
// for ntohs etc
// can also be necessary to include netinet/in
#include <arpa/inet.h>
#include "packet_struct.h"
#include <pcap.h>
#define SNAP_LEN 1518
int packet_count = 0;
void handleARP(const struct pkt_eth * eth) {
const struct pkt_arp * arp = (const struct pkt_arp *) (eth + ETH_SIZE);
print_pkt_arp(arp);
if(ntohs(arp->htype) != 1) {
fprintf(stderr, "Error : ARP packet does not contain a Hardware type Ethernet -> %d\n",ntohs(arp->htype));
return;
}
// check protocol type
if(ntohs(arp->ptype) != 0x800) {
fprintf(stderr,"Error : ARP packet does not contain a IPv4 type\n");
return;
}
}
void sniff_callback(u_char * user, const struct pcap_pkthdr * h,const u_char * bytes) {
int i = 0;
for(i=0; i < 25; i++) { printf("-"); }; printf("\n");
printf("Received packet number %d ==> %d\n",packet_count++,h->len);
const struct pkt_eth * eth;
unsigned short eth_type;
unsigned int captureLength = h->caplen;
unsigned int packetLength = h->len;
if(captureLength != packetLength) {
fprintf(stderr,"Error : received packet with %d available instead of %d \n",captureLength,packetLength);
return;
}
if(captureLength < ETH_SIZE) {
fprintf(stderr,"Error : received too small packet , %d bytes",captureLength);
return;
}
eth = (struct pkt_eth*)(bytes);
// print the packet
print_pkt_eth(eth);
eth_type = ntohs(eth->type);
if(eth_type == ETHERTYPE_ARP) {
handleARP(eth);
}
for(i=0; i < 25; i++) { printf("-"); }; printf("\n");
return;
}
/* returns 0 if everything went well */
int set_options(pcap_t * handle) {
int ret = 0;
ret = pcap_set_promisc(handle,1);
if(ret != 0) {
fprintf(stderr,"Error setting promiscuous mode\n");
return ret;
}
ret = pcap_set_snaplen(handle,SNAP_LEN);
if(ret != 0) {
fprintf(stderr,"Error setting snapshot length\n");
return ret;
}
ret = pcap_set_timeout(handle,1000);
if(ret != 0) {
fprintf(stderr,"Error setting timeout\n");
return ret;
}
return ret;
}
int activate(pcap_t * handle) {
int ret = pcap_activate(handle);
switch(ret) {
case 0:
fprintf(stdout,"Activation complete\n");
break;
case PCAP_WARNING_PROMISC_NOTSUP:
fprintf(stderr,"Promiscuous mode not supported\n");
return ret;
case PCAP_ERROR_PERM_DENIED:
fprintf(stderr,"Not have the permission required\n");
return ret;
case PCAP_ERROR_PROMISC_PERM_DENIED:
fprintf(stderr,"Not have the permission required for promiscuous\n");
return ret;
default:
fprintf(stderr,"Error occured during activation, see code\n");
return ret;
}
return ret;
}
/* Will activate device , filter & call the sniffing loop */
int sniffing_method(char * interface, char * filter,int packet_count) {
char err[PCAP_ERRBUF_SIZE]; //error buffer
pcap_t * handle; // handler of the interface by pcap
struct bpf_program bpf;
bpf_u_int32 mask; // network mask
bpf_u_int32 ip; // network ip
struct in_addr addr; // network number
int ret;
/* get mask & ip */
if(pcap_lookupnet(interface, &ip, &mask, err) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n",interface,err);
exit(EXIT_FAILURE);
}
handle = pcap_create(interface,err);
if (handle == NULL) {
fprintf(stderr,"Error pcap_create() : %s \n",err);
exit(EXIT_FAILURE);
}
if(set_options(handle) != 0) {
fprintf(stderr,"Exiting\n");
exit(EXIT_FAILURE);
}
if (activate(handle) != 0) {
fprintf(stderr,"Exiting\n");
exit(EXIT_FAILURE);
}
/* FILTER PART */
if(filter != NULL) {
if(pcap_compile(handle,&bpf,filter,0,ip) == -1){
fprintf(stderr,"Couldn't compile filter expr %s : %s\n",filter,pcap_geterr(handle));
exit(EXIT_FAILURE);
}
if(pcap_setfilter(handle, &bpf) == -1) {
fprintf(stderr,"Couldn't install filter %s : %s\n",filter,pcap_geterr(handle));
exit(EXIT_FAILURE);
}
}
/* SNIFF starts */
printf("Sniffing starting on %s ...\n",interface);
pcap_loop(handle,packet_count,sniff_callback,NULL);
pcap_freecode(&bpf);
pcap_close(handle);
return EXIT_SUCCESS;
}
void usage() {
printf("sniff interface [filter] [count]");
printf("interface is the interface you want to listen on. It will try to put it in monitor mode");
printf("filter can be a filter for libpcap to apply for packets it reads");
}
int main(int argc, char * argv[])
{
int i = 0; // counter
int ret;
char * default_filter = "ip";
char * filter;
int pcount = -1; //take all packet by defaults
char * interface;
if(argc < 2) {
fprintf(stderr, "No interfaces specified in arguments\n");
usage();
exit(EXIT_FAILURE);
}
// take command line filter
if(argc > 2) {
filter = argv[2];
} else {
filter = default_filter;
}
// take command line packet count limit
if(argc > 3) {
pcount = atoi(argv[3]);
}
fprintf(stdout,"Args : ");
for(i = 0; i < argc; i++) {
fprintf(stdout,"\t%s",argv[i]);
}
printf("\n");
interface = argv[1];
sniffing_method(interface,filter,pcount);
}
And here is one output (all tries giving the same output anyway)
Received packet number 2 ==> 42
Ethernet Layer
Source: 00:ee:bd:aa:f4:98:
Dest: FF:FF:FF:FF:FF:FF:
Type: ARP
ARP Layer
Hardware type: 00
Protocol type: 00
Hardware addresses length: 0
Protocol addresses length: 0
Operation code: 0
Hardware sender: 20e9a152:20e9a152:20e9a152:20e9a152:20e9a152:20e9a152:
Software sender: 20e9a158:20e9a158:20e9a158:20e9a158:
Error : ARP packet does not contain a Hardware type Ethernet -> 0
-------------------------
-------------------------
Received packet number 3 ==> 42
Ethernet Layer
Source: 00:ee:bd:aa:f4:98:
Dest: FF:FF:FF:FF:FF:FF:
Type: ARP
ARP Layer
Hardware type: 00
Protocol type: 00
Hardware addresses length: 0
Protocol addresses length: 0
Operation code: 0
Hardware sender: 20e5a152:20e5a152:20e5a152:20e5a152:20e5a152:20e5a152:
Software sender: 20e5a158:20e5a158:20e5a158:20e5a158:
This part is wrong:
void handleARP(const struct pkt_eth * eth) {
const struct pkt_arp * arp = (const struct pkt_arp *) (eth + ETH_SIZE);
Here you're passing in a struct pkt_eth*, to which you add ETH_SIZE. Pointer arithmetic advances to the next element, not to the next byte. You're essentially looking sizeof(struct pkt_eth) * ETH_SIZE bytes past the pointer passed in.
You should just do
const struct pkt_arp * arp = (const struct pkt_arp *) (eth + 1);
(Or pass in an unsigned char * that already starts at the layer you want to decode.)
I have written a program to capture wireless network packets from my network interface card(ralink 2870(USB),atheros(PCI),etc).Now I am not able to capture the correct format packet I needed,even no packets was captured.1st,I tried turned my card to monitor mode or add a interface mon0 for it.but it output "do not support that interface".2nd,this program can only clarify the "this is the ethernet link type" via pcap_datalink(),why?my wlan0 interface is that link type?. Here is my code:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<unistd.h>
#include<net/if.h>
#include<netinet/if_ether.h>
#include<pcap.h>
/*ugly shortcuts - Defining our header types*/
#define ETH_HEADER_SIZE 14
#define AVS_HEADER_SIZE 64 /*AVS capture header size*/
#define DATA_80211_FRAME_SIZE 24 /*header for 802.11 data packet*/
#define LLC_HEADER_SIZE 8 /*LLC frame for encapsulation*/
#define MAC_MASK (0XFF)
/*
#define uint8 unsigned char;
#define int8 char;
#define uint16 int;
#define int16 int;
#define u_int32_t unsigned int;
#define int32 signed int;
*/
/*for the sake of clarity we'll use globals for a few things*/
char *device; /*device to sniff on*/
int verbose = 0; /*verbose output about the device*/
int wired = 0; /*flag for the opened pcap session*/
pcap_t *handle; /*handle for the opened pcap session*/
/*8 bytes SNAP LLC header format*/
struct snap_header_t{
u_int8_t dsap;
u_int8_t ssap;
u_int8_t ctl;
u_int16_t org;
u_int8_t org2;
u_int16_t ether_type; /* ethernet type */
}__attribute__((__PACKED__));
//24 bytes 80211 header
struct wireless_80211_header_t{
u_int16_t fc; /*2 bytes */
u_int16_t dur; /*2 bytes duration*/
u_int8_t da[6]; /*6 bytes destination*/
u_int8_t sa[6]; /*6 bytes source*/
u_int8_t bssid[6]; /*6 bytes bssid*/
u_int16_t seq_ctrl; /*2 bytes sequence control*/
};
//64 bytes AVS header
struct AVS_header_t
{
u_int32_t version;
u_int32_t length;
u_int64_t mactime;
u_int64_t hosttime;
u_int32_t phytype;
u_int32_t channel;
u_int32_t datarate;
u_int32_t antenna;
u_int32_t priority;
u_int32_t ssi_type;
int32_t ssi_signal;
int32_t ssi_noise;
u_int32_t preamble;
u_int32_t encoding;
};
/*========defined but not used=========*/
/*prism value */
struct prism_value{
u_int32_t did;
u_int16_t status;
u_int16_t len;
u_int32_t data;
};
/*prism header for traditional wireless card*/
struct prism_header{
u_int32_t msgcode;
u_int32_t msglen;
struct prism_value hosttime;
struct prism_value mactime;
struct prism_value channel;
struct prism_value rssi;
struct prism_value sq;
struct prism_value signal;
struct prism_value noise;
struct prism_value rate;
struct prism_value istx;
struct prism_value frmlen;
};
/*===============================*/
/*gracefully handle a Control + C action*/
void
ctrl_c()
{
printf("\nExiting\n");
pcap_breakloop(handle); /*tell pcap_loop or pcap_dispatch to stop capturing*/
pcap_close(handle);
exit(0);
}
/*Usage of this program*/
void
usage (char *name)
{
printf("\n%s - simple ARP sniffer\n",name);
printf("Usage: %s [-i interface] [-l] [-v]\n",name);
printf("\t-i\tinterface to sniff on\n");
printf("\t-l\tlist available interfaces\n");
printf("\t-v\tprint verbose info\n");
exit(1);
}
/*callback function to process a packet when captured*/
void
process_packet(u_char *args, const struct pcap_pkthdr *header,\
const u_char *packet)
{
struct ether_header *eth_header; /*in ethernet.h included by if_eth.h*/
struct wireless_80211_header_t *wireless_header; /*80211 header*/
struct snap_header_t *llc_header; /*RFC 1042 encapsulation header*/
struct ether_arp *arp_packet; /*from if_eth.h*/
if(wired) /*global flag - wired or wireless*/
{
eth_header = (struct ether_header *) packet;
arp_packet = (struct ether_arp *) (packet + ETH_HEADER_SIZE);
if(ntohs(eth_header->ether_type) != ETHERTYPE_ARP)return;
}
else
{
/*wireless*/
wireless_header = (struct wireless_80211_header_t *)
(packet + AVS_HEADER_SIZE);
llc_header = (struct snap_header_t *)
(packet + AVS_HEADER_SIZE + DATA_80211_FRAME_SIZE);
arp_packet = (struct ether_arp *)
(packet + AVS_HEADER_SIZE + DATA_80211_FRAME_SIZE + LLC_HEADER_SIZE);
if(ntohs(llc_header->ether_type) != ETHERTYPE_ARP)return;
}
printf("SRC: %.2X.%.2X.%.2X.%.2X.%.2X.%.2X--> DES:"
"%.2X.%.2X.%.2X.%.2X.%.2X.%.2X\n",
wireless_header->sa[0]&MAC_MASK,
wireless_header->sa[1]&MAC_MASK,
wireless_header->sa[2]&MAC_MASK,
wireless_header->sa[3]&MAC_MASK,
wireless_header->sa[4]&MAC_MASK,
wireless_header->sa[5]&MAC_MASK,
wireless_header->da[0]&MAC_MASK,
wireless_header->da[1]&MAC_MASK,
wireless_header->da[2]&MAC_MASK,
wireless_header->da[3]&MAC_MASK,
wireless_header->da[4]&MAC_MASK,
wireless_header->da[5]&MAC_MASK);
printf("Src: %d.%d.%d.%d--> Des: %d.%d.%d.%d\n",
arp_packet->arp_spa[0],
arp_packet->arp_spa[1],
arp_packet->arp_spa[2],
arp_packet->arp_spa[3],
arp_packet->arp_tpa[0],
arp_packet->arp_tpa[1],
arp_packet->arp_tpa[2],
arp_packet->arp_tpa[3]);
}/*end of process_packet*/
/*the main function*/
int
main(int argc,char *argv[])
{
char opt; /*for option processing*/
char errbuf[PCAP_ERRBUF_SIZE]; /*pcap error messages buffer*/
struct pcap_pkthdr header; /*packet header from pcap*/
const u_char *packet; /*packet*/
bpf_u_int32 netp; /*ip address of interface*/
bpf_u_int32 maskp; /*subnet mask of interface*/
char *filter = "arp"; /*filter for BPF (human readable)*/
struct bpf_program fp; /*compiled BPF filter*/
int ret; /*gegeric return value*/
pcap_if_t *alldevsp; /*list of interfaces*/
while((opt = getopt(argc, argv, "i:vl")) > 0)
{
switch(opt)
{
case 'i':
device = optarg;
break;
case 'l':
if(pcap_findalldevs (&alldevsp,errbuf) < 0)
{
fprintf(stderr,"erros in find all devs: %s\n",errbuf);
exit(1);
}
while(alldevsp != NULL)
{
printf("%s\n",alldevsp->name);
alldevsp = alldevsp->next;
}
exit(0);
case 'v':
verbose = 1;
break;
default:
usage(argv[0]);
break;
}//end of switch
}//end of while
/*setup signal handler to Control+C will graceful*/
signal(SIGINT,ctrl_c);
/*find device for sniffing if needed*/
if(device == NULL)/*if user hasn't specified a device*/
{
device = pcap_lookupdev(errbuf);/*let pcap find a compatible device*/
if(device == NULL)//there was an error
{
fprintf(stderr,"%s\n",errbuf);
exit(1);
}
}
/*set errbuf to 0 length string to check for warnings*/
//memset(errbuf,PCAP_ERRBUF_SIZE,0);
errbuf[0] = 0;
/*open device for sniffing*/
handle = pcap_open_live(device, /*device to sniff on*/
BUFSIZ, /*maximum number of bytes to capture per packet*/
1, /*set 1 for promisc mode,0 to not*/
0, /*0,snigg until an error occurs*/
errbuf);
if(handle == NULL)
{
fprintf(stderr,"%s\n",errbuf);
exit(1);
}
if(strlen(errbuf) > 0)
{
fprintf(stderr,"warning: %s\n",errbuf);
errbuf[0] = 0;
}
if(verbose)
{
printf("Using device: %s\n",device);
printf("libpcap version: %s\n",(char *)pcap_lib_version);
}
/*find out the datalink type of the connection*/
if(pcap_datalink (handle) == DLT_EN10MB)
{
wired = 1;/*ethernet link*/
printf("this is a ethernet link\n");
}
else if((pcap_datalink (handle) == DLT_IEEE802_11_RADIO_AVS)\
||(pcap_datalink (handle) == DLT_IEEE802_11_RADIO)\
||(pcap_datalink (handle) == DLT_IEEE802_11)\
||(pcap_datalink (handle) == DLT_PRISM_HEADER))
{
wired = 0;
printf("this is a wireless link\n");
}
else
{
fprintf(stderr,"do not support this interface type!\n");
exit(1);
}
/*get the IP subnet mask of the device,so we set a filter on it*/
if(pcap_lookupnet(device,&netp,&maskp,errbuf) == -1)
{
fprintf(stderr,"%s\n",errbuf);
exit(1);
}
/*compile the filter,so we can capture only stuff we are interested in*/
if(pcap_compile(handle,&fp,filter,0,maskp) == -1)
{
fprintf(stderr,"%s\n",pcap_geterr(handle));
exit(1);
}
/*set the filter for the device we have opened*/
if(pcap_setfilter(handle,&fp) == -1)
{
fprintf(stderr,"%s\n",pcap_geterr(handle));
exit(1);
}
/*it will be nice and free the memory used for the compiled filter*/
pcap_freecode(&fp);
/*the 'main loop' of capturing packet with our callback function*/
if((ret = pcap_loop(handle, /*our session created previous*/
-1, /*(count) a negative number means sniff until error*/
process_packet, /*callback function*/
NULL)) < 0)/*arg can be transfer to callback function*/
{
if(ret == -1)
{ fprintf(stderr,"%s\n",pcap_geterr(handle));
exit(1);
}/*otherwise return should be -2,meaning pcap_breakloop has been called*/
}
/*close our session*/
pcap_close(handle);
return 0;
}
The following is a program that captures TCP packets < port 80 > and prints header related information in the console for every packet. I have also included a timer , so that after every 1000 millisec i.e. 1 sec , the frequency of occurence of various flags , and distinct number of Src IPs , Ack nos and Seq nos encountered are written into a file. I'm working in fedora core 5. I am encountering the following problems :
1.file writing part works fine during some executions , but most of the other times ,in the same machine , the file is not at all written to.
2.When i execute this program in my house , about 30 packets are captured every second. But when i run the same program in my lab , just 1 packet is captured per second. ( though i do the same amount of browsing in both places )
#define INTERVAL 1000 /* number of milliseconds to go off */
#include <pcap.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h> // for setitimer
#include<unistd.h> // for pause
#include <signal.h> /* for signal */
/* default snap length (maximum bytes per packet to capture) */
#define SNAP_LEN 1518
/* ethernet headers are always exactly 14 bytes [1] */
#define SIZE_ETHERNET 14
/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN 6
/* Ethernet header */
struct sniff_ethernet {
u_char ether_dhost[ETHER_ADDR_LEN]; /* destination host address */
u_char ether_shost[ETHER_ADDR_LEN]; /* source host address */
u_short ether_type; /* IP? ARP? RARP? etc */
};
/* IP header */
struct sniff_ip {
u_char ip_vhl; /* version << 4 | header length >> 2 */
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)
/* TCP header */
typedef u_int tcp_seq;
struct sniff_tcp {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
tcp_seq th_seq; /* sequence number */
tcp_seq th_ack; /* acknowledgement number */
u_char th_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)
u_char th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
u_short th_win; /* window */
u_short th_sum; /* checksum */
u_short th_urp; /* urgent pointer */
};
u_short sport[100];int spd=0;
u_int seq[100];int seqd=0;
u_short win[100];int wind=0;
FILE* urlfile;
int count = 1,flag=0,t=0;
float sc=0,ac=0,fc=0,pc=0,uc=0,rc=0;
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
void
print_payload(const u_char *payload, int len);
void
print_hex_ascii_line(const u_char *payload, int len, int offset);
void
print_app_usage(void);
void DoStuff(void);
void DoStuff(void) {
t++;
printf("Timer %d went off.########################################\n",t);
// fprintf(urlfile,"\n hi hi");
fprintf(urlfile,"\ntime %d 1:%f 2:%f 3:%f 4:%f 5:%f 6:%f 7:%f 8:%f 9:%f",t,sc/count,ac/count,fc/count,pc/count,uc/count,rc/count,(float)spd/count,(float)wind/count,(float)seqd/count);
printf("\ntime %d 1:%f 2:%f 3:%f 4:%f 5:%f 6:%f 7:%f 8:%f 9:%f",t,sc/count,ac/count,fc/count,pc/count,uc/count,rc/count,(float)spd/count,(float)wind/count,(float)seqd/count);
printf("\n a_count : %f , total_packets : %d , frequency : %f",ac,count,ac/count);
printf("\n r_count : %f , total_packets : %d , frequency : %f",rc,count,rc/count);
printf("\n p_count : %f , total_packets : %d , frequency : %f",pc,count,pc/count);
printf("\n s_count : %f , total_packets : %d , frequency : %f",sc,count,sc/count);
printf("\n u_count : %f , total_packets : %d , frequency : %f",uc,count,uc/count);
printf("\n f_count : %f , total_packets : %d , frequency : %f",fc,count,fc/count);
printf("\ncount of distinct seq nos : %d no/pcount : %f ",seqd,(float)seqd/count);
printf("\ncount of distinct sports : %d no/pcount : %f ",spd,(float)spd/count);
printf("\ncount of distinct win nos : %d no/pcount : %f\n\n ",wind,(float)wind/count);
ac=rc=pc=fc=sc=uc=0;count=1;
spd=seqd=wind=0;
}
void
print_app_usage(void)
{
printf("Usage: ./a.out [interface]\n");
printf("\n");
printf("Options:\n");
printf(" interface Listen on <interface> for packets.\n");
printf("\n");
return;
}
/*
* dissect/print packet
*/
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
/* packet counter */
int j;
/* declare pointers to packet headers */
const struct sniff_ethernet *ethernet; /* The ethernet header [1] */
const struct sniff_ip *ip; /* The IP header */
const struct sniff_tcp *tcp; /* The TCP header */
const char *payload; /* Packet payload */
int size_ip;
int size_tcp;
int size_payload;
printf("\nPacket number %d:\n", count);
count++;
/* define ethernet header */
ethernet = (struct sniff_ethernet*)(packet);
/* define/compute ip header offset */
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
size_ip = IP_HL(ip)*4;
if (size_ip < 20) {
printf(" * Invalid IP header length: %u bytes\n", size_ip);
return;
}
switch(ip->ip_p) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
break;
case IPPROTO_UDP:
printf(" Protocol: UDP\n");
return;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
return;
case IPPROTO_IP:
printf(" Protocol: IP\n");
return;
default:
printf(" Protocol: unknown\n");
return;
}
/* define/compute tcp header offset */
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
size_tcp = TH_OFF(tcp)*4;
if (size_tcp < 20) {
printf(" * Invalid TCP header length: %u bytes\n", size_tcp);
return;
}
flag=0;
for(j=0;j<spd;j++)
{
if(sport[j]==ntohs(tcp->th_sport)) { flag=1; break; }
}
if(flag==0) sport[spd++]=ntohs(tcp->th_sport);
flag=0;
for(j=0;j<seqd;j++)
{
if(seq[j]==ntohs(tcp->th_seq)) { flag=1; break; }
}
if(flag==0) seq[seqd++]=ntohs(tcp->th_seq);
flag=0;
for(j=0;j<wind;j++)
{
if(win[j]==ntohs(tcp->th_win)) { flag=1; break; }
}
if(flag==0) win[wind++]=ntohs(tcp->th_win);
printf(" Src port: %d\n", ntohs(tcp->th_sport));
printf(" Window: %d\n", ntohs(tcp->th_win));
printf(" Sequence no: %d\n", ntohs(tcp->th_seq));
if (tcp->th_flags & TH_URG){
printf(" Flag: TH_URG");uc++;
}
if (tcp->th_flags & TH_RST){
printf(" Flag: TH_RST");rc++;
}
if (tcp->th_flags & TH_ACK){
printf(" Flag: TH_ACK");ac++;
}
if (tcp->th_flags & TH_PUSH){
printf(" Flag: TH_PUSH");pc++;
}
if (tcp->th_flags & TH_SYN){
printf(" Flag: TH_SYN");sc++;
}
if (tcp->th_flags & TH_FIN){
printf(" Flag: TH_FIN");fc++;
}
if (size_payload > 0) {
printf(" Payload (%d bytes):\n", size_payload);
}
return;
}
int main(int argc, char **argv)
{
char *dev = NULL; /* capture device name */
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */
char filter_exp[] = "tcp port 80";
struct bpf_program fp; /* compiled filter program (expression) */
bpf_u_int32 mask; /* subnet mask */
bpf_u_int32 net; /* ip */
//int num_packets = 10; /* number of packets to capture */
/* check for capture device name on command-line */
if (argc == 2) {
dev = argv[1];
}
else if (argc > 2) {
fprintf(stderr, "error: unrecognized command-line options\n\n");
print_app_usage();
exit(EXIT_FAILURE);
}
else {
/* find a capture device if not specified on command-line */
dev = pcap_lookupdev(errbuf);
if (dev == NULL) {
fprintf(stderr, "Couldn't find default device: %s\n",
errbuf);
exit(EXIT_FAILURE);
}
}
/* get network number and mask associated with capture device */
if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
dev, errbuf);
net = 0;
mask = 0;
}
/* print capture info */
printf("Device: %s\n", dev);
printf("Filter expression: %s\n", filter_exp);
/* open capture device */
handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
exit(EXIT_FAILURE);
}
/* make sure we're capturing on an Ethernet device [2] */
if (pcap_datalink(handle) != DLT_EN10MB) {
fprintf(stderr, "%s is not an Ethernet\n", dev);
exit(EXIT_FAILURE);
}
/* compile the filter expression */
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
/* apply the compiled filter */
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
}
urlfile=fopen("output.txt","w");
if(urlfile==NULL) printf("Unable to create file.");
// timer code
struct itimerval it_val; /* for setting itimer */
/* Upon SIGALRM, call DoStuff().
* Set interval timer. We want frequency in ms,
* but the setitimer call needs seconds and useconds. */
if (signal(SIGALRM, (void (*)(int)) DoStuff) == SIG_ERR) {
perror("Unable to catch SIGALRM");
exit(1);
}
it_val.it_value.tv_sec = INTERVAL/1000;
it_val.it_value.tv_usec = (INTERVAL*1000) % 1000000;
it_val.it_interval = it_val.it_value;
if (setitimer(ITIMER_REAL, &it_val, NULL) == -1) {
perror("error calling setitimer()");
exit(1);
}
/* now we can set our callback function */
//pcap_loop(handle, num_packets, got_packet, NULL);
pcap_loop(handle,-1, got_packet, NULL);// set num_packets to -1 to capture indefinitely.
/* cleanup */
pcap_freecode(&fp);
pcap_close(handle);
fclose(urlfile);
printf("\nCapture complete.\n");
return 0;
}
As this is a part of my project , i'm right now stuck at this point.. Can anyone please suggest regarding what may have gone wrong.. Thanks in advance.
Have you tried fflush()?
I could solve the problem no [2] , with just a small change in the filter expression : i changed it from "tcp port 80" to "tcp". And , now this program is working as well in my lab as it did at my home.
still , the problem no [1] is yet unresolved.. And moreover , The file writing is not keeping in pace with the console i/o.. By the time the console displays capture details for 120 seconds , the file has only around 90 second - data filled in.. I wonder if this is a general problem with file i/o..