Ubuntu 20.04。

起步

一、下载libpcap 库

前往http://www.tcpdump.org/release/ ,下载格式为xxxx.tar.gz的文件。

二、安装

  1. 解压文件到你的当前目录
tar zxvf xxxx.tar.gz
  1. 进入刚才解开的libpcap目录,生成Makefile文件
sudo ./configure

配置过程如果出现错误,
请查看你是否安装了所有的依赖包bison, m4, flex以及libpcap-dev(安装方法 sudo apt install ****)
尝试运行 sudo apt install bison m4 flex libpcap-dev -y

  1. 将生成的库安装到系统默认目录中。此目录为 /usr/lib ,如果需要修改,可以修改文件Makefile 的 prefix。
sudo make install

三、使用

  1. 编译选项:
gcc 源文件.c -lpcap -o 输出文件名
  1. Warning不用管:

  2. 测试程序:

#include <pcap.h>
#include <stdio.h> int main()
{
char errBuf[PCAP_ERRBUF_SIZE], * device;
//look for the net device
device = pcap_lookupdev(errBuf); if(device)
{
printf("success: device: %s\n", device);
}
else
{
printf("error: %s\n", errBuf);
} return 0;
}
  1. 测试程序运行结果:

完整程序 (们)

注意,
解析报文的时候,
结构体很可能因为字节对齐出现问题!
如下:

struct CAN_layer{
u_int16_t pkg_type;
u_int16_t layer_addr_type;
u_int16_t layer_addr_len;
u_int64_t unused; //。。。字节对齐
u_int16_t protocol;
};

应改写成:

struct CAN_layer{
u_int16_t pkg_type;
u_int16_t layer_addr_type;
u_int16_t layer_addr_len;
u_char unused[8]; //。。。字节对齐
u_int16_t protocol;
};

1. 头文件集锦

myheader.h

/* ethernet headers are always exactly 14 bytes [1] */
#define SIZE_ETHERNET 14 /* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN 6 #define PACKET_LEN 1500 /* Ethernet header */
struct ethheader {
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 ipheader {
unsigned char iph_ihl:4, iph_ver:4; //IP Header length & Version.
unsigned char iph_tos; //Type of service
unsigned short int iph_len; //IP Packet length (Both data and header)
unsigned short int iph_ident; //Identification
unsigned short int iph_flag:3, iph_offset:13; //Flags and Fragmentation offset
unsigned char iph_ttl; //Time to Live
unsigned char iph_protocol; //Type of the upper-level protocol
unsigned short int iph_chksum; //IP datagram checksum
struct in_addr iph_sourceip; //IP Source address (In network byte order)
struct in_addr iph_destip;//IP Destination address (In network byte order)
}; /* ICMP Header */
struct icmpheader {
unsigned char icmp_type; //ICMP message type
unsigned char icmp_code; //Error code
unsigned short int icmp_chksum; //Checksum for ICMP Header and data
unsigned short int icmp_id; //Used in echo request/reply to identify request
unsigned short int icmp_seq;//Identifies the sequence of echo messages,
//if more than one is sent.
}; /* TCP Header */
struct tcpheader {
u_short tcp_sport; /* source port */
u_short tcp_dport; /* destination port */
u_int tcp_seq; /* sequence number */
u_int tcp_ack; /* acknowledgement number */
u_char tcp_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->tcp_offx2 & 0xf0) >> 4)
u_char tcp_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 tcp_win; /* window */
u_short tcp_sum; /* checksum */
u_short tcp_urp; /* urgent pointer */
}; /* UDP Header */
struct udpheader
{
u_int16_t udp_sport; /* source port */
u_int16_t udp_dport; /* destination port */
u_int16_t udp_ulen; /* udp length */
u_int16_t udp_sum; /* udp checksum */
}; struct pseudo_tcp
{
unsigned saddr, daddr;
unsigned char mbz;
unsigned char ptcl;
unsigned short tcpl;
struct tcpheader tcp;
char payload[PACKET_LEN];
}; // DNS layer header's structure
struct dnsheader {
unsigned short int query_id;
unsigned short int flags;
unsigned short int QDCOUNT;
unsigned short int ANCOUNT;
unsigned short int NSCOUNT;
unsigned short int ARCOUNT;
};

2. 打印报文内容

sniff.c

