netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Stephen Suryaputra <ssuryaextr@gmail.com>
To: netfilter-devel@vger.kernel.org
Cc: fw@strlen.de, Stephen Suryaputra <ssuryaextr@gmail.com>
Subject: [PATCH nftables] exthdr: doc: add support for matching IPv4 options
Date: Thu, 23 May 2019 05:42:01 -0400	[thread overview]
Message-ID: <20190523094201.3875-1-ssuryaextr@gmail.com> (raw)

This is the userspace change for the overall changes with this
description:
Add capability to have rules matching IPv4 options. This is developed
mainly to support dropping of IP packets with loose and/or strict source
route route options. Nevertheless, the implementation include others and
ability to get specific fields in the option.

Signed-off-by: Stephen Suryaputra <ssuryaextr@gmail.com>
---
 doc/payload-expression.txt          |  44 +++++-
 include/Makefile.am                 |   1 +
 include/exthdr.h                    |   1 +
 include/ipopt.h                     |  30 ++++
 include/linux/netfilter/nf_tables.h |   2 +
 src/Makefile.am                     |   1 +
 src/evaluate.c                      |  17 +++
 src/exthdr.c                        |  22 ++-
 src/ipopt.c                         | 217 ++++++++++++++++++++++++++++
 src/parser_bison.y                  |  42 ++++++
 src/payload.c                       |   4 +
 src/scanner.l                       |  11 ++
 tests/py/ip/ipopt.t                 |  41 ++++++
 tests/py/ip/ipopt.t.payload         | 147 +++++++++++++++++++
 14 files changed, 576 insertions(+), 4 deletions(-)
 create mode 100644 include/ipopt.h
 create mode 100644 src/ipopt.c
 create mode 100644 tests/py/ip/ipopt.t
 create mode 100644 tests/py/ip/ipopt.t.payload

diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index 7f3ca42..2a9739f 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -494,9 +494,9 @@ input meta iifname enp2s0 arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh
 
 EXTENSION HEADER EXPRESSIONS
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Extension header expressions refer to data from variable-sized protocol headers, such as IPv6 extension headers and TCP options.
+Extension header expressions refer to data from variable-sized protocol headers, such as IPv6 extension headers, TCP options and IPv4 options.
 
-nftables currently supports matching (finding) a given ipv6 extension header or TCP option.
+nftables currently supports matching (finding) a given ipv6 extension header, TCP option or IPv4 option.
 [verse]
 *hbh* {*nexthdr* | *hdrlength*}
 *frag* {*nexthdr* | *frag-off* | *more-fragments* | *id*}
@@ -505,11 +505,13 @@ nftables currently supports matching (finding) a given ipv6 extension header or
 *mh* {*nexthdr* | *hdrlength* | *checksum* | *type*}
 *srh* {*flags* | *tag* | *sid* | *seg-left*}
 *tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-permitted* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
+*ip option* {eol | lsrr | noop | ra | rr | sid | sec | ssrr | timestamp} 'ip_option_field'
 
 The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only:
 [verse]
 *exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*}
 *tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-permitted* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
+*ip option* {eol | lsrr | noop | ra | rr | sid | sec | ssrr | timestamp}
 
 .IPv6 extension headers
 [options="header"]
@@ -568,6 +570,39 @@ TCP Timestamps |
 kind, length, tsval, tsecr
 |============================
 
+.IP Options
+[options="header"]
+|==================
+|Keyword| Description | IP option fields
+|eol|
+End of option list |
+type
+|lsrr|
+Loose Source Route |
+type, length, ptr, addr
+|noop|
+No operation |
+type
+|ra|
+Router Alert |
+type, length, value
+|rr|
+Record Route |
+type, length, ptr, addr
+|sid|
+Stream ID |
+type, length, value
+|sec|
+Security |
+type, length, value
+|ssrr|
+Strict Source Route |
+type, length, ptr, addr
+|timestamp|
+Time Stamp |
+type, length, ptr, overflow, flag, timestamp
+|============================
+
 .finding TCP options
 --------------------
 filter input tcp option sack-permitted kind 1 counter
@@ -578,6 +613,11 @@ filter input tcp option sack-permitted kind 1 counter
 ip6 filter input frag more-fragments 1 counter
 ---------------------------------------
 
