2

I have the seemingly simple task of printing very basic information regarding frames passing through a specific ethernet interface. I have a socket defined as

if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) == -1) return __LINE__;
strcpy(ifr.ifr_name, argv[1]);
if (ioctl(sd, SIOCGIFFLAGS, &ifr) == -1) return __LINE__;
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl(sd, SIOCSIFFLAGS, &ifr) == -1) return __LINE__;
if (ioctl(sd, SIOCGIFINDEX, &ifr) == -1) return __LINE__;

I loop my input like so

while (active) {
        FD_SET(sd, &fds);
        FD_SET(STDIN_FILENO, &fds);
        if ((rv = select(sd + 1, &fds, NULL, NULL, &tv)) < 0)
            active = 0;
        if (FD_ISSET(sd, &fds)) input(sd, buf);

This is where I am having problems. I define the ethernet header each frame is cast into with a struct

struct ethheader {
    unsigned char       dsta[6];
    unsigned char       srca[6];
    uint16_t            type;
};

And output the information like

void input(int sd, char *buf) {
    int i;
    char *p = buf;
    struct ethheader *eth = (struct ethheader*)buf;
    int len = read(sd, buf, BUF_SIZ);
    if (len < sizeof(struct ethheader)) {
        printf("smaller than an ethernet frame\n");
        return;
    } else {
        char dst[18];
        char src[18];
        for (i = 0; i < 6; i++) {
            sprintf(dst + i * 3, "%02x:", eth->dsta[i]);
            sprintf(src + i * 3, "%02x:", eth->srca[i]);
        }
        dst[17] = '\0';
        src[17] = '\0';
        printf("dst: %s src: %s ", dst, src);
        switch (eth->type) {
        case 0x0800:
            printf("IPv4\n");
            break;
        case 0x0842:
            printf("ARP\n");
            break;
        case 0x86DD:
            printf("IPv6\n");
            break;
        default:
            printf("unknown\n");
            break;
        }
    }
}

The output i receive indicates I am properly printing MAC addresses, I am not properly detecting protocols. I am pretty sure the bug deals with either lvalue byte sizes, or endian order-ness; or both. And it is at this point I feel compelled to ask here how I can better define my structs values, and why my protocol switch is broken?

OK so after reading some comments, I was able to properly read the ethernet type:

struct ethheader {
    unsigned char       dsta[6];
    unsigned char       srca[6];
    unsigned char       type[2];
};
int type = (eth->type[0] << 8) + eth->type[1];

My secondary question remains: How can I better define these structs with more portable types; or am I fine with unsigned char?

8
  • Use correct serialisation technique, not error-prone and non-portable casting. Commented Feb 10, 2016 at 3:04
  • @Olaf Will you elaborate on that? Commented Feb 10, 2016 at 3:12
  • Sorry, no. Using a search engine really is a skill which can be presumed nowadays. I gave you one keyword already. Commented Feb 10, 2016 at 3:15
  • @Olaf OK Thanks. I'm perusing some information already. Commented Feb 10, 2016 at 3:18
  • A struct declaration tells you nothing about the binary format of the data. It is implementation-specific at best, and undefined behavior at worst, and has no place in portable code. IOW, you can't use C struct declarations to unmarshall binary data. You have to manipulate each input byte explicitly to extract the data you need: yes, you do need to read individual bytes to reconstitute words of various lengths, etc. Commented Feb 10, 2016 at 3:23

1 Answer 1

5

If you include <net/ethernet.h> you'll have struct ether_header:

struct ether_header
{
  u_int8_t  ether_dhost[ETH_ALEN];      /* destination eth addr */
  u_int8_t  ether_shost[ETH_ALEN];      /* source ether addr    */
  u_int16_t ether_type;                 /* packet type ID field */
} __attribute__ ((__packed__));

There are library functions you might want to use like:

   #include <netinet/ether.h>

   char *ether_ntoa(const struct ether_addr *addr);

Have you considered using libpcap? It really makes these things easy.

(like getting a tachikoma to do the work for you :)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.