WinPcap编程(三)

1.过滤器设置

  设置过滤器,得到你想要的哪种类型的包。Like WireShark。

  过程:编译过滤器,然后设置过滤器。直接上参考文档的代码:

  

    if (d->addresses != NULL)
        /* 获取接口第一个地址的掩码 */
        netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    else
        /* 如果这个接口没有地址,那么我们假设这个接口在C类网络中 */
        netmask=0xffffff; 

compile the filter
    if (pcap_compile(adhandle, &fcode, "ip and tcp", 1, netmask) < 0)
    {
        fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

set the filter
    if (pcap_setfilter(adhandle, &fcode) < 0)
    {
        fprintf(stderr,"\nError setting the filter.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

2.分析数据包

  只需要知道怎么构造,然后怎么处理就可以了。

源码:

#define WIN32
#include "pcap.h"

typedef struct mac{
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
    u_char byte5;
    u_char byte6;
}mac;

typedef struct eth_header{
    mac dmac;
    mac smac;
    u_short type;
}eth_header;

/* 4字节的IP地址 */
typedef struct ip_address{
    u_char byte1;
    u_char byte2;
    u_char byte3;
    u_char byte4;
}ip_address;

/* IPv4 首部 */
typedef struct ip_header{
    u_char  ver_ihl;        // 版本 (4 bits) + 首部长度 (4 bits)
    u_char  tos;            // 服务类型(Type of service)
    u_short tlen;           // 总长(Total length)
    u_short identification; // 标识(Identification)
    u_short flags_fo;       // 标志位(Flags) (3 bits) + 段偏移量(Fragment offset) (13 bits)
    u_char  ttl;            // 存活时间(Time to live)
    u_char  proto;          // 协议(Protocol)
    u_short crc;            // 首部校验和(Header checksum)
    ip_address  saddr;      // 源地址(Source address)
    ip_address  daddr;      // 目的地址(Destination address)
    u_int   op_pad;         // 选项与填充(Option + Padding)
}ip_header;

/* UDP 首部*/
typedef struct udp_header{
    u_short sport;          // 源端口(Source port)
    u_short dport;          // 目的端口(Destination port)
    u_short len;            // UDP数据包长度(Datagram length)
    u_short crc;            // 校验和(Checksum)
}udp_header;

/* 回调函数原型 */
void packet_handler2(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);

int main()
{
    pcap_if_t *alldevs;
    pcap_if_t *d;

    int inum;
    int i = 0;
    pcap_t *adhandle;
    char errbuf[PCAP_ERRBUF_SIZE];
    u_int netmask;
    char packet_filter[] = "ip";
    struct bpf_program fcode;

    /* 获得设备列表 */
    if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
    {
        fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf);
        exit(1);
    }

    /* 打印列表 */
    for (d = alldevs; d; d = d->next)
    {
        printf("%d. %s", ++i, d->name);
        if (d->description)
            printf(" (%s)\n", d->description);
        else
            printf(" (No description available)\n");
    }

    if (i == 0)
    {
        printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
        return -1;
    }

    printf("Enter the interface number (1-%d):", i);
    scanf_s("%d", &inum);

    if (inum < 1 || inum > i)
    {
        printf("\nInterface number out of range.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    /* 跳转到已选设备 */
    for (d = alldevs, i = 0; i< inum - 1; d = d->next, i++);

    /* 打开适配器 */
    //if ((adhandle = pcap_open(d->name,  // 设备名
    //    65536,     // 要捕捉的数据包的部分
    //    // 65535保证能捕获到不同数据链路层上的每个数据包的全部内容
    //    PCAP_OPENFLAG_PROMISCUOUS,         // 混杂模式
    //    0,      // 读取超时时间
    //    NULL,      // 远程机器验证
    //    errbuf     // 错误缓冲池
    //    )) == NULL)
    if ((adhandle = pcap_open_live(d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS,0,errbuf)) == NULL)
    {
        fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    /* 检查数据链路层,为了简单,我们只考虑以太网 */
    //if (pcap_datalink(adhandle) != DLT_EN10MB)
    //{
    //    fprintf(stderr, "\nThis program works only on Ethernet networks.\n");
    //    /* 释放设备列表 */
    //    pcap_freealldevs(alldevs);
    //    return -1;
    //}

    if (d->addresses != NULL)
        /* 获得接口第一个地址的掩码 */
        netmask = ((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
    else
        /* 如果接口没有地址,那么我们假设一个C类的掩码 */
        netmask = 0xffffff;

    //编译过滤器
    if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0)
    {
        fprintf(stderr, "\nUnable to compile the packet filter. Check the syntax.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    //设置过滤器
    if (pcap_setfilter(adhandle, &fcode)<0)
    {
        fprintf(stderr, "\nError setting the filter.\n");
        /* 释放设备列表 */
        pcap_freealldevs(alldevs);
        return -1;
    }

    printf("\nlistening on %s...\n", d->description);

    /* 释放设备列表 */
    pcap_freealldevs(alldevs);

    /* 开始捕捉 */
    pcap_loop(adhandle, 0, packet_handler2, NULL);
    system("pause");
    return 0;
}

/* 回调函数,当收到每一个数据包时会被libpcap所调用 */
void packet_handler2(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
    struct tm ltime;
    char timestr[16];
    time_t local_tv_sec;

    eth_header *eh;

    ip_header *ih;
    udp_header *uh;

    u_int ip_len;
    u_short sport=0, dport=0;

    int i;

    /* 将时间戳转换成可识别的格式 */
    local_tv_sec = header->ts.tv_sec;
    localtime_s(&ltime,&local_tv_sec);
    strftime(timestr, sizeof timestr, "%H:%M:%S", &ltime);

    /* 打印数据包的时间戳和长度 */
    printf("Time Stamp:%s.%.6d \nLength:%d \n", timestr, header->ts.tv_usec, header->len);

    ///*获得以太网帧的首部*/
    //eh = (eth_header *)(pkt_data);

    ///* 获得IP数据包头部的位置 */
    //ih = (ip_header *)(pkt_data +
    //    14); //以太网头部长度

    ///* 获得UDP首部的位置
    //IP数据报头部是4bits,单位是32bit(4个字节)
    //一个IP包头的长度最长为“1111”,即15*4=60个字节。IP包头最小长度为20字节。
    //*/
    //ip_len = (ih->ver_ihl & 0xf) * 4;
    //uh = (udp_header *)((u_char*)ih + ip_len);

    ///* 将网络字节序列转换成主机字节序列 */
    //sport = ntohs(uh->sport);
    //dport = ntohs(uh->dport);

    /*打印数据包的数据*/
    printf("\nDATA:");
    for (i = 0; i< header->len; ++i)
    {
        printf(" %02x", pkt_data[i]);
        if ((i + 1) % 16 == 0)
        {
            printf("\n");
        }
    }

    /*打印MAC地址*/
    //printf("\nDestination: %02x-%02x-%02x-%02x-%02x-%02x",
    //    eh->dmac.byte1,
    //    eh->dmac.byte2,
    //    eh->dmac.byte3,
    //    eh->dmac.byte4,
    //    eh->dmac.byte5,
    //    eh->dmac.byte6);
    //printf("\nResources: %02x-%02x-%02x-%02x-%02x-%02x",
    //    eh->smac.byte1,
    //    eh->smac.byte2,
    //    eh->smac.byte3,
    //    eh->smac.byte4,
    //    eh->smac.byte5,
    //    eh->smac.byte6);
    ///* 打印IP地址和UDP端口 */
    //printf("\nIP ADDRESS:%d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\nUDP LENGTH:%d\n",
    //    ih->saddr.byte1,
    //    ih->saddr.byte2,
    //    ih->saddr.byte3,
    //    ih->saddr.byte4,
    //    sport,
    //    ih->daddr.byte1,
    //    ih->daddr.byte2,
    //    ih->daddr.byte3,
    //    ih->daddr.byte4,
    //    dport,
    //    ih->tlen);
}

3.发送包比较简单,就不多说了。

时间: 2024-10-28 15:04:48

WinPcap编程(三)的相关文章

WinPcap编程(二)

0. 这一次具体讲抓包的两种方法. 不过说明之前得知道几点: 第一,无线网卡的包需要特定网卡驱动才能抓到. 第二,抓以太网上的包的时候,需要禁用无线网卡.(这一点没搞清楚原因,有了解的希望能给个答案,解个惑.感谢.回学校了问问老师.) 第三,(建议)清除ARP表,最好自己写个批处理命令.快一点. 1.0 抓包步骤 步骤很简单:先打开适配器列表 --> 选择适配器 --> 通过遍历链表的方式到达你选择的适配器位置 --> 打开设备 --> 开始抓包. 每一个步骤都是一个函数.了解步骤

ILGenerator.Emit动态 MSIL编程(三)之动态代理

using System; using System.Linq; using System.Reflection; using System.Reflection.Emit; public sealed class DynamicProxy { private static readonly string AssemblyName = "DynamicProxy", ModuleName = "DynamicProxy", TypeName = "Dyna

Win32 Windows编程 三

一.NMAKE 和 Makefile 1.1  NMAKE - 命令解释器, 根据Makefile文件中定义的脚本,完成项目的编译等操作 1.2 Makefile - 定义编译.连接等脚本语言 1.3 Makefile 文件的使用 1.3.1 基本语法规则 window.exe:window.obj //依赖行 cl.exe window.c /c   //命令行 link.exe window.obj user32.lib window.exe 的依赖项是window.obj,如果window

网络编程模型及网络编程三要素

网络模型 计算机网络之间以何种规则进行通信,就是网络模型研究问题. 网络模型一般是指 OSI(Open SystemInterconnection开放系统互连)参考模型 TCP/IP参考模型 网络模型7层概述: 1.物理层:主要定义物理设备标准,如网线的接口类型.光纤的接口类型.各种传输介质的传输速率等.它的主要作用是传输比特流(就是由1.0转化为电流强弱来进行传输,到达目的地后在转化为1.0,也就是我们常说的数模转换与模数转换).这一层的数据叫做比特. 2. 数据链路层:主要将从物理层接收的数

iOS网络编程(三) 异步加载及缓存图片----&gt;SDWebImage

@SDWebImage提供一个UIImageView的类别以支持加载来自网络的远程图片.具有缓存管理.异步下载.同一个URL下载次数控制和优化等特征. @SDWebImage的导入1.https://github.com/rs/SDWebImage 下载SDWebImage开源包2.将类包拖入工程,再导入MapKit.framework.ImageIO.framework两个框架3.SDWebImage是支持ARC的,在MRC的工程中要注意,可参考MRC工程配置ARC4.注意:SDWebImag

java面向对象编程(三)--类变量、类方法

1.什么是类变量? 类变量是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量. 如何定义类变量? 定义语法:     访问修饰符 static 数据类型 变量名; 如何访问类变量?     类名.类变量名 或者 对象名.类变量名 案例:有一群小孩玩堆雪人,不时有新的小朋友加入,请问如何知道现在共有多少人在玩?请使用面向对象的思想,编写程序解决. public class Demo113{ public static

java面向对象编程(三)--this

看一段代码:(Demo112.java),先了解为什么要使用this. /* this的必要性 */ public class Demo112{ public static void main(String []args){ Dog dog1=new Dog(2,"大黄"); Person p1=new Person(dog1,23,"刚子"); Person p2=new Person(dog1,24,"小龙"); p1.showInfo();

winform网络编程(三)

TcpClient类和TcpListener类 (1)TcpClient的用途: 用于在同步阻止模式下通过网络来链接.发送和接受流数据,在此情况下,必须有侦听此连接的请求,而侦听的任务就交给TcpListener实例或Socket实例 (2)TcpClient的两种方法连接到侦听器 第一种:创建一个TcpClient,并调用3个可用的Connect方法之一 第二种:使用远程主机的主机名和端口号创建TcpClient,此构造函数将自动尝试一个连接 (3)TcpClient的常用属性和方法 Avai

Java并发编程三个性质:原子性、可见性、有序性

并发编程 并发程序要正确地执行,必须要保证其具备原子性.可见性以及有序性:只要有一个没有被保证,就有可能会导致程序运行不正确 线程不安全在编译.测试甚至上线使用时,并不一定能发现,因为受到当时的CPU调度顺序,线程个数.指令重排的影响,偶然触发 线程安全的定义 比如说一个类,不论通过怎样的调度执行顺序,并且调用处不用对其进行同步操作,其都能表现出正确的行为,则这个类就是线程安全的 并发编程三个概念 原子性: 一个操作或多个操作要么全部执行且执行过程不被中断,要么不执行 可见性: 多个线程修改同一

网络编程三素概述

1.1网络编程概述计算机网络 ●是指将地理位置不同的具有独立功能的多 台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统 网络编程●在网络通信协议下, 实现网络互连的不同计算机上运行的程序间可以进行数据交换 网络编程三要素 IP地址●要想让网络中的计算 机能够互相通信,必须为每台计算机指定一个标识号, 通过这个标识号来指定要接收数据的计算机和识别发送的计算机,而IP地址就是这个标识号.也就是设备的标识 端口●网