Unix环境下C实现网络抓包

拾起去年扔下的UNIX高级环境编程看了下网络编程章节,对着写了点,废话少说.

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ether.h>

#define iip2cip(...) inet_ntoa((struct in_addr){__VA_ARGS__})
#define BUFFER_MAX_SZ 2048

typedef struct mac_frm_hdr { //按照以太网帧格式定义,长度必须一致
    unsigned char dest_addr[6];
    unsigned char src_addr[6];
    unsigned short type;
}__attribute__((packed)) MAC_FRM_HDR;//取消编译器自动优化对齐结构体,保证与帧中的结构一致.

typedef struct ip_hdr{  //只支持IPV4
    unsigned char ver:4, len:4;
    unsigned char  tos;
    unsigned short total_len;
    unsigned short id;
    unsigned short flags;
    unsigned char  ttl;
    unsigned char  protocol;
    unsigned short chksum;
    uint32_t src;
    uint32_t dest;    
}__attribute__((packed)) IP_HDR;


int main(int argc,char *argv[])
{
    int sock_raw_fd = 0,rf_fd = 0,AND_LOGIC = 0xFF;
    unsigned char buf[BUFFER_MAX_SZ] = {0};

    if((sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0){
        perror("create socket failed.\n");
        return -1;
    }
    printf("sock: %d\n",sock_raw_fd);

    MAC_FRM_HDR *mac_hdr;
    IP_HDR *ip_hdr;
    char *tmp1, *tmp2;

    while(1)
    {
        rf_fd = recvfrom(sock_raw_fd,buf,BUFFER_MAX_SZ,0,NULL,NULL);
        mac_hdr = (MAC_FRM_HDR *) buf;
        ip_hdr = (IP_HDR *)(buf + sizeof(MAC_FRM_HDR));

        tmp1 = mac_hdr->src_addr;
        tmp2 = mac_hdr->dest_addr;

        printf("MAC:%.2X:%.2X:%.2X:%.2X:%.2X:%.2X" " -> " "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X  Protocol:",
            tmp1[0]&AND_LOGIC, tmp1[1]&AND_LOGIC, tmp1[2]&AND_LOGIC,tmp1[3]&AND_LOGIC,
            tmp1[4]&AND_LOGIC, tmp1[5]&AND_LOGIC,
            tmp2[0]&AND_LOGIC, tmp2[1]&AND_LOGIC, tmp2[2]&AND_LOGIC,tmp2[3]&AND_LOGIC,
            tmp2[4]&AND_LOGIC, tmp2[5]&AND_LOGIC);
        switch (ip_hdr->protocol)
        {
        case IPPROTO_ICMP: printf("ICMP\n");break;
        case IPPROTO_IGMP: printf("IGMP\n");break;
        case IPPROTO_GRE: printf("GRE\n");break;
        case IPPROTO_IPIP: printf("IPIP\n");break;
        case IPPROTO_TCP:
        case IPPROTO_UDP:
            printf("%s  ",ip_hdr->protocol == IPPROTO_TCP? "TCP":"UDP");
            printf("IP: %s  ->  %s\n",iip2cip((in_addr_t)(ip_hdr->src)),iip2cip((in_addr_t)(ip_hdr->dest)));
            //这儿可以放某些功能的函数,比如过滤某些关键的IP数据包.
            break;
        case IPPROTO_RAW: printf("RAW");break;
        default:
            printf("Other\n");
            break;
        }
    }
    return 0;
}

发现在Ubuntu下需要root权限才可运行,而CentOS下则可以直接运行.