下面展示一个极其简单的例子,看如何使用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. docker-compose up使用自定义的网段的两种方式(从其根源指定)

    问题描述         还是那个研究安全大业的同事,在部署他的秘密武器,是用docker-compose部署的,有差不多20多个docker-compose.yml文件,然后由于docker-com ...

  2. .NET Remoting、WebService、WCF、WebApi一些简单描述

    1. .NET Remoting是传输层协议TCP封装的,速度非常快,.NET Remoting基于.net反射机制,只方便.net使用,因此它有平台限制.(.NET Remoting的工作原理:服务 ...

  3. IO练习

    #IO操作 import time; fileObj = open('log.txt','a'); while(True): data = input('请输入要写入的内容 : '); if data ...

  4. 时光如梭,MES生产制造执行系统上线2周年--->2016.08,发个博客展示一下系统的主要功能!

    以下程序是系统当中的主要功能信息,一些相对简单功能就不在此处展示了. 1.模具基础资料Excel导入与模具资料手动更新功能.友情提示:为了避免不必要的麻烦已经将部分信息打码.! 2.配方资料Excel ...

  5. CSS3 Vendor-prefixing

    Browser vendors needed a way to add support for new features that were not yet standardized, but wit ...

  6. Google SketchUp Cookbook: (Chapter 2) Following Paths with Follow Me

    软件环境 SketchUp Pro 2018 参考书籍 Google SketchUp Cookbook Follow Me工具 Follow Me工具,将2D图形沿着一条路径挤出生成3D物体. 使用 ...

  7. 关于new你应当知道的一切

    new在C++中是一个我们经常用到的运算符.由它所创建的变量会被分配在堆中,并且在程序结束之前应当将分配的内存delete掉,否则就会导致内存泄漏.但是除此之外,你对new有更深入的了解吗?本篇文章将 ...

  8. Java经典代码片段——使用NIO进行快速的文件拷贝

    public static void fileCopy(File in, File out) throws IOException { FileChannel inChannel = new File ...

  9. php curl使用 常用操作

    1. http Get 简单的只需要 这四行 就 $ch = curl_init (); curl_setopt ( $ch, CURLOPT_URL, "http://site" ...

  10. JavaScript数组方法--flat、forEach、map

    今天到flat了,一个第一次知道该方法还是看到一个面试题,别人给了个答案,用到了flat才知道的方法. 前面也写过关于这道面试题的文章,<一道关于数组的前端面试题>. 这里再来说说吧! f ...