+.finding IP option
+------------------
+filter input ip option lsrr exists counter
+---------------------------------------
+
 CONNTRACK EXPRESSIONS
 ~~~~~~~~~~~~~~~~~~~~~
 Conntrack expressions refer to meta data of the connection tracking entry associated with a packet. +
diff --git a/include/Makefile.am b/include/Makefile.am
index b1f4fcf..9606ae1 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -6,6 +6,7 @@ noinst_HEADERS = 	cli.h		\
 			expression.h	\
 			fib.h		\
 			hash.h		\
+			ipopt.h		\
 			json.h		\
 			mini-gmp.h	\
 			gmputil.h	\
diff --git a/include/exthdr.h b/include/exthdr.h
index 32f99c9..3959a65 100644
--- a/include/exthdr.h
+++ b/include/exthdr.h
@@ -3,6 +3,7 @@
 
 #include <proto.h>
 #include <tcpopt.h>
+#include <ipopt.h>
 
 /**
  * struct exthdr_desc - extension header description
diff --git a/include/ipopt.h b/include/ipopt.h
new file mode 100644
index 0000000..7cb03f5
--- /dev/null
+++ b/include/ipopt.h
@@ -0,0 +1,30 @@
+#ifndef NFTABLES_IPOPT_H
+#define NFTABLES_IPOPT_H
+
+#include <proto.h>
+#include <exthdr.h>
+#include <statement.h>
+
+extern struct expr *ipopt_expr_alloc(const struct location *loc,
+				      uint8_t type, uint8_t field, uint8_t ptr);
+
+extern void ipopt_init_raw(struct expr *expr, uint8_t type,
+			    unsigned int offset, unsigned int len,
+			    uint32_t flags, bool set_unknown);
+
+extern bool ipopt_find_template(struct expr *expr, unsigned int offset,
+			  unsigned int len);
+
+enum ipopt_fields {
+	IPOPT_FIELD_INVALID,
+	IPOPT_FIELD_TYPE,
+	IPOPT_FIELD_LENGTH,
+	IPOPT_FIELD_VALUE,
+	IPOPT_FIELD_PTR,
+	IPOPT_FIELD_ADDR_0,
+	IPOPT_FIELD_OVERFLOW,
+	IPOPT_FIELD_FLAG,
+	IPOPT_FIELD_TIMESTAMP_0,
+};
+
+#endif /* NFTABLES_IPOPT_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 09a7b9e..c0487fa 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -728,10 +728,12 @@ enum nft_exthdr_flags {
  *
  * @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers
  * @NFT_EXTHDR_OP_TCP: match against tcp options
+ * @NFT_EXTHDR_OP_IPV4: match against ip options
  */
 enum nft_exthdr_op {
 	NFT_EXTHDR_OP_IPV6,
 	NFT_EXTHDR_OP_TCPOPT,
+	NFT_EXTHDR_OP_IPV4,
 	__NFT_EXTHDR_OP_MAX
 };
 #define NFT_EXTHDR_OP_MAX	(__NFT_EXTHDR_OP_MAX - 1)
diff --git a/src/Makefile.am b/src/Makefile.am
index 8e1a4d8..a45d8e3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -61,6 +61,7 @@ libnftables_la_SOURCES =			\
 		nfnl_osf.c			\
 		tcpopt.c			\
 		socket.c			\
+		ipopt.c			\
 		libnftables.c
 
 # yacc and lex generate dirty code
diff --git a/src/evaluate.c b/src/evaluate.c
index 3593eb8..8227ab8 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -518,6 +518,20 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
 					  totlen, max_tcpoptlen);
 		break;
 	}
+	case NFT_EXTHDR_OP_IPV4: {
+		static const unsigned int max_ipoptlen = 40 * BITS_PER_BYTE;
+		unsigned int totlen = 0;
+
+		totlen += expr->exthdr.tmpl->offset;
+		totlen += expr->exthdr.tmpl->len;
+		totlen += expr->exthdr.offset;
+
+		if (totlen > max_ipoptlen)
+			return expr_error(ctx->msgs, expr,
+					  "offset and size %u exceeds max ip option len (%u)",
+					  totlen, max_ipoptlen);
+		break;
+	}
 	default:
 		break;
 	}
