netfiler的优势不仅包含防火墙的实现,还包括各种报文的处理工作(如报文的加密,统计等)。可以方便地利用netfilter提供的接口实现内核态的报文处理。

在netfilter中可以解析报文,同时根据阻断规则做匹配,将符合阻断的报文直接DROP,但是在tcp的会话中,这样并不优雅,tcp是可靠传输,如果是直接drop掉某一个报文,则发送端会一直重发,所以在tcp的协议中需要向发送端发送一个fin或者是rst的报文,用来断来链接。下面是我测试使用的代码。

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/udp.h>
#include <linux/ip.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/etherdevice.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/inet.h>
#include <linux/types.h>
#include <linux/string.h>#include <net/checksum.h>
#include <net/tcp.h>
#include <net/netfilter/nf_conntrack.h>//模块声明
//GPL, Dual BSD/GPL, Dual MPL/GPL, Proprietary
//内核可以识别上述四种许可方式,没有采用上面的则被假定为私有的,内核加载这种私有模块会被“污染”
MODULE_LICENSE("GPL");#define NIPQUAD(addr)          \((uint8_t *)&addr)[0], \((uint8_t *)&addr)[1], \((uint8_t *)&addr)[2], \((uint8_t *)&addr)[3], \addr#define MAC_FFF(mac)          \((uint8_t *)&mac)[0], \((uint8_t *)&mac)[1], \((uint8_t *)&mac)[2], \((uint8_t *)&mac)[3], \((uint8_t *)&mac)[4], \((uint8_t *)&mac)[5]#define BLOKEN_IP (1107077312) //  断链的IP (192.168.252.65 网络字节序)const char* client_break_msg = "C_break"; //检查payload 前面的字符static uint32_t ipv4_hook_in_func(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))
{    //struct SKernelMsgIpV4Stats _ipv4Stats;struct ethhdr *eth_header = (struct ethhdr *)skb_mac_header(skb); //eth_hdrstruct iphdr *ip_header = (struct iphdr *)skb_network_header(skb); //ip_hdrstruct tcphdr *tcp_header = NULL;unsigned int nip_hdr_len;unsigned int ntcp_hdr_len;struct net_device * send_dev = NULL;int i=0;uint16_t nt_header=0;unsigned char *payload=NULL;uint16_t payload_len=0;int is_bloken = 0;struct sk_buff *fack_skb = NULL;struct ethhdr *fack_eth_header = NULL; //eth_hdrstruct iphdr *fack_ip_header = NULL; //ip_hdrstruct tcphdr *fack_tcp_header = NULL;if (NULL == skb || NULL == eth_header || NULL == ip_header){return NF_ACCEPT;}//tcp协议if(likely(ip_header->protocol==IPPROTO_TCP)){tcp_header = (struct tcphdr *)skb_transport_header(skb); //tcp_hdrif (NULL == tcp_header){return NF_ACCEPT;}//判断 包中ip是不是符合需要 断链的IPif (BLOKEN_IP == ip_header->saddr || BLOKEN_IP == ip_header->daddr){printk(KERN_DEBUG "ipv4_hook_func. %02x:%02x:%02x:%02x:%02x:%02x_%u.%u.%u.%u(%u):%u->%02x:%02x:%02x:%02x:%02x:%02x_%u.%u.%u.%u(%u):%u. seq:%u ack:%u \n", MAC_FFF(eth_header->h_source), NIPQUAD(ip_header->saddr), ntohs(tcp_header->source), MAC_FFF(eth_header->h_dest), NIPQUAD(ip_header->daddr), ntohs(tcp_header->dest), tcp_header->seq, tcp_header->ack_seq);is_blokennip_hdr_len = ip_header->ihl << 2; //IP头长度ntcp_hdr_len = tcp_header->doff << 2; //tcp头长度nt_header = nip_hdr_len + ntcp_hdr_len;payload = skb->data + nt_header;payload_len = skb->len - nt_header;if(payload_len > 0){printk("tcp segment msg: "); for(i=0;i<payload_len;i++){printk("%c", payload[i]);}printk("\r\n");}//检查payload中 从第一个字符开始是否符合if(payload_len >= strlen(client_break_msg)){is_bloken = 1;for(i=0; i < strlen(client_break_msg); i++){if(payload[i] != client_break_msg[i]){is_bloken = 0;break;}       }}//符号断链if(is_bloken){printk("block.......\r\n");if(skb->data_len!=0){           if(skb_linearize(skb)){printk("error line skb\r\n");printk("skb->data_len %d\r\n",skb->data_len);return NF_DROP;}}//获取包出去的网卡send_dev = dev_get_by_name(&init_net, "eth0");//send_dev = dev_get_by_name(&init_net, skb->dev->name);if(send_dev == NULL){printk("%s\n\n", "dev_get_by_name return NULL");return NF_DROP;}//分配一个sk_buff 这个包发送给源端,包含了tcp的fin或事rst,用来断链,这个包不需要payload数据fack_skb = alloc_skb(LL_RESERVED_SPACE (send_dev) + sizeof (struct iphdr) + sizeof (struct tcphdr), GFP_ATOMIC);if(NULL == fack_skb){printk("skb_copy error\n\n");return NF_DROP;}fack_skb->pkt_type = PACKET_OTHERHOST;fack_skb->protocol = skb->protocol;// __constant_htons(ETH_P_IP);fack_skb->ip_summed = CHECKSUM_NONE;fack_skb->priority = 0;//skb_reset_mac_header, skb_reset_network_header, skb_reset_transport_header//skb_mac_header, skb_network_header, skb_transport_header//skb_put、skb_push、skb_pull、skb_reserve//fack_skb是一个新的 sk_buff,可以将data和tail都置到末尾,然后自顶向下填充数据//data tail 全部置到末尾skb_reserve (fack_skb, LL_RESERVED_SPACE (send_dev) + sizeof (struct iphdr) + sizeof (struct tcphdr));//tcp data前移,此时data开始位置为tcphdr开始位置skb_push(fack_skb, sizeof (struct tcphdr));skb_reset_transport_header(fack_skb);{fack_tcp_header = (struct tcphdr *) skb_transport_header(fack_skb);memset (fack_tcp_header, 0, sizeof (struct tcphdr));fack_tcp_header->source = tcp_header->dest; //用原包的目的port填充fack_tcp_header->dest = tcp_header->source; //用原包的源port填充fack_tcp_header->seq = tcp_header->ack_seq; //用原包的ack填充fack_tcp_header->ack_seq = htonl(ntohl(tcp_header->seq) + payload_len); //这个需要确认收到的原包,注意字节序fack_tcp_header->doff = sizeof(struct tcphdr)>>2;fack_tcp_header->psh = 0;fack_tcp_header->rst = 1; //这里将rst置为1,用于断链fack_tcp_header->fin = 0;fack_tcp_header->syn = 0;fack_tcp_header->ack = 1;fack_tcp_header->window = __constant_htons (5840);fack_tcp_header->check = 0;}//ip data前移skb_push(fack_skb, sizeof (struct iphdr));skb_reset_network_header(fack_skb);{fack_ip_header = (struct iphdr*) skb_network_header(fack_skb);memset (fack_ip_header, 0, sizeof (struct iphdr));fack_ip_header->version = ip_header->version;fack_ip_header->ihl = sizeof(struct iphdr)>>2;fack_ip_header->frag_off = 0x40;fack_ip_header->protocol = ip_header->protocol;fack_ip_header->tos = 0;fack_ip_header->daddr = ip_header->saddr;fack_ip_header->saddr = ip_header->daddr;fack_ip_header->ttl = 0x40;fack_ip_header->tot_len = __constant_htons(fack_skb->len);fack_ip_header->check = 0;fack_ip_header->check=ip_fast_csum((unsigned char*)fack_ip_header, fack_ip_header->ihl); //ip层的校验和}//校验和fack_skb->csum = 0;//fack_skb->csum = csum_partial(fack_tcp_header, sizeof(struct tcphdr), 0);fack_skb->csum = skb_checksum (fack_skb, sizeof(struct iphdr), sizeof(struct tcphdr), 0);fack_tcp_header->check = csum_tcpudp_magic (fack_ip_header->saddr, fack_ip_header->daddr, sizeof(struct tcphdr), fack_ip_header->protocol, fack_skb->csum);//mac层skb_push(fack_skb, ETH_HLEN);skb_reset_mac_header(fack_skb);if(skb_mac_header_was_set(skb)){fack_eth_header = (struct ethhdr *)skb_mac_header(fack_skb); //eth_hdrmemcpy(fack_eth_header->h_dest, eth_header->h_source, ETH_ALEN);memcpy(fack_eth_header->h_source, eth_header->h_dest, ETH_ALEN);}fack_eth_header->h_proto = eth_header->h_proto;fack_skb->dev = send_dev;dev_hold(fack_skb->dev);printk("%s\n", "dev_hold ok");if (dev_queue_xmit(fack_skb) < 0){printk("dev_queue_xmit() error\n");dev_put(fack_skb->dev);kfree_skb(fack_skb);return NF_DROP;}printk(KERN_DEBUG "ipv4_hook_func_sour. %02x:%02x:%02x:%02x:%02x:%02x_%u.%u.%u.%u(%u):%u->%02x:%02x:%02x:%02x:%02x:%02x_%u.%u.%u.%u(%u):%u seq:%u ack:%u. \n\n", MAC_FFF(fack_eth_header->h_source), NIPQUAD(fack_ip_header->saddr), ntohs(fack_tcp_header->source), MAC_FFF(fack_eth_header->h_dest), NIPQUAD(fack_ip_header->daddr), ntohs(fack_tcp_header->dest), fack_tcp_header->seq, fack_tcp_header->ack_seq);}}}return NF_ACCEPT;
}static struct nf_hook_ops ipv4_nfin = {.hook = ipv4_hook_in_func,.hooknum = NF_INET_PRE_ROUTING,.pf = PF_INET,.priority = NF_IP_PRI_CONNTRACK - 1, // NF_IP_PRI_CONNTRACK
};//子模块初始化回调函数
static int __init init_nf(void)
{int ret = 0;if(0 != nf_register_hook(&ipv4_nfin)){printk(KERN_ERR "nf_register_hook(&ipv4_nfin) error");ret = -1;}printk(KERN_INFO "Register netfilter module succ.\n");return 0;
}//子模块销毁回调函数
static void __exit exit_nf(void)
{nf_unregister_hook(&ipv4_nfin);printk(KERN_INFO "Unregister netfilter module succ.\n");
}module_init(init_nf);
module_exit(exit_nf);MODULE_AUTHOR("xuwaiwai"); //作者描述
MODULE_DESCRIPTION("TCP broken chain test demo");//模块用途的简短描述
MODULE_VERSION("0.0.1");//模块的版本号
MODULE_ALLAS("broken ipv4");//模块的别名

