1.5个HOOK点的执行点说明:
数据包从进入系统,进行IP校验以后,首先经过第一个HOOK函数NF_IP_PRE_ROUTING进行处理;
然后就进入FORWARD路由匹配,其决定该数据报是需要转发还是发给本机的;
若该数据包是发给本机的,则该数据经过HOOK函数NF_IP_LOCAL_IN处理以后然后传递给上层协议;
若该数据报应该被转发则它被NF_IP_FORWARD处理;
经过转发的数据报经过最后一个HOOK函数NF_IP_POST_ROUTING处理以后,再传输到网络上。
本地产生的数据经过HOOK函数NF_IP_LOCAL_OUT 处理后,进行路由选择处理,然后经过NF_IP_POST_ROUTING处理后发送出去。
2.nf_hooks结构:
3.协议头字段
#include <linux/netfilter.h>
/* only for userspace compatibility */
#include <limits.h> /* for INT_MIN, INT_MAX */
/* IP Cache bits. */
/* Src IP address. */
#define NFC_IP_SRC 0x0001
/* Dest IP address. */
#define NFC_IP_DST 0x0002
/* Input device. */
#define NFC_IP_IF_IN 0x0004
/* Output device. */
#define NFC_IP_IF_OUT 0x0008
/* TOS. */
#define NFC_IP_TOS 0x0010
/* Protocol. */
#define NFC_IP_PROTO 0x0020
/* IP options. */
#define NFC_IP_OPTIONS 0x0040
/* Frag & flags. */
#define NFC_IP_FRAG 0x0080
/* Per-protocol information: only matters if proto match. */
/* TCP flags. */
#define NFC_IP_TCPFLAGS 0x0100
/* Source port. */
#define NFC_IP_SRC_PT 0x0200
/* Dest port. */
#define NFC_IP_DST_PT 0x0400
/* Something else about the proto */
#define NFC_IP_PROTO_UNKNOWN 0x2000
1.通过源码make编译,生成simple_nf_test.ko,加载进内核使用;
2.使用rmmod卸载模块,将内核计算数据保存进user file;
3.使用od -tu /root/netfilter.log查看保存的file数据。
#Makefile
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
obj-m += simple_nf_test.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
[root@test02 netfilter-test]# insmod simple_nf_test.ko
[root@test02 netfilter-test]# ping 114.114.114.114
PING 114.114.114.114 (114.114.114.114) 56(84) bytes of data.
^C
--- 114.114.114.114 ping statistics ---
64 packets transmitted, 0 received, 100% packet loss, time 64552ms
[root@test02 netfilter-test]# rmmod simple_nf_test
#dmesg日志
[22038.705777] ----------------------------------------------------------
[22038.705779] 114.114.114.114 is denied by netfilter!
[22038.705780] drop 114.114.114.114 packets count is : 20
[22039.575591] ----------------------------------------------------------
[22039.575602] # source address is 63baf772 , xxx.xxx.xxx.99
[22039.575607] # dest address is bc14a8c0 , 192.168.20.188
[22039.575609] ----------------------------------------------------------
[22039.575611] ...packet pass filter...
[22039.575613] [simple_nf_test] packet_filter. end.
[22039.729706] ----------------------------------------------------------
[22039.729762] # source address is 72727272 , 114.114.114.114
[22039.729767] # dest address is bc14a8c0 , 192.168.20.188
[22039.729770] ----------------------------------------------------------
[22039.729772] 114.114.114.114 is denied by netfilter!
[22039.729774] drop 114.114.114.114 packets count is : 21
[22040.753807] ----------------------------------------------------------
[22040.753822] # source address is 72727272 , 114.114.114.114
[22040.753826] # dest address is bc14a8c0 , 192.168.20.188
[22040.753829] ----------------------------------------------------------
[22040.753830] 114.114.114.114 is denied by netfilter!
[22040.753832] drop 114.114.114.114 packets count is : 22
...
[22088.630236] ----------------------------------------------------------
[22088.630237] ...packet pass filter...
[22088.630239] [simple_nf_test] packet_filter. end.
[22089.055705] ----------------------------------------------------------
[22089.055722] # source address is 63baf772 , xxx.xxx.xxx.99
[22089.055727] # dest address is bc14a8c0 , 192.168.20.188
[22089.055729] ----------------------------------------------------------
[22089.055731] ...packet pass filter...
[22089.055733] [simple_nf_test] packet_filter. end.
[22089.060209] packet fillter capture count: 64
[22089.060212] begin to write to netfilter.log
[22089.060258] record file write done .
[22089.060470] [simple_nf_test] remove hook lkm success!
#netfilter.log记录(8byte)
[root@test02 netfilter-test]# od -tu /root/netfilter.log
0000000 64 0
0000010
#simple_nf_test.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
//count变量用于统计filter hook的拦截次数
unsigned long int count = 0L;
//内核数据写入本地文件方法
static int _fileWrite(unsigned long int count)
{
unsigned long int buf[]= {
count };
printk("packet fillter capture count: %ld \n",count);
struct file *fp;
mm_segment_t fs;
loff_t pos;
printk("begin to write to netfilter.log \n");
//打开本地文件句柄
fp =filp_open("/root/netfilter.log",O_RDWR|O_CREAT,0644);
if (IS_ERR(fp)){
printk("open file error\n");
return -1;
}
//保护内核空间,地址参数检查
fs =get_fs();
//扩大空间限制到内核地址空间,从而可以在内核空间中使用文件系统调用
set_fs(KERNEL_DS);
//ssize_t kernel_write(struct file *file, const void *buf, size_t count, loff_t *pos)
//内核数据写入用户态文件API,注意buf如果为Int类型,将以ascii码的方式,保存进文件。所以从文件中获取Int数据时,需要使用od -tu filename命令。
pos =0;
kernel_write(fp,buf, sizeof(buf), &pos);
//关闭文件句柄
filp_close(fp,NULL);
//关闭内核空间的文件系统调用
set_fs(fs);
return 0;
}
unsigned int packet_filter(unsigned int hooknum, struct sk_buff *skb,const struct net_device *in, const struct net_device *out,int (*okfn)(struct sk_buff *))
{
//ip协议头部
struct iphdr *iph;
//tcp协议头部
struct tcphdr *tcph;
//udp协议头部
struct udphdr *udph;
//如socket buffer指针为空,则当前hook点允许该数据包继续在协议栈中流转。
//define NF_ACCEPT 1
if(skb == NULL)
return NF_ACCEPT;
//如skb不为空,则从skb获取ip头,使用内核API ip_hdr()
iph = ip_hdr(skb);
//如ip头为空,则当前hook点允许该数据包继续在协议栈中流转。
if(iph == NULL)
return NF_ACCEPT;
//打印经过hook的包信息
printk("----------------------------------------------------------");
printk("# source address is %x , %pI4 \n",iph->saddr,&iph->saddr);
printk("# dest address is %x , %pI4 \n",iph->daddr,&iph->daddr);
printk("----------------------------------------------------------");
//示例增加对IP地址114.114.114.114(十六进制表示:0x72727272)的地址过滤
if(iph->saddr == 0x72727272){
printk("114.114.114.114 is denied by netfilter!\n");
//命中计数器统计
count++;
printk("drop 114.114.114.114 packets count is : %ld \n",count);
// 丢弃该数据包
return NF_DROP;
/*
#include\uapi\linux\netfilter.h
/* Responses from hook functions. */
#define NF_DROP 0 // 丢弃该数据包
#define NF_ACCEPT 1 // 当前hook点,允许该数据包继续在协议栈中流转
#define NF_STOLEN 2 // 让netfilter框架忽略该数据包的处理
#define NF_QUEUE 3 // 该数据包加入到用户队列,供用户程序处理
#define NF_REPEAT 4
#define NF_STOP 5 /* Deprecated, for userspace nf_queue compatibility. */
#define NF_MAX_VERDICT NF_STOP
*/
}
printk("...packet pass filter...");
//协议层逻辑
switch(iph->protocol)
{
case IPPROTO_TCP:
tcph = (struct tcphdr *)(skb->data + (iph->ihl * 4));
//printk("#tcp source port is [%d].\n",ntohs(tcph->source));
//printk("#tcp dest port is [%d].\n",ntohs(tcph->dest));
//if TCP then do something
break;
case IPPROTO_UDP:
udph = (struct udphdr *)(skb->data + (iph->ihl * 4));
//printk("#udp source port is [%d].\n",ntohs(udph->source));
//printk("#udp dest port is [%d].\n",ntohs(udph->source));
//if UDP then do someting
break;
default :
//放行数据包
return NF_ACCEPT;
}
printk("[simple_nf_test] %s. end.\n", __func__);
return NF_ACCEPT;
};
/*
//hook结构体
struct nf_hook_ops {
struct list_head list; /* 标准链表—由于链接所有钩子点 */
/* User fills in from here down. */
nf_hookfn *hook; /* 钩子函数回调指针 */
struct net_device *dev; /* 网络设备指针 */
void *priv; /* 私有数据,在钩子回调函数中使用 */
u_int8_t pf; /* 协议族 */
unsigned int hooknum; /* hook点 */
/* Hooks are ordered in ascending priority. */
int priority; /* 优先级 */
};
*/
//初始化hook参数
static struct nf_hook_ops packet_simple_nf_opt = {
//hook函数packet_filter
.hook = (nf_hookfn *)packet_filter,
//协议指定为ip协议
.pf = NFPROTO_INET,
//hook点 NF_INET_PRE_ROUTING 优先级最高
.hooknum = NF_INET_PRE_ROUTING,
.priority = NF_IP_PRI_FIRST,
/*
//hook支持的协议
enum {
NFPROTO_UNSPEC = 0,
NFPROTO_INET = 1,
NFPROTO_IPV4 = 2,
NFPROTO_ARP = 3,
NFPROTO_NETDEV = 5,
NFPROTO_BRIDGE = 7,
NFPROTO_IPV6 = 10,
NFPROTO_DECNET = 12,
NFPROTO_NUMPROTO,
};
*/
/*
内核中注册的5个HOOK点如下:
enum nf_inet_hooks {
NF_INET_PRE_ROUTING,
NF_INET_LOCAL_IN,
NF_INET_FORWARD,
NF_INET_LOCAL_OUT,
NF_INET_POST_ROUTING,
NF_INET_NUMHOOKS
};
*/
/*
enum nf_ip_hook_priorities {
NF_IP_PRI_FIRST = INT_MIN,
NF_IP_PRI_RAW_BEFORE_DEFRAG = -450,
NF_IP_PRI_CONNTRACK_DEFRAG = -400,
NF_IP_PRI_RAW = -300,
NF_IP_PRI_SELINUX_FIRST = -225,
NF_IP_PRI_CONNTRACK = -200,
NF_IP_PRI_MANGLE = -150,
NF_IP_PRI_NAT_DST = -100,
NF_IP_PRI_FILTER = 0,
NF_IP_PRI_SECURITY = 50,
NF_IP_PRI_NAT_SRC = 100,
NF_IP_PRI_SELINUX_LAST = 225,
NF_IP_PRI_CONNTRACK_HELPER = 300,
NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
NF_IP_PRI_LAST = INT_MAX,
};
*/
};
static int simple_nf_init(void)
{
//注册函数钩子,内核版本大于4.3.0的内核函数API为nf_register_net_hook,否则为nf_register_hook
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)
//int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg)
//网络系统在初始化的时候会初始化一个初始网络命名空间,即init_net命名空间。后续创建的net namespace命名空间会和init_net一起通过list项组织起来,且每个网络设备都对应一个命名空间
nf_register_net_hook(&init_net, &packet_simple_nf_opt);
#else
nf_register_hook(&packet_simple_nf_opt);
#endif
printk("[simple_nf_test] network hooks success.\n");
return 0;
};
static void simple_nf_exit(void)
{
//write capute packets count to user file.
_fileWrite(count);
printk("record file write done.\n");
//卸载hook函数
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)
nf_unregister_net_hook(&init_net, &packet_simple_nf_opt);
#else
nf_unregister_hook(&packet_simple_nf_opt);
#endif
printk("[simple_nf_test] remove hook lkm success!\n");
};
//内核模块加载和卸载时,执行的函数
module_init(simple_nf_init);
module_exit(simple_nf_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Jeb");
文章浏览阅读1.7k次。vue下载无后缀名的文件被加上后缀.txt_window.url.createobjecturl 被加上后缀.txt
文章浏览阅读7k次。 系统:Windows Server 2003 r2 - IIS6 说明:PHP之所以选择Thread Safe版,是因为Zend Optimizer(一些php商业程序是用它加密的,比如shopex)只能用于Thread Safe版。 ps:FastCGI方式执行PHP不需要Thread Safe(线程安全检查),如果不用Zend Optimizer,PHP就用Non Thr_php5.2.17src http_range 编译 vc6 windows
文章浏览阅读1.1k次,点赞6次,收藏7次。【三维重建】【深度学习】NeuS代码Pytorch实现--训练阶段代码解析(下)_学习三维重建需要学习pytorch深度学习框架吗
文章浏览阅读2.6k次,点赞2次,收藏17次。树莓派4B Ubuntu 21.04 自动温控开关风扇以及RPi.GPIO避坑指南本人对树莓派有一些了解,虽然学过模电数电,但也只是学过,过于硬件的东西也不懂。好了,首先说明,树莓派GPIO引脚都是3.3v的,一般风扇都是5v的,所以不能用GPIO直接供电。即使你的风扇额定电压为 3V, GPIO的电流也难以驱动它, 即使能驱动也不推荐这么干, 一个原因是可能会损坏树莓派, 根据RaspberryPi官方GPIO使用文档明确的警告指出, 不能将电机直接接在 GPIO 针脚上(风扇实际上就是由电._树莓派4b散热风扇连接哪个gpio
文章浏览阅读10w+次,点赞17次,收藏64次。昨天晚上和@buptpatriot讨论函数返回指针(malloc生成的)的问题,说道字符串拼接,做个总结。#include#include#includechar *join1(char *, char*);void join2(char *, char *);char *join3(char *, char*);int main(void) { char a[] =_char字符串拼接
文章浏览阅读1.7k次。暮色呼如是先把这个int类型的数据转换成String类型,然后判断String类型的数据是否为空。int point;String val=point +"";而是一个中间变量,int point= GiftInfo.getPoints();在数据库表中有属性字段名称points,类型为int。如果我们没有向这个表中插数据,这时候point就是空值,而不是默认的0 问题补充:Aubergine_k..._整型判空java
文章浏览阅读487次,点赞10次,收藏9次。【代码】第十一届“图灵杯“NEUQ-ACM程序设计竞赛题解。_图灵杯大赛程序代码
文章浏览阅读432次。图片边框切图介绍_echarts边框图片
文章浏览阅读936次。简介:基于开放的技术标准、理念和实践,云原生已经成为企业数字化转型的最短路径。中间件作为云原生的核心支点,凭借种类丰富、接入简单、稳定高效的核心优势,已经成为在线教育企业业务稳定、效率提升的“法宝”。 阿里云中间件正在以全面领先的技术、产品和最佳实践,引领在线教育进入新的阶段。“停课不停学”,疫情之下,几乎所有教育机构或平台都趁热打铁,上百项公益课程纷至沓来,令人眼花缭乱。据统计,从年初至今,13家在线教育相关公司的市值已经累计上涨近800亿元。线下教育停滞,巨额流量瞬间涌入线上。此次疫情对于在线教育.
文章浏览阅读6.8k次。 使用SQL Server 2005 FOR XML嵌套查询日期:2008-06-08作者:郑佐相比SQL Server 2000提供的FOR XML查询,SQL Server 2005版本对现有功能增强的基础上增加了不少新功能,最为吸引人的功能包括对Xml数据类型支持、使用PATH模式以及嵌套FOR XML查询支持等,这意味着通过新的FOR XML查询功能可以构造出结构更加灵活的_两个 for xml path sql 嵌套
文章浏览阅读2w次。佩戴 Apple Watch 的同学或许会经常遇到这种情况 , 在手机听歌的时候 , 想看下时间 , 抬腕后手表却显示正在听的音乐 , 如下图 :这时候还得按下表冠按键在能返回 , 比较麻烦 ; 这个可以通过如下几个步骤关闭 (Watch OS 4.3) :我的手表 -> 通用 -> 唤醒屏幕 , 去掉 自动启用音频应用 这一项 , 设置完就不会再自动显示正在听的音乐了..._手机播放音乐如何不在手表上显示
文章浏览阅读18次。近期学了点web,发现还是不能为了学而学学习的目的在于解决问题, 更多时候, 要根据问题来学习MVC模式一知半解, JAVA SE的知识不扎实, JDBC还不熟悉, 就想着学框架了...虽然是因为要赶项目进度的缘故...还是要脚踏实地的, 才能走得更远下一阶段学习规划J2SE基础 补全熟悉jdbc + 前端深入理解MVC模式, 私以为这是入门之重, 框架在小型应用中并不必要...