#include <pcap.h>
#include <stdio.h>
#include <arpa/inet.h>
#include "myheader.h"
#include <ctype.h> /* This function will be invoked by pcap for each captured packet.
We can process each packet inside the function. */ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
int i=0;
int size_data=0;
printf("\nGot a packet\n");
struct ethheader *eth=(struct ethheader *)packet; if(ntohs(eth->ether_type) == 0x800)
{
struct ipheader *ip = (struct ipheader *)(packet + sizeof(struct ethheader));
printf(" From: %s\n",inet_ntoa(ip->iph_sourceip));
printf(" To: %s\n",inet_ntoa(ip->iph_destip)); struct tcpheader *tcp = (struct tcpheader *)(packet + sizeof(struct ethheader) + sizeof(struct ipheader)); printf(" Source Port: %d\n",ntohs(tcp->tcp_sport));
printf(" Destination Port: %d\n",ntohs(tcp->tcp_dport)); switch(ip->iph_protocol) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
break;
case IPPROTO_UDP:
printf(" Protocol: UDP\n");
break;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
break;
default:
printf(" Protocol: Others\n");
break;
} char *data = (u_char *)packet + sizeof(struct ethheader) + sizeof(struct ipheader) + sizeof(struct tcpheader);
size_data = ntohs(ip->iph_len) - (sizeof(struct ipheader) + sizeof(struct tcpheader));
if (size_data > 0) {
printf(" Payload (%d bytes):\n", size_data);
for(i = 0; i < size_data; i++) {
if (isprint(*data))
printf("%c", *data);
else
printf(".");
data++;
}
}
} return; } int main()
{
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
char filter_exp[] = "proto TCP and dst portrange 10-100";
bpf_u_int32 net; // Step 1: Open live pcap session on NIC with interface name
handle = pcap_open_live("enp0s3", BUFSIZ, 1, 1000, errbuf); // Step 2: Compile filter_exp into BPF psuedo-code
pcap_compile(handle, &fp, filter_exp, 0, net);
pcap_setfilter(handle, &fp); // Step 3: Capture packets
pcap_loop(handle, -1, got_packet, NULL); pcap_close(handle); //Close the handle
return 0;
}

3. 嗅探与伪造

icmpspoof.c

