@@ -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}
3842EXPORT_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+
224248static 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