iptables/netfilter命令、实现及利用(转)
原文链接:http://blog.csdn.net/sealyao/article/details/5934268
一、Netfilter和Iptables概述
netfilter/iptables IP 信息包过滤系统是一种功能强大的工具,可用于添加、编辑和除去规则,这些规则是在做信息包过滤决定时,防火墙所遵循和组成的规则。这些规则存储在专用的信息包过滤表中,而这些表集成在 Linux 内核中。在信息包过滤表中,规则被分组放在我们所谓的链(chain)中。
虽然 netfilter/iptables IP 信息包过滤系统被称为单个实体,但它实际上由两个组件 netfilter 和 iptables 组成。
netfilter 组件也称为内核空间(kernelspace),是内核的一部分,由一些信息包过滤表组成,这些表包含内核用来控制信息包过滤处理的规则集。
iptables 组件是一种工具,也称为用户空间(userspace),它使插入、修改和除去信息包过滤表中的规则变得容易。
iptables包含4个表,5个链。其中表是按照对数据包的操作区分的,链是按照不同的Hook点来区分的,表和链实际上是netfilter的两个维度。
4个表:filter,nat,mangle,raw,默认表是filter(没有指定表的时候就是filter表)。表的处理优先级:raw>mangle>nat>filter。
filter:一般的过滤功能
nat:用于nat功能(端口映射,地址映射等)
mangle:用于对特定数据包的修改
raw:有限级最高,设置raw时一般是为了不再让iptables做数据包的链接跟踪处理,提高性能
5个链:PREROUTING,INPUT,FORWARD,OUTPUT,POSTROUTING。
PREROUTING:数据包进入路由表之前
INPUT:通过路由表后目的地为本机
FORWARDING:通过路由表后,目的地不为本机
OUTPUT:由本机产生,向外转发
POSTROUTIONG:发送到网卡接口之前。如下图:
iptables中表和链的对应关系如下:
数据包在netfilter中的传递流程:
二、Iptables的使用:
iptables [-t 表名] -命令 –链表 [-匹配] [-j 动作/目标]
表名:filter;nat;mangle;raw
常用命令:
-A, --append chain rule-specification:添加
-D, --delete chain rule-specification:删除
-D, --delete chain rulenum:删除
-I, --insert chain [rulenum] rule-specification:插入
-R, --replace chain rulenum rule-specification:替换
-L, --list [chain]:显示
-F, --flush [chain]:刷新
链表:INPUT;OUTPUT;FORWORD;PREROUTING;POSTROUTING
匹配:
-p -protocal [!]protocol:协议
-s -source [!] address[/mask]:源地址
-d --destination [!] address[/mask]:目的地址
-j --jump target:
-i –in-interface [!][name]:入口
-o --out-interface [!][name]:出口
-f, --fragment:分片
匹配扩展:
指定-p tcp时:
--source-port [!] [port[:port]]:原端口(也作--sport)
--destionation-port [!] [port:[port]]:目的端口(也作--dport)
--tcp-flags [!] mask comp:匹配指定的TCP标记
[!] –syn:设置了SYN位而清除了ACK和FIN位的TCP包。
--tcp-option [!] number:设置了TCP选项的包
指定 –p udp时:
--source-port [!] [port:[port]]
--destination-port [!] [port:[port]]
常见动作:
ACCEPT:放行
DROP:拒绝
QUEUE:传递给应用层
REJECT:和DROP类似,只是REJECT还返回一个错误包消息
REDIRECT:在nat表PREROUTING链中使用,修改数据包为本机地址和用户指定的端口。
TPROXY:在mangle表的PREROUTING链中使用,不修改数据包包头,直接把数据传递给一个本地socket。
较完整的命令参数见下图:
三、NetFilter的内核实现
Netfilter中有两个要点:一个是Hooks点的实现,一个是表、链、规则的概念
Hooks
struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]是其中核心的数据结构。nf_hooks的功能类似一个二维的函数指针数组。
nf_hooks数组的第一维是按照协议进行分类的,对于不同的协议有不同的hook点和hook函数,常见的协议包括ipv4,ipv6,arp,bridge等。
nf_hooks数组的第二维是按照hook点进行划分的,分为
NF_INET_PRE_ROUTING,NF_INET_LOCAL_IN,NF_INET_FORWARD,NF_INET_LOCAL_OUT,NF_INET_POST_ROUTING等5个hook点,与iptables的5个链相对应。
nf_hooks数组中的每一个元素可以理解为一个函数指针链表的链表头。这个函数指针链表是一个有序链表,按照函数hook的优先级进行排序。iptables的4个表分别对应不同的优先级:NF_IP_PRI_RAW、NF_IP_PRI_MANGLE、NF_IP_PRI_NAT_DST /NF_IP_PRI_NAT_SRC、NF_IP_PRI_LAST等。iptables中的表的优先级就是通过有序链表的方式来实现的。
链表元素的实际的数据结构是struct nf_hook_ops,其核心的数据成员就是一
个函数指针,还包含其他的一些属性。
struct nf_hook_ops
{
struct list_head list; //链表成员
/* User fills in from here down. */
nf_hookfn *hook; //钩子函数指针
struct module *owner;
int pf; //协议簇,对于ipv4而言,是PF_INET
int hooknum; //hook类型
int priority; //优先级
};
nf_hooks的全局结构示意图如下:
netfilter中的数据流程如下图:
上图为ipv4协议的数据包,当数据包到达对应的hook点时,检查对应的nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]函数指针链表是否为空,如果为空则继续tcp/ip协议栈的后续流程;如果不为空,则按照链表中的顺序依次调用hook函数。
iptables的默认的核心hook函数是ipt_do_table(ip_tables.c),其核心功能是检查对应的协议的对应的表中的对应的链中的规则是否和当前的数据包相匹配,如果匹配则执行对应的动作。
Tabales
netfilter中提供了一系列的表(tables),每个表包含若干个链(chains),而每条链中包含由一条或若干条规则(rules),每一条规则都被用于数据包的检测。实际上netfilter是表的容器,表是链的容器,而链又是规则的容器。
相关的数据结构:
struct xt_table //表结构
{
struct list_head list;//表链
unsigned int valid_hooks;
struct xt_table_info *private;// iptable的数据区
struct module *me;
u_int8_t af; //协议簇
int priority; //优先级
const char name[XT_TABLE_MAXNAMELEN];// 表名,如"filter"、"nat"等,为了满足自动模块加载的设计,包含该表的模块应命名为iptable_'name'.o
};
struct ipt_table_info //表的实际数据结构
{
unsigned int size;//表大小
unsigned int number;//表中规则数
unsigned int initial_entries;//初识的规则数,用于模块计数
unsigned int hook_entry[NF_IP_NUMHOOKS];// 记录所影响的HOOK的规则入口相对于下面的entries变量的偏移量
unsigned int underflow[NF_IP_NUMHOOKS];//与hook_entry相对应的规则表上限偏移量,当无规则录入时,相应的hook_entry和underflow均为0
char entries[0] ____cacheline_aligned;//规则表入口
};
下面的3种数据额结构是被填充到struct ipt_table_info的规则表(entries开始的)中的。
ipt_entry结构如下图所示,其成员ip指向结构ipt_ip,该结构主要保存规则中标准匹配的内容 (IP、mask、interface、proto等),target_offset的值等于ipt_entry的长度与 ipt_entry_matches的长度之和,next_offset的值等于规则中三个部分的长度之和。通过target_offset与 next_offset可以实现规则的遍历。
struct ipt_entry
{
struct ipt_ip ip;/* 所要匹配的报文的IP头信息 */
unsigned int nfcache;/* 位向量,标示本规则关心报文的什么部分,暂未使用 */
u_int16_t target_offset;/* target区的偏移,通常target区位于match区之后,而match区则在ipt_entry的末尾;初始化为sizeof(struct ipt_entry),即假定没有match */
u_int16_t next_offset;/* 下一条规则相对于本规则的偏移,也即本规则所用空间的总和,初始化为sizeof(struct ipt_entry)+sizeof(struct ipt_target),即没有match */
unsigned int comefrom;/* 规则返回点,标记调用本规则的HOOK号,可用于检查规则的有效性 */
struct ipt_counters counters;/* 记录该规则处理过的报文数和报文总字节数 */
unsigned char elems[0];/*target或者是match的起始位置 */
}
ipt_entry_match主要保存规则中扩展匹配内容(tos、ttl、time等),其是 Netfilter中内核与用户态交互的关键数据结构,在其内核部分由一个函数指针指向一个ipt_match结构,该结构体中包含了对包做匹配的函数, 是真正对包做匹配的地方。ipt_entry_target结构与ipt_entry_match结构很类似。
struct xt_entry_
union {
struct {
__u16 match_size;
char name[XT_EXTENSION_MAXNAMELEN];
__u8 revision;
} user;
struct {
__u16 match_size;
struct xt_match *match;
} kernel;
__u16 match_size;
} u;
unsigned char data[0];
};
struct xt_entry_target {
union {
struct {
__u16 target_size;
char name[XT_EXTENSION_MAXNAMELEN];
__u8 revision;
} user;
struct {
__u16 target_size;
struct xt_target *target;
} kernel;
__u16 target_size;
} u;
unsigned char data[0];
};
上面各种数据结构是按照下图的形式进行关联的。这里被分成表、链、规则三级。
每个表(xt_tables)都有一个private指针指向一个ipt_table_info结构,在ipt_table_info结构之后紧接着的是是实际的规则。
从数据结构中看链结构不是很明显,但是规则是被封装在链中的。ipt_table_info结构中的hook_entry成员和underflow成员就是用于划分规则所在的链。
每个规则由一个ipt_entry结构,N个xt_entry_match结构和一个xt_entry_target结构组成。ipt_entry结构表示的是基本的匹配规则(协议、地址等),xt_entry_match结构表示的是扩展的匹配规则,xt_entry_target结构表示的是匹配之后的动作。
四、NetFilter的利用
由于netfilter在内核中预留了Hook点,因此可以通过加载模块的方式方便对其加以利用。下面代码可以在2.6.20上运行。
- //nethook.c
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/netfilter.h>
- #include <linux/netfilter_ipv4.h>
- #include <linux/netdevice.h>
- #include <linux/skbuff.h>
- #include <linux/ip.h>
- #include <linux/tcp.h>
- static struct nf_hook_ops nfho;
- unsigned int hook_func(unsigned int hooknum,
- struct sk_buff **skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
- {
- #ifdef BASE_TEST
- return NF_DROP;
- #endif
- #ifdef INTF_TEST
- if(strcmp(in->name,"eth0") == 0){
- return NF_DROP;
- }
- #endif
- #ifdef ADDR_TEST
- static unsigned char *drop_ip = "/x0a/x08/x50/x6c";
- struct sk_buff *sk = *skb;
- if(sk->nh.iph->saddr == *(unsigned int *)drop_ip){
- return NF_DROP;
- }
- #endif
- #ifdef PORT_TEST
- unsigned char *deny_port = "/x00/x19"; /* port 25 */
- struct tcphdr *thead;
- if (!skb )
- return NF_ACCEPT;
- if (!(skb->nh.iph))
- return NF_ACCEPT;
- if (skb->nh.iph->protocol != IPPROTO_TCP) {
- return NF_ACCEPT;
- }
- thead = (struct tcphdr *)(skb->data +(skb->nh.iph->ihl * 4));
- if ((thead->dest) == *(unsigned short *)deny_port) {
- return NF_DROP;
- }
- #endif
- return NF_ACCEPT;
- }
- static int __init init_nethook(void)
- {
- nfho.hook = hook_func;
- nfho.hooknum = NF_IP_PRE_ROUTING;
- nfho.pf = PF_INET;
- nfho.priority = NF_IP_PRI_FIRST;
- nf_register_hook(&nfho);
- return 0;
- }
- static void __exit exit_nethook(void)
- {
- nf_unregister_hook(&nfho);
- }
- module_init(init_nethook);
- module_exit(exit_nethook);
//nethook.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>
static struct nf_hook_ops nfho;
unsigned int hook_func(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
#ifdef BASE_TEST
return NF_DROP;
#endif
#ifdef INTF_TEST
if(strcmp(in->name,"eth0") == 0){
return NF_DROP;
}
#endif
#ifdef ADDR_TEST
static unsigned char *drop_ip = "/x0a/x08/x50/x6c";
struct sk_buff *sk = *skb;
if(sk->nh.iph->saddr == *(unsigned int *)drop_ip){
return NF_DROP;
}
#endif
#ifdef PORT_TEST
unsigned char *deny_port = "/x00/x19"; /* port 25 */
struct tcphdr *thead;
if (!skb )
return NF_ACCEPT;
if (!(skb->nh.iph))
return NF_ACCEPT;
if (skb->nh.iph->protocol != IPPROTO_TCP) {
return NF_ACCEPT;
}
thead = (struct tcphdr *)(skb->data +(skb->nh.iph->ihl * 4));
if ((thead->dest) == *(unsigned short *)deny_port) {
return NF_DROP;
}
#endif
return NF_ACCEPT;
}
static int __init init_nethook(void)
{
nfho.hook = hook_func;
nfho.hooknum = NF_IP_PRE_ROUTING;
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST;
nf_register_hook(&nfho);
return 0;
}
static void __exit exit_nethook(void)
{
nf_unregister_hook(&nfho);
}
module_init(init_nethook);
module_exit(exit_nethook);
Makefile:
- obj-m = nethook.o
- KVERSION = $(shell uname -r)
- all:
- make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
- clean:
- make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
obj-m = nethook.o
KVERSION = $(shell uname -r)
all:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean
利用上述模块可以简单实现对地址、端口的过滤
iptables/netfilter命令、实现及利用(转)的更多相关文章
- iptables/Netfilter 学习
开始学iptables,因为它是和路由器技术紧密结合在一起的. iptables的命令看起来眼花缭乱,随便找两个: iptables -A FORWARD -p tcp -s -d -j ACCEPT ...
- IPtables/NetFilter
前提知识 任何主机若要与非同网络中的主机通信,则必须将报文发送到默认网关: 对Linux而言,IP地址是属于主机(内核中)的,不属于网卡,只要属于当前主机的IP地址间,都可直接响应,不称为转发 私有地 ...
- Linux对外提供服务 网络操作 端口操作 1.开启服务监听端口 2.设置防火墙,放行访问端口的包 iptables&netfilter 四表五链和通堵策略
主题: Linux服务器上软件提供服务 1.网络操作 2.端口操作 1.网络操作 本机必须能够ping通目标主机(本地虚拟机或者远程主机) 2.端口操作 1.开启服务监听端口 2.设置防火墙,放行访问 ...
- Linux内核下包过滤框架——iptables&netfilter
iptables & netfilter 1.简介 netfilter/iptables(下文中简称为iptables)组成Linux内核下的包过滤防火墙,完成封包过滤.封包重定向和网络地址转 ...
- Linux数据包路由原理、Iptables/netfilter入门学习
相关学习资料 https://www.frozentux.net/iptables-tutorial/cn/iptables-tutorial-cn-1.1.19.html http://zh.wik ...
- ThinkPHP5.0.21&5.1.* 代码执行和命令执行漏洞利用
ThinkPHP5.0.21&5.1.* 代码执行和命令执行漏洞利用 ThinkPHP5.0.21&5.1.* exploit code execution and command ...
- iptables简单命令
IPTables是基于Netfilter基本架构实现的一个可扩展的数据报高级管理系统或核外配置工具,利用table.chain.rule三级来存储数据报的各种规则.Netfilter-iptables ...
- iptables基础命令详解
TCP/IP基本概念: TCP/IP将网络分为四层:应用层,传输层,网络层,链路层. 传输层:定义了两种通信协议,分别为TCP协议和UDP协议. TCP协议:TCP协议在传输 数据过程中会检查数据的完 ...
- Linux iptables常用命令
iptables 是 Linux 中重要的访问控制手段,是俗称的 Linux 防火墙系统的重要组成部分.这里记录了iptables 防火墙规则的一些常用的操作指令. 下面的操作以 CentOS 为基础 ...
随机推荐
- Python属性、方法和类管理系列之----元类
元类的介绍 请看位于下面网址的一篇文章,写的相当好. http://blog.jobbole.com/21351/ 实例补充 class Meta(type): def __new__(meta, c ...
- 类模板 template<class T>
参考网址:http://c.biancheng.net/cpp/biancheng/view/213.html // demo3.cpp : 定义控制台应用程序的入口点. // #include &q ...
- Java 应用发布后,需要关注的7个性能指标
在某个重大发布之后,都需要记录相应的指标,本文介绍了最重要的几个 Java 性能指标,包括响应时间和平均负载等.为理解应用程序在生产环境中如何运行,就需要遵循一些 Java 性能指标. 在以前,当软件 ...
- Access forbidden! XAMPP虚拟主机的问题
XAMPP Control Panel v3.2.1添加虚拟主机出现 Access forbidden! You don't have permission to access the request ...
- HDU 2986 Ballot evaluation(精度问题)
点我看题目 题意 : 给你n个人名,每个名后边跟着一个数,然后m个式子,判断是否正确. 思路 :算是一个模拟吧,但是要注意浮点数容易丢失精度,所以要好好处理精度,不知道多少人死在精度上,不过我实在是不 ...
- DJANGO:从当前用户的所属用户组里查找其所拥有的权限矩阵
没办法,随时项目越来越精进,要求也越来越多. 以前的权限精度已满足不了现在的要求, 那就设计一个权限矩阵,用HOOK返回来判断吧... [莫名其妙的ORM,留个念想] 主要是在表之间的跳转,要注意语法 ...
- 独立两套DJANGO+CELERY配置(生产+测试)时要注意的一些细节
1,生产的NGINX环境,要指定自己的目录,而不是PROJ默认的. upstream ism_host { server ; } server { listen ; server_name local ...
- android一个纠结的VFY错误
08-16 09:06:45.018: W/dalvikvm(2286): VFY: unable to resolve static method 3273: Lorg/slf4j/LoggerFa ...
- 【HDOJ】2045 不容易系列之(3)—— LELE的RPG难题
着色问题,递推,当超过3个块时,规律明显,此时可以是n-2的头尾重复+与头尾不同颜色,也可以是n-1+与头尾均不相同眼色情况.经典递推.注意long long. #include <stdio. ...
- bzoj1497
这道题让我涨姿势了 对于这类问题,我们称作最大权闭合图问题 就是每个点都有一个点权,要求选择一个点集,其中每个点的指向的点也在点集中,使这样一个点权和最大 对于这种问题,我们添加源点s,汇点t 对于点 ...