#include <pcap.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h> #include "myheader.h" char DEST_IP[]="172.17.0.2"; //被欺骗机docker的IP地址 unsigned short in_cksum(unsigned short *buf,int length);
void send_raw_ip_packet(struct ipheader* ip);
void send_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet); int main(){
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
//设置报文过滤条件:来源于docker的icmp请求报文
char* filter_exp = "(icmp[0] == 8) && (src 172.17.0.2)";
printf("filter: %s\n",filter_exp); bpf_u_int32 net;
send_packet();
// Step 1: 用网卡名字docker0打开pcap会话
handle = pcap_open_live("docker0", BUFSIZ, 1, 1000, errbuf); // Step 2: 为侦听进程(bpf_program)fp添加过滤条件
pcap_compile(handle, &fp, filter_exp, 0, net);
pcap_setfilter(handle, &fp); // Step 3: 抓取报文,回调函数send_packet,功能是抓取到请求报文时发欺骗答复包
pcap_loop(handle, -1, send_packet, NULL); pcap_close(handle); //关闭句柄 return 0;
} /******************************************************************
抓取到请求报文时,伪造并发送欺骗答复包
*******************************************************************/
void send_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet){
//获得真实请求报文的IP头和ICMP头
struct ipheader *ip_true=(struct ipheader *)(packet+sizeof(struct ethheader));
struct icmpheader *icmp_true=(struct icmpheader *)(packet+sizeof(struct ethheader)+sizeof(struct ipheader));
printf("Get a icmp request packet from %s,to %s\n",DEST_IP,inet_ntoa(ip_true->iph_destip));
printf("Send a cheat reply.\n"); char buffer[PACKET_LEN];
memset(buffer, 0, PACKET_LEN); // 构造ICMP头
struct icmpheader *icmp;
icmp = (struct icmpheader *)(buffer + sizeof(struct ipheader)); icmp->icmp_type = 0; //设置类型为答复 // 计算icmp的数据校验位(调用in_cksum函数)
icmp->icmp_chksum = 0;
icmp->icmp_chksum = in_cksum((unsigned short *)icmp,
sizeof(struct icmpheader)); // 将真实的ICMP头的id和seq填入伪造的ICMP头中,显得更真实一些
icmp->icmp_id = icmp_true->icmp_id;
icmp->icmp_seq = icmp_true->icmp_seq; // 构造IP头,填入常规参数
struct ipheader *ip = (struct ipheader *) buffer;
ip->iph_ver = 4;
ip->iph_ihl = 5;
ip->iph_tos = 16;
ip->iph_ident = htons(54321);
ip->iph_ttl = 128;
// 设置源地址为真实地址的目的地址,目的地址为被欺骗主机的IP地址
ip->iph_sourceip.s_addr = inet_addr(inet_ntoa(ip_true->iph_destip));
ip->iph_destip.s_addr = inet_addr(DEST_IP);
ip->iph_protocol = IPPROTO_ICMP; // The value is 1, representing ICMP.
ip->iph_len = htons(sizeof(struct ipheader) + sizeof(struct icmpheader)); // ip->iph_chksum 可由系统补全,不需要手动设置 // 最后,结合IP头和ICMP头发送报文
send_raw_ip_packet (ip); } /*******************************************************************************
用 raw socket 发 IP报文
*******************************************************************************/
void send_raw_ip_packet(struct ipheader* ip)
{
struct sockaddr_in dest_info;
int enable = 1; // 创建一个原始网络套接字sock, and 设置相关参数
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &enable, sizeof(enable)); // 提供必要的信息和地址
dest_info.sin_family = AF_INET;
dest_info.sin_addr = ip->iph_destip; // 把数据包发出去
printf("Sending spoofed IP packet...\n");
if(sendto(sock,ip,ntohs(ip->iph_len),0,(struct sockaddr *)&dest_info,sizeof(dest_info)) < 0)
{//要是发送失败
perror("PACKET NOT SENT\n");
return;
}
else {//发送成功时,打印发送的报文的源IP和目标IP
printf("\n---------------------------------------------------\n");
printf(" From: %s\n",inet_ntoa(ip->iph_sourceip));
printf(" To: %s\n",inet_ntoa(ip->iph_destip));
printf("\n---------------------------------------------------\n");
} close(sock);//关闭sock
} /*******************************************************************************
生成ICMP头的数据校验码,其内在逻辑是既定的,无需多加注释
*******************************************************************************/
unsigned short in_cksum(unsigned short *buf,int length)
{
unsigned short *w = buf;
int nleft = length;
int sum = 0;
unsigned short temp=0; /*
* The algorithm uses a 32 bit accumulator (sum), adds
* sequential 16 bit words to it, and at the end, folds back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
} /* treat the odd byte at the end, if any */
if (nleft == 1) {
*(u_char *)(&temp) = *(u_char *)w ;
sum += temp;
} /* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); // add hi 16 to low 16
sum += (sum >> 16); // add carry
return (unsigned short)(~sum);
}

附加内容

unmask(0)

原文链接
linux中的 umask 函数主要用于:在创建新文件或目录时 屏蔽掉新文件或目录不应有的访问允许权限。文件的访问允许权限共有9种,分别是:r w x r w x r w x(它们分别代表:用户读 用户写 用户执行 组读 组写 组执行 其它读 其它写 其它执行)。
其实这个函数的作用,就是设置允许当前进程创建文件或者目录最大可操作的权限,比如这里设置为0,它的意思就是0取反再创建文件时权限相与,也就是:(~0) & mode 等于八进制的值0777 & mode了,这样就是给后面的代码调用函数mkdir给出最大的权限,避免了创建目录或文件的权限不确定性。

共享内存

参考文章:
Linux 进程间通信(IPC)—大总结
共享内存无锁队列的实现
写得实在太好了。

报文时间戳处理

时间戳相减函数

报文的时间戳存储在回调函数的const struct pcap_pkthdr *中,结构如下:

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) */
};

其中struct timeval结构如下:

struct timeval
{
__time_t tv_sec; /* Seconds. */
__suseconds_t tv_usec; /* Microseconds. */
};

根据两个结构的特点,报文相对时间戳的计算函数如下:

void diffstamp(struct timeval* stamp1, struct timeval stamp2)
{
stamp1->tv_sec = stamp1->tv_sec - stamp2.tv_sec;
stamp1->tv_usec = stamp1->tv_usec - stamp2.tv_usec;
if(stamp1->tv_usec<0)
{
stamp1->tv_sec -=1;
stamp1->tv_usec += 1000000;
}
}

时间戳处理结果:

