Commit 202a8ff5 authored by Ahmed Abdelsalam's avatar Ahmed Abdelsalam Committed by Pablo Neira Ayuso

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: default avatarAhmed Abdelsalam <amsalam20@gmail.com>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent cbef426c
/* 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.
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
config IP6_NF_TARGET_HL
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_RPFILTER) += ip6t_rpfilter.o
obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o
obj-$(CONFIG_IP6_NF_MATCH_SRH) += ip6t_srh.o
# targets
obj-$(CONFIG_IP6_NF_TARGET_MASQUERADE) += ip6t_MASQUERADE.o
......
/* 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>");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment