注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

linux 学习

 
 
 

日志

 
 

【转】基于Linux Socket实现的网卡抓包程序  

2011-04-08 16:48:37|  分类: 应用编程 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
【前言】通过对数据包的分析,我们可以判断通信双方的操作系统、网络信息流量、经过的路由、数据包的大小,以及数据包的内容等等。尤其对于喜欢网络安全的人来说,掌握这方面的知识是相当重要的。本文介绍一个基于Linux平台实现的网络抓包工具。
 
0.基础知识
    在Linux环境下,可以使用raw socket,即原始套接字,接收本机网卡上的数据帧或者数据包,实现对与监听网络的流量和分析是很有作用的。一共可以有3种方式创建这种socket:  1.socket(AF_INET, SOCK_RAW, IPPROTO_TCP|IPPROTO_UDP|IPPROTO_ICMP)发送接收ip数据包  2.socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))发送接收以太网数据帧  3.socket(AF_INET, SOCK_PACKET, htons(ETH_P_IP|ETH_P_ARP|ETH_P_ALL))过时了,不要用啊
 
1.程序代码

/********************************************************
 * 功能:网络抓包工具
 * 环境: GCC-4.2.4 
 * 作者:YSQ-NJUST,yushengqiangyu@163.com
 * 备注:自由软件,主要用于学习、交流、共享。
 *******************************************************/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netpacket/packet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <errno.h>

/* 接收缓冲区大小 */
#define RCV_BUF_SIZE     1024 * 5

/* 接收缓冲区 */
static int g_iRecvBufSize = RCV_BUF_SIZE; 
static char g_acRecvBuf[RCV_BUF_SIZE] = {0};

/* 物理网卡接口,需要根据具体情况修改 */
static const char *g_szIfName = "eth1";
 
/* 以太网帧封装的协议类型 */
static const int      g_iEthProId[] = { ETHERTYPE_PUP, 
                                        ETHERTYPE_SPRITE, 
                                        ETHERTYPE_IP, 
                                        ETHERTYPE_ARP,
                                        ETHERTYPE_REVARP,
                                        ETHERTYPE_AT,
                                        ETHERTYPE_AARP,
                                        ETHERTYPE_VLAN,
                                        ETHERTYPE_IPX,
                                        ETHERTYPE_IPV6,
                                        ETHERTYPE_LOOPBACK
                                      };
static const char g_szProName[][24] = { "none", "xerox pup", "sprite", "ip", "arp", 
                                        "rarp", "apple-protocol", "apple-arp", 
                                        "802.1q", "ipx", "ipv6", "loopback" 
                                      };


/* 输出MAC地址 */
static void ethdump_showMac(const int iType, const char acHWAddr[]) 
{
    int i = 0;

    if (0 == iType)
    {
        printf("SMAC=[");
    }
    else
    {
        printf("DMAC=[");
    }

    for(i = 0; i < ETHER_ADDR_LEN - 1; i++)
    {
        printf("%02x:", *((unsigned char *)&(acHWAddr[i])));
    }
    printf("%02x] ", *((unsigned char *)&(acHWAddr[i])));
}

/* 物理网卡混杂模式属性操作 */
static int ethdump_setPromisc(const char *pcIfName, int fd, int iFlags)
{
    int iRet = -1;
    struct ifreq stIfr;

    /* 获取接口属性标志位 */
    strcpy(stIfr.ifr_name, pcIfName);
    iRet = ioctl(fd, SIOCGIFFLAGS, &stIfr);
    if (0 > iRet)
    {
        perror("[Error]Get Interface Flags");    
        return -1;
    }
    
    if (0 == iFlags)
    {
        /* 取消混杂模式 */
        stIfr.ifr_flags &= ~IFF_PROMISC;
    }
    else
    {
        /* 设置为混杂模式 */
        stIfr.ifr_flags |= IFF_PROMISC;
    }

    iRet = ioctl(fd, SIOCSIFFLAGS, &stIfr);
    if (0 > iRet)
    {
        perror("[Error]Set Interface Flags");
        return -1;
    }
    
    return 0;
}

/* 获取L2帧封装的协议类型 */
static char *ethdump_getProName(const int iProNum)
{
    int iIndex = 0; 
    
    for(iIndex = 0; iIndex < sizeof(g_iEthProId) / sizeof(g_iEthProId[0]); iIndex++)
    {
        if (iProNum == g_iEthProId[iIndex])
        {
            break;
        }
    }

    return (char *)(g_szProName[iIndex + 1]);
}

/* Init L2 Socket */
static int ethdump_initSocket()
{
    int iRet = -1;
    int fd = -1;
    struct ifreq stIf;
    struct sockaddr_ll stLocal = {0};
    
    /* 创建SOCKET */
    fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (0 > fd)
    {
        perror("[Error]Initinate L2 raw socket");
        return -1;
    }
    
    /* 网卡混杂模式设置 */
    ethdump_setPromisc(g_szIfName, fd, 1);

    /* 设置SOCKET选项 */
    iRet = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &g_iRecvBufSize,sizeof(int));
    if (0 > iRet)
    {
        perror("[Error]Set socket option");
        close(fd);
        return -1; 
    }
    
    /* 获取物理网卡接口索引 */
    strcpy(stIf.ifr_name, g_szIfName);
    iRet = ioctl(fd, SIOCGIFINDEX, &stIf);
    if (0 > iRet)
    {
        perror("[Error]Ioctl operation");
        close(fd);
        return -1;
    }

    /* 绑定物理网卡 */
    stLocal.sll_family = PF_PACKET;
    stLocal.sll_ifindex = stIf.ifr_ifindex;
    stLocal.sll_protocol = htons(ETH_P_ALL);
    iRet = bind(fd, (struct sockaddr *)&stLocal, sizeof(stLocal)); 
    if (0 > iRet)
    {
        perror("[Error]Bind the interface");
        close(fd);
        return -1;
    }
    
    return fd;    
}

