Skip to content

Commit bfff486

Browse files
roopa-prabhudavem330
authored andcommitted
net: fib_rules: support for match on ip_proto, sport and dport
uapi for ip_proto, sport and dport range match in fib rules. Signed-off-by: Roopa Prabhu <[email protected]> Acked-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 2927499 commit bfff486

File tree

3 files changed

+133
-3
lines changed

3 files changed

+133
-3
lines changed

include/net/fib_rules.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ struct fib_rule {
2727
u8 action;
2828
u8 l3mdev;
2929
u8 proto;
30-
/* 1 byte hole, try to use */
30+
u8 ip_proto;
3131
u32 target;
3232
__be64 tun_id;
3333
struct fib_rule __rcu *ctarget;
@@ -40,6 +40,8 @@ struct fib_rule {
4040
char iifname[IFNAMSIZ];
4141
char oifname[IFNAMSIZ];
4242
struct fib_kuid_range uid_range;
43+
struct fib_rule_port_range sport_range;
44+
struct fib_rule_port_range dport_range;
4345
struct rcu_head rcu;
4446
};
4547

@@ -144,6 +146,38 @@ static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla)
144146
return frh->table;
145147
}
146148

149+
static inline bool fib_rule_port_range_set(const struct fib_rule_port_range *range)
150+
{
151+
return range->start != 0 && range->end != 0;
152+
}
153+
154+
static inline bool fib_rule_port_inrange(const struct fib_rule_port_range *a,
155+
__be16 port)
156+
{
157+
return ntohs(port) >= a->start &&
158+
ntohs(port) <= a->end;
159+
}
160+
161+
static inline bool fib_rule_port_range_valid(const struct fib_rule_port_range *a)
162+
{
163+
return a->start != 0 && a->end != 0 && a->end < 0xffff &&
164+
a->start <= a->end;
165+
}
166+
167+
static inline bool fib_rule_port_range_compare(struct fib_rule_port_range *a,
168+
struct fib_rule_port_range *b)
169+
{
170+
return a->start == b->start &&
171+
a->end == b->end;
172+
}
173+
174+
static inline bool fib_rule_requires_fldissect(struct fib_rule *rule)
175+
{
176+
return rule->ip_proto ||
177+
fib_rule_port_range_set(&rule->sport_range) ||
178+
fib_rule_port_range_set(&rule->dport_range);
179+
}
180+
147181
struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *,
148182
struct net *);
149183
void fib_rules_unregister(struct fib_rules_ops *);

include/uapi/linux/fib_rules.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ struct fib_rule_uid_range {
3535
__u32 end;
3636
};
3737

38+
struct fib_rule_port_range {
39+
__u16 start;
40+
__u16 end;
41+
};
42+
3843
enum {
3944
FRA_UNSPEC,
4045
FRA_DST, /* destination address */
@@ -59,6 +64,9 @@ enum {
5964
FRA_L3MDEV, /* iif or oif is l3mdev goto its table */
6065
FRA_UID_RANGE, /* UID range */
6166
FRA_PROTOCOL, /* Originator of the rule */
67+
FRA_IP_PROTO, /* ip proto */
68+
FRA_SPORT_RANGE, /* sport */
69+
FRA_DPORT_RANGE, /* dport */
6270
__FRA_MAX
6371
};
6472

net/core/fib_rules.c

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ bool fib_rule_matchall(const struct fib_rule *rule)
3333
if (!uid_eq(rule->uid_range.start, fib_kuid_range_unset.start) ||
3434
!uid_eq(rule->uid_range.end, fib_kuid_range_unset.end))
3535
return false;
36+
if (fib_rule_port_range_set(&rule->sport_range))
37+
return false;
38+
if (fib_rule_port_range_set(&rule->dport_range))
39+
return false;
3640
return true;
3741
}
3842
EXPORT_SYMBOL_GPL(fib_rule_matchall);
@@ -221,6 +225,26 @@ static int nla_put_uid_range(struct sk_buff *skb, struct fib_kuid_range *range)
221225
return nla_put(skb, FRA_UID_RANGE, sizeof(out), &out);
222226
}
223227

228+
static int nla_get_port_range(struct nlattr *pattr,
229+
struct fib_rule_port_range *port_range)
230+
{
231+
const struct fib_rule_port_range *pr = nla_data(pattr);
232+
233+
if (!fib_rule_port_range_valid(pr))
234+
return -EINVAL;
235+
236+
port_range->start = pr->start;
237+
port_range->end = pr->end;
238+
239+
return 0;
240+
}
241+
242+
static int nla_put_port_range(struct sk_buff *skb, int attrtype,
243+
struct fib_rule_port_range *range)
244+
{
245+
return nla_put(skb, attrtype, sizeof(*range), range);
246+
}
247+
224248
static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops,
225249
struct flowi *fl, int flags,
226250
struct fib_lookup_arg *arg)
@@ -425,6 +449,17 @@ static int rule_exists(struct fib_rules_ops *ops, struct fib_rule_hdr *frh,
425449
!uid_eq(r->uid_range.end, rule->uid_range.end))
426450
continue;
427451

