Linux内核转发技术

前言

在linux内核中,通常集成了带有封包过滤和防火墙功能的内核模块, 不同内核版本的模块名称不同,

在2.4.x版本及其以后的内核中, 其名称为iptables, 已取代了早期的ipchains和远古时期的ipfwadm.

在命令行中可以通过lsmod | grep -i iptable来查看当前加载的相关模块信息.

iptables作为内核模块, 由一些信息包过滤表组成,这些表包含内核用来控制信息包过滤处理的规则集.

与此同时, iptables也作为用户空间(userspace)的一个管理工具而存在,使得我们使插入,

修改和除去信息包过滤表中的规则变得非常容易,不需要每次修改规则后都重新编译内核.

本文主要讨论的也正是iptables在用户空间的功能.

基本概念

linux内核的转发机制主要通过查表(tables)来完成, 而iptables则用来设置,管理和检查linux内核中ip包过滤规则表.

table后面加了s说明可以定义多张表, 而每张表中又包含了若干链路(chains), 链路表示一系列应用于匹配ip包的规则(rules).

下面就对这"三座大山"分别加以解释. 为了使概念明了, 我们自底向上说明:

规则(rules)

规则又称为rule-specification, 其主要作用是匹配特定的ip封包, 并作出相应的动作, 其格式为:

rule-specification = [matches...] [target]

其中,

match = -m matchname [per-match-options]
target = -j targetname [per-target-options]

matchname表示匹配的格式的名称, targetname表示所执行的动作的名称. iptables定义了一系列内置的格式和动作,

如target为accept表示接受, masquerade表示执行类似路由器的动作(用于nat)等, 具体可以通过man iptables-extensions查看.

链路(chains)

所谓链路, 顾名思义就是表示ip数据包传输的路径, 一个封包的源和目的不同, 其走的路径即有可能不同,

就像路途中的朋友们, 在任何一个节点都有可能分道扬镳.这些节点有:

  • pre_routing : 外部数据刚刚进入时.
  • post_routing : 外部数据准备离开时.
  • input : 数据包的目的地址为本地socket.
  • output : 数据包由本地生成.
  • forward : 数据包被本机转发.

事实上, 链路在内核中以钩子的形式存在, 在每个结点给用户预留了回调函数来处理封包(即用前面提到的规则).

ip封包从外部进入后,所经过的链路如下图所示:

网口接收到ip封包后, 首先经过mangle和nat表的pre_routing表的处理, 然后判断是否目的地址为本机的应用程序,

若是则往左边的路径往下, 由接收程序处理完后再发出. 在未开启内核转发的情况下, 目的地址不为本机的ip包都会丢弃掉,

若开启了转发则往右边路径将其从网口转发出去. 在图中每个链路点都能对ip包做相应的修改和过滤.

注意: prerouting链只会匹配流的第一个包,也就是说,这个流的所有其他的包都不会被此链检查.

因此prerouting链只能做网络地址转换,不能被用来做任何过滤.

表(tables)

当前最新版本的iptables中包含了五个独立的表, 工作时使用哪张表取决于内核选项以及当前应用了哪个模块. 各表说明如下:

  • filter: filter表为(iptables命令)默认使用的表, 包含input,forward和output链路.
  • nat: 当遇到一个创建了新链接的ip包时, 内核就会查找nat表, 其包含了prerouting和postrouting链路.
  • mangle: mangle表用于专门的封包修改,如改变tos,ttl,mark等. 在内核2.4.17之前只包含prerouting和output链路,

    在之后的版本中增加了input,forward和postrouting链路.

  • raw: raw主要用来在连接跟踪中配置notrack行为, 其在netfilter的hook注册了更高优先级的回调,因此可以在ip_conntrack表

    亦即其他ip表之前被调用. raw包含了prerouting和output链路.

  • security: security表用于命令访问控制(mandatory access control, mac)网络的规则. mac由linux安全模块如selinux实现,

    security表在filter表之后调用, 提供了input,output和forward链路.

