Custom DNS answers - c

I'm currently working on a project for my summer internship and I've got to make an oblivious DNS translation server. I'm not here to speak about the oblivious part in detail but I'll explane the architecture of my program.
There is a server side that receives obfuscated requests and sends back an answer that it doesn't understand itself.
On the client side there is a proxy that translate requests into obfuscated requests. For that I use an iptables rule to send all DNS requests to a NFQUEUE, and then I work with libnetfilter_queue to handle the packet.
After that I received the answer from the server I make a DNS answer with all the information I get (from the DNS request and from the server) and send it using libnet.
Now let's talk about my problem : When using my proxy I check the traffic with Wireshark and it seems that my proxy sends valid answers but if I try to browse the Internet with Firefox it doesn't work.
You can find my code here : https://github.com/AurelienCasimir/PrivateDNS
Is there a problem in my way of building DNS packets ?
Here is the DNS sender :
int send_answer(char *dst_ip_array, char *src_ip_array, int dport, int sport, int dns_id, char *query, char *req_ip, int logfd)
{
char c;
u_long src_ip = arrayToLong(src_ip_array), dst_ip = arrayToLong(dst_ip_array), requested_ip_long=dotToLong(req_ip);
char requested_ip[4];
u_short type = LIBNET_UDP_DNSV4_H;
libnet_t *l;
libnet_ptag_t ip;
libnet_ptag_t ptag4; /* TCP or UDP ptag */
libnet_ptag_t dns;
char errbuf[LIBNET_ERRBUF_SIZE];
char payload[1024];
u_short payload_s;
char log_buffer[500];
int length = 0;
/*
* Initialize the library. Root priviledges are required.
*/
l = libnet_init(
LIBNET_RAW4, /* injection type */
NULL, /* network interface */
errbuf); /* error buffer */
if (!l)
{
length += sprintf(log_buffer + length, "\tlibnet_init: %s", errbuf);
exit(EXIT_FAILURE);
}
/*
* build dns payload
*/
requested_ip[0]=requested_ip_long/(256*256*256);
requested_ip_long=requested_ip_long%(256*256*256);
requested_ip[1]=requested_ip_long/(256*256);
requested_ip_long=requested_ip_long%(256*256);
requested_ip[2]=requested_ip_long/256;
requested_ip_long=requested_ip_long%256;
requested_ip[3]=requested_ip_long;
payload_s = snprintf(payload, sizeof payload, "%c%s%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
(char)(strlen(query)&0xff), query, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x0d, 0xe0, 0x00, 0x04, requested_ip[0], requested_ip[1], requested_ip[2], requested_ip[3]);
/*
* build packet
*/
dns = libnet_build_dnsv4(
type, /* TCP or UDP */
dns_id, /* id */
0x8100, /* request */
1, /* num_q */
1, /* num_anws_rr */
0, /* num_auth_rr */
0, /* num_addi_rr */
payload,
payload_s,
l,
0
);
if (dns == -1)
{
length += sprintf(log_buffer + length, "\tCan't build DNS packet: %s\n", libnet_geterror(l));
goto bad;
}
ptag4 = libnet_build_udp(
sport, /* source port */
dport, /* destination port */
LIBNET_UDP_H + LIBNET_UDP_DNSV4_H + payload_s, /* packet length */
0, /* checksum */
NULL, /* payload */
0, /* payload size */
l, /* libnet handle */
0); /* libnet id */
if (ptag4 == -1)
{
length += sprintf(log_buffer + length, "\tCan't build UDP header: %s\n", libnet_geterror(l));
goto bad;
}
ip = libnet_build_ipv4(
LIBNET_IPV4_H + LIBNET_UDP_H + type + payload_s,/* length */
0, /* TOS */
242, /* IP ID */
0, /* IP Frag */
64, /* TTL */
IPPROTO_UDP, /* protocol */
0, /* checksum */
src_ip, /* source IP */
dst_ip, /* destination IP */
NULL, /* payload */
0, /* payload size */
l, /* libnet handle */
0); /* libnet id */
if (ip == -1)
{
length += sprintf(log_buffer + length, "\tCan't build IP header: %s\n", libnet_geterror(l));
exit(EXIT_FAILURE);
}
/*
* write to the wire
*/
c = libnet_write(l);
if (c == -1)
{
length += sprintf(log_buffer + length, "\tWrite error: %s\n", libnet_geterror(l));
goto bad;
}
else
{
length += sprintf(log_buffer + length, "\tWrote %d byte DNS packet; check the wire.\n", c);
}
length = strlen(log_buffer);
write(logfd, log_buffer, length); // Write to the log.
libnet_destroy(l);
return (EXIT_SUCCESS);
bad:
length = strlen(log_buffer);
write(logfd, log_buffer, length); // Write to the log.
libnet_destroy(l);
return (EXIT_FAILURE);
}
Here is an example of DNS answer sent by my proxy:
http://imgur.com/9c5RgLj