@@ -542,6 +556,9 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
 		dependency = &proto_tcp;
 		pb = PROTO_BASE_TRANSPORT_HDR;
 		break;
+	case NFT_EXTHDR_OP_IPV4:
+		dependency = &proto_ip;
+		break;
 	case NFT_EXTHDR_OP_IPV6:
 	default:
 		dependency = &proto_ip6;
diff --git a/src/exthdr.c b/src/exthdr.c
index 0cd0319..d73cbcc 100644
--- a/src/exthdr.c
+++ b/src/exthdr.c
@@ -38,6 +38,11 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
 		if (offset)
 			nft_print(octx, "%d", offset);
 		nft_print(octx, " %s", expr->exthdr.tmpl->token);
+	} else if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
+		nft_print(octx, "ip option %s", expr->exthdr.desc->name);
+		if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
+			return;
+		nft_print(octx, " %s", expr->exthdr.tmpl->token);
 	} else {
 		if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
 			nft_print(octx, "exthdr %s", expr->exthdr.desc->name);
@@ -172,6 +177,8 @@ void exthdr_init_raw(struct expr *expr, uint8_t type,
 	assert(expr->etype == EXPR_EXTHDR);
 	if (op == NFT_EXTHDR_OP_TCPOPT)
 		return tcpopt_init_raw(expr, type, offset, len, flags);
+	if (op == NFT_EXTHDR_OP_IPV4)
+		return ipopt_init_raw(expr, type, offset, len, flags, true);
 
 	expr->len = len;
 	expr->exthdr.flags = flags;
@@ -222,7 +229,8 @@ bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned i
 {
 	unsigned int off, mask_offset, mask_len;
 
-	if (expr->exthdr.tmpl != &exthdr_unknown_template)
+	if (expr->exthdr.op != NFT_EXTHDR_OP_IPV4 &&
+	    expr->exthdr.tmpl != &exthdr_unknown_template)
 		return false;
 
 	/* In case we are handling tcp options instead of the default ipv6
@@ -237,8 +245,18 @@ bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned i
 	off = expr->exthdr.offset;
 	off += round_up(mask->len, BITS_PER_BYTE) - mask_len;
 
+	/* Handle ip options after the offset and mask have been calculated. */
+	if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
+		if (ipopt_find_template(expr, off, mask_len - mask_offset)) {
+			*shift = mask_offset;
+			return true;
+		} else {
+			return false;
+		}
+	}
+
 	exthdr_init_raw(expr, expr->exthdr.desc->type,
-			off, mask_len - mask_offset, NFT_EXTHDR_OP_IPV6, 0);
+			off, mask_len - mask_offset, expr->exthdr.op, 0);
 
 	/* still failed to find a template... Bug. */
 	if (expr->exthdr.tmpl == &exthdr_unknown_template)
diff --git a/src/ipopt.c b/src/ipopt.c
new file mode 100644
index 0000000..5f291a3
--- /dev/null
+++ b/src/ipopt.c
@@ -0,0 +1,217 @@
+#include <stdint.h>
+
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/tcp.h>
+
+#include <utils.h>
+#include <headers.h>
+#include <expression.h>
+#include <ipopt.h>
+
+static const struct proto_hdr_template ipopt_unknown_template =
+	PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
+
+#define PHT(__token, __offset, __len) \
+	PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \
+			   __offset, __len)
+static const struct exthdr_desc ipopt_end = {
+	.name		= "eol",
+	.type		= IPOPT_END,
+	.templates	= {
+		[IPOPT_FIELD_TYPE]		= PHT("type",  0,    8),
+	},
+};
+
+static const struct exthdr_desc ipopt_nop = {
+	.name		= "noop",
+	.type		= IPOPT_NOP,
+	.templates	= {
+		[IPOPT_FIELD_TYPE]		= PHT("type",   0,   8),
+	},
+};
+
+static const struct exthdr_desc ipopt_sec = {
+	.name		= "sec",
+	.type		= IPOPT_SEC,
+	.templates	= {
+		[IPOPT_FIELD_TYPE]		= PHT("type",    0,  8),
+		[IPOPT_FIELD_LENGTH]		= PHT("length",  8,  8),
+		[IPOPT_FIELD_VALUE]		= PHT("value",  16, 72),
+	},
+};
+
+static const struct exthdr_desc ipopt_lsrr = {
+	.name		= "lsrr",
+	.type		= IPOPT_LSRR,
+	.templates	= {
+		[IPOPT_FIELD_TYPE]		= PHT("type",    0,  8),
+		[IPOPT_FIELD_LENGTH]		= PHT("length",  8,  8),
+		[IPOPT_FIELD_PTR]		= PHT("ptr",    16,  8),
+		[IPOPT_FIELD_ADDR_0]		= PHT("addr",   24, 32),
+	},
+};
+
+static const struct exthdr_desc ipopt_timestamp = {
+	.name		= "timestamp",
+	.type		= IPOPT_TIMESTAMP,
+	.templates	= {
+		[IPOPT_FIELD_TYPE]		= PHT("type",       0,  8),
+		[IPOPT_FIELD_LENGTH]		= PHT("length",     8,  8),
+		[IPOPT_FIELD_PTR]		= PHT("ptr",       16,  8),
+		[IPOPT_FIELD_OVERFLOW]		= PHT("overflow",  24,  4),
+		[IPOPT_FIELD_FLAG]		= PHT("flag",      28,  4),
+		[IPOPT_FIELD_TIMESTAMP_0]	= PHT("timestamp", 32, 32),
+	},
+};
+
+static const struct exthdr_desc ipopt_rr = {
+	.name		= "rr",
+	.type		= IPOPT_RR,
+	.templates	= {
+		[IPOPT_FIELD_TYPE]		= PHT("type",   0,   8),
+		[IPOPT_FIELD_LENGTH]		= PHT("length",  8,  8),
+		[IPOPT_FIELD_PTR]		= PHT("ptr",    16,  8),
+		[IPOPT_FIELD_ADDR_0]		= PHT("addr",   24, 32),
+	},
+};
+
+static const struct exthdr_desc ipopt_sid = {
+	.name		= "sid",
+	.type		= IPOPT_SID,
+	.templates	= {
+		[IPOPT_FIELD_TYPE]		= PHT("type",       0,  8),
+		[IPOPT_FIELD_LENGTH]		= PHT("length",     8,  8),
+		[IPOPT_FIELD_VALUE]		= PHT("value", 16, 16),
+	},
+};
+
+static const struct exthdr_desc ipopt_ssrr = {
+	.name		= "ssrr",
+	.type		= IPOPT_SSRR,
+	.templates	= {
+		[IPOPT_FIELD_TYPE]		= PHT("type",   0,   8),
+		[IPOPT_FIELD_LENGTH]		= PHT("length",  8,  8),
+		[IPOPT_FIELD_PTR]		= PHT("ptr",    16,  8),
+		[IPOPT_FIELD_ADDR_0]		= PHT("addr",   24, 32),
+	},
+};
+
+static const struct exthdr_desc ipopt_ra = {
+	.name		= "ra",
+	.type		= IPOPT_RA,
+	.templates	= {
+		[IPOPT_FIELD_TYPE]		= PHT("type",   0,   8),
+		[IPOPT_FIELD_LENGTH]		= PHT("length", 8,   8),
+		[IPOPT_FIELD_VALUE]		= PHT("value",  16, 16),
+	},
+};
+
+static const struct exthdr_desc *ipopt_protocols[] = {
+	[IPOPT_END]		= &ipopt_end,
+	[IPOPT_NOP]		= &ipopt_nop,
+	[IPOPT_SEC]		= &ipopt_sec,
+	[IPOPT_LSRR]		= &ipopt_lsrr,
+	[IPOPT_TIMESTAMP]	= &ipopt_timestamp,
+	[IPOPT_RR]		= &ipopt_rr,
+	[IPOPT_SID]		= &ipopt_sid,
+	[IPOPT_SSRR]		= &ipopt_ssrr,
+	[IPOPT_RA]		= &ipopt_ra,
+};
+
+static unsigned int calc_offset(const struct exthdr_desc *desc,
+				const struct proto_hdr_template *tmpl,
+				unsigned int arg)
+{
+	if (!desc || tmpl == &ipopt_unknown_template)
+		return 0;
+
+	switch (desc->type) {
+	case IPOPT_RR:
+	case IPOPT_LSRR:
+	case IPOPT_SSRR:
+		if (tmpl == &desc->templates[IPOPT_FIELD_ADDR_0])
+			return (tmpl->offset < 24) ? 0 : arg;
+		return 0;
+	case IPOPT_TIMESTAMP:
+		if (tmpl == &desc->templates[IPOPT_FIELD_TIMESTAMP_0])
+			return (tmpl->offset < 24) ? 0 : arg;
+		return 0;
+	default:
+		return 0;
+	}
+}
+
+struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type,
+			       uint8_t field, uint8_t ptr)
+{
+	const struct proto_hdr_template *tmpl;
+	const struct exthdr_desc *desc;
+	struct expr *expr;
+
+	desc = ipopt_protocols[type];
+	tmpl = &desc->templates[field];
+	if (!tmpl)
+		return NULL;
+
+	expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
+			  BYTEORDER_BIG_ENDIAN, tmpl->len);
+	expr->exthdr.desc   = desc;
+	expr->exthdr.tmpl   = tmpl;
+	expr->exthdr.op     = NFT_EXTHDR_OP_IPV4;
+	expr->exthdr.offset = calc_offset(desc, tmpl, ptr);
+
+	return expr;
+}
+
+void ipopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
+		     unsigned int len, uint32_t flags, bool set_unknown)
+{
+	const struct proto_hdr_template *tmpl;
+	unsigned int i;
+
+	assert(expr->etype == EXPR_EXTHDR);
+
+	expr->len = len;
+	expr->exthdr.flags = flags;
+	expr->exthdr.offset = offset;
+
+	assert(type < array_size(ipopt_protocols));
+	expr->exthdr.desc = ipopt_protocols[type];
+	expr->exthdr.flags = flags;
+
+	for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
+		tmpl = &expr->exthdr.desc->templates[i];
+
+		/* Make sure that it's the right template based on offset and len */
+		if (tmpl->offset != offset || tmpl->len != len)
+			continue;
+
+		if (flags & NFT_EXTHDR_F_PRESENT)
+			expr->dtype = &boolean_type;
+		else
+			expr->dtype = tmpl->dtype;
+		expr->exthdr.tmpl = tmpl;
+		expr->exthdr.op   = NFT_EXTHDR_OP_IPV4;
+		break;
+	}
+	if (i == array_size(expr->exthdr.desc->templates) && set_unknown) {
+		expr->exthdr.tmpl = &ipopt_unknown_template;
+		expr->exthdr.op   = NFT_EXTHDR_OP_IPV4;
+	}
+}
+
+bool ipopt_find_template(struct expr *expr, unsigned int offset,
+			  unsigned int len)
+{
+	if (expr->exthdr.tmpl != &ipopt_unknown_template)
+		return false;
+
+	ipopt_init_raw(expr, expr->exthdr.desc->type, offset, len, 0, false);
+
+	if (expr->exthdr.tmpl == &ipopt_unknown_template)
+		return false;
+
+	return true;
+}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 9aea652..4c56885 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -309,6 +309,17 @@ int nft_lex(void *, void *, void *);
 %token PROTOCOL			"protocol"
 %token CHECKSUM			"checksum"
 
