aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/netfilter_ipv6/ip6t_srh.h43
-rw-r--r--net/ipv6/netfilter/ip6t_srh.c173
2 files changed, 205 insertions, 11 deletions
diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_srh.h b/include/uapi/linux/netfilter_ipv6/ip6t_srh.h
index f3cc0ef514a7..54ed83360dac 100644
--- a/include/uapi/linux/netfilter_ipv6/ip6t_srh.h
+++ b/include/uapi/linux/netfilter_ipv6/ip6t_srh.h
@@ -17,7 +17,10 @@
17#define IP6T_SRH_LAST_GT 0x0100 17#define IP6T_SRH_LAST_GT 0x0100
18#define IP6T_SRH_LAST_LT 0x0200 18#define IP6T_SRH_LAST_LT 0x0200
19#define IP6T_SRH_TAG 0x0400 19#define IP6T_SRH_TAG 0x0400
20#define IP6T_SRH_MASK 0x07FF 20#define IP6T_SRH_PSID 0x0800
21#define IP6T_SRH_NSID 0x1000
22#define IP6T_SRH_LSID 0x2000
23#define IP6T_SRH_MASK 0x3FFF
21 24
22/* Values for "mt_invflags" field in struct ip6t_srh */ 25/* Values for "mt_invflags" field in struct ip6t_srh */
23#define IP6T_SRH_INV_NEXTHDR 0x0001 26#define IP6T_SRH_INV_NEXTHDR 0x0001
@@ -31,7 +34,10 @@
31#define IP6T_SRH_INV_LAST_GT 0x0100 34#define IP6T_SRH_INV_LAST_GT 0x0100
32#define IP6T_SRH_INV_LAST_LT 0x0200 35#define IP6T_SRH_INV_LAST_LT 0x0200
33#define IP6T_SRH_INV_TAG 0x0400 36#define IP6T_SRH_INV_TAG 0x0400
34#define IP6T_SRH_INV_MASK 0x07FF 37#define IP6T_SRH_INV_PSID 0x0800
38#define IP6T_SRH_INV_NSID 0x1000
39#define IP6T_SRH_INV_LSID 0x2000
40#define IP6T_SRH_INV_MASK 0x3FFF
35 41
36/** 42/**
37 * struct ip6t_srh - SRH match options 43 * struct ip6t_srh - SRH match options
@@ -54,4 +60,37 @@ struct ip6t_srh {
54 __u16 mt_invflags; 60 __u16 mt_invflags;
55}; 61};
56 62
63/**
64 * struct ip6t_srh1 - SRH match options (revision 1)
65 * @ next_hdr: Next header field of SRH
66 * @ hdr_len: Extension header length field of SRH
67 * @ segs_left: Segments left field of SRH
68 * @ last_entry: Last entry field of SRH
69 * @ tag: Tag field of SRH
70 * @ psid_addr: Address of previous SID in SRH SID list
71 * @ nsid_addr: Address of NEXT SID in SRH SID list
72 * @ lsid_addr: Address of LAST SID in SRH SID list
73 * @ psid_msk: Mask of previous SID in SRH SID list
74 * @ nsid_msk: Mask of next SID in SRH SID list
75 * @ lsid_msk: MAsk of last SID in SRH SID list
76 * @ mt_flags: match options
77 * @ mt_invflags: Invert the sense of match options
78 */
79
80struct ip6t_srh1 {
81 __u8 next_hdr;
82 __u8 hdr_len;
83 __u8 segs_left;
84 __u8 last_entry;
85 __u16 tag;
86 struct in6_addr psid_addr;
87 struct in6_addr nsid_addr;
88 struct in6_addr lsid_addr;
89 struct in6_addr psid_msk;
90 struct in6_addr nsid_msk;
91 struct in6_addr lsid_msk;
92 __u16 mt_flags;
93 __u16 mt_invflags;
94};
95
57#endif /*_IP6T_SRH_H*/ 96#endif /*_IP6T_SRH_H*/
diff --git a/net/ipv6/netfilter/ip6t_srh.c b/net/ipv6/netfilter/ip6t_srh.c
index 33719d5560c8..1059894a6f4c 100644
--- a/net/ipv6/netfilter/ip6t_srh.c
+++ b/net/ipv6/netfilter/ip6t_srh.c
@@ -117,6 +117,130 @@ static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
117 return true; 117 return true;
118} 118}
119 119
120static bool srh1_mt6(const struct sk_buff *skb, struct xt_action_param *par)
121{
122 int hdrlen, psidoff, nsidoff, lsidoff, srhoff = 0;
123 const struct ip6t_srh1 *srhinfo = par->matchinfo;
124 struct in6_addr *psid, *nsid, *lsid;
125 struct in6_addr _psid, _nsid, _lsid;
126 struct ipv6_sr_hdr *srh;
127 struct ipv6_sr_hdr _srh;
128
129 if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0)
130 return false;
131 srh = skb_header_pointer(skb, srhoff, sizeof(_srh), &_srh);
132 if (!srh)
133 return false;
134
135 hdrlen = ipv6_optlen(srh);
136 if (skb->len - srhoff < hdrlen)
137 return false;
138
139 if (srh->type != IPV6_SRCRT_TYPE_4)
140 return false;
141
142 if (srh->segments_left > srh->first_segment)
143 return false;
144
145 /* Next Header matching */
146 if (srhinfo->mt_flags & IP6T_SRH_NEXTHDR)
147 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NEXTHDR,
148 !(srh->nexthdr == srhinfo->next_hdr)))
149 return false;
150
151 /* Header Extension Length matching */
152 if (srhinfo->mt_flags & IP6T_SRH_LEN_EQ)
153 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_EQ,
154 !(srh->hdrlen == srhinfo->hdr_len)))
155 return false;
156 if (srhinfo->mt_flags & IP6T_SRH_LEN_GT)
157 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_GT,
158 !(srh->hdrlen > srhinfo->hdr_len)))
159 return false;
160 if (srhinfo->mt_flags & IP6T_SRH_LEN_LT)
161 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LEN_LT,
162 !(srh->hdrlen < srhinfo->hdr_len)))
163 return false;
164
165 /* Segments Left matching */
166 if (srhinfo->mt_flags & IP6T_SRH_SEGS_EQ)
167 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_EQ,
168 !(srh->segments_left == srhinfo->segs_left)))
169 return false;
170 if (srhinfo->mt_flags & IP6T_SRH_SEGS_GT)
171 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_GT,
172 !(srh->segments_left > srhinfo->segs_left)))
173 return false;
174 if (srhinfo->mt_flags & IP6T_SRH_SEGS_LT)
175 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_SEGS_LT,
176 !(srh->segments_left < srhinfo->segs_left)))
177 return false;
178
179 /**
180 * Last Entry matching
181 * Last_Entry field was introduced in revision 6 of the SRH draft.
182 * It was called First_Segment in the previous revision
183 */
184 if (srhinfo->mt_flags & IP6T_SRH_LAST_EQ)
185 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_EQ,
186 !(srh->first_segment == srhinfo->last_entry)))
187 return false;
188 if (srhinfo->mt_flags & IP6T_SRH_LAST_GT)
189 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_GT,
190 !(srh->first_segment > srhinfo->last_entry)))
191 return false;
192 if (srhinfo->mt_flags & IP6T_SRH_LAST_LT)
193 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LAST_LT,
194 !(srh->first_segment < srhinfo->last_entry)))
195 return false;
196
197 /**
198 * Tag matchig
199 * Tag field was introduced in revision 6 of the SRH draft
200 */
201 if (srhinfo->mt_flags & IP6T_SRH_TAG)
202 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_TAG,
203 !(srh->tag == srhinfo->tag)))
204 return false;
205
206 /* Previous SID matching */
207 if (srhinfo->mt_flags & IP6T_SRH_PSID) {
208 if (srh->segments_left == srh->first_segment)
209 return false;
210 psidoff = srhoff + sizeof(struct ipv6_sr_hdr) +
211 ((srh->segments_left + 1) * sizeof(struct in6_addr));
212 psid = skb_header_pointer(skb, psidoff, sizeof(_psid), &_psid);
213 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_PSID,
214 ipv6_masked_addr_cmp(psid, &srhinfo->psid_msk,
215 &srhinfo->psid_addr)))
216 return false;
217 }
218
219 /* Next SID matching */
220 if (srhinfo->mt_flags & IP6T_SRH_NSID) {
221 if (srh->segments_left == 0)
222 return false;
223 nsidoff = srhoff + sizeof(struct ipv6_sr_hdr) +
224 ((srh->segments_left - 1) * sizeof(struct in6_addr));
225 nsid = skb_header_pointer(skb, nsidoff, sizeof(_nsid), &_nsid);
226 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_NSID,
227 ipv6_masked_addr_cmp(nsid, &srhinfo->nsid_msk,
228 &srhinfo->nsid_addr)))
229 return false;
230 }
231
232 /* Last SID matching */
233 if (srhinfo->mt_flags & IP6T_SRH_LSID) {
234 lsidoff = srhoff + sizeof(struct ipv6_sr_hdr);
235 lsid = skb_header_pointer(skb, lsidoff, sizeof(_lsid), &_lsid);
236 if (NF_SRH_INVF(srhinfo, IP6T_SRH_INV_LSID,
237 ipv6_masked_addr_cmp(lsid, &srhinfo->lsid_msk,
238 &srhinfo->lsid_addr)))
239 return false;
240 }
241 return true;
242}
243
120static int srh_mt6_check(const struct xt_mtchk_param *par) 244static int srh_mt6_check(const struct xt_mtchk_param *par)
121{ 245{
122 const struct ip6t_srh *srhinfo = par->matchinfo; 246 const struct ip6t_srh *srhinfo = par->matchinfo;
@@ -136,23 +260,54 @@ static int srh_mt6_check(const struct xt_mtchk_param *par)
136 return 0; 260 return 0;
137} 261}
138 262
139static struct xt_match srh_mt6_reg __read_mostly = { 263static int srh1_mt6_check(const struct xt_mtchk_param *par)
140 .name = "srh", 264{
141 .family = NFPROTO_IPV6, 265 const struct ip6t_srh1 *srhinfo = par->matchinfo;
142 .match = srh_mt6, 266
143 .matchsize = sizeof(struct ip6t_srh), 267 if (srhinfo->mt_flags & ~IP6T_SRH_MASK) {
144 .checkentry = srh_mt6_check, 268 pr_info_ratelimited("unknown srh match flags %X\n",
145 .me = THIS_MODULE, 269 srhinfo->mt_flags);
270 return -EINVAL;
271 }
272
273 if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
274 pr_info_ratelimited("unknown srh invflags %X\n",
275 srhinfo->mt_invflags);
276 return -EINVAL;
277 }
278
279 return 0;
280}
281
282static struct xt_match srh_mt6_reg[] __read_mostly = {
283 {
284 .name = "srh",
285 .revision = 0,
286 .family = NFPROTO_IPV6,
287 .match = srh_mt6,
288 .matchsize = sizeof(struct ip6t_srh),
289 .checkentry = srh_mt6_check,
290 .me = THIS_MODULE,
291 },
292 {
293 .name = "srh",
294 .revision = 1,
295 .family = NFPROTO_IPV6,
296 .match = srh1_mt6,
297 .matchsize = sizeof(struct ip6t_srh1),
298 .checkentry = srh1_mt6_check,
299 .me = THIS_MODULE,
300 }
146}; 301};
147 302
148static int __init srh_mt6_init(void) 303static int __init srh_mt6_init(void)
149{ 304{
150 return xt_register_match(&srh_mt6_reg); 305 return xt_register_matches(srh_mt6_reg, ARRAY_SIZE(srh_mt6_reg));
151} 306}
152 307
153static void __exit srh_mt6_exit(void) 308static void __exit srh_mt6_exit(void)
154{ 309{
155 xt_unregister_match(&srh_mt6_reg); 310 xt_unregister_matches(srh_mt6_reg, ARRAY_SIZE(srh_mt6_reg));
156} 311}
157 312
158module_init(srh_mt6_init); 313module_init(srh_mt6_init);