下面展示一个极其简单的例子,看如何使用netfilter来将一个指定端口的syn报文给rst掉。

//***************************************************************
// https://i.cnblogs.com/EditPosts.aspx?postid=10650263&update=1
//
// Simple hook test to be called.
// We drop the syn packet and rst the request
//***************************************************************
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <net/tcp.h>
#include <linux/init.h> #ifndef NIPQUAD
#define NIPQUAD(addr) \
((unsigned char *)&addr)[0], \
((unsigned char *)&addr)[1], \
((unsigned char *)&addr)[2], \
((unsigned char *)&addr)[3]
#endif #ifndef NIPQUAD_FMT
#define NIPQUAD_FMT "%u.%u.%u.%u"
#endif #define Serve_Port 5886
#define My_DEBUG_ENABLE 1 static unsigned int test_nf_filter(const struct nf_hook_ops *ops,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
#ifndef __GENKSYMS__
const struct nf_hook_state *state
#else
int (*okfn)(struct sk_buff *)
#endif
)
{
struct sk_buff * skb_send;
struct iphdr *iph_send ;
struct tcphdr *tcph_send;
struct ethhdr *eth_send;
struct iphdr *iph ;
struct tcphdr *tcph;
struct ethhdr *eth;
__u32 sip;
__u32 dip;
__u16 sport;
__u16 dport;
int tcphdrlen, iphdrlen, ethhdrlen;
int err; int tcphdrlen_recv, iphdrlen_recv; /*取出mac头部*/
eth = (struct ethhdr *)skb_mac_header(skb); /*取出IP头,源IP地址.目的IP地址*/
iph=ip_hdr(skb);
sip=iph->saddr;
dip=iph->daddr; /*如果不是TCP协议,直接返回*/
if(iph->protocol != IPPROTO_TCP){
return NF_ACCEPT;
} tcph = (struct tcphdr *)((__u32 *)iph + iph->ihl);
sport = tcph->source;
dport = tcph->dest; /*如果不是指定的端口,直接返回*/
if (ntohs(dport)!=Serve_Port)
{
return NF_ACCEPT;
}
if(!(tcph->syn))
{
return NF_ACCEPT;
}
if (My_DEBUG_ENABLE)
{
printk("TCP PACKET. ");
printk("recv packet,syn=%u\r\n,tcph->syn");
printk("from %d.%d.%d.%d to %d.%d.%d.%d - ",
NIPQUAD(sip),NIPQUAD(dip));
printk("from %u to %u. ",ntohs(sport),ntohs(dport));
printk("skb->len(%u) ", skb->len);
printk("seq(%x) ", ntohl(tcph->seq));
printk("ack_seq(%x) ", ntohl(tcph->ack_seq));
printk(".\n");
} /*分析tcp载荷,并存放接收的Rtsp信息*/
iphdrlen_recv = iph->ihl * 4;
tcphdrlen_recv = tcph->doff * 4; /* handle syn packet ,first Malloc up new buffer. */
ethhdrlen = sizeof(struct ethhdr);
iphdrlen = sizeof(struct iphdr);
tcphdrlen = sizeof(struct tcphdr);
/* only respond with one byte */
skb_send = dev_alloc_skb(ethhdrlen + iphdrlen + tcphdrlen);
if (skb_send == NULL)
{
printk(KERN_WARNING "Memory squeeze, dropping packet.\n");
return NF_ACCEPT;
} if (skb_send)
{
/*将头部指针往后移动。然后从高层协议开始填充。*/
skb_reserve(skb_send, ethhdrlen + iphdrlen + tcphdrlen); /*调整TCP指针*/
tcph_send = (struct tcphdr *)__skb_push(skb_send, tcphdrlen);
skb_set_transport_header(skb_send, 0);
tcph_send->source = dport;
tcph_send->dest = sport;
tcph_send->seq = tcph->ack_seq;
//tcph_send->ack_seq =0;
tcph_send->ack_seq = htonl(ntohl(tcph->seq)+1); tcph_send->res1 = 0;
tcph_send->doff = htons(sizeof(struct tcphdr) >> 2);
tcph_send->fin = 0;
tcph_send->syn = 0;
tcph_send->rst = 1;
tcph_send->psh = 0;
tcph_send->ack = 1;
tcph_send->urg = 0;
tcph_send->ece = 0;
tcph_send->cwr = 0; //*(((__be16 *)tcph_send) + 6) = htons(((tcphdrlen >> 2) << 12) |0x0014);
tcph_send->doff = (tcphdrlen >> 2); tcph_send->window = htons(0x3CF2);
tcph_send->urg_ptr = 0;
tcph_send->check = 0; /*ip头部*/
iph_send = (struct iphdr * )__skb_push(skb_send, iphdrlen);
skb_set_network_header(skb_send, 0); iph_send->version = 4;
iph_send->ihl = sizeof(struct iphdr)/4;
iph_send->tos = 0;
iph_send->tot_len = htons(iphdrlen + tcphdrlen);
iph_send->id = 0;
iph_send->frag_off = 0;
iph_send->ttl = 55;
iph_send->protocol = IPPROTO_TCP;
iph_send->check = 0;
iph_send->saddr = iph->daddr;
iph_send->daddr = iph->saddr;
iph_send->check = 0;
iph_send->check = ip_fast_csum((unsigned char *)iph_send, iph_send->ihl); /*tcp头部校验和初始值计算*/
skb_send->csum = 0;
skb_send->ip_summed = CHECKSUM_UNNECESSARY;
tcph_send->check = tcp_v4_check(tcphdrlen , iph_send->saddr, iph_send->daddr,
csum_partial(tcph_send, tcphdrlen , 0)); /*eth头部*/
eth_send = (struct ethhdr * )__skb_push(skb_send, ethhdrlen);
skb_set_mac_header(skb_send, 0);
memcpy(eth_send->h_dest, eth->h_source, ETH_ALEN);
memcpy(eth_send->h_source, eth->h_dest, ETH_ALEN);
eth_send->h_proto = eth->h_proto; /*其他配置*/
skb_send->mac_len = ethhdrlen;
skb_send->dev = skb->dev;
skb_send->queue_mapping = skb->queue_mapping;
skb_send->protocol = htons(ETH_P_IP);;
skb_send->vlan_tci = skb->vlan_tci;
skb_send->pkt_type = PACKET_OUTGOING;
skb_send->mark = 0;
memset(skb_send->cb, 0, sizeof(skb_send->cb)); /*完成数据包的发送*/
err = dev_queue_xmit(skb_send);
if (err > 0 && (err = net_xmit_errno(err)) != 0)
{
printk(KERN_WARNING "dev_queue_xmit=%d.\n", err);
}
} //*走到这,丢弃所有的包*/
return NF_DROP;
} static struct nf_hook_ops test_filter = {
.owner = THIS_MODULE,
.list = {NULL, NULL},
.hook = &test_nf_filter,
.pf = PF_INET,
//.hooknum = NF_INET_LOCAL_IN, /*NF_IP_LOCAL_IN,*/
.hooknum = NF_INET_PRE_ROUTING, /*NF_IP_LOCAL_IN,*/
.priority = NF_IP_PRI_FIRST
}; static int testnf_init(void)
{
printk(KERN_ALERT "Test netfilter!\n"); return nf_register_hook(&test_filter);
} static void testnf_exit(void)
{
nf_unregister_hook(&test_filter); printk(KERN_ALERT "GOODBYE netfilter!\n");
}
MODULE_LICENSE("GPL");
module_init(testnf_init); module_exit(testnf_exit);

服务器端监听端口:

[root@localhost hook]# gdb ./tcp_sever.o
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-100.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/caq/hook/tcp_sever.o...done.
(gdb) r
Starting program: /home/caq/hook/./tcp_sever.o
========waiting for client's request========

端口已经侦听:

[root@localhost hook]# ss -tlp |grep -i 5886
LISTEN 0 10 *:5886 *:* users:(("tcp_sever.o",pid=42818,fd=7))

客户端发起链接,很快被服务器端rst掉。

linux:/home/caq # ./tcp_client.o
connect: Connection refused

执行的抓包结果:

10:39:29.762503 IP (tos 0x0, ttl 64, id 58665, offset 0, flags [DF], proto TCP (6), length 52) 10.229.200.12.13952 > 10.229.200.30.5886: S, cksum 0xa61b (incorrect (-> 0x0ae2), 744885068:744885068(0) win 14600 <mss 1460,nop,nop,sackOK,nop,wscale 9>
0x0000: 0004 0001 0006 98f5 37e2 f373 0000 0800
0x0010: 4500 0034 e529 4000 4006 afa5 0ae5 c80c
0x0020: 0ae5 c81e 3680 16fe 2c66 0b4c 0000 0000
0x0030: 8002 3908 a61b 0000 0204 05b4 0101 0402
0x0040: 0103 0309
10:39:29.763024 IP (tos 0x0, ttl 55, id 0, offset 0, flags [none], proto TCP (6), length 40) 10.229.200.30.5886 > 10.229.200.12.13952: R, cksum 0x47b8 (correct), 0:0(0) ack 744885069 win 15602
0x0000: 0000 0001 0006 74a4 b500 f12e 0000 0800
0x0010: 4500 0028 0000 0000 3706 dddb 0ae5 c81e
0x0020: 0ae5 c80c 16fe 3680 0000 0000 2c66 0b4d
0x0030: 5014 3cf2 47b8 0000 0000 0000 0000

这个简单的示例,是展示netfilter的钩子到底怎么使用,当然,我们不可能对所有的规则都写一个模块实现,所以,用户态的配置工具就出来了,我们后续博客再记录。

有个tcpkill的工具,也可以实现类似的功能,它的原理是利用抓包,然后根据获取的seq和四源组信息,发送rst来干掉链路。如果抓不到包,比如对于一条不活跃的链接,

可以构造syn包,然后等对端回复一个正确的ack,里面有seq信息,再发送rst复位之。

把一个syn报文给rst掉的更多相关文章

  1. TCP协议: SYN ACK FIN RST PSH URG 详解

    TCP的三次握手是怎么进行的了:发送端发送一个SYN=1,ACK=0标志的数据包给接收端,请求进行连接,这是第一次握手:接收端收到请求并且允许连接的话,就会发送一个SYN=1,ACK=1标志的数据包给 ...

  2. 一个TCP报文段的数据部分最多为多少个字节,为什么

    IP数据报的最大长度=2^16-1=65535(字节)TCP报文段的数据部分=IP数据报的最大长度-IP数据报的首部-TCP报文段的首部=65535-20-20=65495(字节) 一个tcp报文段的 ...

  3. php同一个用户同时只能登陆一个, 后登陆者踢掉前登陆者(排他登陆)

    通常用户登陆,如果没有特别的限定, 同一个用户可以同时登陆, 今天搞了一个东西限定一个用户不能同时登陆到一个系统上, 后登陆者会把前面登陆的踢出来.(有点像QQ,同个帐号不能在多个地方同时在线, 后面 ...

  4. Android ListView的一个坑,你可掉进去过?

    需要的功能很简单,就是一个带checkbox的列表,提交时需要知道用户选择了那些项目,如下图: 使用SimpleAdapter作为数据适配器,重写SimpleAdapter.ViewBinder的方法 ...

  5. [SoapUI] 怎样确定一个应答报文的格式是不是标准的JSON

    有一个网站 : http://jsonviewer.stack.hu/ 将Response的文本贴进去,如果是标准的JSON格式,就可以以JSON的view显示出来

  6. TCP重置报文段及RST常见场景分析

    RST表示连接重置,用于关闭那些已经没有必要继续存在的连接.一般情况下表示异常关闭连接,区别与四次分手正常关闭连接. 产生RST的三个条件是: 目的地为某端口的SYN到达,然而在该端口上并没有正在监听 ...

  7. linux内核参数sysctl.conf,TCP握手ack,洪水攻击syn,超时关闭wait

    题记:优化Linux内核sysctl.conf参数来提高服务器并发处理能力 PS:在服务器硬件资源额定有限的情况下,最大的压榨服务器的性能,提高服务器的并发处理能力,是很多运维技术人员思考的问题.要提 ...

  8. linux内核参数sysctl.conf,TCP握手ack,洪水攻击syn,超时关闭wait(转)

    http://www.xshell.net/linux/Linux_sysctl_conf.html 优化Linux内核sysctl.conf参数来提高服务器并发处理能力 Posted by 破冰 o ...

  9. 为什么服务器突然回复RST——小心网络中的安全设备

    RST产生原因 一般情况下导致TCP发送RST报文的原因有如下3种:    1. SYN数据段指定的目的端口处没有接收进程在等待.        2.TCP想放弃一个已经存在的连接.    3.TCP ...

随机推荐

  1. oracle 的 exp 和imp命令

    数据导出: 1 将数据库TEST完全导出,用户名gdoa 密码123 导出到D:\TEST_BK.dmp中 exp gdoa/123@TEST file=d:\TEST_BK.dmp full=y   ...

  2. Python之 操作 MySQL 数据库

    什么是MySQLdb? MySQLdb 是用于Python链接Mysql数据库的接口,它实现了 Python 数据库 API 规范 V2.0,基于 MySQL C API 上建立的. 安装 Pytho ...

  3. 弹出的 Dialog 里,包含 Form,如何在关闭 Dialog 时,执行 resetFields(对整个表单进行重置,将所有字段值重置为初始值并移除校验结果)

    做法: before-close 事件中,调用 resetFields 取消按钮事件中,调用 resetFields <el-dialog title="弹出窗口" :vis ...

  4. cannal&otter源码解析

    一点引用资料的整理 http://www.tianshouzhi.com/api/tutorials/canal/381 canal 同步工具 https://github.com/alibaba/c ...

  5. 用EM4305/T5557模拟EM4100的ID卡,原理解释

    用EM4305/T5557模拟EM4100,原理解释 来源: https://www.cnblogs.com/osnosn/p/10593297.html 来自osnosn的博客 写于: 2019-0 ...

  6. javaAgent介绍

    JavaAgent(转载) http://www.cnblogs.com/diyunpeng/archive/2011/05/26/2057932.html 一文带你了解Java Agent http ...

  7. apache2.4+php7.3.2+mysql5.7

    一.下载php7和apache2.4 1 首先下载php7的windows压缩包,到这里下载http://windows.php.net/download/ 我选择的是php7的这个版本,由于它是vc ...

  8. Hibernate查询部分字段并封装到指定类中

    Hibernate 使用查询部分/指定字段,有几种字现方式: 第一种方式是通过HQL语句实现,类似SQL,方法如下: String hql = "select id,name from Li ...

  9. cefsharp插入自定义JS

       string script_1 = "document.getElementsByTagName('head')[0].appendChild(document.createEleme ...

  10. RESTful levels、HATEOAS

    概述: REST(英文:Representational State Transfer,简称REST)描述了一个架构样式的网络系统,比如 web 应用程序.它首次出现在 2000 年 Roy Fiel ...