Raw Ethernet Packet Capture

G

gustavo.samour

Hi,

I am writing a very basic raw ethernet sniffer based on what I found
in Andreas Schaufler's raw ethernet article:
http://aschauf.landshut.org/fh/linux/udp_vs_raw/ch01s03.html

I'm trying to print the output of each ethernet frame in both
hexadecimal and character representations. I'm new at network
programming in C. Here's a code snippet:

while(1)
{

length = recvfrom(s, buffer, ETH_FRAME_LEN, 0, NULL, NULL);

if (length == -1) {

printf("Error receiving ethernet frame...\n");

}
else {

printf("Hex:\n\n");
for (int i = 0; i < length; i++)
{
printf("%x" buffer);
}

printf("\n\nChar:\n\n");
for (int i = 0; i < length; i++)
{
printf("%c" buffer);
}

}

}

Most of the characters I get are shown in two digit hexadecimal
representation like this "A0". But sometimes I get something like
"FFFFFFFF" or "FFFFFFA0". Why does this happen? I also compared the
results of using the Linux wireshark sniffer and my program, and
noticed different hexadecimal values for the frames. I know wireshark
is correct, so what am I doing wrong? Any help is appreciated.

Note: I posted this in alt.comp.lang.c before and someone named
"mimus" said the "FFFFFFFF" behavior could be a signed/unsigned
problem. How can I tell?
 
U

user923005

Hi,

I am writing a very basic raw ethernet sniffer based on what I found
in Andreas Schaufler's raw ethernet article:http://aschauf.landshut.org/fh/linux/udp_vs_raw/ch01s03.html

I'm trying to print the output of each ethernet frame in both
hexadecimal and character representations. I'm new at network
programming in C. Here's a code snippet:

while(1)
{

length = recvfrom(s, buffer, ETH_FRAME_LEN, 0, NULL, NULL);

if (length == -1) {

printf("Error receiving ethernet frame...\n");

}
else {

printf("Hex:\n\n");
for (int i = 0; i < length; i++)
{
printf("%x" buffer);
}

printf("\n\nChar:\n\n");
for (int i = 0; i < length; i++)
{
printf("%c" buffer);
}

}

}

Most of the characters I get are shown in two digit hexadecimal
representation like this "A0". But sometimes I get something like
"FFFFFFFF" or "FFFFFFA0". Why does this happen? I also compared the
results of using the Linux wireshark sniffer and my program, and
noticed different hexadecimal values for the frames. I know wireshark
is correct, so what am I doing wrong? Any help is appreciated.

Note: I posted this in alt.comp.lang.c before and someone named
"mimus" said the "FFFFFFFF" behavior could be a signed/unsigned
problem. How can I tell?


The data type of buffer is not specified, but I guess signed char.

The printf() function is a varadic function. So signed char will
promote to what by default promotions?

It would have been funnier if the poster was named 'minus'.

I guess that if you change your data type to unsigned char, it may
surprise you a bit.
 
T

Tor Rustad

(e-mail address removed) wrote:

[...]
Note: I posted this in alt.comp.lang.c before and someone named
"mimus" said the "FFFFFFFF" behavior could be a signed/unsigned
problem. How can I tell?

The %X specifier expect an 'unsigned int' type, you can try e.g.

int write_hex(FILE *out, unsigned char *binary, size_t binary_len)
{
size_t i;
int n = 0;

for (i=0; i<binary_len; i++)
{
n = fprintf(out, "%02X", binary);
}
return n;
}

instead.
 
T

Tor Rustad

Tor said:
(e-mail address removed) wrote:

[...]
Note: I posted this in alt.comp.lang.c before and someone named
"mimus" said the "FFFFFFFF" behavior could be a signed/unsigned
problem. How can I tell?

The %X specifier expect an 'unsigned int' type, you can try e.g.

