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
47struct 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
240 240
241 To compile it as a module, choose M here. If unsure, say N.241 To compile it as a module, choose M here. If unsure, say N.
242 242
243config 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
243# The targets252# The targets
244config IP6_NF_TARGET_HL253config IP6_NF_TARGET_HL
245 tristate '"HL" hoplimit target support'254 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
57obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o57obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
58obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o58obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
59obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o59obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
60obj-$(CONFIG_IP6_NF_MATCH_SRH) += ip6t_srh.o
60 61
61# targets62# targets
62obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o63obj-$(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
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_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
137static 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
146static int __init srh_mt6_init(void)
147{
148 return xt_register_match(&srh_mt6_reg);
149}
150
151static void __exit srh_mt6_exit(void)
152{
153 xt_unregister_match(&srh_mt6_reg);
154}
155
156module_init(srh_mt6_init);
157module_exit(srh_mt6_exit);
158
159MODULE_LICENSE("GPL");
160MODULE_DESCRIPTION("Xtables: IPv6 Segment Routing Header match");
161MODULE_AUTHOR("Ahmed Abdelsalam <amsalam20@gmail.com>");