基于域名的iptables防火墙设计与实现

作者: 李臣

基于域名的iptables防火墙设计与实现0

摘要:网络安全问题在现实生活中变的愈发重要,而研究利用操作系统自带的防火墙系统来阻断异常流量是解决网络安全问题最常使用且高效的手段。Linux操作系统作为一个开源的操作系统广泛应用于服务器和嵌入式领域,而这些领域往往是网络安全问题的重灾区,研究Linux下的防火墙具有重要意义。现有的防火墙系统中的配置规则一般是基于IP配置的,但是对于多个域名对应一个IP的场景这种配置便不再适用,文章在Netfilter框架的基础上设计实现了一个基于域名进行配置的内核模块来解决上述问题。

关键词: 网络安全; 异常流量;Linux操作系统; 防火墙规则; Netfilter框架

中图分类号:TP311      文献标识码:A

文章编号:1009-3044(2023)06-0066-03

开放科学(资源服务)标识码(OSID)

随着虚拟主机的广泛应用,一个IP经常会对应多个域名[1]。这样导致我们在使用防火墙进行单个或多个IP流量阻断时会发生错误域名的阻断。为了解决这一难题,本文基于Netfilter框架的可扩展性开发了一个Linux内核模块使得防火墙可以针对具体的域名或者域名集进行流量的阻断。

1  Netfilter/Iptables框架

Netfilter/Iptables 由三部分组成,分别是Netfilter框架,Iptables(内核空间)和Iptables 命令行工具(用户空间)[2]。

1.1  Netfilter框架

Netfilter是Linux内核提供的一个框架[3],它允许以自定义处理程序的形式实现各种与网络相关的操作。Netfilter 在 Linux内核中表现为一系列的hook, 并允许Linux 内核模块注册为回调函数,Linux内核模块通过回调函数操作网络报文。Netfilter框架一共提供了5个hook,分别位于linux 网络栈中的各个处理节点,如图1所示:

Netfilter Hook的意义:

NF_IP_PRE_ROUTING: 位于路由之前,报文一致性检查之后(报文一致性检查包括: 报文版本、报文长度和checksum)。

NF_IP_LOCAL_IN: 位于报文经过路由之后,并且目的是本机的。

NF_IP_FORWARD:位于在报文路由之后,目的地非本机的。

NF_IP_LOCAL_OUT: 由本机发出去的报文,并且在路由之前。

NF_IP_POST_ROUTING: 所有即将离开本机的报文。

Linux 内核模块可以注册到任何的hook,注册的回调函数也必须指定优先级。当一个报文通过hook的时候,hook将会依据优先级调用回调函数。注册的回调函数,可以有五种返回,每种返回代表对报文不同的操作:

NF_ACCEPT: 继续正常处理此报文,即允许报文通过。

NF_DROP: 丢弃此报文,不再进行继续处理,即拒绝此报文。

NF_STOLEN: 取走这个报文,不再继续处理。

NF_QUEUE: 报文进行重新排队,可以将报文发到用户空间的程序,进行修改或者决定是拒绝或者允许。

NF_REPEAT: 报文重新调用hook。

1.2 Iptables内核空间

Iptables 是基于Netfilter框架实现的报文选择系统[4],其可以用于报文的过滤、网络地址转换和报文修改等功能。Iptables 本质上是包含了5个规则表,而规则表则包含了一些列的报文的匹配规则以及操作目标。以下对每个规则表进行了简单说明:

Filter Table: 是一个默认的规则表,用于报文的过滤,注册了三个链: INPUT、FORWARD和OUTPUT。

NAT Table: 主要用于NAT转换,注册了四个链:PREROUTING、INPUT、OUTPUT和POSTROUTING。

Mangle Table: 主要用于报文的修改,一共注册了五个链: PREROUTING、OUTPUT、INPUT、FORWARD和POSTROUTING。

Raw Table: 可以对报文不进行链路跟踪,其优先级在hook中注册很高,注册了两个链: PREROUTING和OUTPUT。

Security Table: 用于强制网络接入控制,注册了三个链:INPUT、OUTPUT 和 FORWARD。

1.3 Iptables命令行工具(用户空间)

Iptables命令行工具是工作在用户空间的操作工具,用于修改内核空间的规则表[5]。

2 SNI(服务器名称指示)

SNI 是 TLS 协议(以前称为 SSL 协议)的扩展[6],该协议在 HTTPS 中使用,它的出现是为了解决多个服务器域名对应同一个IP而产生客户端不知道链接哪个服务端的问题。它包含在 TLS/SSL 握手流程中,以确保客户端设备能够看到他们尝试访问的网站的正确 SSL 证书。该扩展使得可以在 TLS 握手期间指定网站的主机名或域名 ,而不是在握手之后打开 HTTP 连接时指定。