例子中直接新分配了一个 skb_buff, 然后在此结构中填充依次L4,L3,L2的数据并发送。

关于编译可以参考:netfilter模块编译和运行


凡是过往,即为序章

netfilter 子系统实现tcp断链相关推荐

  1. Linux网络相关、firewalld、netfilter及其5表5链、iptables语法

    2019独角兽企业重金招聘Python工程师标准>>> 1.Linux 网络相关 ifconfig 查看网卡IP,见下图, net-tools 包之前安装过了,这边还可以执行这个命令 ...

  2. 应用使用Druid连接池经常性断链问题分析

    前段时间有应用使用Druid连接池经常的提示断链报错,整个问题排查分析过程很有意思.这里将Druid连接池.数据库层以及负载均衡层的配置分析下,记录整个问题的分析过程,同时梳理下Druid连接池的配置 ...

  3. nats断链情况总结

    1.客户端启动时nats server连不上 代码段: func setupConnOptions() []nats.Option {opts := make([]nats.Option,0)opts ...

  4. Netty ChannelInactive 断链场景分析

    本文档主要列举离会.关闭进程.断网.重连等会导致sdk与服务端断开连接的场景的设计与实现,并试图解释其原理 1.Netty断链场景分析 1. Netty对断链的处理 简单来说Netty在检测到断开连接 ...

  5. 模块学习4:(2)MQTT协议连接、发布、订阅、心跳、断链等分析和代码实现,并且通过mqtt.fx连接服务器,使用wireshark抓包分析mqtt实现过程

    文章目录 一.MQTT控制报文的结构 (1)固定报头(类型/标志 + 剩余长度) 剩余长度(这个要注意下,要注意它的计算方法,有一点特殊) 可变报头 有效载荷 二.下面直接开整各个具体的报文(MQTT ...

  6. (54)线程结构体 ETHREAD,线程断链

    一.回顾 上次课我们学习了进程,我们知道了进程是空间概念,最主要的功能是提供CR3,而线程才是CPU调度的最小单位: 更早的时候做SSDT HOOK FindWindow 时我们还了解到了,当3环程序 ...

  7. (53)进程结构体EPROCESS,擦除 DebugPort 实现反调试,ActiveProcessLinks 断链实现进程隐藏

    一.进程的作用 进程最重要的作用是提供了CR3,10-10-12分页下CR3指向页目录表,2-9-9-12分页下CR3指向页目录指针表. 每个进程有一个或多个线程.本质上,没有进程切换,只有线程切换. ...

  8. (35)3环PEB断链

    一.断链原理 3环下PEB断链是一种常见的模块隐藏技术,原理是修改 _PEB_LDR_DATA 中的三个双向链表,删除链表中的项,让 CreateToolhelp32Snapshot 之类的API无法 ...

  9. 断链在平曲线计算中的处理——短链篇

    第十二篇  断链在平曲线计算中的处理--短链篇 1. 短链在平曲线编程数据库里的处理方法 断链是在一些线路设计或施工中因某种情况下而产生的,具体原因在此不做讨论,短链就是断链的其中一种常见形式,另一种 ...

最新文章

  1. 4.7 mini趴 走进猎豹
  2. java selectcommand_“对于不返回任何基表信息的 SelectCommand 不支持动态SQL生成”-奇怪的错误,不知道原因! | 学步园...
  3. 【单页应用巨坑之History】细数History带给单页应用的噩梦
  4. 关于Javascript Hijacking
  5. apollo java客户端_携程配置中心Apollo的Java客户端API的使用
  6. adsl密码查看器,宽带密码查看器,无广告,绿色版
  7. [转载]JXTA概念介绍
  8. 如何用计算机计算一元三次方程,计算器如何解一元三次方程?
  9. html5shiv不起作用,HTML5shiv不会对IE8
  10. 工程导论【职业能力与职业培养】
  11. 无穷级数求和7个公式_Excel技能:职场必备的三个SUM函数、10个求和公式
  12. gen-cpp/.deps/ChildService.Plo: No such file or directory
  13. 拉丁舞身形研究之恰恰恰
  14. 神级程序员都在用什么工具?【建议收藏】
  15. 限制网页只能在微信浏览器打开
  16. 《Android Studio开发实战》学习(二)- 聊天室
  17. 流利说AI刘扬:从教授到”AI虚拟老师“
  18. 《炬丰科技-半导体工艺》IC制造化学清洗过程中硅上重金属污染的表面光电压监测
  19. 牛逼!百度大佬深度分享AI助力RNA二级结构预测!
  20. 爬虫之Selenium模块

热门文章

  1. 文件包含漏洞认识认识
  2. 0R电阻和1R电阻的用处
  3. Jmeter录制接口自动化
  4. oCPC实践录 | 随你千变万化,oCPC PID控制(2)
  5. 浅谈变电站综合自动化系统微机综合保护装置—安科瑞 孙斌
  6. JAVA与西门子S7协议通讯
  7. 【笔记】嵌入式C语言随堂笔记
  8. 15种可切换404自适应页面源码
  9. SRAM的性能及结构
  10. 统计分析基础-描述数据