diff --git a/include/linux/fib_rules.h b/include/linux/fib_rules.h index 87b606b..dc5a75b 100644 --- a/include/linux/fib_rules.h +++ b/include/linux/fib_rules.h @@ -47,6 +47,8 @@ enum FRA_UNUSED8, FRA_TABLE, /* Extended table id */ FRA_FWMASK, /* mask for netfilter mark */ + FRA_IPSET_N, /* ipset name */ + FRA_IPSET_M, /* ipset match: src or dst */ __FRA_MAX }; diff --git a/include/linux/netfilter_ipv4/ip_set.h b/include/linux/netfilter_ipv4/ip_set.h index da17319..1302e4c 100644 --- a/include/linux/netfilter_ipv4/ip_set.h +++ b/include/linux/netfilter_ipv4/ip_set.h @@ -480,6 +480,8 @@ extern void ip_set_put_byindex(ip_set_id_t index); extern ip_set_id_t ip_set_id(ip_set_id_t index); extern ip_set_id_t __ip_set_get_byname(const char name[IP_SET_MAXNAMELEN], struct ip_set **set); +extern ip_set_id_t __ip_set_get_byindex(ip_set_id_t index, struct ip_set **set); +extern ip_set_id_t __ip_set_byindex(ip_set_id_t index, struct ip_set **set); extern void __ip_set_put_byindex(ip_set_id_t index); /* API for iptables set match, and SET target */ diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index c2bb5ca..585b4ec 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -12,7 +12,10 @@ struct fib_rule struct list_head list; atomic_t refcnt; int ifindex; + int ipset_idx; char ifname[IFNAMSIZ]; + char ipset_n[IFNAMSIZ]; + u32 ipset_m; u32 mark; u32 mark_mask; u32 pref; diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 79de3b1..7943e1e 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -14,6 +14,10 @@ #include #include #include +#ifdef CONFIG_IP_NF_SET +#include +#include +#endif int fib_default_rule_add(struct fib_rules_ops *ops, u32 pref, u32 table, u32 flags) @@ -258,6 +262,17 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) rule->ifindex = dev->ifindex; } + #ifdef CONFIG_IP_NF_SET + if (tb[FRA_IPSET_N]) { + nla_strlcpy(rule->ipset_n, tb[FRA_IPSET_N], IFNAMSIZ); + rule->ipset_idx=IP_SET_INVALID_ID; + } + + if (tb[FRA_IPSET_M]) { + rule->ipset_m = nla_get_u32(tb[FRA_IPSET_M]); + } + #endif + if (tb[FRA_FWMARK]) { rule->mark = nla_get_u32(tb[FRA_FWMARK]); if (rule->mark) @@ -392,6 +407,16 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) nla_strcmp(tb[FRA_IFNAME], rule->ifname)) continue; + #ifdef CONFIG_IP_NF_SET + if (tb[FRA_IPSET_N] && + nla_strcmp(tb[FRA_IPSET_N], rule->ipset_n)) + continue; + + if (tb[FRA_IPSET_M] && + (rule->ipset_m != nla_get_u32(tb[FRA_IPSET_M]))) + continue; + #endif + if (tb[FRA_FWMARK] && (rule->mark != nla_get_u32(tb[FRA_FWMARK]))) continue; @@ -428,6 +453,13 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) } } + #ifdef CONFIG_IP_NF_SET + if(rule->ipset_m && rule->ipset_idx!=IP_SET_INVALID_ID) { + rule->ipset_m=0; + __ip_set_put_byindex(rule->ipset_idx); + } + #endif + synchronize_rcu(); notify_rule_change(RTM_DELRULE, rule, ops, nlh, NETLINK_CB(skb).pid); @@ -448,10 +480,12 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, { size_t payload = NLMSG_ALIGN(sizeof(struct fib_rule_hdr)) + nla_total_size(IFNAMSIZ) /* FRA_IFNAME */ + + nla_total_size(IFNAMSIZ) /* FRA_IPSET_N */ + nla_total_size(4) /* FRA_PRIORITY */ + nla_total_size(4) /* FRA_TABLE */ + nla_total_size(4) /* FRA_FWMARK */ - + nla_total_size(4); /* FRA_FWMASK */ + + nla_total_size(4) /* FRA_FWMASK */ + + nla_total_size(4); /* FRA_IPSET_M */ if (ops->nlmsg_payload) payload += ops->nlmsg_payload(rule); @@ -488,6 +522,13 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, frh->flags |= FIB_RULE_DEV_DETACHED; } + #ifdef CONFIG_IP_NF_SET + if (rule->ipset_m) { + NLA_PUT_STRING(skb, FRA_IPSET_N, rule->ipset_n); + NLA_PUT_U32(skb, FRA_IPSET_M, rule->ipset_m); + } + #endif + if (rule->pref) NLA_PUT_U32(skb, FRA_PRIORITY, rule->pref); diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 6080d71..f4ed3aa 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -31,6 +31,9 @@ #include #include #include +#ifdef CONFIG_IP_NF_SET +#include +#endif struct fib4_rule { @@ -105,6 +108,11 @@ errout: static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) { struct fib4_rule *r = (struct fib4_rule *) rule; + #ifdef CONFIG_IP_NF_SET + struct ip_set *set; + int err; + __be32 addr; + #endif __be32 daddr = fl->fl4_dst; __be32 saddr = fl->fl4_src; @@ -115,6 +123,32 @@ static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) if (r->tos && (r->tos != fl->fl4_tos)) return 0; + #ifdef CONFIG_IP_NF_SET + if(!rule->ipset_m) + return 1; + if(rule->ipset_idx==IP_SET_INVALID_ID) { + if((rule->ipset_idx=__ip_set_get_byname(rule->ipset_n,&set))==IP_SET_INVALID_ID) + return 0; + } + if(__ip_set_byindex(rule->ipset_idx,&set)==IP_SET_INVALID_ID) + return 0; + switch(rule->ipset_m) { + case 1: + addr=ntohl(saddr); + break; + + case 2: + addr=ntohl(daddr); + break; + + default: + return 0; + } + err=set->type->testip(set,&addr,4); + if(!err || err<0) + return 0; + #endif + return 1; } diff --git a/net/ipv4/netfilter/ip_set.c b/net/ipv4/netfilter/ip_set.c index 7ecdc83..a583389 100644 --- a/net/ipv4/netfilter/ip_set.c +++ b/net/ipv4/netfilter/ip_set.c @@ -225,6 +225,33 @@ __ip_set_get_byname(const char *name, struct ip_set **set) return index; } +ip_set_id_t +__ip_set_get_byindex(ip_set_id_t index, struct ip_set **set) +{ + if (index >= ip_set_max) + return IP_SET_INVALID_ID; + + if (ip_set_list[index]) { + __ip_set_get(index); + *set = ip_set_list[index]; + return index; + } + return IP_SET_INVALID_ID; +} + +ip_set_id_t +__ip_set_byindex(ip_set_id_t index, struct ip_set **set) +{ + if (index >= ip_set_max) + return IP_SET_INVALID_ID; + + if (ip_set_list[index]) { + *set = ip_set_list[index]; + return index; + } + return IP_SET_INVALID_ID; +} + void __ip_set_put_byindex(ip_set_id_t index) {