/* 解析Ethernet帧首部 */
static int ethdump_parseEthHead(const struct ether_header *pstEthHead)
{
    unsigned short usEthPktType;

    if (NULL == pstEthHead)
    {
        return -1;
    }

    /* 协议类型、源MAC、目的MAC */
    usEthPktType = ntohs(pstEthHead->ether_type);
    printf(">>>\nEth-Pkt-Type:0x%04x(%s) ", usEthPktType, ethdump_getProName(usEthPktType));
    ethdump_showMac(0, pstEthHead->ether_shost);
    ethdump_showMac(1, pstEthHead->ether_dhost);
    
    return 0;    
}

/* 解析IP数据包头 */
static int ethdump_parseIpHead(const struct ip *pstIpHead)
{
    struct protoent *pstIpProto = NULL;

    if (NULL == pstIpHead)
    {
        return -1;
    }

    /* 协议类型、源IP地址、目的IP地址 */
    pstIpProto = getprotobynumber(pstIpHead->ip_p);
    if(NULL != pstIpProto)
    {
        printf("\nIP-Pkt-Type:%d(%s) ", pstIpHead->ip_p, pstIpProto->p_name);
    }
    else
    {
        printf("\nIP-Pkt-Type:%d(%s) ", pstIpHead->ip_p, "None");
    }
    printf("SAddr=[%s] ", inet_ntoa(pstIpHead->ip_src));
    printf("DAddr=[%s]\n", inet_ntoa(pstIpHead->ip_dst));

    return 0;
}

/* 数据帧解析函数 */
static int ethdump_parseFrame(const char *pcFrameData)
{
    int iRet = -1;

    struct ether_header *pstEthHead = NULL;
    struct ip *pstIpHead = NULL;

    /* Ethnet帧头解析 */
    pstEthHead = (struct ether_header*)g_acRecvBuf;
    iRet = ethdump_parseEthHead(pstEthHead);
    if (0 > iRet)
    {
        return iRet;
    }

    /* IP数据包类型 */
    pstIpHead  = (struct ip *)(pstEthHead + 1);
    iRet = ethdump_parseIpHead(pstIpHead);

    return iRet;
}

/* 捕获网卡数据帧 */
static void ethdump_startCapture(const int fd)
{
    int iRet = -1;
    socklen_t stFromLen = 0;
    
    /* 循环监听 */
    while(1)
    {
        /* 清空接收缓冲区 */
        memset(g_acRecvBuf, 0, RCV_BUF_SIZE);

        /* 接收数据帧 */
        iRet = recvfrom(fd, g_acRecvBuf, g_iRecvBufSize, 0, NULL, &stFromLen);
        if (0 > iRet)
        {
            continue;
        }
        
        /* 解析数据帧 */
        ethdump_parseFrame(g_acRecvBuf);
    }
}   

/* Main */
int main(int argc, char *argv[])
{
    int iRet = -1;
    int fd   = -1;
    
    /* 初始化SOCKET */
    fd = ethdump_initSocket();
    if(0 > fd)
    {
        return -1;
    }
    
    /* 捕获数据包 */
    ethdump_startCapture(fd);
    
    /* 关闭SOCKET */
    close(fd);

    return 0;
}

 
2.编译命令

sudo gcc -g -o dump dump.c

sudo ./dump

3.运行效果
 

...

 

>>>Eth-Pkt-Type:0x0800(ip) SMAC=[00:1a:92:ef:b6:dd] DMAC=[00:24:7e:dc:99:18] IP-Pkt-Type:6(tcp) SAddr=[192.168.0.111] DAddr=[192.168.0.100]

>>> Eth-Pkt-Type:0x0800(ip) SMAC=[00:24:7e:dc:99:18] DMAC=[00:1a:92:ef:b6:dd] IP-Pkt-Type:6(tcp) SAddr=[192.168.0.100] DAddr=[192.168.0.111]

>>> Eth-Pkt-Type:0x0800(ip) SMAC=[00:24:7e:dc:99:18] DMAC=[00:1a:92:ef:b6:dd] IP-Pkt-Type:1(icmp) SAddr=[192.168.0.100] DAddr=[192.168.0.111]

>>> Eth-Pkt-Type:0x0800(ip) SMAC=[00:1a:92:ef:b6:dd] DMAC=[00:24:7e:dc:99:18] IP-Pkt-Type:1(icmp) SAddr=[192.168.0.111] DAddr=[192.168.0.100]

>>> Eth-Pkt-Type:0x0800(ip) SMAC=[00:1a:92:ef:b6:dd] DMAC=[00:24:7e:dc:99:18] IP-Pkt-Type:6(tcp) SAddr=[192.168.0.111] DAddr=[192.168.0.100]

 

...

  评论这张
 
阅读(3151)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018