具体应用

工具的产生终究要服务于生产, 光解释名词也不能形象地展现linux强大的内核转发机制,因此以几个小例子来说明iptables的

具体使用, 并依据上述介绍来写出有实际效用的脚本. iptables命令的一般格式如下:

iptables [-t table] {-a|-c|-d} chain rule-specification

其中命令分为三部分,亦即上面说到的指定表,链路和规则

-t table指定表的名字, 若不指定则默认为filter.
-a chain表示在链路中增加规则, -c和-d分别表示检查和删除.
剩余部分指定规则, 格式为`[matches...] [target]`

完整的命令可以通过iptables的manpages查看.

例1.作为防火墙

假设这么一种场景, 我们连接上了一个烦人的局域网, 为什么说它烦人呢? 因为局域网内有很多脚本小子,

来来回回扫描不说, 还在某些端口进行爆破. 因此我想简单生成一个防火墙, 除了网关不允许子网内任何其他的

ip对我进行连接, 甚至连ping都ping不到我.

需求明确, 那么如何实现呢? 其实很简单, 只需要以下命令(假设子网为192.168.1.0/24):

#1. 清空现有规则
iptables -t filter -f
#2. 打开网关访问权限
iptables -t filter -a input -s 192.168.1.1 -j accept
#3. 指定不过滤ping的返回
iptables -t filter -a input -p icmp --icmp-type 0 -s 192.168.1.0/24 -j accept
#4. 关闭其他所有内网访问权限
iptables -t filter -a input -p all -s 192.168.1.0/24 -j drop

一般来说防火墙策略一般是从非信任->信任,先用策略(-p policy)关闭所有访问权限,再添加规则按需要逐条打开.

这里为了简单就在默认策略(accept)的基础上添加规则. 各个表的当前策略可以通过iptables -t table -s查看.

要注意的是所有规则是按顺序检查的, 一旦检查到符合的条件就会执行,而不往下继续检查,如果所有规则都不匹配,

则会执行默认的操作(默认策略).因此在逐条添加规则的时候最好是从小到大添加.

在#3命令中,我们打开了icmp type为0的输入,即ping echo reply封包, 这样别人ping不到我的同时,我却能ping到别人,是不是很方便?

例2.作为路由器

在管制的网络中经常有这么一种情况, 即内网是绑定mac地址的, 客户端要接入路由器必须要网络管理员添加,

因为即使有wifi密码,连接上之后也无法获取ip,因而不能上网. 我的pc已经被添加到网络中,但是手机,平板之类

的设备不想一一要网管去添加, 那该怎么连上wifi呢? 解决办法有很多, 在windows下有各种xxx-wifi软件, linux的

networkmanager也有类似添加热点的解决方案. 这里讲的是iptables的解决办法.

现假定笔记本启动了热点at0,并已配置好dhcp服务. 我们的子网还是192.168.1.0/24, 热点的子网为10.0.0.0/24,

共用同一块无线网卡wlan0. 此时子网的请求会到wlan0上, 但是目的地址不是我, 根据上图可以知道, 这时

ip封包应该往右边的路径转发出去, 不过需要出去前改变一下网络地址(即nat, 详见p2p通信原理与实现).

设置nat转发的规则也很简单:

iptables -t nat -a postrouting -o wlan0 -j masquerade

这是在当我们既用wlan0上网,也用wlan0做路由器的时候配置的nat规则,但是这样性能会不太理想,

更普遍的情况是我们用一个网卡连接网络(假设为wlan0), 另一个网卡作为路由器(设为wlan1),

这种情况下只需要将wlan1的流量转发到wlan0上:

iptables -t filter -a forward -i wlan1 -o wlan0 -j accept
iptables -t filter -a forward -i wlan0 -o wlan1 -m state --state established,related -j accept
iptables -t nat -a postrouting -o wlan0 -j masquerade

