2016-02-10 20 views
1

我有看似简单的任务,即打印有关通过特定以太网接口的帧的非常基本的信息。我有一个插座定义为解析以太网帧和数据类型

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

我环路我的输入,像这样

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

这是我有问题。我定义了以太网标题中的每个帧被铸造成与struct

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

并输出信息等

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

我接收指示我正确打印的MAC地址的输出,我不正确检测的协议。我很确定这个bug处理的是左值字节大小还是endian order-ness;或两者。在这一点上,我不得不在此问一问,我可以如何更好地定义我的struct的值,以及为什么我的协议switch被破坏?

行,所以读了一些意见之后,我能够正确读取以太网类型:

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

我二次的问题是:我怎样才能更好地定义这些struct s的更便携的类型;或者我很好,unsigned char

+0

使用正确的序列化技术做的工作,不容易出错和非便携式铸造。 – Olaf

+0

@Olaf你会详细解释一下吗? – motoku

+0

对不起,没有。使用搜索引擎确实是一项现在可以推测的技能。我已经给你一个关键字。 – Olaf

回答

2

如果包括<net/ethernet.h>你必须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__)); 

有你可能想使用像库函数:

#include <netinet/ether.h> 

    char *ether_ntoa(const struct ether_addr *addr); 

你有没有考虑过使用libpcap?它确实使这些事情变得简单。

(象得到塔奇克马你:)