+%token FLAG			"flag"
+%token OVERFLOW			"overflow"
+%token PTR			"ptr"
+%token VALUE			"value"
+
+%token SEC			"sec"
+%token LSRR			"lsrr"
+%token RR			"rr"
+%token SSRR			"ssrr"
+%token RA			"ra"
+
 %token ICMP			"icmp"
 %token CODE			"code"
 %token SEQUENCE			"seq"
@@ -698,6 +709,7 @@ int nft_lex(void *, void *, void *);
 %type <expr>			ip_hdr_expr	icmp_hdr_expr		igmp_hdr_expr numgen_expr	hash_expr
 %destructor { expr_free($$); }	ip_hdr_expr	icmp_hdr_expr		igmp_hdr_expr numgen_expr	hash_expr
 %type <val>			ip_hdr_field	icmp_hdr_field		igmp_hdr_field
+%type <val>			ip_option_type	ip_option_field
 %type <expr>			ip6_hdr_expr    icmp6_hdr_expr
 %destructor { expr_free($$); }	ip6_hdr_expr	icmp6_hdr_expr
 %type <val>			ip6_hdr_field   icmp6_hdr_field
@@ -4248,6 +4260,15 @@ ip_hdr_expr		:	IP	ip_hdr_field
 			{
 				$$ = payload_expr_alloc(&@$, &proto_ip, $2);
 			}