其中masquerade表示提供一种类似路由器的转发行为,即为出去的tcp/udp包改变源地址,为进来的包改变目的地址,

用-j snat可以实现同样功能, 只不过ip地址需要自己指定(这里为wlan0在内网中的地址). masquerade被专门设计

用于那些动态获取ip地址的连接,比如拨号上网,dhcp连接等.如果你有静态ip,使用snat target可以减少开销.

iptables -t nat -a postrouting -o wlan0 -p tcp -j snat --to-source [wlan0-ip]
# 这里不需要设置dnat, 因为snat会记住连接,把响应转发给对应的请求.不过为了例示还是写出来:
iptables -t nat -a prerouting -i wlan0 -d [wlan0-ip] -p tcp -j dnat --to [client-ip]

这里值得一提的是, iptables本质上只是过滤和处理数据, 所以准确说是允许将wlan1的流量转发到wlan0上,

事实上如果用默认策略, forward都是允许的, 不用额外设置.

例3.作为透明代理

不同的人对代理有不同的需求, 最常见的就是http代理, 一般提供了地址和端口号. 我们在浏览器中配置使用

代理并指定地址和端口后, 上网冲浪的请求会经过代理服务器接收,然后根据需要会从为我们去向目的网站请求内容,

或者从缓存中直接给我们返回内容. 假设我们现在已经配置好并运行了squid代理服务器, 工作在3128端口.

和作为路由器类似, 不过除了改变ip还需要改变目的端口号:

iptables -t nat -a prerouting -i wlan1 -p tcp --dport 80 -j dnat --to [wlan0-ip]:3128
iptables -t nat -a prerouting -i wlan0 -p tcp --dport 80 -j redirect --to-port 3128

透明代理完整的iptables配置可以参考set up squid in linux.

后记

对于linux内核转发的技术介绍感觉差不多了, 虽然没有完全表现出其强大的功能,

但相信有需要的人可以根据基本规则来举一反三; 通过google查看别人的iptables"脚本",

也能获得很多灵感. 另外关于iptables的更多具体命令,要记得多使用简单的办法查阅(man iptables).

参考资料

时间: 2024-08-28 23:32:23

Linux内核转发技术的相关文章

Linux内核调试技术——jprobe使用与实现

前一篇博文介绍了kprobes的原理与kprobe的使用与实现方式,本文介绍kprobes中的第二种探测技术jprobe,它基于kprobe实现,不能在函数的任意位置插入探测点,只能在函数的入口处探测,一般用于监测函数的入参值.本文首先通过一个简单的示例介绍jprobe的使用方式,然后通过源码详细分析jprobe的实现流程. 内核源码:Linux-4.1.x 实验环境:Fedora25(x86_64).树莓派1b 1.jprobe使用实例 使用jprobe探测函数的入参值,需要编写内核模块.同k

Cgroup maintainer李泽帆:解剖Linux内核容器技术

摘要:Cgroup和namespace等内核特性如何出现,在社区处于怎样的开发状况?Docker如火如荼,内核社区是否会因此加紧完善容器技术的隔离性安全性?华为Linux内核高级工程师李泽帆将在2015 Container技术峰会上详细解说. 2015年4月16-18日,由CSDN主办.CSDN专家顾问团支持的OpenCloud 2015大会将在北京国家会议中心拉开帷幕.为期三天的大会,以推进行业应用中的云计算核心技术发展为主旨,聚焦技术创新与应用实践,设置了"2015 OpenStack技术大

Linux内核调试技术——kretprobe使用与实现

摘自:https://blog.csdn.net/luckyapple1028/article/details/54782659前两篇博文介绍了kprobes探测技术中kprobe和jprobe的使用与实现.本文介绍kprobes中的最后一种探测技术kretprobe,它同样基于kprobe实现,可用于探测函数的返回值以及计算函数执行的耗时.本文首先通过一个简单的示例程序介绍kretprobe的使用方式,然后通过源码分析它是如何实现的. 内核源码:Linux-4.1.x 实验环境:Fedora2