int write_hex(FILE *out, unsigned char *binary, size_t binary_len)
{
size_t i;
int n = 0;

for (i=0; i<binary_len; i++)
{
n = fprintf(out, "%02X", binary);


I forgot to put in some error check here for n<0, also the 'n' return
value is rather misleading, since it typically doesn't return the total
length printed.
 
G

gustavo.samour

You guys were right. I was using a signed char. I changed it to
unsigned char and I noticed the following change:

the "ffffffff" or "ffffffa0" now appear as "ff" and "a0" respectively.
I also noticed I was trying to print some unprintable characters using
printf("%c", thechar)...characters like the frame header (silly me).
So thanks! It worked.

But now I noticed some odd behavior. I'm sending some raw ethernet
packets from a Windows machine and sniffing them in my linux box. When
I only run my C program, those packets are not received for some
reason. But when I run both my program and the Wireshark capture
SIMULTANEOUSLY, I DO receive those packets coming from my Windows
machine. Any ideas? Is there some sort of flag I'm not setting in my
code that gets set in Wireshark? Here's my code:


#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>


int main(void)
{

int i = 0;
int s; /*socketdescriptor*/
int frameCount = 1;
int MAX_FRAMES = 1000;

s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s == -1) { printf("ERROR BINDING SOCKET...\n"); exit(0); }

unsigned char* buffer = (unsigned char*)malloc(ETH_FRAME_LEN); /
*Buffer for ethernet frame*/
int length = 0; /*length of the received frame*/

while(frameCount <= MAX_FRAMES){

length = recvfrom(s, buffer, ETH_FRAME_LEN, 0, NULL, NULL);

if (length == -1)
{
printf("Error while receiving ethernet frame...\n");
}
else {

printf("Frame %d (hex)\n\n", frameCount);
for(i=0; i<length; i++)
{
printf("%.2x ", buffer);
}
printf("\n\n");

printf("Frame %d (char)\n\n", frameCount);
for(i=0; i<length; i++)
{
if (buffer > 32 && buffer <= 127 )
printf("%c ", buffer);
else
printf(". ");
}
printf("\n\n");

frameCount++;

}

}

close(s);

}
 
R

Richard Heathfield

Tor Rustad said:
Tor Rustad wrote:
int write_hex(FILE *out, unsigned char *binary, size_t binary_len)
{
size_t i;
int n = 0;

for (i=0; i<binary_len; i++)
{
n = fprintf(out, "%02X", binary);


I forgot to put in some error check here for n<0, also the 'n' return
value is rather misleading, since it typically doesn't return the total
length printed.


This can easily be fixed with +=, or the function could simply return
ferror(out) instead.
 
S

santosh

You guys were right. I was using a signed char. I changed it to
unsigned char and I noticed the following change:

the "ffffffff" or "ffffffa0" now appear as "ff" and "a0" respectively.
I also noticed I was trying to print some unprintable characters using
printf("%c", thechar)...characters like the frame header (silly me).
So thanks! It worked.

But now I noticed some odd behavior. I'm sending some raw ethernet
packets from a Windows machine and sniffing them in my linux box. When
I only run my C program, those packets are not received for some
reason. But when I run both my program and the Wireshark capture
SIMULTANEOUSLY, I DO receive those packets coming from my Windows
machine. Any ideas? Is there some sort of flag I'm not setting in my
code that gets set in Wireshark? Here's my code:


#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>

<snip rest>

I think this might be the point where it might be fruitful to take your
problem over to a UNIX or Linux group like <<<<etc.
 
G

gustavo.samour

<snip rest>

I think this might be the point where it might be fruitful to take your
problem over to a UNIX or Linux group like <<<<etc.

Good idea, thanks Santosh!
 
J

J. J. Farrell

I am writing a very basic raw ethernet sniffer based on what I found
in Andreas Schaufler's raw ethernet article:http://aschauf.landshut.org/fh/linux/udp_vs_raw/ch01s03.html

I'm trying to print the output of each ethernet frame in both
hexadecimal and character representations. I'm new at network
programming in C. Here's a code snippet:

while(1)
{

length = recvfrom(s, buffer, ETH_FRAME_LEN, 0, NULL, NULL);

if (length == -1) {

printf("Error receiving ethernet frame...\n");

}
else {

printf("Hex:\n\n");
for (int i = 0; i < length; i++)
{
printf("%x" buffer);
}

printf("\n\nChar:\n\n");
for (int i = 0; i < length; i++)
{
printf("%c" buffer);
}

}

}

Most of the characters I get are shown in two digit hexadecimal
representation like this "A0". But sometimes I get something like
"FFFFFFFF" or "FFFFFFA0". Why does this happen? I also compared the
results of using the Linux wireshark sniffer and my program, and
noticed different hexadecimal values for the frames. I know wireshark
is correct, so what am I doing wrong? Any help is appreciated.

Note: I posted this in alt.comp.lang.c before and someone named
"mimus" said the "FFFFFFFF" behavior could be a signed/unsigned
problem. How can I tell?


You've missed out the piece of code which is vital to understanding
this problem - the definition of 'buffer'. I'm guessing it's an array
of char, and the compiler you are using is treating char as a signed
type. So, buffer is a char which is signed, and you're passing it
to printf. If the bit pattern which has found its way into buffer
can be interpreted as a negative number, buffer is negative. When
you pass a char which is signed to printf (which is a variadic
function) it gets promoted to s signed int (in most implementations,
and certainly in this one). Now the number you are asking printf to
print is an int (which with your compiler appears to be 32 bits)
containing a negative number. You've told printf to expect an unsigned
int (by using %x) so it treats the signed negative int as an unsigned
int. The high-order bits of your int are all 1s since the int is a
negative number, so when this value is treated as an unsigned int it
becomes a large 32-bit positive value with all the high-order bits set
to 1. That's what gets printed.

The simplest solution is to define your buffer as an array of unsigned
char.
 
T

Tor Rustad

Richard said:
Tor Rustad said:
[...]
n = fprintf(out, "%02X", binary);

I forgot to put in some error check here for n<0, also the 'n' return
value is rather misleading, since it typically doesn't return the total
length printed.


This can easily be fixed with +=,


Yes, which left on purpose as an exercise to OP. :)
or the function could simply return
ferror(out) instead.

In the general case (even if not relevant here), I think the n<0 check
is needed, since I don't expect ferror() to catch fprintf() encoding errors.
 
G

gustavo.samour

Thanks to everyone who posted! You pointed me in the right direction
with the unsigned/signed char issue... I felt like such a newbie
haha... As for the Wireshark issue:

Turns out, I wasn't far off.. there WAS a "flag" I wasn't setting.
It's called "promiscuous mode". By default, Network cards are not in
promiscuous mode which means they don't allow certain packets thru
(packets where the destination is not its MAC address or something
like that). When this mode is set, the network interface gets ALL
traffic, even packets not meant for it. So promiscuous mode was the
key. To set this mode in linux go to your shell and type a command
similar to this one:
ifconfig eth0 promisc

Be sure to replace "eth0" with your own network interface in case it's
"wlan0" or something else. To remove promiscuous mode, type:
ifconfig eth0 -promisc

Thanks again for all your help!
 
G

gustavo.samour

To set promiscuous mode within your C code, add code similar to the
following:

struct ifreq ethreq;
strncpy(ethreq.ifr_name,"eth0",IFNAMSIZ);
ioctl(sock, SIOCGIFFLAGS, &ethreq);
ethreq.ifr_flags |= IFF_PROMISC;
ioctl(sock, SIOCSIFFLAGS, &ethreq);

This snippet is taken from:

http://www.linuxjournal.com/article/4659
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top