+			|	IP	OPTION	ip_option_type ip_option_field
+			{
+				$$ = ipopt_expr_alloc(&@$, $3, $4, 0);
+			}
+			|	IP	OPTION	ip_option_type
+			{
+				$$ = ipopt_expr_alloc(&@$, $3, IPOPT_FIELD_TYPE, 0);
+				$$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+			}
 			;
 
 ip_hdr_field		:	HDRVERSION	{ $$ = IPHDR_VERSION; }
@@ -4264,6 +4285,27 @@ ip_hdr_field		:	HDRVERSION	{ $$ = IPHDR_VERSION; }
 			|	DADDR		{ $$ = IPHDR_DADDR; }
 			;
 
+ip_option_type		:	EOL		{ $$ = IPOPT_END; }
+			|	NOOP		{ $$ = IPOPT_NOOP; }
+			|	SEC		{ $$ = IPOPT_SEC; }
+			|	LSRR		{ $$ = IPOPT_LSRR; }
+			|	TIMESTAMP	{ $$ = IPOPT_TIMESTAMP; }
+			|	RR		{ $$ = IPOPT_RR; }
+			|	SID		{ $$ = IPOPT_SID; }
+			|	SSRR		{ $$ = IPOPT_SSRR; }
+			|	RA		{ $$ = IPOPT_RA; }
+			;
+
+ip_option_field		:	TYPE		{ $$ = IPOPT_FIELD_TYPE; }
+			|	LENGTH		{ $$ = IPOPT_FIELD_LENGTH; }
+			|	VALUE		{ $$ = IPOPT_FIELD_VALUE; }
+			|	PTR		{ $$ = IPOPT_FIELD_PTR; }
+			|	ADDR		{ $$ = IPOPT_FIELD_ADDR_0; }
+			|	OVERFLOW	{ $$ = IPOPT_FIELD_OVERFLOW; }
+			|	FLAG		{ $$ = IPOPT_FIELD_FLAG; }
+			|	TIMESTAMP	{ $$ = IPOPT_FIELD_TIMESTAMP_0; }
+			;
+
 icmp_hdr_expr		:	ICMP	icmp_hdr_field
 			{
 				$$ = payload_expr_alloc(&@$, &proto_icmp, $2);
diff --git a/src/payload.c b/src/payload.c
index 338a4b7..931370f 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -524,6 +524,10 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
 		if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR))
 			payload_dependency_release(ctx);
 		break;
