用Pcap获取报文

1.PCAP工作流程

1.选择嗅探的设备(Linux eth0,FreeBSD xll),或者让PCAP选择一个。

2.初始PCAP,通过会话(session)来区分多个嗅探,通过handle来处理嗅探。

3.捕获想要捕获的报文。设置规则集合(RuleSet)–>编译规则–>应用规则

4.嗅探循环,会话会一直等待指定报文的到来。在抓取到报文后可以存储,或者是打印给用户。

5.关闭会话

一、选择嗅探设备
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>


int main(int argc, char *argv[]){

        char *dev, errbuf[PCAP_ERRBUF_SIZE];
        pcap_t *handle;

        dev = pcap_lookupdev(errbuf); // interface
        if (dev == NULL) {
            fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
            return(2);
        }
        printf("Device: %s\n", dev);


        exit(0);
}

二、开启嗅探会话
pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms,
    char *ebuf);
device 是嗅探设备
snaplen捕获报文的最大长度
promisc 混杂模式
to_ms 读取时间间隔
errbuf 错误信息

模式区别:非混杂模式只捕获直连网络的报文
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>

int main(int argc, char *argv[]){


        char *dev, errbuf[PCAP_ERRBUF_SIZE];
        pcap_t *handle;

        dev = pcap_lookupdev(errbuf); // interface
        if (dev == NULL) {
            fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
            return(2);
        }
        printf("Device: %s\n", dev);

        handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
        if (handle == NULL) {
                fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
                return(2);
        }



        exit(0);
}

测试本机是否支持链路层报文

#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>

int main(int argc, char *argv[]){


        char *dev, errbuf[PCAP_ERRBUF_SIZE];
        pcap_t *handle;

        dev = pcap_lookupdev(errbuf); // interface
        if (dev == NULL) {
            fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
            return(2);
        }
        printf("Device: %s\n", dev);

        handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
        if (handle == NULL) {
                fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
                return(2);
        }

if (pcap_datalink(handle) != DLT_EN10MB) {
	fprintf(stderr, "Device %s doesn't provide Ethernet headers - not supported\n", dev);
	return(2);
}

pcap_close(handle);
        exit(0);
}
三、捕获报文
int pcap_compile(pcap_t *p, struct bpf_program *fp,

	const char *str, int optimize, bpf_u_int32 netmask);
	
p是处理会话的handle
fp是存放编译版本的地方
str是过滤规则字符串参见
optimize是否优化
netmask为ipv4的子网掩码
int pcap_setfilter(pcap_t *p, struct bpf_program *fp)
p是会话的handle
fp同pcap_compile()的fp
int pcap_lookupnet(const char *device, bpf_u_int32 *netp,


        bpf_u_int32 *maskp, char *errbuf)

//为指定嗅探设备找到关联的IP地址与子网掩码
device嗅探的设备
netp与maskp都是bpf_u_int32的指针
errbuf是错误信息
#include <stdio.h>
#include <stdlib.h>
#include <pcap.h>

int main(int argc, char *argv[]){

 pcap_t *handle;                 /* Session handle */
        char *dev;                      /* The device to sniff on */
        char errbuf[PCAP_ERRBUF_SIZE];  /* Error string */
        struct bpf_program fp;          /* The compiled filter */
        char filter_exp[] = "port 53";  /* The filter expression */
        bpf_u_int32 mask;               /* Our netmask */
        bpf_u_int32 net;                /* Our IP */
        struct pcap_pkthdr header;      /* The header that pcap gives us */
        const u_char *packet;           /* The actual packet */

        /* Define the device */
        dev = pcap_lookupdev(errbuf);
        if (dev == NULL) {
                fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
                return(2);
        }
        /* Find the properties for the device */
        if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
                fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
                net = 0;
                mask = 0;
        }
        /* Open the session in promiscuous mode */
        handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);
        if (handle == NULL) {
                fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
                return(2);
        }
        /* Compile and apply the filter */
        if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
                fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
                return(2);
        }
        if (pcap_setfilter(handle, &fp) == -1) {
                fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
                return(2);
        }
pcap_close(handle);

exit(0);
}
分析和使用报文
u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)
h是一个有关报文信息的结构体
返回一个指向报文的指针
只返回捕获的第一个
struct pcap_pkthdr {
	struct timeval ts; /* 时间 time stamp */
	bpf_u_int32 caplen; /* 分隔长度 length of portion present */
	bpf_u_int32 len; /* 报文长度 length this packet (off wire) */
};
int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
cnt需要嗅探的报文数目
callback是一个回调函数

回调函数原型
void got_packet(u_char *args, const struct pcap_pkthdr *header,
    const u_char *packet);
args就是user
header是包的结构体信息指针

u_char *packet如何使用?
  1. 首先定义一些需要用的报文的结构体,以及一些宏定义。
/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN	6

/* Ethernet header */
struct sniff_ethernet {
	u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */
	u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */
	u_short ether_type; /* IP? ARP? RARP? etc */
};

/* IP header */
struct sniff_ip {
	u_char ip_vhl;		/* version << 4 | header length >> 2 */
	u_char ip_tos;		/* type of service */
	u_short ip_len;		/* total length */
	u_short ip_id;		/* identification */
	u_short ip_off;		/* fragment offset field */
#define IP_RF 0x8000		/* reserved fragment flag */
#define IP_DF 0x4000		/* don't fragment flag */
#define IP_MF 0x2000		/* more fragments flag */
#define IP_OFFMASK 0x1fff	/* mask for fragmenting bits */
	u_char ip_ttl;		/* time to live */
	u_char ip_p;		/* protocol */
	u_short ip_sum;		/* checksum */
	struct in_addr ip_src,ip_dst; /* source and dest address */
};
#define IP_HL(ip)		(((ip)->ip_vhl) & 0x0f)
#define IP_V(ip)		(((ip)->ip_vhl) >> 4)

/* TCP header */
typedef u_int tcp_seq;

struct sniff_tcp {
	u_short th_sport;	/* source port */
	u_short th_dport;	/* destination port */
	tcp_seq th_seq;		/* sequence number */
	tcp_seq th_ack;		/* acknowledgement number */
	u_char th_offx2;	/* data offset, rsvd */
#define TH_OFF(th)	(((th)->th_offx2 & 0xf0) > 4)
	u_char th_flags;
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
	u_short th_win;		/* window */
	u_short th_sum;		/* checksum */
	u_short th_urp;		/* urgent pointer */
};
  1. 处理方式
/* ethernet headers are always exactly 14 bytes */
#define SIZE_ETHERNET 14

const struct sniff_ethernet *ethernet; /* The ethernet header */
const struct sniff_ip *ip; /* The IP header */
const struct sniff_tcp *tcp; /* The TCP header */
const char *payload; /* Packet payload */

u_int size_ip;
u_int size_tcp;

----------------------------------------------------
ethernet = (struct sniff_ethernet*)(packet);
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
size_ip = IP_HL(ip)*4;
if (size_ip < 20) {
	printf("   * Invalid IP header length: %u bytes\n", size_ip);
	return;
}
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
size_tcp = TH_OFF(tcp)*4;
if (size_tcp < 20) {
	printf("   * Invalid TCP header length: %u bytes\n", size_tcp);
	return;
}
payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);


原文链接: Programming with pcap.
This document is Copyright 2002 Tim Carstens. All rights reserved. Redistribution and use, with or without modification, are permitted provided that the following conditions are met:

Redistribution must retain the above copyright notice and this list of conditions.
The name of Tim Carstens may not be used to endorse or promote products derived from this document without specific prior written permission.
/* Insert ‘wh00t’ for the BSD license here */

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值