It seems the DNS response is correct. I would look at:
If the flag recursion available is necessary (0x8180)
Check the returned IP address is OK. I could not access that IP address that you showed in your image (https://db-ip.com/26.193.206.130)
Is the UDP checksum correct?
Does the transaction ID correspond to the transaction ID of the DNS query?
I'm sure this is OK but just check the server is requesting that Type and Class of address

Related

How can i create a file .csv?

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);

Print HTTP packet data from inside Kernel Module

I am trying to write a kernel module that will dump all the HTTP packet data to dmesg.
I registered a nf_hook in POST ROUTING (tried also hooking OUTPUT table), and printing all the packets which sport is 80 (HTTP responses)
I read the following post - Print TCP Packet Data
and really got it to work! but I have a problem, the kernel module is printing only the first line of the response - HTTP/1.0 200 OK without printing all the HTTP headers and HTML.
this is my hook function -
struct iphdr *iph; /* IPv4 header */
struct tcphdr *tcph; /* TCP header */
u16 sport, dport; /* Source and destination ports */
u32 saddr, daddr; /* Source and destination addresses */
unsigned char *user_data; /* TCP data begin pointer */
unsigned char *tail; /* TCP data end pointer */
unsigned char *it; /* TCP data iterator */
/* Network packet is empty, seems like some problem occurred. Skip it */
if (!skb)
return NF_ACCEPT;
iph = ip_hdr(skb); /* get IP header */
/* Skip if it's not TCP packet */
if (iph->protocol != IPPROTO_TCP)
return NF_ACCEPT;
tcph = tcp_hdr(skb); /* get TCP header */
/* Convert network endianness to host endiannes */
saddr = ntohl(iph->saddr);
daddr = ntohl(iph->daddr);
sport = ntohs(tcph->source);
dport = ntohs(tcph->dest);
/* Watch only port of interest */
if (sport != PTCP_WATCH_PORT)
return NF_ACCEPT;
/* Calculate pointers for begin and end of TCP packet data */
user_data = (unsigned char *)((unsigned char *)tcph + (tcph->doff * 4));
tail = skb_tail_pointer(skb);
/* ----- Print all needed information from received TCP packet ------ */
/* Show only HTTP packets */
if (user_data[0] != 'H' || user_data[1] != 'T' || user_data[2] != 'T' ||
user_data[3] != 'P') {
return NF_ACCEPT;
}
/* Print packet route */
pr_debug("print_tcp: %pI4h:%d -> %pI4h:%d\n", &saddr, sport,
&daddr, dport);
/* Print TCP packet data (payload) */
pr_debug("print_tcp: data:\n");
for (it = user_data; it != tail; ++it) {
char c = *(char *)it;
if (c == '\0')
break;
printk("%c", c);
}
printk("\n\n");
return NF_ACCEPT;
I want to print the whole packet, not only the first row.
why it's printing only the first row ? My guess is that there is some routing caching (like when using IPTABLES) , is there a way to disable the caching ?
I have the same problem until closed my proxy client (like v2ray or shadowsocks), look likes the proxy client cached/simplify the http request data, you can try tcpdump to catch the http request data, there is only a line like: HTTP GET / 1.1.

libpcap Packet sniffing Traffic analysing