+	case NFT_EXTHDR_OP_IPV4:
+		if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR))
+			payload_dependency_release(ctx);
+		break;
 	default:
 		break;
 	}
diff --git a/src/scanner.l b/src/scanner.l
index 558bf92..a75b1e9 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -401,6 +401,17 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr})
 "protocol"		{ return PROTOCOL; }
 "checksum"		{ return CHECKSUM; }
 
+"sec"			{ return SEC; }
+"lsrr"			{ return LSRR; }
+"rr"			{ return RR; }
+"ssrr"			{ return SSRR; }
+"ra"			{ return RA; }
+
+"value"			{ return VALUE; }
+"ptr"			{ return PTR; }
+"overflow"		{ return OVERFLOW; }
+"flag"			{ return FLAG; }
+
 "echo"			{ return ECHO; }
 "eol"			{ return EOL; }
 "maxseg"		{ return MAXSEG; }
diff --git a/tests/py/ip/ipopt.t b/tests/py/ip/ipopt.t
new file mode 100644
index 0000000..539c206
--- /dev/null
+++ b/tests/py/ip/ipopt.t
@@ -0,0 +1,41 @@
+:input;type filter hook input priority 0
+
+*ip;test-ipopt;input
+
+ip option eol type 1;ok
+ip option noop type 1;ok
+ip option sec type 1;ok
+ip option sec length 1;ok
+ip option sec value 1;ok
+ip option lsrr type 1;ok
+ip option lsrr length 1;ok
+ip option lsrr ptr 1;ok
+ip option lsrr addr 1;ok
+ip option timestamp type 1;ok
+ip option timestamp length 1;ok
+ip option timestamp ptr 1;ok
+ip option timestamp overflow 1;ok
+ip option timestamp flag 1;ok
+ip option timestamp timestamp 1;ok
+ip option rr type 1;ok
+ip option rr length 1;ok
+ip option rr ptr 1;ok
+ip option rr addr 1;ok
+ip option sid type 1;ok
+ip option sid length 1;ok
+ip option sid value 1;ok
+ip option ssrr type 1;ok
+ip option ssrr length 1;ok
+ip option ssrr ptr 1;ok
+ip option ssrr addr 1;ok
+ip option ra type 1;ok
+ip option ra length 1;ok
+ip option ra value 1;ok
+
+ip option foobar;fail
+ip option foo bar;fail
+ip option eol length;fail
+ip option eol length 1;fail
+ip option eol addr 1;fail
+ip option lsrr type;fail
+ip option lsrr flag 1;fail
diff --git a/tests/py/ip/ipopt.t.payload b/tests/py/ip/ipopt.t.payload
new file mode 100644
index 0000000..b4c2246
--- /dev/null
+++ b/tests/py/ip/ipopt.t.payload
@@ -0,0 +1,147 @@
+# ip option eol type 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 0 + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option noop type 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 1 + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option sec type 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 130 + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option sec length 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 130 + 1 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option sec value 1
+ip test-ipopt input 
+  [ exthdr load ipv4 9b @ 130 + 2 => reg 1 ]
+  [ cmp eq reg 1 0x00000000 0x00000000 0x00000001 ]
+
+# ip option lsrr type 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 131 + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option lsrr length 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 131 + 1 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option lsrr ptr 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 131 + 2 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option lsrr addr 1
+ip test-ipopt input 
+  [ exthdr load ipv4 4b @ 131 + 3 => reg 1 ]
+  [ cmp eq reg 1 0x01000000 ]
+
+# ip option timestamp type 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 68 + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option timestamp length 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 68 + 1 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option timestamp ptr 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 68 + 2 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option timestamp overflow 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 68 + 3 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x00000010 ]
+
+# ip option timestamp flag 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 68 + 3 => reg 1 ]
+  [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option timestamp timestamp 1
+ip test-ipopt input 
+  [ exthdr load ipv4 4b @ 68 + 4 => reg 1 ]
+  [ cmp eq reg 1 0x01000000 ]
+
+# ip option rr type 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 7 + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option rr length 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 7 + 1 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option rr ptr 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 7 + 2 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option rr addr 1
+ip test-ipopt input 
+  [ exthdr load ipv4 4b @ 7 + 3 => reg 1 ]
+  [ cmp eq reg 1 0x01000000 ]
+
+# ip option sid type 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 136 + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option sid length 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 136 + 1 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option sid value 1
+ip test-ipopt input 
+  [ exthdr load ipv4 2b @ 136 + 2 => reg 1 ]
+  [ cmp eq reg 1 0x00000100 ]
+
+# ip option ssrr type 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 137 + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option ssrr length 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 137 + 1 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option ssrr ptr 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 137 + 2 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option ssrr addr 1
+ip test-ipopt input 
+  [ exthdr load ipv4 4b @ 137 + 3 => reg 1 ]
+  [ cmp eq reg 1 0x01000000 ]
+
+# ip option ra type 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 148 + 0 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option ra length 1
+ip test-ipopt input 
+  [ exthdr load ipv4 1b @ 148 + 1 => reg 1 ]
+  [ cmp eq reg 1 0x00000001 ]
+
+# ip option ra value 1
+ip test-ipopt input 
+  [ exthdr load ipv4 2b @ 148 + 2 => reg 1 ]
+  [ cmp eq reg 1 0x00000100 ]
+
-- 
2.17.1


                 reply	other threads:[~2019-05-23 13:29 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190523094201.3875-1-ssuryaextr@gmail.com \
    --to=ssuryaextr@gmail.com \
    --cc=fw@strlen.de \
    --cc=netfilter-devel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).