linux/net/ipv6/netfilter/ip6t_srh.c
<<
>>
Prefs
   1/* Kernel module to match Segment Routing Header (SRH) parameters. */
   2
   3/* Author:
   4 * Ahmed Abdelsalam <amsalam20@gmail.com>
   5 *
   6 *  This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License
   8 *      as published by the Free Software Foundation; either version 2
   9 *      of the License, or (at your option) any later version.
  10 */
  11
  12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  13#include <linux/module.h>
  14#include <linux/skbuff.h>
  15#include <linux/ipv6.h>
  16#include <linux/types.h>
  17#include <net/ipv6.h>
  18#include <net/seg6.h>
  19
  20#include <linux/netfilter/x_tables.h>
  21#include <linux/netfilter_ipv6/ip6t_srh.h>
  22#include <linux/netfilter_ipv6/ip6_tables.h>
  23
  24/* Test a struct->mt_invflags and a boolean for inequality */
  25#define NF_SRH_INVF(ptr, flag, boolean) \
  26        ((boolean) ^ !!((ptr)->mt_invflags & (flag)))
  27
  28static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
  29{
  30        const struct ip6t_srh *srhinfo = par->matchinfo;
  31        struct ipv6_sr_hdr *srh;
  32        struct ipv6_sr_hdr _srh;
  33        int hdrlen, srhoff = 0;
  34
  35        if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
  36                return false;
  37        srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
  38        if (!srh)
  39                return false;
  40
  41        hdrlen = ipv6_optlen(srh);
  42        if (skb->len - srhoff < hdrlen)
  43                return false;
  44
  45        if (srh->type != IPV6_SRCRT_TYPE_4)
  46                return false;
  47
  48        if (srh->segments_left > srh->first_segment)
  49                return false;
  50
  51        /* Next Header matching */
  52        if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
  53                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NEXTHDR,
  54                                !(srh->nexthdr == srhinfo->next_hdr)))
  55                        return false;
  56
  57        /* Header Extension Length matching */
  58        if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
  59                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_EQ,
  60                                !(srh->hdrlen == srhinfo->hdr_len)))
  61                        return false;
  62
  63        if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
  64                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_GT,
  65                                !(srh->hdrlen > srhinfo->hdr_len)))
  66                        return false;
  67
  68        if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
  69                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_LT,
  70                                !(srh->hdrlen < srhinfo->hdr_len)))
  71                        return false;
  72
  73        /* Segments Left matching */
  74        if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
  75                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_EQ,
  76                                !(srh->segments_left == srhinfo->segs_left)))
  77                        return false;
  78
  79        if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
  80                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_GT,
  81                                !(srh->segments_left > srhinfo->segs_left)))
  82                        return false;
  83
  84        if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
  85                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_LT,
  86                                !(srh->segments_left < srhinfo->segs_left)))
  87                        return false;
  88
  89        /**
  90         * Last Entry matching
  91         * Last_Entry field was introduced in revision 6 of the SRH draft.
  92         * It was called First_Segment in the previous revision
  93         */
  94        if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
  95                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_EQ,
  96                                !(srh->first_segment == srhinfo->last_entry)))
  97                        return false;
  98
  99        if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
 100                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_GT,
 101                                !(srh->first_segment > srhinfo->last_entry)))
 102                        return false;
 103
 104        if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
 105                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_LT,
 106                                !(srh->first_segment < srhinfo->last_entry)))
 107                        return false;
 108
 109        /**
 110         * Tag matchig
 111         * Tag field was introduced in revision 6 of the SRH draft.
 112         */
 113        if (srhinfo->mt_flags & IP6T_SRH_TAG)
 114                if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_TAG,
 115                                !(srh->tag == srhinfo->tag)))
 116                        return false;
 117        return true;
 118}
 119
 120static int srh_mt6_check(const struct xt_mtchk_param *par)
 121{
 122        const struct ip6t_srh *srhinfo = par->matchinfo;
 123
 124        if (srhinfo->mt_flags & ~IP6T_SRH_MASK) {
 125                pr_info_ratelimited("unknown srh match flags  %X\n",
 126                                    srhinfo->mt_flags);
 127                return -EINVAL;
 128        }
 129
 130        if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
 131                pr_info_ratelimited("unknown srh invflags %X\n",
 132                                    srhinfo->mt_invflags);
 133                return -EINVAL;
 134        }
 135
 136        return 0;
 137}
 138
 139static struct xt_match srh_mt6_reg __read_mostly = {
 140        .name           = "srh",
 141        .family         = NFPROTO_IPV6,
 142        .match          = srh_mt6,
 143        .matchsize      = sizeof(struct ip6t_srh),
 144        .checkentry     = srh_mt6_check,
 145        .me             = THIS_MODULE,
 146};
 147
 148static int __init srh_mt6_init(void)
 149{
 150        return xt_register_match(&srh_mt6_reg);
 151}
 152
 153static void __exit srh_mt6_exit(void)
 154{
 155        xt_unregister_match(&srh_mt6_reg);
 156}
 157
 158module_init(srh_mt6_init);
 159module_exit(srh_mt6_exit);
 160
 161MODULE_LICENSE("GPL");
 162MODULE_DESCRIPTION("Xtables: IPv6 Segment Routing Header match");
 163MODULE_AUTHOR("Ahmed Abdelsalam <amsalam20@gmail.com>");
 164