i have made a packet sniffer using libpcap on C++.
I am using pcap_loop and calling a loopback function , which at the moment i havent put much thought of.
Here is my code.
int PacketSniff(int *count)
{
int ifnum;
int NumOfDevs=0;
char errbuf[PCAP_ERRBUF_SIZE];
bpf_u_int32 ip;
bpf_u_int32 netmask;
struct in_addr ip_addr , netmask_addr;
pcap_if_t *devs , *d;
pcap_t *handler;
char packet_filter[] = "ip";
struct bpf_program fcode;
/* Find all interface devices */
pcap_findalldevs(&devs, errbuf);
for(d=devs; d; d=d->next)
{
printf("%d. %s", ++NumOfDevs, d->name);
if (d->description)
{
printf(" (%s)\n", d->description);
}
else
{
printf(" (No description available)\n");
}
}
if(NumOfDevs==0)
{
printf("\nNo interfaces found!\n");
return (-1);
}
/* Prompt User to select interface */
printf("Enter the interface number (1-%d):\n",NumOfDevs);
scanf("%d",&ifnum);
if(ifnum < 1 || ifnum > NumOfDevs)
{
printf("\nInterface number out of range.\n");
/* Free the device list */
pcap_freealldevs(devs);
return (-1);
}
/* Jump to the selected adapter/interface */
for(d=devs; ifnum>1 ;d=d->next, ifnum--);
/* Open the selected adapter/interface */
handler = pcap_open_live(d->name, 65535, 0, 2000, errbuf);
if ((handler = pcap_open_live(d->name, 65535, 0, 2000, errbuf)) == NULL)
{
fprintf(stderr, "Couldn't open device %s: %s\n", d->name, errbuf);
return(-1);
}
if (pcap_datalink(handler) != DLT_EN10MB )
{
fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
pcap_freealldevs(devs);
return -1;
}
/* This means that we set the datalink layer header size at 14 */
int linkhdrlen = 14;
if (pcap_lookupnet(d->name, &ip, &netmask, errbuf) <0 )
{
fprintf(stderr, "Can't get netmask for device %s\n", d->name);
netmask = 0;
ip = 0;
}
/* Compile the filter */
if (pcap_compile(handler, &fcode, packet_filter, 1, netmask) <0 )
{
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax. Error: %s\n", errbuf);
pcap_freealldevs(devs);
return -1;
}
/* Set the filter */
if (pcap_setfilter(handler, &fcode)<0)
{
fprintf(stderr,"\nError setting the filter. Error: %s\n", errbuf);
pcap_freealldevs(devs);
return -1;
}
printf("\nListening for packets on interface <%s>...\n", d->name);
/* At this point, we don't need any more the device list. Free it */
pcap_freealldevs(devs);
pcap_loop(handler, 0, my_callback, NULL);}
And my_callback is like this:
void my_callback(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_ptr){
struct tm ltime;
char timestr[16];
struct ip_header *iphdr;
struct tcp_header *tcphdr;
time_t local_tv_sec;
/* Convert the timestamp to readable format */
local_tv_sec = header->ts.tv_sec;
localtime_r(&local_tv_sec , &ltime);
strftime( timestr, sizeof timestr, "%H:%M:%S", &ltime);
/* Print timestamp and length of the packet */
printf("Time >> %s.%.6d \nPacket Length:%d \n\n", timestr, header->ts.tv_usec, header->len);
/* Retireve the position of the ip header http://www.tcpdump.org/pcap.html */
iphdr = (ip_header *) (pkt_ptr +14);
// Advance to the transport layer header then parse and display
// the fields based on the type of hearder: tcp, udp or icmp.
pkt_ptr += 4*iphdr->ver_ihl ;
tcphdr = (tcp_header *)(pkt_ptr + 14);
/* print ip addresses and tcp ports */
printf("%d.%d.%d.%d : %d ---> %d.%d.%d.%d : %d\n\n",
iphdr->saddr.byte1,
iphdr->saddr.byte2,
iphdr->saddr.byte3,
iphdr->saddr.byte4,
tcphdr->src_port,
iphdr->daddr.byte1,
iphdr->daddr.byte2,
iphdr->daddr.byte3,
iphdr->daddr.byte4,
tcphdr->dst_port);}
Now i can sniff packets and print various things .
But my goal is to Extract Stats from the packets (like numOfpackets , numOfTCPpackets , numOfIncomingPAcket , numOfOutgoingPackets , Packet Size Variance , Time Interval Variance ) while they are being sniffed .
But i want this to be done in 1000ms Time-Windows.
For example: Every 1000ms i want an output file of..
numOfTCPPackets = ....
numof = ....
.
.
.
My questions are :
How can i incorporate those Time-Windows?
How to extract the needed stats without interfering too muchwith the sniffing speed.?
Thank you a lot!
Use pcap_next() instead of pcap_loop() to get the packet and set the timeout with pcap_set_timeout() to a small value such as 10 milliseconds to prevent pcap_next() blocking forever so that your code to write the statistics to the file gets a chance to run. You need to call pcap_next() in a loop and have code like the following after the pcap_next() call:
if (cur_time64() - last_time64 >= stat_time64)
{
last_time64 += stat_time64;
print_statistics_to_file();
}
...where cur_time64() returns the current time as a 64-bit integer in microseconds since the epoch (you can use gettimeofday() to implement cur_time64() if you use a Unix-like operating system). stat_time64 would be 1 second, i.e. 1000*1000, in your example.
Then, proceed to process the packet. Check the return value of pcap_next() to see if it returned a packet: if no, continue the loop; if yes, process the packet.
To do the checks without interfering too much with the sniffing speed, your only option is to write the code as efficiently as possible. Handle only those header fields you absolutely need to handle, i.e. you can avoid checking the checksums of IP and TCP headers.