452+
if (r->ip_proto != rule->ip_proto)
453+
continue;
454+
455+
if (!fib_rule_port_range_compare(&r->sport_range,
456+
&rule->sport_range))
457+
continue;
458+
459+
if (!fib_rule_port_range_compare(&r->dport_range,
460+
&rule->dport_range))
461+
continue;
462+
428463
if (!ops->compare(r, frh, tb))
429464
continue;
430465
return 1;
@@ -569,6 +604,23 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh,
569604
rule->uid_range = fib_kuid_range_unset;
570605
}
571606

607+
if (tb[FRA_IP_PROTO])
608+
rule->ip_proto = nla_get_u8(tb[FRA_IP_PROTO]);
609+
610+
if (tb[FRA_SPORT_RANGE]) {
611+
err = nla_get_port_range(tb[FRA_SPORT_RANGE],
612+
&rule->sport_range);
613+
if (err)
614+
goto errout_free;
615+
}
616+
617+
if (tb[FRA_DPORT_RANGE]) {
618+
err = nla_get_port_range(tb[FRA_DPORT_RANGE],
619+
&rule->dport_range);
620+
if (err)
621+
goto errout_free;
622+
}
623+
572624
if ((nlh->nlmsg_flags & NLM_F_EXCL) &&
573625
rule_exists(ops, frh, tb, rule)) {
574626
err = -EEXIST;
@@ -634,6 +686,8 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
634686
{
635687
struct net *net = sock_net(skb->sk);
636688
struct fib_rule_hdr *frh = nlmsg_data(nlh);
689+
struct fib_rule_port_range sprange = {0, 0};
690+
struct fib_rule_port_range dprange = {0, 0};
637691
struct fib_rules_ops *ops = NULL;
638692
struct fib_rule *rule, *r;
639693
struct nlattr *tb[FRA_MAX+1];
@@ -667,6 +721,20 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
667721
range = fib_kuid_range_unset;
668722
}
669723

724+
if (tb[FRA_SPORT_RANGE]) {
725+
err = nla_get_port_range(tb[FRA_SPORT_RANGE],
726+
&sprange);
727+
if (err)
728+
goto errout;
729+
}
730+
731+
if (tb[FRA_DPORT_RANGE]) {
732+
err = nla_get_port_range(tb[FRA_DPORT_RANGE],
733+
&dprange);
734+
if (err)
735+
goto errout;
736+
}
737+
670738
list_for_each_entry(rule, &ops->rules_list, list) {
671739
if (tb[FRA_PROTOCOL] &&
672740
(rule->proto != nla_get_u8(tb[FRA_PROTOCOL])))
@@ -712,6 +780,18 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh,
712780
!uid_eq(rule->uid_range.end, range.end)))
713781
continue;
714782

783+
if (tb[FRA_IP_PROTO] &&
784+
(rule->ip_proto != nla_get_u8(tb[FRA_IP_PROTO])))
785+
continue;
786+
787+
if (fib_rule_port_range_set(&sprange) &&
788+
!fib_rule_port_range_compare(&rule->sport_range, &sprange))
789+
continue;
790+
791+
if (fib_rule_port_range_set(&dprange) &&
792+
!fib_rule_port_range_compare(&rule->dport_range, &dprange))
793+
continue;
794+
715795
if (!ops->compare(rule, frh, tb))
716796
continue;
717797

@@ -790,7 +870,10 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops,
790870
+ nla_total_size(4) /* FRA_FWMASK */
791871
+ nla_total_size_64bit(8) /* FRA_TUN_ID */
792872
+ nla_total_size(sizeof(struct fib_kuid_range))
793-
+ nla_total_size(1); /* FRA_PROTOCOL */
873+
+ nla_total_size(1) /* FRA_PROTOCOL */
874+
+ nla_total_size(1) /* FRA_IP_PROTO */
875+
+ nla_total_size(sizeof(struct fib_rule_port_range)) /* FRA_SPORT_RANGE */
876+
+ nla_total_size(sizeof(struct fib_rule_port_range)); /* FRA_DPORT_RANGE */
794877

795878
if (ops->nlmsg_payload)
796879
payload += ops->nlmsg_payload(rule);
@@ -855,7 +938,12 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule,
855938
(rule->l3mdev &&
856939
nla_put_u8(skb, FRA_L3MDEV, rule->l3mdev)) ||
857940
(uid_range_set(&rule->uid_range) &&
858-
nla_put_uid_range(skb, &rule->uid_range)))
941+
nla_put_uid_range(skb, &rule->uid_range)) ||
942+
(fib_rule_port_range_set(&rule->sport_range) &&
943+
nla_put_port_range(skb, FRA_SPORT_RANGE, &rule->sport_range)) ||
944+
(fib_rule_port_range_set(&rule->dport_range) &&
945+
nla_put_port_range(skb, FRA_DPORT_RANGE, &rule->dport_range)) ||
946+
(rule->ip_proto && nla_put_u8(skb, FRA_IP_PROTO, rule->ip_proto)))
859947
goto nla_put_failure;
860948

861949
if (rule->suppress_ifgroup != -1) {

0 commit comments

Comments
 (0)