iprange匹配帮助信息如下。

iprange match options:
[!] --src-range ip[-ip]    Match source IP in the specified range
[!] --dst-range ip[-ip]    Match destination IP in the specified range

配置如下策略,丢弃源地址在区间:[192.168.1.90 - 192.168.1.110]中的报文。

# iptables -A INPUT -m iprange --src-range 192.168.1.90-192.168.1.110 -j DROP 
# 
# iptables -L -n -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            source IP range 192.168.1.90-192.168.1.110

iprange匹配

函数xt_register_matches注册匹配结构iprange_mt_reg。

static struct xt_match iprange_mt_reg[] __read_mostly = {
    {
        .name      = "iprange",
        .revision  = 1,
        .family    = NFPROTO_IPV4,
        .match     = iprange_mt4,
        .matchsize = sizeof(struct xt_iprange_mtinfo),
        .me        = THIS_MODULE,
    },
    {
        .name      = "iprange",
        .revision  = 1,
        .family    = NFPROTO_IPV6,
        .match     = iprange_mt6,
        .matchsize = sizeof(struct xt_iprange_mtinfo),
        .me        = THIS_MODULE,
    },
};
static int __init iprange_mt_init(void)
{
    return xt_register_matches(iprange_mt_reg, ARRAY_SIZE(iprange_mt_reg));

对于IPv4协议,规则参数src-range对应于标志IPRANGE_SRC;参数dst-range对应于标志IPRANGE_DST,分别判断报文IP头部的源和目的地址,是否位于配置的区间之外,为真返回false,否则,返回true。

static bool
iprange_mt4(const struct sk_buff *skb, struct xt_action_param *par)
{
    const struct xt_iprange_mtinfo *info = par->matchinfo;
    const struct iphdr *iph = ip_hdr(skb);

    if (info->flags & IPRANGE_SRC) {
        m  = ntohl(iph->saddr) < ntohl(info->src_min.ip);
        m |= ntohl(iph->saddr) > ntohl(info->src_max.ip);
        m ^= !!(info->flags & IPRANGE_SRC_INV);
        if (m)
            return false;
    }
    if (info->flags & IPRANGE_DST) {
        m  = ntohl(iph->daddr) < ntohl(info->dst_min.ip);
        m |= ntohl(iph->daddr) > ntohl(info->dst_max.ip);
        m ^= !!(info->flags & IPRANGE_DST_INV);
        if (m)
            return false;
    }
    return true;

对于IPv6协议,由函数iprange_ipv6_lt比较两个地址的大小。

static inline int
iprange_ipv6_lt(const struct in6_addr *a, const struct in6_addr *b)
{
    unsigned int i; 
        
    for (i = 0; i < 4; ++i) {
        if (a->s6_addr32[i] != b->s6_addr32[i])
            return ntohl(a->s6_addr32[i]) < ntohl(b->s6_addr32[i]);
    }               
    return 0;

将报文头部的IPv6地址,与配置的区间进行比较。

static bool 
iprange_mt6(const struct sk_buff *skb, struct xt_action_param *par)
{   
    const struct xt_iprange_mtinfo *info = par->matchinfo;
    const struct ipv6hdr *iph = ipv6_hdr(skb);
    bool m;
        
    if (info->flags & IPRANGE_SRC) {
        m  = iprange_ipv6_lt(&iph->saddr, &info->src_min.in6);
        m |= iprange_ipv6_lt(&info->src_max.in6, &iph->saddr);
        m ^= !!(info->flags & IPRANGE_SRC_INV);
        if (m)
            return false;
    }
    if (info->flags & IPRANGE_DST) {
        m  = iprange_ipv6_lt(&iph->daddr, &info->dst_min.in6);
        m |= iprange_ipv6_lt(&info->dst_max.in6, &iph->daddr);
        m ^= !!(info->flags & IPRANGE_DST_INV);
        if (m)
            return false;
    }
    return true;

内核版本 5.10