3 SNI防火墙实现

基于Netfilter框架很好的扩展性,用户可以开发编写自定义的Linux内核模块并在Netfilter上注册为回调函数来实现自定义的防火墙功能。

3.1  匹配模块的实现

每一条iptables配置的规则中都包含了匹配条件(match)和动作(target),要定义一个新的匹配条件就要实现一个匹配条件模块[7]。匹配模块的职责是检测每一个数据包确定是否满足匹配条件。首先要定义一个xt_match结构体类型的变量,模块初始化的时候调用xt_register_match函数将其注册到netfilter框架中,xt_match结构体的定义如下:

struct xt_match {

const char name[XT_EXTENSION_MAXNAMELEN];

unsigned short family;

bool (*match) (const struct sk_buff *sbk, struct xt_action_param *);

int (*checkentry) (const struct xt_mtchk_param *);

void (*destroy) (const struct xt_mtdtor_param *);

}

3.1.1 自定义结构体

我们在iptables命令中支持的匹配条件包括域名精确匹配、域名模糊匹配和域名集匹配。域名集的匹配借鉴了ipsets[8]。为了支持这些功能自定义了一个结构体xt_tls_info和host_set

struct xt_tls_info {

char host_or_set_name[MAX_HOSTNAME_LEN + 1]; //匹配条件中的单个域名和域名集

__s32 hostset_index; //域名集存储在域名表中的位置

}

3.1.2 域名集数据的存入与查询

域名集中的数据集合的存入使用Linux系统中的proc文件系统,每一个域名集对应proc文件系统中的一个目录。

host_set hs;

hs->proc_file = proc_create_data(name, 0644, proc_fs_hostset_dir, &proc_fops, hs);

在做查询的时候我们使用红黑树来做高性能查询。

3.1.3 tls_mt_init函数

原型为:static int __init tls_mt_init (void)

主要完成xt_register_matches函数将xt_match类型的变量tls_mt_regs[]注册到netfilter框架中及host_set表的初始化:

static struct host_set *host_set_table;

host_set_table = kmalloc(sizeof (struct host_set) * max_host_sets, GFP_KERNEL);

3.1.4 tls_mt_check函数

原型为:static int tls_mt_check (const struct xt_mtchk_param *par)

首先得到iptable命令中的匹配信息,对应到代码中的xt_tls_info类型的变量match_info,判断规则中的匹配信息是不是域名集,如果是则把该域名集信息存入到host_set_table中。存入到表中的索引位置也要放入match_info变量的hostset_index中。

3.1.5 tls_mt函数

原型为:static bool tls_mt(const struct sk_buff *skb, struct xt_action_param *par)

首先我们会根据HTTPS协议的格式从skb->data中解析出SNI中的域名,然后从par->mathchinfo中取出我们在iptables中创建的匹配信息,从而进行规则匹配。根据标准以太网数据格式RFC6066[],SNI字段的位置和多个字段有关。具体处理流程为:

在整个TCP报文中截取TCP报文头之后的有效TLS协议负载报文数据data

检测data数组的第一个元素Content Type判断是否为0x16(Handshake)

检测data数组的第六个元素Handshake协议判断是否为0x01(Client Hello)

依次检测Session ID长度、ciphers长度、compression types长度是否小于报文头长度

检测通过后得到所有扩展数据项,依次遍历这些扩展数据得到SNI的数据

得到域名的信息之后我们再与规则中的域名或者域名集信息进行匹配。若是域名信息则直接使用glob_match函数进行精确或者模糊匹配。若是域名集信息则根据match_info的索引信息精确定位到host_set_table表中的位置再进行匹配。

3.1.6 tls_mt_destroy函数

原型为:static void tls_mt_destroy(const struct xt_mtdtor_param *par)

在iptables命令中删除规则时根据par中的match_info信息删除相应的域名或者域名集信息。

3.2 用户态功能实现

首先定义一个xtables_match类型的变量:

static struct xtables_match tls_match = {

.name = "tls",    // 扩展名称与匹配模块中的名称一致

.size = XT_ALIGN(sizeof(struct xt_tls_info)),

.userspacesize = XT_ALIGN(sizeof(struct xt_tls_info)),

.help = tls_help,  // 输入iptables -m tls -h调用

上一篇 点击页面呼出菜单 下一篇