2016-02-10 34 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?它確實使這些事情變得簡單。

(象得到塔奇克馬你:)