Linux系统有线网络抓包程序

来源:互联网 发布:无线网络破解软件 编辑:程序博客网 时间:2024/04/28 07:47

今天心血来潮,玩一玩linux抓包。思路如下:

1、使用raw socket接收网络数据;

2、先解析以太帧头,得到是IP还是ARP包;

3、再解析IP头,知道是UDP还是TCP;

4、再解析UDP、TCP,得到IP地址、端口号等信息。

注意事项:

1、网络传输使用大端字节序,对于如端口号、数据长度等字段,要使用ntohs做转换,否则结果不正确。

2、对于创建raw socket,不同参数得到的数据包不同,如传递ETH_P_IP则不会接收ARP、RARP包。

完整代码:

#include <unistd.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <netdb.h>#include <sys/ioctl.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/ip.h>#include <netinet/tcp.h>#include <netinet/udp.h>#include <netinet/in.h>#include <netpacket/packet.h>#include <net/if.h>#include <arpa/inet.h>#include <net/ethernet.h>#define BUFFER_SIZE 2048int debug_level = 0;#define _AUTHOR "Late Lee"#define _VERSION_STR "1.0"#define _DATE ""// 默认打印error等级enum{    MSG_ERROR = 0,    MSG_WARNING,    MSG_INFO,    MSG_DEBUG,    MSG_MSGDUMP,    MSG_EXCESSIVE, };void ll_printf(int level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));void ll_printf(int level, const char *fmt, ...){    va_list ap;    va_start(ap, fmt);    if (debug_level >= level)    {#ifdef CONFIG_DEBUG_SYSLOG        if (wpa_debug_syslog) {            vsyslog(syslog_priority(level), fmt, ap);        } else {#endif /* CONFIG_DEBUG_SYSLOG */        //debug_print_timestamp();#ifdef CONFIG_DEBUG_FILE        if (out_file) {            vfprintf(out_file, fmt, ap);            fprintf(out_file, "\n");        } else {#endif /* CONFIG_DEBUG_FILE */        vprintf(fmt, ap);        printf("\n");#ifdef CONFIG_DEBUG_FILE        }#endif /* CONFIG_DEBUG_FILE */#ifdef CONFIG_DEBUG_SYSLOG        }#endif /* CONFIG_DEBUG_SYSLOG */    }    va_end(ap);}void show_version(char* name){    printf("%s by %s, version: %s\n", name, _AUTHOR, _VERSION_STR);}const char* my_opt = "hvd:i:";void usage(char* name){    show_version(name);    printf("    -h,    short help\n");    printf("    -v,    show version\n");    printf("    -d,    debug level\n");    printf("    -i,    ethernet device\n");        exit(0);}void dump(const char *buffer, int len){    int i, j, n;    int line = 16;    char c;    unsigned char* buf = (unsigned char *)buffer;    // 必须是unsigned char类型    n = len / line;    if (len % line)        n++;    for (i=0; i<n; i++)    {        //printf("0x%08x: ", (unsigned int)(buf+i*line)); // linux ok        printf("0x%8p: ", buf+i*line); // windows ok                for (j=0; j<line; j++)        {            if ((i*line+j) < len)                printf("%02x ", buf[i*line+j]);            else                printf("   ");        }        printf(" ");        for (j=0; j<line && (i*line+j)<len; j++)        {            if ((i*line+j) < len)            {                c = buf[i*line+j];                printf("%c", c >= ' ' && c < '~' ? c : '.');            }            else                printf("   ");        }        printf("\n");    }}int setPromiscMode(int socket, const char* eth, bool enable){    // 混杂模式    struct ifreq req;    strcpy(req.ifr_name, eth);    ioctl(socket, SIOCGIFFLAGS, &req);        if (enable)    {        req.ifr_flags |= IFF_PROMISC;    }    else    {        req.ifr_flags &= ~IFF_PROMISC;    }        int ret = ioctl(socket, SIOCSIFFLAGS, &req);    if (ret < 0)    {        perror("Set promisc mode failed:");        return -1;    }    return 0;}int initSocket(const char* eth){    int ret = 0;    int fd = -1;        if (eth == NULL)    {        return -1;    }        // 注意与下面绑定时协议一致    fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); // tocheck ETH_P_IP |     if (fd < 0)    {        perror("init socket failed:");        return -1;    }    // 接收buffer大小    int size = BUFFER_SIZE;    ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(int));    if (ret < 0)    {        goto end;    }    // 绑定网卡    struct ifreq req;    strcpy(req.ifr_name, eth);    ioctl(fd, SIOCGIFINDEX, &req);        struct sockaddr_ll addr;    addr.sll_family = PF_PACKET;    addr.sll_ifindex = req.ifr_ifindex;    addr.sll_protocol = htons(ETH_P_IP); // 取决于此处协议 ETH_P_ALL  ETH_P_IP |ETH_P_ARP    ret = bind(fd, (struct sockaddr *)&addr, sizeof(sockaddr_ll));    if (ret < 0)    {        goto end;    }    // 混杂模式    //setPromiscMode(fd, eth, true);end:    if (ret < 0)    {        close(fd);        return ret;    }    else    {        return fd;    }}int deintSocket(int socket){    close(socket);    return 0;}int showMacAddr(const struct ether_header *ethhead){    printf("mac: [%02x:%02x:%02x:%02x:%02x:%02x] --> ",                    ethhead->ether_shost[0], ethhead->ether_shost[1],                    ethhead->ether_shost[2], ethhead->ether_shost[3],                    ethhead->ether_shost[4], ethhead->ether_shost[5]);    printf("mac: [%02x:%02x:%02x:%02x:%02x:%02x]\n",                    ethhead->ether_dhost[0], ethhead->ether_dhost[1],                    ethhead->ether_dhost[2], ethhead->ether_dhost[3],                    ethhead->ether_dhost[4], ethhead->ether_dhost[5]);    return 0;}int parseTcpHeader(const char* buffer){    struct tcphdr* hdr = (struct tcphdr*)buffer;    printf("port: [%d] --> [%d]\n", ntohs(hdr->th_sport), ntohs(hdr->th_dport));    return 0;}int parseUdpHeader(const char* buffer){    const struct udphdr* hdr = reinterpret_cast<const struct udphdr *>(buffer); // (struct udphdr*)buffer;    // 长度字段与实际接收数据不符合,不知原因为何    printf("port: [%d] --> [%d] [%d bytes]\n", ntohs(hdr->uh_sport), ntohs(hdr->uh_dport), ntohs(hdr->uh_ulen));    return 0;}int parseIpHeader(const char* buffer){    if (NULL == buffer)    {        return -1;    }        #if 0    const struct ip* pstIP = reinterpret_cast<const struct ip *>(buffer); //(struct ip *)buffer;        /* 协议类型、源IP地址、目的IP地址 */    struct protoent* pstIpProto = getprotobynumber(pstIP->ip_p);    if(NULL != pstIpProto)    {        printf("%s(%d) ", pstIpProto->p_name, pstIP->ip_p);    }    else    {        printf("%s(%d) ", "None", pstIP->ip_p);    }    printf("ip: [%s] --> ", inet_ntoa(pstIP->ip_src));    printf("[%s]\n", inet_ntoa(pstIP->ip_dst));        struct protoent* pstIpProto = getprotobynumber(hdr->protocol);    if(NULL != pstIpProto)    {        printf("%s(%d) ", pstIpProto->p_name, hdr->protocol);    }    else    {        printf("%s(%d) ", "None", hdr->protocol);    }        #endif        const struct iphdr* hdr = (struct iphdr *)buffer;    struct in_addr saddr;    saddr.s_addr = hdr->saddr;    printf("ip: [%s] --> ", inet_ntoa(saddr));    saddr.s_addr = hdr->daddr;    printf("[%s] [%d bytes] ", inet_ntoa(saddr), ntohs(hdr->tot_len));        switch (hdr->protocol)    {        case IPPROTO_TCP:            printf("TCP\n");            parseTcpHeader(buffer+sizeof(iphdr));            break;        case IPPROTO_UDP:            printf("UDP\n");            parseUdpHeader(buffer+sizeof(iphdr));            break;        case IPPROTO_ICMP:            printf("ICMP\n");            break;        case IPPROTO_IGMP:            printf("IGMP\n");            break;        default:            break;    }    #if 0    if ( == IPPROTO_TCP)    {        printf("TCP\n");        parseTcpHeader(buffer+sizeof(iphdr));    }    if (hdr->protocol == IPPROTO_UDP)    {        printf("UDP\n");        parseUdpHeader(buffer+sizeof(iphdr));    }    if (hdr->protocol == IPPROTO_ICMP)    {        printf("ICMP\n");    }    if (hdr->protocol == IPPROTO_IGMP)    {        printf("IGMP\n");    }    #endif        return 0;}int parsePakcet(const char* buffer){    if (buffer == NULL)    {        return -1;    }        const struct ether_header *ethhead = reinterpret_cast<const struct ether_header *>(buffer); //(struct ether_header*)buffer;    ///////////////////    int type = ntohs(ethhead->ether_type);    if (type == ETHERTYPE_ARP)    {        printf("ethnet type: ARP\n");        showMacAddr(ethhead);    }    if (type == ETHERTYPE_IP)    {        //printf("ethnet type: IP\n");        showMacAddr(ethhead);        parseIpHeader(buffer+sizeof(struct ether_header));    }        //printf("-------------------------------------------\n");        return 0;}int startCapture(int socket){    int ret = 0;    socklen_t len = sizeof(struct sockaddr);    char buffer[BUFFER_SIZE] = {0};        while (1)    {        memset(buffer, '\0', BUFFER_SIZE);        ret = recvfrom(socket, buffer, BUFFER_SIZE, 0, NULL, &len);        if (ret < 0)        {            continue;        }        //printf("--recv len: %d\n", ret);        if (debug_level)            dump(buffer, ret);        parsePakcet(buffer);        usleep(10*1000);    }        return 0;}int main(int argc, char* argv[]){    char eth[8] = "eth0";        while(1)    {        int c = getopt(argc, argv, my_opt);        ll_printf(8, "option char: %x %c\n", c, c);        if (c < 0)        {            break;        }        switch(c)        {        case 'd':                debug_level = atoi(optarg);                //printf("debug level: %d\n", debug_level);                break;        case 'i':                strncpy(eth, optarg, 8);                break;        case '?':        case 'h':        default:                usage(argv[0]);                break;        }    }        printf("Start capture on %s\n", eth);    int socket = initSocket(eth);    if (socket < 0)    {        printf("Init socket failed.\n");        return -1;    }    startCapture(socket);    return 0;}

注:为什么要表明“有线网络”?因为还要做无线网络抓包。


李迟 2016.9.6 周二 夜

0 0
原创粉丝点击