【笔记】libpcap安装与使用的更多相关文章

  1. CentOS学习笔记--Tomcat安装

    Tomcat安装 通常情况下我们要配置Tomcat是很容易的一件事情,但是如果您要架设多用户多服务的Java虚拟主机就不那么容易了.其中最大的一个问题就是Tomcat执行权限.普通方式配置的Tomca ...

  2. (转)ZooKeeper 笔记(1) 安装部署及hello world

    ZooKeeper 笔记(1) 安装部署及hello world   先给一堆学习文档,方便以后查看 官网文档地址大全: OverView(概述) http://zookeeper.apache.or ...

  3. LNMP笔记:安装 Xcache 缓存扩展,降低服务器负载

    LNMP笔记:安装 Xcache 缓存扩展,降低服务器负载 2014/11/27 教程笔记 4,743 14     WordPress 精品主机推荐:恒创主机 | 阿里云(本站目前所用云主机) 倡萌 ...

  4. OracleDesigner学习笔记1――安装篇

    OracleDesigner学习笔记1――安装篇   QQ:King MSN:qiutianwh@msn.com Email:qqking@gmail.com 一.       前言 Oracle是当 ...

  5. 笔记-docker-2安装(centos6.5环境)

    笔记-docker-2安装(centos6.5环境) 1.      centos6.5安装docker 1.1.    升级内核 安装docker,官方文档要求linux kernel至少3.8以上 ...

  6. 笔记-redis安装

    笔记-redis安装配置 1.      redis安装配置 1.1.    windows环境安装 win8已有redis 查看版本:redis-server –version 想更新到5.0.0, ...

  7. Docker笔记--ubuntu安装docker

    Docker笔记--ubuntu安装docker 1.更换国内软件源,推荐中国科技大学的源,稳定速度快(可选) sudo cp /etc/apt/sources.list /etc/apt/sourc ...

  8. Ubuntu下libpcap安装

    1.首先按下面的博客教程下载和安装四个软件包: 点击打开链接 2.这四个软件都安装好之后按下面教程新建Makefile文件和test.c文件: 点击打开链接 Makefie: all: test.c ...

  9. CUBRID学习笔记 2 安装教程

    下载地址  http://www.cubrid.org/?mid=downloads&item=any&os=detect&cubrid=9.3.0 选择适合你的服务器版本 l ...

  10. nodejs学习笔记<一>安装及环境搭建

    零零散散学了几天nodejs,进度一直停滞不前,今天沉下心来好好看了下nodejs的介绍和代码.自己也试着玩了下,算是有点入门了. 这里来做个学习笔记. ——————————————————————— ...

随机推荐

  1. 松下机器人示教器AUR01062触摸无反维修

    Panasonic松下机器人示教器AUR01062触摸无反应解决方案 松下机器人示教器现象:触摸屏幕时鼠标箭头无任何动作,没有发生位置改变. 原因:造成此现象产生的原因很多,下面就松下机器人维修中示教 ...

  2. 二叉树层次遍历下到上,左到右python

    # 利用队列进行层次遍历就行class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None ...

  3. mybatis - [08] mybatis-config.xml 详解

    mybatis-config.xml中的标签需要按照一定顺序配置,否则会有以下提示. configuration(配置) properties(属性) settings(设置) typeAliases ...

  4. Java01 - Scanner对象

    简介 之前我们学的基本语法中并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入.java.util.Scanner是Java5的新特征,我们可以通过Scanner ...

  5. ABC391E题解

    大概评级:绿. 题目传送门. 显然动态规划,设 \(f_{i,k}\) 表示经过 \(i\) 次变换后能将 \(a_k\) 取反的最大值,显然答案为 \(f_{n,1}\),状态转移很简单,枚举 \( ...

  6. Educational Codeforces Round 175 (Rated for Div. 2) 比赛记录

    Educational Codeforces Round 175 (Rated for Div. 2) 比赛记录 比赛连接 手速场,上蓝场,但是有点唐,C 想错了写了半个多小时,想到正解不到 \(10 ...

  7. Codeforces Round 1006 (Div. 3) 比赛记录

    Codeforces Round 1006 (Div. 3) 比赛记录 比赛链接 这场的题目名称都很长啊~. 很简单的一场(毕竟是div3,能不简单嘛)赛时切掉了A - F,C题花的时间有点多,G题偶 ...

  8. springboot項目打jar/war包

    一.打jar包 (1)不打入项目引用的第三方jar <build> <plugins> <plugin> <groupId>org.apache.mav ...

  9. 解决bootstrapvalidator配合select2插件不能正常校验的问题

    我在使用bootstrapvalidator对select2插件进行校验时,出现了不能校验的问题,于是求助度娘,发现大多的解决方法是这样的: 1.添加一个隐藏域,将bootstrapvalidator ...

  10. 重生之数据结构与算法----队列&栈

    简介 上文说到,数据结构只有两种.其它的数据结构都是它的整花活. 栈 栈只能在表的一端(称为栈顶)进行插入和删除操作,遵循 "后进先出"(Last In First Out,LIF ...