From b049e91df68d58846203f72233acc0a476317791 Mon Sep 17 00:00:00 2001
From: ABC <abc@openwall.com>
Date: Wed, 18 Jan 2023 09:40:48 +0300
Subject: [PATCH 16/17] Fix ipv4 options parsing and bit numbering

RFC 5102 and its Errata[1] several times messed with a bit numbering.

  "Options are mapped to bits according to their option numbers.
  Option number X is mapped to bit X."

But actually it's in inverted order.

  "A misunderstand arose as to whether bits were assigned in host order
  or network order - so clarify that the bits are assigned from the
  least significant to the most significant, ie right-to-left rather
  than left-to-right."

That's about bit numbering in diagram. So final correct options mask is (from
Errata 2944):

           0      1      2      3      4      5      6      7
       +------+------+------+------+------+------+------+------+
       |      |  EXP |   to be assigned by IANA  |  QS  | UMP  | ...
       +------+------+------+------+------+------+------+------+

           8      9     10     11     12     13     14     15
       +------+------+------+------+------+------+------+------+
   ... | DPS  |NSAPA | SDB  |RTRALT|ADDEXT|  TR  | EIP  |IMITD | ...
       +------+------+------+------+------+------+------+------+

          16     17     18     19     20     21     22     23
       +------+------+------+------+------+------+------+------+
   ... |ENCODE| VISA | FINN | MTUR | MTUP | ZSU  | SSR  | SID  | ...
       +------+------+------+------+------+------+------+------+

          24     25     26     27     28     29     30     31
       +------+------+------+------+------+------+------+------+
   ... |  RR  |CIPSO |E-SEC |  TS  | LSR  | SEC  | NOP  | EOOL |
       +------+------+------+------+------+------+------+------+

Link: https://www.rfc-editor.org/errata/rfc5102
Fixes: f631ed5 ("IPv6 support, and IP options support for v9/IPFIX.")
Signed-off-by: ABC <abc@openwall.com>
---
 ipt_NETFLOW.c | 64 ++++++++++++++-------------------------------------
 1 file changed, 17 insertions(+), 47 deletions(-)

diff --git a/ipt_NETFLOW.c b/ipt_NETFLOW.c
index ab4afda..b3c2c99 100644
--- a/ipt_NETFLOW.c
+++ b/ipt_NETFLOW.c
@@ -4769,39 +4769,7 @@ static inline __u16 observed_hdrs(const __u8 currenthdr)
 	return SetXBit(3); /* Unknown header. */
 }
 
-/* http://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml */
-static const __u8 ip4_opt_table[] = {
-	[7]	= 0,	/* RR */ /* parsed manually because of 0 */
-	[134]	= 1,	/* CIPSO */
-	[133]	= 2,	/* E-SEC */
-	[68]	= 3,	/* TS */
-	[131]	= 4,	/* LSR */
-	[130]	= 5,	/* SEC */
-	[1]	= 6,	/* NOP */
-	[0]	= 7,	/* EOOL */
-	[15]	= 8,	/* ENCODE */
-	[142]	= 9,	/* VISA */
-	[205]	= 10,	/* FINN */
-	[12]	= 11,	/* MTUR */
-	[11]	= 12,	/* MTUP */
-	[10]	= 13,	/* ZSU */
-	[137]	= 14,	/* SSR */
-	[136]	= 15,	/* SID */
-	[151]	= 16,	/* DPS */
-	[150]	= 17,	/* NSAPA */
-	[149]	= 18,	/* SDB */
-	[147]	= 19,	/* ADDEXT */
-	[148]	= 20,	/* RTRALT */
-	[82]	= 21,	/* TR */
-	[145]	= 22,	/* EIP */
-	[144]	= 23,	/* IMITD */
-	[30]	= 25,	/* EXP */
-	[94]	= 25,	/* EXP */
-	[158]	= 25,	/* EXP */
-	[222]	= 25,	/* EXP */
-	[25]	= 30,	/* QS */
-	[152]	= 31,	/* UMP */
-};
+/* https://www.iana.org/assignments/ip-parameters/ip-parameters.xhtml */
 /* Parse IPv4 Options array int ipv4Options IPFIX value. */
 static inline __u32 ip4_options(const u_int8_t *p, const unsigned int optsize)
 {
@@ -4810,20 +4778,22 @@ static inline __u32 ip4_options(const u_int8_t *p, const unsigned int optsize)
 
 	for (i = 0; likely(i < optsize); ) {
 		u_int8_t op = p[i++];
-
-		if (op == 7) /* RR: bit 0 */
-			ret |= 1;
-		else if (likely(op < ARRAY_SIZE(ip4_opt_table))) {
-			/* Btw, IANA doc is messed up in a crazy way:
-			 *   http://www.ietf.org/mail-archive/web/ipfix/current/msg06008.html (2011)
-			 * I decided to follow IANA _text_ description from
-			 *   http://www.iana.org/assignments/ipfix/ipfix.xhtml (2013-09-18)
-			 *
-			 * Set proper bit for htonl later. */
-			if (ip4_opt_table[op])
-				ret |= 1 << (31 - ip4_opt_table[op]);
-		}
-		if (likely(i >= optsize || op == 0))
+		u_int8_t nn = op & 0x17; /* 5 bits  option number */
+
+		/*
+		 * "Note that for identifying an option not just the 5-bit Option
+		 * Number, but all 8 bits of the Option Type need to match one
+		 * of the IPv4 options specified at
+		 * http://www.iana.org/assignments/ip-parameters.
+		 *
+		 * Options are mapped to bits according to their option numbers.
+		 * Option number X is mapped to bit X." - In inverted order, see
+		 * RFC 5102 Errata 2944.
+		 */
+
+		if (likely(nn < 32))
+			ret |= 1 << (31 - nn);
+		if (i >= optsize || op == 0) /* 0 is EOOL. */
 			break;
 		else if (unlikely(op == 1))
 			continue;
-- 
2.39.5

