forked from mirrors/linux
		
	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 Signed-off-by: Ahmed Abdelsalam <amsalam20@gmail.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
		
							parent
							
								
									cbef426ce7
								
							
						
					
					
						commit
						202a8ff545
					
				
					 4 changed files with 228 additions and 0 deletions
				
			
		
							
								
								
									
										57
									
								
								include/uapi/linux/netfilter_ipv6/ip6t_srh.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								include/uapi/linux/netfilter_ipv6/ip6t_srh.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,57 @@
 | 
				
			||||||
 | 
					/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
 | 
				
			||||||
 | 
					#ifndef _IP6T_SRH_H
 | 
				
			||||||
 | 
					#define _IP6T_SRH_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					#include <linux/netfilter.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Values for "mt_flags" field in struct ip6t_srh */
 | 
				
			||||||
 | 
					#define IP6T_SRH_NEXTHDR        0x0001
 | 
				
			||||||
 | 
					#define IP6T_SRH_LEN_EQ         0x0002
 | 
				
			||||||
 | 
					#define IP6T_SRH_LEN_GT         0x0004
 | 
				
			||||||
 | 
					#define IP6T_SRH_LEN_LT         0x0008
 | 
				
			||||||
 | 
					#define IP6T_SRH_SEGS_EQ        0x0010
 | 
				
			||||||
 | 
					#define IP6T_SRH_SEGS_GT        0x0020
 | 
				
			||||||
 | 
					#define IP6T_SRH_SEGS_LT        0x0040
 | 
				
			||||||
 | 
					#define IP6T_SRH_LAST_EQ        0x0080
 | 
				
			||||||
 | 
					#define IP6T_SRH_LAST_GT        0x0100
 | 
				
			||||||
 | 
					#define IP6T_SRH_LAST_LT        0x0200
 | 
				
			||||||
 | 
					#define IP6T_SRH_TAG            0x0400
 | 
				
			||||||
 | 
					#define IP6T_SRH_MASK           0x07FF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Values for "mt_invflags" field in struct ip6t_srh */
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_NEXTHDR    0x0001
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_LEN_EQ     0x0002
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_LEN_GT     0x0004
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_LEN_LT     0x0008
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_SEGS_EQ    0x0010
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_SEGS_GT    0x0020
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_SEGS_LT    0x0040
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_LAST_EQ    0x0080
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_LAST_GT    0x0100
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_LAST_LT    0x0200
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_TAG        0x0400
 | 
				
			||||||
 | 
					#define IP6T_SRH_INV_MASK       0x07FF
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 *      struct ip6t_srh - SRH match options
 | 
				
			||||||
 | 
					 *      @ next_hdr: Next header field of SRH
 | 
				
			||||||
 | 
					 *      @ hdr_len: Extension header length field of SRH
 | 
				
			||||||
 | 
					 *      @ segs_left: Segments left field of SRH
 | 
				
			||||||
 | 
					 *      @ last_entry: Last entry field of SRH
 | 
				
			||||||
 | 
					 *      @ tag: Tag field of SRH
 | 
				
			||||||
 | 
					 *      @ mt_flags: match options
 | 
				
			||||||
 | 
					 *      @ mt_invflags: Invert the sense of match options
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ip6t_srh {
 | 
				
			||||||
 | 
						__u8                    next_hdr;
 | 
				
			||||||
 | 
						__u8                    hdr_len;
 | 
				
			||||||
 | 
						__u8                    segs_left;
 | 
				
			||||||
 | 
						__u8                    last_entry;
 | 
				
			||||||
 | 
						__u16                   tag;
 | 
				
			||||||
 | 
						__u16                   mt_flags;
 | 
				
			||||||
 | 
						__u16                   mt_invflags;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /*_IP6T_SRH_H*/
 | 
				
			||||||
| 
						 | 
					@ -240,6 +240,15 @@ config IP6_NF_MATCH_RT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	  To compile it as a module, choose M here.  If unsure, say N.
 | 
						  To compile it as a module, choose M here.  If unsure, say N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config IP6_NF_MATCH_SRH
 | 
				
			||||||
 | 
					        tristate '"srh" Segment Routing header match support'
 | 
				
			||||||
 | 
					        depends on NETFILTER_ADVANCED
 | 
				
			||||||
 | 
					        help
 | 
				
			||||||
 | 
					          srh matching allows you to match packets based on the segment
 | 
				
			||||||
 | 
						  routing header of the packet.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          To compile it as a module, choose M here.  If unsure, say N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# The targets
 | 
					# The targets
 | 
				
			||||||
config IP6_NF_TARGET_HL
 | 
					config IP6_NF_TARGET_HL
 | 
				
			||||||
	tristate '"HL" hoplimit target support'
 | 
						tristate '"HL" hoplimit target support'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,7 @@ obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o
 | 
				
			||||||
obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
 | 
					obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o
 | 
				
			||||||
obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
 | 
					obj-$(CONFIG_IP6_NF_MATCH_RPFILTER) += ip6t_rpfilter.o
 | 
				
			||||||
obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 | 
					obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_IP6_NF_MATCH_SRH) += ip6t_srh.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# targets
 | 
					# targets
 | 
				
			||||||
obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
 | 
					obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										161
									
								
								net/ipv6/netfilter/ip6t_srh.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								net/ipv6/netfilter/ip6t_srh.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,161 @@
 | 
				
			||||||
 | 
					/* Kernel module to match Segment Routing Header (SRH) parameters. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Author:
 | 
				
			||||||
 | 
					 * Ahmed Abdelsalam <amsalam20@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  This program is free software; you can redistribute it and/or
 | 
				
			||||||
 | 
					 *	modify it under the terms of the GNU General Public License
 | 
				
			||||||
 | 
					 *	as published by the Free Software Foundation; either version 2
 | 
				
			||||||
 | 
					 *	of the License, or (at your option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 | 
				
			||||||
 | 
					#include <linux/module.h>
 | 
				
			||||||
 | 
					#include <linux/skbuff.h>
 | 
				
			||||||
 | 
					#include <linux/ipv6.h>
 | 
				
			||||||
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					#include <net/ipv6.h>
 | 
				
			||||||
 | 
					#include <net/seg6.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/netfilter/x_tables.h>
 | 
				
			||||||
 | 
					#include <linux/netfilter_ipv6/ip6t_srh.h>
 | 
				
			||||||
 | 
					#include <linux/netfilter_ipv6/ip6_tables.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Test a struct->mt_invflags and a boolean for inequality */
 | 
				
			||||||
 | 
					#define NF_SRH_INVF(ptr, flag, boolean)	\
 | 
				
			||||||
 | 
						((boolean) ^ !!((ptr)->mt_invflags & (flag)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool srh_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct ip6t_srh *srhinfo = par->matchinfo;
 | 
				
			||||||
 | 
						struct ipv6_sr_hdr *srh;
 | 
				
			||||||
 | 
						struct ipv6_sr_hdr _srh;
 | 
				
			||||||
 | 
						int hdrlen, srhoff = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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;
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int srh_mt6_check(const struct xt_mtchk_param *par)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const struct ip6t_srh *srhinfo = par->matchinfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (srhinfo->mt_flags & ~IP6T_SRH_MASK) {
 | 
				
			||||||
 | 
							pr_err("unknown srh match flags  %X\n", srhinfo->mt_flags);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (srhinfo->mt_invflags & ~IP6T_SRH_INV_MASK) {
 | 
				
			||||||
 | 
							pr_err("unknown srh invflags %X\n", srhinfo->mt_invflags);
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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 __init srh_mt6_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return xt_register_match(&srh_mt6_reg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void __exit srh_mt6_exit(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						xt_unregister_match(&srh_mt6_reg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module_init(srh_mt6_init);
 | 
				
			||||||
 | 
					module_exit(srh_mt6_exit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					MODULE_DESCRIPTION("Xtables: IPv6 Segment Routing Header match");
 | 
				
			||||||
 | 
					MODULE_AUTHOR("Ahmed Abdelsalam <amsalam20@gmail.com>");
 | 
				
			||||||
		Loading…
	
		Reference in a new issue