Add arp entry Linux

Read the question carefully in order to propose a solution, please
I need to add permanent arp entry in Linux somehow.
The problem is: if I add an entry via shell, or via sockets, it always gets flag 0x6. Even if I use the code posted downhere, where I specify the flag, it remains the same, 0x6.
I found this information about 0x6 flag:
Notice the ARP flag of "0x6". The ASIC ARP entry with flag 0x6 is
MAC-cache related entry. It is caused by arp lookup failure when
installing the session. The session will try to use the source MAC
address of incoming packet, but it is not necessary for using this mac
address. We can get the MAC address when the reply packet arrives by
sending an ARP packet to the source host.
So anytime I add any arp entry, then I ping the same ip address, it always results in ARP request broadcast.
The question is, is there a way how to add a permanent ARP entry with proper flag? So I add an entry, and in case of any comunication afterwards, there wont be any ARP broadcast?
Btw, to get into what I am up to: I am sending a broadcast(L3) from PC1 containing PC1's IP and MAC, PC2 gets the packet and add addresses them into ARP table and establish TCP session, but always first run ARP broadcast.
via shell:
#!/bin/sh
arp -s $1 $2 2>/dev/null
via sockets:
char *mac_ntoa(unsigned char *ptr){
static char address[30];
sprintf(address, "%02X:%02X:%02X:%02X:%02X:%02X",
ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]);
return(address);
} /* End of mac_ntoa */
int mac_aton(char *addr, unsigned char *ptr){
int i, v[6];
if((i = sscanf(addr, "%x:%x:%x:%x:%x:%x", &v[0], &v[1], &v[2], &v[3],
&v[4], &v[5])) !=6){
fprintf(stderr, "arp: invalid Ethernet address '%s'\n", addr);
return(1);
} /* End of If*/
for(i = 0; i < 6; i++){
ptr[i] = v[i];
} /* End of For */
return(0);
}
int main(int argc, char* argv[]){
if(argc < 3 || argc > 4){
fprintf(stderr,"usage: %s <ip_addr> <hw_addr> [temp|pub|perm|trail]\n",
argv[0]);
fprintf(stderr, "default: temp.\n");
exit(-1);
} /* End of If */
int s, flags;
char *host = argv[1];
struct arpreq req;
struct hostent *hp;
struct sockaddr_in *sin;
bzero((caddr_t)&req, sizeof(req)); /* caddr_t is not really needed. */
sin = (struct sockaddr_in *)&req.arp_pa;
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = inet_addr(host);
if(sin->sin_addr.s_addr ==-1){
if(!(hp = gethostbyname(host))){
fprintf(stderr, "arp: %s ", host);
herror((char *)NULL);
return(-1);
} /* End of If */
bcopy((char *)hp->h_addr,
(char *)&sin->sin_addr, sizeof(sin->sin_addr));
} /* End of If */
if(mac_aton(argv[2], req.arp_ha.sa_data)){ /* If address is valid... */
return(-1);
}
argc -=2;
argv +=2;
flags = ATF_PERM | ATF_COM;
while(argc-- > 0){
if(!(strncmp(argv[0], "temp", 4))){
flags &= ~ATF_PERM;
} else if(!(strncmp(argv[0], "pub", 3))){
flags |= ATF_PUBL;
} else if(!(strncmp(argv[0], "trail", 5))){
flags |= ATF_USETRAILERS;
} else if(!(strncmp(argv[0], "dontpub", 7))){ /* Not working yet */
flags |= ATF_DONTPUB;
} else if(!(strncmp(argv[0], "perm", 4))){
flags = ATF_PERM;
} else {
flags &= ~ATF_PERM;
} /* End of Else*/
argv++;
}/* End of While */
req.arp_flags = flags; /* Finally, asign the flags to the structure */
strcpy(req.arp_dev, "eth0"); /* Asign the device. */
if((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
perror("socket() failed.");
exit(-1);
} /* End of If */
if(ioctl(s, SIOCSARP, (caddr_t)&req) <0){ /* caddr_t not really needed. */
perror(host);
exit(-1);
} /* End of If */
printf("ARP cache entry successfully added.\n");
close(s);
return(0);
}
0x06 flag value means the entry is complete and permanent. So I guess your shell script is good enough to add a static arp entry. Here is the relevant flag values -
#define ATF_COM 0x02 /* completed entry (ha valid) */
#define ATF_PERM 0x04 /* permanent entry */
The definition of flag 0x06 that you posted is not related to the linux kernel.
The reason you're seeing an arp request may be due to problems in your topology or IP addressing. Can you post those details? Or you could post the packet trace where PC2 does an arp request even when it has a static arp entry.

Router Alert options on IGMPv2 packets

I'm trying to forge an IGMPv2 Membership Request packet and send it on a RAW socket.
The RFC 3376 states:
IGMP messages are encapsulated in IPv4 datagrams, with an IP protocol number of 2. Every IGMP message described in this document is sent with an IP Time-to-Live of 1, IP Precedence of Internetwork Control (e.g., Type of Service 0xc0), and carries an IP Router Alert option [RFC-2113] in its IP header
So the IP_ROUTER_ALERT flag must be set.
I'm trying to forge the strict necessary of the packet (e.g. only the IGMP header & payload), so i'm using the setsockopt to edit the IP options.
some useful variables:
#define C_IP_MULTICAST_TTL 1
#define C_IP_ROUTER_ALERT 1
int sockfd = 0;
int ecsockopt = 0;
int bytes_num = 0;
int ip_multicast_ttl = C_IP_MULTICAST_TTL;
int ip_router_alert = C_IP_ROUTER_ALERT;
Here's how I open the RAW socket:
sock_domain = AF_INET;
sock_type = SOCK_RAW;
sock_proto = IPPROTO_IGMP;
if ((ecsockopt = socket(sock_domain,sock_type,sock_proto)) < 0) {
printf("Error %d: Can't open socket.\n", errno);
return 1;
} else {
printf("** Socket opened.\n");
}
sockfd = ecsockopt;
Then I set the TTL and Router Alert option:
// Set the sent packets TTL
if((ecsockopt = setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL, &ip_multicast_ttl, sizeof(ip_multicast_ttl))) < 0) {
printf("Error %d: Can't set TTL.\n", ecsockopt);
return 1;
} else {
printf("** TTL set.\n");
}
// Set the Router Alert
if((ecsockopt = setsockopt(sockfd, IPPROTO_IP, IP_ROUTER_ALERT, &ip_router_alert, sizeof(ip_router_alert))) < 0) {
printf("Error %d: Can't set Router Alert.\n", ecsockopt);
return 1;
} else {
printf("** Router Alert set.\n");
}
The setsockopt of IP_ROUTER_ALERT returns 0. After forging the packet, i send it with sendto in this way:
// Send the packet
if((bytes_num = sendto(sockfd, packet, packet_size, 0, (struct sockaddr*) &mgroup1_addr, sizeof(mgroup1_addr))) < 0) {
printf("Error %d: Can't send Membership report message.\n", bytes_num);
return 1;
} else {
printf("** Membership report message sent. (bytes=%d)\n",bytes_num);
}
The packet is sent, but the IP_ROUTER_ALERT option (checked with wireshark) is missing.
Am i doing something wrong? is there some other methods to set the IP_ROUTER_ALERT option?
Thanks in advance.
Finally i've found out that the IP_ROUTER_ALERT has to be set by the Linux Kernel. IGMP membership requests are sent after a IP_ADD_MEMBERSHIP is done and the Kernel takes charge of setting the IP_ROUTER_ALERT flag.
I do not know why your code is not working (it looks fine to me), but I can suggest a workaround: Drop one more layer down on your raw socket and build Ethernet frames. You may also want to take a look at Libnet, which handles building packets like this for you.
The documentation states:
Pass all to-be forwarded packets with
the IP Router Alert option set to this
socket. Only valid for raw sockets.
This is useful, for instance, for user
space RSVP daemons. The tapped packets
are not forwarded by the kernel, it is
the users responsibility to send them
out again. Socket binding is ignored,
such packets are only filtered by
protocol. Expects an integer flag.
This sounds as if the option only matters when receiving packets on the socket, not when sending them. If you're sending raw packets, can't you just set the required option in the IP header yourself?
As a reference I would recommend one of the many IGMP aware programs out there.
One example is igmpproxy:
https://github.com/ViToni/igmpproxy/blob/logging/src/igmp.c#L54
/*
* Open and initialize the igmp socket, and fill in the non-changing
* IP header fields in the output packet buffer.
*/
void initIgmp(void) {
struct ip *ip;
recv_buf = malloc(RECV_BUF_SIZE);
send_buf = malloc(RECV_BUF_SIZE);
k_hdr_include(true); /* include IP header when sending */
k_set_rcvbuf(256*1024,48*1024); /* lots of input buffering */
k_set_ttl(1); /* restrict multicasts to one hop */
k_set_loop(false); /* disable multicast loopback */
ip = (struct ip *)send_buf;
memset(ip, 0, sizeof(struct ip));
/*
* Fields zeroed that aren't filled in later:
* - IP ID (let the kernel fill it in)
* - Offset (we don't send fragments)
* - Checksum (let the kernel fill it in)
*/
ip->ip_v = IPVERSION;
ip->ip_hl = (sizeof(struct ip) + 4) >> 2; /* +4 for Router Alert option */
ip->ip_tos = 0xc0; /* Internet Control */
ip->ip_ttl = MAXTTL; /* applies to unicasts only */
ip->ip_p = IPPROTO_IGMP;
allhosts_group = htonl(INADDR_ALLHOSTS_GROUP);
allrouters_group = htonl(INADDR_ALLRTRS_GROUP);
alligmp3_group = htonl(INADDR_ALLIGMPV3_GROUP);
}
and https://github.com/ViToni/igmpproxy/blob/logging/src/igmp.c#L271
/*
* Construct an IGMP message in the output packet buffer. The caller may
* have already placed data in that buffer, of length 'datalen'.
*/
static void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, int datalen) {
struct ip *ip;
struct igmp *igmp;
extern int curttl;
ip = (struct ip *)send_buf;
ip->ip_src.s_addr = src;
ip->ip_dst.s_addr = dst;
ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen);
if (IN_MULTICAST(ntohl(dst))) {
ip->ip_ttl = curttl;
} else {
ip->ip_ttl = MAXTTL;
}
/* Add Router Alert option */
((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[0] = IPOPT_RA;
((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[1] = 0x04;
((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[2] = 0x00;
((unsigned char*)send_buf+MIN_IP_HEADER_LEN)[3] = 0x00;
igmp = (struct igmp *)(send_buf + IP_HEADER_RAOPT_LEN);
igmp->igmp_type = type;
igmp->igmp_code = code;
igmp->igmp_group.s_addr = group;
igmp->igmp_cksum = 0;
igmp->igmp_cksum = inetChksum((unsigned short *)igmp,
IP_HEADER_RAOPT_LEN + datalen);
}

Resources