Raw Ethernet Packet Capture

Discussion in 'C Programming' started by gustavo.samour@gmail.com, Oct 22, 2007.

  1. Guest

    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?
    , Oct 22, 2007
    #1
    1. Advertising

  2. user923005 Guest

    On Oct 22, 2:58 pm, wrote:
    > 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.
    user923005, Oct 22, 2007
    #2
    1. Advertising

  3. Tor Rustad Guest

    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.

    --
    Tor <torust [at] online [dot] no>

    "Technical skill is mastery of complexity, while creativity is mastery
    of simplicity"
    Tor Rustad, Oct 22, 2007
    #3
  4. Tor Rustad Guest

    Tor Rustad wrote:
    > 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.


    --
    Tor <torust [at] online [dot] no>

    "Technical skill is mastery of complexity, while creativity is mastery
    of simplicity"
    Tor Rustad, Oct 23, 2007
    #4
  5. Guest

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

    }
    , Oct 23, 2007
    #5
  6. Tor Rustad said:
    > Tor Rustad wrote:


    <snip>

    >> 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.

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -http://www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Oct 23, 2007
    #6
  7. santosh Guest

    wrote:

    > 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 <news:comp.unix.programmer>,
    <news:comp.os.linux.development.apps>,
    <news:comp.os.linux.development.system>,
    <news:comp.os.linux.networking>
    etc.
    santosh, Oct 23, 2007
    #7
  8. Guest

    On 22 oct, 17:26, santosh <> wrote:
    > wrote:
    > > 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 <news:comp.unix.programmer>,
    > <news:comp.os.linux.development.apps>,
    > <news:comp.os.linux.development.system>,
    > <news:comp.os.linux.networking>
    > etc.


    Good idea, thanks Santosh!
    , Oct 23, 2007
    #8
  9. On Oct 22, 10:58 pm, wrote:
    >
    > 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.
    J. J. Farrell, Oct 23, 2007
    #9
  10. Tor Rustad Guest

    Richard Heathfield wrote:
    > 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.

    --
    Tor <torust [at] online [dot] no>

    "Technical skill is mastery of complexity, while creativity is mastery
    of simplicity"
    Tor Rustad, Oct 23, 2007
    #10
  11. Tor Rustad said:

    > Richard Heathfield wrote:
    >>
    >> This can easily be fixed [...]

    >
    > Yes, which left on purpose as an exercise to OP. :)


    Whoops! Sorry, Tor.

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -http://www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
    Richard Heathfield, Oct 23, 2007
    #11
  12. Guest

    SOLVED! Re: Raw Ethernet Packet Capture

    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:

    > > 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?


    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!
    , Oct 23, 2007
    #12
  13. Guest

    Re: SOLVED! Re: Raw Ethernet Packet Capture

    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
    , Oct 24, 2007
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    0
    Views:
    433
  2. Grant Edwards

    How to do raw Ethernet under Win32?

    Grant Edwards, Jul 23, 2003, in forum: Python
    Replies:
    7
    Views:
    680
    =?ISO-8859-1?Q?Gerhard_H=E4ring?=
    Jul 24, 2003
  3. K-man

    Ethernet packet size python

    K-man, Jan 13, 2009, in forum: Python
    Replies:
    2
    Views:
    1,502
    K-man
    Jan 13, 2009
  4. Li Han
    Replies:
    2
    Views:
    505
    bobicanprogram
    Feb 9, 2009
  5. Gelonida N
    Replies:
    4
    Views:
    878
    Gelonida N
    Sep 11, 2011
Loading...

Share This Page