下面展示一个极其简单的例子,看如何使用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. 自定义事件——Event和CustomEvent

    之前在学习自定义事件时,在MDN的Event.initEvent()页面顶端有写:该特性已从Web标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性. 作 ...

  2. mysql入门学习笔记

    MySQL的登陆和退出 mysql -u 用户名 -p 密码 #登陆 quit #退出(exit or \q) 具体参数: 参数 描述 -D,--database=name 打开指定数据库 -deli ...

  3. 西门子S7-200SMART PLC视频教程(百度网盘)

    西门子S7-200SMART PLC视频教程(百度网盘)西门子S7-200 SMART PLC是西门子公司推出的高性价比小型plc,是国内广泛使用的S7-200PLC的更新换代产品. 以下是关于S7- ...

  4. Android studio 中添加依赖model时依赖所需的准备

    例如向app中添加依赖core: core要做如下修改: 1.将core中build.gradle中   修改为  . 2.将core中的 applicationId 注释掉.

  5. javaScript中的redirect

    <script type="text/javascript"> <!-- window.location = "http://www.google.co ...

  6. fragment滑动界面

    1.代码页面 package com.example.fragment_list_copy; import android.app.FragmentManager;import android.sup ...

  7. 工控随笔_17_西门子_WinCC的VBS脚本_06_过程和函数

    和其他语言一样,vbs提供了过程和函数机制,通过函数和过程可以优化代码结构和实现代码复用, 减少代码的编写量. 一.代码 具体不再多说,看实例代码. ' vbs的函数和过程 '1.过程式编程是一大编程 ...

  8. solr中Cache综述

    一.概述 Solr查询的核心类就是SolrIndexSearcher,每个core通常在同一时刻只由当前的SolrIndexSearcher供上层的handler使用(当切换SolrIndexSear ...

  9. c#经典三层框架中的SqlHelper帮助类

    using System; using System.Collections.Generic; using System.Configuration; using System.Data; using ...

  10. html+css常用小笔记(持续更新)

    1 去掉input点击时的蓝色边框 outline:none; 2 禁止文本选中 -webkit-touch-callout: none; /* iOS Safari */ -webkit-user- ...