|
@@ -117,6 +117,130 @@ static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static bool srh1_mt6(const struct sk_buff *skb, struct xt_action_param *par)
|
|
|
+{
|
|
|
+ int hdrlen, psidoff, nsidoff, lsidoff, srhoff = 0;
|
|
|
+ const struct ip6t_srh1 *srhinfo = par->matchinfo;
|
|
|
+ struct in6_addr *psid, *nsid, *lsid;
|
|
|
+ struct in6_addr _psid, _nsid, _lsid;
|
|
|
+ struct ipv6_sr_hdr *srh;
|
|
|
+ struct ipv6_sr_hdr _srh;
|
|
|
+
|
|
|
+ if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
|
|
|
+ return false;
|
|
|
+ srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
|
|
|
+ if (!srh)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ hdrlen = ipv6_optlen(srh);
|
|
|
+ if (skb->len - srhoff < hdrlen)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (srh->type != IPV6_SRCRT_TYPE_4)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (srh->segments_left > srh->first_segment)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* Next Header matching */
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NEXTHDR,
|
|
|
+ !(srh->nexthdr == srhinfo->next_hdr)))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* Header Extension Length matching */
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_EQ,
|
|
|
+ !(srh->hdrlen == srhinfo->hdr_len)))
|
|
|
+ return false;
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_GT,
|
|
|
+ !(srh->hdrlen > srhinfo->hdr_len)))
|
|
|
+ return false;
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_LT,
|
|
|
+ !(srh->hdrlen < srhinfo->hdr_len)))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* Segments Left matching */
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_EQ,
|
|
|
+ !(srh->segments_left == srhinfo->segs_left)))
|
|
|
+ return false;
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_GT,
|
|
|
+ !(srh->segments_left > srhinfo->segs_left)))
|
|
|
+ return false;
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_LT,
|
|
|
+ !(srh->segments_left < srhinfo->segs_left)))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Last Entry matching
|
|
|
+ * Last_Entry field was introduced in revision 6 of the SRH draft.
|
|
|
+ * It was called First_Segment in the previous revision
|
|
|
+ */
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_EQ,
|
|
|
+ !(srh->first_segment == srhinfo->last_entry)))
|
|
|
+ return false;
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_GT,
|
|
|
+ !(srh->first_segment > srhinfo->last_entry)))
|
|
|
+ return false;
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_LT,
|
|
|
+ !(srh->first_segment < srhinfo->last_entry)))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Tag matchig
|
|
|
+ * Tag field was introduced in revision 6 of the SRH draft
|
|
|
+ */
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_TAG)
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_TAG,
|
|
|
+ !(srh->tag == srhinfo->tag)))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* Previous SID matching */
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_PSID) {
|
|
|
+ if (srh->segments_left == srh->first_segment)
|
|
|
+ return false;
|
|
|
+ psidoff = srhoff + sizeof(struct ipv6_sr_hdr) +
|
|
|
+ ((srh->segments_left + 1) * sizeof(struct in6_addr));
|
|
|
+ psid = skb_header_pointer(skb, psidoff, sizeof(_psid), &_psid);
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_PSID,
|
|
|
+ ipv6_masked_addr_cmp(psid, &srhinfo->psid_msk,
|
|
|
+ &srhinfo->psid_addr)))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Next SID matching */
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_NSID) {
|
|
|
+ if (srh->segments_left == 0)
|
|
|
+ return false;
|
|
|
+ nsidoff = srhoff + sizeof(struct ipv6_sr_hdr) +
|
|
|
+ ((srh->segments_left - 1) * sizeof(struct in6_addr));
|
|
|
+ nsid = skb_header_pointer(skb, nsidoff, sizeof(_nsid), &_nsid);
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NSID,
|
|
|
+ ipv6_masked_addr_cmp(nsid, &srhinfo->nsid_msk,
|
|
|
+ &srhinfo->nsid_addr)))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Last SID matching */
|
|
|
+ if (srhinfo->mt_flags & IP6T_SRH_LSID) {
|
|
|
+ lsidoff = srhoff + sizeof(struct ipv6_sr_hdr);
|
|
|
+ lsid = skb_header_pointer(skb, lsidoff, sizeof(_lsid), &_lsid);
|
|
|
+ if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LSID,
|
|
|
+ ipv6_masked_addr_cmp(lsid, &srhinfo->lsid_msk,
|
|
|
+ &srhinfo->lsid_addr)))
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
static int srh_mt6_check(const struct xt_mtchk_param *par)
|
|
|
{
|
|
|
const struct ip6t_srh *srhinfo = par->matchinfo;
|
|
@@ -136,23 +260,54 @@ static int srh_mt6_check(const struct xt_mtchk_param *par)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static struct xt_match srh_mt6_reg __read_mostly = {
|
|
|
- .name = "srh",
|
|
|
- .family = NFPROTO_IPV6,
|
|
|
- .match = srh_mt6,
|
|
|
- .matchsize = sizeof(struct ip6t_srh),
|
|
|
- .checkentry = srh_mt6_check,
|
|
|
- .me = THIS_MODULE,
|
|
|
+static int srh1_mt6_check(const struct xt_mtchk_param *par)
|
|
|
+{
|
|
|
+ const struct ip6t_srh1 *srhinfo = par->matchinfo;
|
|
|
+
|
|
|
+ if (srhinfo->mt_flags & ~IP6T_SRH_MASK) {
|
|
|
+ pr_info_ratelimited("unknown srh match flags %X\n",
|
|
|
+ srhinfo->mt_flags);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
|
|
|
+ pr_info_ratelimited("unknown srh invflags %X\n",
|
|
|
+ srhinfo->mt_invflags);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static struct xt_match srh_mt6_reg[] __read_mostly = {
|
|
|
+ {
|
|
|
+ .name = "srh",
|
|
|
+ .revision = 0,
|
|
|
+ .family = NFPROTO_IPV6,
|
|
|
+ .match = srh_mt6,
|
|
|
+ .matchsize = sizeof(struct ip6t_srh),
|
|
|
+ .checkentry = srh_mt6_check,
|
|
|
+ .me = THIS_MODULE,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ .name = "srh",
|
|
|
+ .revision = 1,
|
|
|
+ .family = NFPROTO_IPV6,
|
|
|
+ .match = srh1_mt6,
|
|
|
+ .matchsize = sizeof(struct ip6t_srh1),
|
|
|
+ .checkentry = srh1_mt6_check,
|
|
|
+ .me = THIS_MODULE,
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
static int __init srh_mt6_init(void)
|
|
|
{
|
|
|
- return xt_register_match(&srh_mt6_reg);
|
|
|
+ return xt_register_matches(srh_mt6_reg, ARRAY_SIZE(srh_mt6_reg));
|
|
|
}
|
|
|
|
|
|
static void __exit srh_mt6_exit(void)
|
|
|
{
|
|
|
- xt_unregister_match(&srh_mt6_reg);
|
|
|
+ xt_unregister_matches(srh_mt6_reg, ARRAY_SIZE(srh_mt6_reg));
|
|
|
}
|
|
|
|
|
|
module_init(srh_mt6_init);
|