Netfilter源码分析(6)

2020-05-27 00:00:00 规则 接口 地址 匹配 目的


ip_packet_match函数,标准match部份的匹配

先来看看相关的数据结构,在内核中,标准的match是以struct ipt_ip 结构来表示的,它包含了一条规则基本的部份:
/* Yes, Virginia, you have to zero the padding. */
struct ipt_ip {
/* 来源/目的地址 */
struct in_addr src, dst;
/* 来源/目的地址的掩码 */
struct in_addr smsk, dmsk;
/*输入输出网络接口*/
char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];

/* 协议, 0 = ANY */
u_int16_t proto;

/* 标志字段 */
u_int8_t flags;
/* 取反标志 */
u_int8_t invflags;
};

这样,再来看这部份的判断是一个很简单的事情了:

/* Returns whether matches rule or not. */
static inline int
ip_packet_match(const struct iphdr *ip,
const char *indev,
const char *outdev,
const struct ipt_ip *ipinfo,
int isfrag)
{
size_t i;
unsigned long ret;
/*定义一个宏,当bool和invflg的是一真一假的情况时,返回真。注意这里使用两个“!”的目的是使得这样计算后的值域只取0和1两个值*/
#define FWINV(bool,invflg) ((bool) ^ !!(ipinfo->invflags & invflg))

/*处理源和目标ip地址,这个if语句的意义是:到达分组的源ip地址经过掩码处理后与规则中的ip不匹配并且规则中
没有包含对ip地址的取反,或者规则中包含了对匹配地址的取反,但到达分组的源ip与规则中的ip地址匹配,if的第
一部分返回真,同样道理处理到达分组的目的ip地址。这两部分任意部分为真时,源或者目标地址不匹配。*/
if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr,
IPT_INV_SRCIP)
|| FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
IPT_INV_DSTIP)) {
dprintf("Source or dest mismatch.\n");

dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n",
NIPQUAD(ip->saddr),
NIPQUAD(ipinfo->smsk.s_addr),
NIPQUAD(ipinfo->src.s_addr),
ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : "");
dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n",
NIPQUAD(ip->daddr),
NIPQUAD(ipinfo->dmsk.s_addr),
NIPQUAD(ipinfo->dst.s_addr),
ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : "");
return 0;
}

/*接着处理输入和输出的接口,for语句处理接口是否与规则中的接口匹配,不匹配时,ret返回非零,离开for语句后,
处理接口的取反问题:当接口不匹配并且接口不取反,或者接口匹配,但是接口取反,说明接口不匹配。*/

/*输入接口*/
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
ret |= (((const unsigned long *)indev)
^ ((const unsigned long *)ipinfo->iniface))
& ((const unsigned long *)ipinfo->iniface_mask);
}

if (FWINV(ret != 0, IPT_INV_VIA_IN)) {
dprintf("VIA in mismatch (%s vs %s).%s\n",
indev, ipinfo->iniface,
ipinfo->invflags&IPT_INV_VIA_IN ?" (INV)":"");
return 0;
}

/*输出接口*/
for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
ret |= (((const unsigned long *)outdev)
^ ((const unsigned long *)ipinfo->outiface))
& ((const unsigned long *)ipinfo->outiface_mask);
}

if (FWINV(ret != 0, IPT_INV_VIA_OUT)) {
dprintf("VIA out mismatch (%s vs %s).%s\n",
outdev, ipinfo->outiface,
ipinfo->invflags&IPT_INV_VIA_OUT ?" (INV)":"");
return 0;
}

/* 检查协议是否匹配的情况 */
if (ipinfo->proto
&& FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) {
dprintf("Packet protocol %hi does not match %hi.%s\n",
ip->protocol, ipinfo->proto,
ipinfo->invflags&IPT_INV_PROTO ? " (INV)":"");
return 0;
}

/* If we have a fragment rule but the packet is not a fragment
* then we return zero */
/*处理分片包的匹配情况*/
if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) {
dprintf("Fragment rule but not fragment.%s\n",
ipinfo->invflags & IPT_INV_FRAG ? " (INV)" : "");
return 0;
}

return 1;
}

文章来源CU社区:[原创]Netfilter源码分析-我来抛砖,望能引玉

相关文章