History

netfilter: add IPv6 segment routing header 'srh' match

It allows matching packets based on Segment Routing Header (SRH) information. The implementation considers revision 7 of the SRH draft. https://tools.ietf.org/html/draft-ietf-6man-segment-routing-header-07 Currently supported match options include: (1) Next Header (2) Hdr Ext Len (3) Segments Left (4) Last Entry (5) Tag value of SRH

Ahmed Abdelsalam committed 8 years ago

Commit 202a8ff1 parent cbef4264 files · +228 −0Browse files

Unified · Split

4 files
  1. include/uapi/linux/netfilter_ipv6/ip6t_srh.h +57 −0
  2. net/ipv6/netfilter/Kconfig +9 −0
  3. net/ipv6/netfilter/Makefile +1 −0
  4. net/ipv6/netfilter/ip6t_srh.c +161 −0
include/uapi/linux/netfilter_ipv6/ip6t_srh.h+57−0
@@ -0,0 +1,57 @@
1+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
2+#ifndef _IP6T_SRH_H
3+#define _IP6T_SRH_H
4+
5+#include <linux/types.h>
6+#include <linux/netfilter.h>
7+
8+/* Values for "mt_flags" field in struct ip6t_srh */
9+#define IP6T_SRH_NEXTHDR 0x0001
10+#define IP6T_SRH_LEN_EQ 0x0002
11+#define IP6T_SRH_LEN_GT 0x0004
12+#define IP6T_SRH_LEN_LT 0x0008
13+#define IP6T_SRH_SEGS_EQ 0x0010
14+#define IP6T_SRH_SEGS_GT 0x0020
15+#define IP6T_SRH_SEGS_LT 0x0040
16+#define IP6T_SRH_LAST_EQ 0x0080
17+#define IP6T_SRH_LAST_GT 0x0100
18+#define IP6T_SRH_LAST_LT 0x0200
19+#define IP6T_SRH_TAG 0x0400
20+#define IP6T_SRH_MASK 0x07FF
21+
22+/* Values for "mt_invflags" field in struct ip6t_srh */
23+#define IP6T_SRH_INV_NEXTHDR 0x0001
24+#define IP6T_SRH_INV_LEN_EQ 0x0002
25+#define IP6T_SRH_INV_LEN_GT 0x0004
26+#define IP6T_SRH_INV_LEN_LT 0x0008
27+#define IP6T_SRH_INV_SEGS_EQ 0x0010
28+#define IP6T_SRH_INV_SEGS_GT 0x0020
29+#define IP6T_SRH_INV_SEGS_LT 0x0040
30+#define IP6T_SRH_INV_LAST_EQ 0x0080
31+#define IP6T_SRH_INV_LAST_GT 0x0100
32+#define IP6T_SRH_INV_LAST_LT 0x0200
33+#define IP6T_SRH_INV_TAG 0x0400
34+#define IP6T_SRH_INV_MASK 0x07FF
35+
36+/**
37+ * struct ip6t_srh - SRH match options
38+ * @ next_hdr: Next header field of SRH
39+ * @ hdr_len: Extension header length field of SRH
40+ * @ segs_left: Segments left field of SRH
41+ * @ last_entry: Last entry field of SRH
42+ * @ tag: Tag field of SRH
43+ * @ mt_flags: match options
44+ * @ mt_invflags: Invert the sense of match options
45+ */
46+
47+struct ip6t_srh {
48+ __u8 next_hdr;
49+ __u8 hdr_len;
50+ __u8 segs_left;
51+ __u8 last_entry;
52+ __u16 tag;
53+ __u16 mt_flags;
54+ __u16 mt_invflags;
55+};
56+
57+#endif /*_IP6T_SRH_H*/
net/ipv6/netfilter/Kconfig+9−0
@@ -240,6 +240,15 @@ config IP6_NF_MATCH_RT · 239 unmodified lines
240240
241241 To compile it as a module, choose M here. If unsure, say N.
242242
243+config IP6_NF_MATCH_SRH
244+ tristate '"srh" Segment Routing header match support'
245+ depends on NETFILTER_ADVANCED
246+ help
247+ srh matching allows you to match packets based on the segment
248+ routing header of the packet.
249+
250+ To compile it as a module, choose M here. If unsure, say N.
251+
243252 # The targets
244253 config IP6_NF_TARGET_HL
245254 tristate '"HL" hoplimit target support'
net/ipv6/netfilter/Makefile+1−0
@@ -57,6 +57,7 @@ obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o · 56 unmodified lines
5757 obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
5858 obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
5959 obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
60+obj-$(CONFIG_IP6_NF_MATCH_SRH) += ip6t_srh.o
6061
6162 # targets
6263 obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
net/ipv6/netfilter/ip6t_srh.c+161−0
@@ -0,0 +1,161 @@
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+
28+static 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+
120+static 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_err("unknown srh match flags %X\n", srhinfo->mt_flags);
126+ return -EINVAL;
127+ }
128+
129+ if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
130+ pr_err("unknown srh invflags %X\n", srhinfo->mt_invflags);
131+ return -EINVAL;
132+ }
133+
134+ return 0;
135+}
136+
137+static struct xt_match srh_mt6_reg __read_mostly = {
138+ .name = "srh",
139+ .family = NFPROTO_IPV6,
140+ .match = srh_mt6,
141+ .matchsize = sizeof(struct ip6t_srh),
142+ .checkentry = srh_mt6_check,
143+ .me = THIS_MODULE,
144+};
145+
146+static int __init srh_mt6_init(void)
147+{
148+ return xt_register_match(&srh_mt6_reg);
149+}
150+
151+static void __exit srh_mt6_exit(void)
152+{
153+ xt_unregister_match(&srh_mt6_reg);
154+}
155+
156+module_init(srh_mt6_init);
157+module_exit(srh_mt6_exit);
158+
159+MODULE_LICENSE("GPL");
160+MODULE_DESCRIPTION("Xtables: IPv6 Segment Routing Header match");
161+MODULE_AUTHOR("Ahmed Abdelsalam <amsalam20@gmail.com>");