Linux内核调试技术——进程上下文R状态死锁监测

前一篇博文介绍了内核监测D状态死锁的hung task机制,本文介绍另一种死锁状态的监测手段--R状态死锁监测.R状态死锁指的是某一任务一直处于TASK_RUNNING态且一直占用着CPU,从而导致其他进程得不到调度而饿死的情况.一般情况下,R状态死锁较可能是由于程序出现死循环导致的,可以出现在内核态的进程上下文中(内核配置为非抢占式,soft lockup),也可以出现在中断上下文中的中断处理程序中(hard lockup).异常的程序一直运行,CPU无法调度到其他的任务运行,对于单CPU的设

Linux内核调试技术——进程D状态死锁检测

Linux的进程存在多种状态,如TASK_RUNNING的运行态.EXIT_DEAD的停止态和TASK_INTERRUPTIBLE的接收信号的等待状态等等(可在include/linux/sched.h中查看).其中有一种状态等待为TASK_UNINTERRUPTIBLE,称为D状态,该种状态下进程不接收信号,只能通过wake_up唤醒.处于这种状态的情况有很多,例如mutex锁就可能会设置进程于该状态,有时候进程在等待某种IO资源就绪时(wait_event机制)会设置进程进入该状态.一般情况

linux内核调试技术之GDB和GDBServer

1.调试原理 GDB调试是应用程序在开发板上运行,然后在PC机上对开发板上得应用程序进行调试,PC机运行GDB,开发板上运行GDBServer.在应用程序调试的时候,pc机上的gdb向开发板上的GDBServer发出命令,而开发板上的gdbserver就会向应用程序发出信号,使应用程序停下来或者完成其他一些工作. 2.安装GDB和GDBServer(gdb-7.4.tar.bz2 ) 2.1.GDB 1.下载: http://ftp.gnu.org/gnu/gdb/ 2.解压:tar xvf g

Linux内核调试的方式以及工具集锦

CSDN GitHub Linux内核调试的方式以及工具集锦 LDD-LinuxDeviceDrivers/study/debug 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可, 转载请注明出处, 谢谢合作 因本人技术水平和知识面有限, 内容如有纰漏或者需要修正的地方, 欢迎大家指正, 也欢迎大家提供一些其他好的调试工具以供收录, 鄙人在此谢谢啦 "调试难度本来就是写代码的两倍. 因此, 如果你写代码的时候聪明用尽, 根据定义, 你就没有能耐去调试它了.&qu

linux内核数据包转发流程(二)中断

[版权声明:转载请保留出处:blog.csdn.net/gentleliu.邮箱:shallnew*163.com] 内核在处理2层数据包之前,必须先处理中断系统,设立中断系统,才有可能每秒处理成千的帧. 当收到一个帧时,驱动程序会代表内核指示设备产生一个硬件中断,内核将中断其他的活动,然后调用一个驱动程序所注册的处理函数,以满足设备的需要.当事件是接收到一个帧时,处理函数就会把该帧排入队列某处,然后通知内核. 使用轮询技术会轻易浪费掉很多系统资源,因为内核会持续去读取检查是否有有帧的到来.但使

【华为云技术分享】Linux内核发展史 (1)

openEuler是基于Linux 内核的企业级Linux 服务器操作系统平台的开源社区发行版.openEuler支持鲲鹏架构,可运行在TaiShan服务器上.本技术连载将会从理论基础.源码分析和实操方法三个方面来比较全面地介绍内核编程与应用编程的基础知识,到2020年8月之前主要介绍内核编程部分.通过本连载的介绍,您将对openEuler内核编程和应用编程的理论和实践知识有一个基本的了解.本小节将从Linux内核发展史出发,带您走进openEuler的世界,一起学习操作系统的基础知识和open