Browse code

Implement --mssfix handling for IPv6 packets.

Rename process_ipv4_header() to process_ip_header() and PIPV4_MSSFIX
flag to PIP_MSSFIX, to make visible that it's no longer IPv4-only.

Inside process_ip_header(), call out to mss_fixup_ipv6() if --mssfix
is active and IPv6 packet seen.

Rename mss_fixup() to mss_fixup_ipv4(), implement mss_fixup_ipv6().

Signed-off-by: Gert Doering <gert@greenie.muc.de>
Acked-by: Arne Schwabe <arne@rfc2549.org>
Message-Id: 1354482672-16136-2-git-send-email-gert@greenie.muc.de
URL: http://article.gmane.org/gmane.network.openvpn.devel/7173
Signed-off-by: David Sommerseth <davids@redhat.com>

Gert Doering authored on 2012/12/03 06:11:12
Showing 7 changed files
... ...
@@ -985,9 +985,9 @@ process_incoming_tun (struct context *c)
985 985
     {
986 986
       /*
987 987
        * The --passtos and --mssfix options require
988
-       * us to examine the IPv4 header.
988
+       * us to examine the IP header (IPv4 or IPv6).
989 989
        */
990
-      process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf);
990
+      process_ip_header (c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf);
991 991
 
992 992
 #ifdef PACKET_TRUNCATION_CHECK
993 993
       /* if (c->c2.buf.len > 1) --c->c2.buf.len; */
... ...
@@ -1009,10 +1009,10 @@ process_incoming_tun (struct context *c)
1009 1009
 }
1010 1010
 
1011 1011
 void
1012
-process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
1012
+process_ip_header (struct context *c, unsigned int flags, struct buffer *buf)
1013 1013
 {
1014 1014
   if (!c->options.ce.mssfix)
1015
-    flags &= ~PIPV4_MSSFIX;
1015
+    flags &= ~PIP_MSSFIX;
1016 1016
 #if PASSTOS_CAPABILITY
1017 1017
   if (!c->options.passtos)
1018 1018
     flags &= ~PIPV4_PASSTOS;
... ...
@@ -1027,9 +1027,9 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
1027 1027
        * us to examine the IPv4 header.
1028 1028
        */
1029 1029
 #if PASSTOS_CAPABILITY
1030
-      if (flags & (PIPV4_PASSTOS|PIPV4_MSSFIX))
1030
+      if (flags & (PIPV4_PASSTOS|PIP_MSSFIX))
1031 1031
 #else
1032
-      if (flags & PIPV4_MSSFIX)
1032
+      if (flags & PIP_MSSFIX)
1033 1033
 #endif
1034 1034
 	{
1035 1035
 	  struct buffer ipbuf = *buf;
... ...
@@ -1042,8 +1042,8 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
1042 1042
 #endif
1043 1043
 			  
1044 1044
 	      /* possibly alter the TCP MSS */
1045
-	      if (flags & PIPV4_MSSFIX)
1046
-		mss_fixup (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
1045
+	      if (flags & PIP_MSSFIX)
1046
+		mss_fixup_ipv4 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
1047 1047
 
1048 1048
 #ifdef ENABLE_CLIENT_NAT
1049 1049
 	      /* possibly do NAT on packet */
... ...
@@ -1061,6 +1061,12 @@ process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
1061 1061
 		    route_list_add_vpn_gateway (c->c1.route_list, c->c2.es, dhcp_router);
1062 1062
 		}
1063 1063
 	    }
1064
+	  else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf))
1065
+	    {
1066
+	      /* possibly alter the TCP MSS */
1067
+	      if (flags & PIP_MSSFIX)
1068
+		mss_fixup_ipv6 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
1069
+	    }
1064 1070
 	}
1065 1071
     }
1066 1072
 }
... ...
@@ -1217,9 +1223,9 @@ process_outgoing_tun (struct context *c)
1217 1217
 
1218 1218
   /*
1219 1219
    * The --mssfix option requires
1220
-   * us to examine the IPv4 header.
1220
+   * us to examine the IP header (IPv4 or IPv6).
1221 1221
    */
1222
-  process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun);
1222
+  process_ip_header (c, PIP_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun);
1223 1223
 
1224 1224
   if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame))
1225 1225
     {
... ...
@@ -228,12 +228,12 @@ void process_outgoing_tun (struct context *c);
228 228
 bool send_control_channel_string (struct context *c, const char *str, int msglevel);
229 229
 
230 230
 #define PIPV4_PASSTOS         (1<<0)
231
-#define PIPV4_MSSFIX          (1<<1)
231
+#define PIP_MSSFIX            (1<<1)         /* v4 and v6 */
232 232
 #define PIPV4_OUTGOING        (1<<2)
233 233
 #define PIPV4_EXTRACT_DHCP_ROUTER (1<<3)
234 234
 #define PIPV4_CLIENT_NAT      (1<<4)
235 235
 
236
-void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf);
236
+void process_ip_header (struct context *c, unsigned int flags, struct buffer *buf);
237 237
 
238 238
 #if P2MP
239 239
 void schedule_exit (struct context *c, const int n_seconds, const int signal);
... ...
@@ -38,8 +38,13 @@
38 38
  * problems which arise from protocol
39 39
  * encapsulation.
40 40
  */
41
+
42
+/*
43
+ * IPv4 packet: find TCP header, check flags for "SYN"
44
+ *              if yes, hand to mss_fixup_dowork()
45
+ */
41 46
 void
42
-mss_fixup (struct buffer *buf, int maxmss)
47
+mss_fixup_ipv4 (struct buffer *buf, int maxmss)
43 48
 {
44 49
   const struct openvpn_iphdr *pip;
45 50
   int hlen;
... ...
@@ -69,6 +74,56 @@ mss_fixup (struct buffer *buf, int maxmss)
69 69
     }
70 70
 }
71 71
 
72
+/*
73
+ * IPv6 packet: find TCP header, check flags for "SYN"
74
+ *              if yes, hand to mss_fixup_dowork()
75
+ *              (IPv6 header structure is sufficiently different from IPv4...)
76
+ */
77
+void
78
+mss_fixup_ipv6 (struct buffer *buf, int maxmss)
79
+{
80
+  const struct openvpn_ipv6hdr *pip6;
81
+  struct buffer newbuf;
82
+
83
+  if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr))
84
+    return;
85
+
86
+  verify_align_4 (buf);
87
+  pip6 = (struct openvpn_ipv6hdr *) BPTR (buf);
88
+
89
+  /* do we have the full IPv6 packet?
90
+   * "payload_len" does not include IPv6 header (+40 bytes)
91
+   */
92
+  if (BLEN (buf) != (int) ntohs(pip6->payload_len)+40 )
93
+    return;
94
+
95
+  /* follow header chain until we reach final header, then check for TCP
96
+   *
97
+   * An IPv6 packet could, theoretically, have a chain of multiple headers
98
+   * before the final header (TCP, UDP, ...), so we'd need to walk that
99
+   * chain (see RFC 2460 and RFC 6564 for details).
100
+   *
101
+   * In practice, "most typically used" extention headers (AH, routing,
102
+   * fragment, mobility) are very unlikely to be seen inside an OpenVPN
103
+   * tun, so for now, we only handle the case of "single next header = TCP"
104
+   */
105
+  if ( pip6->nexthdr != OPENVPN_IPPROTO_TCP )
106
+    return;
107
+
108
+  newbuf = *buf;
109
+  if ( buf_advance( &newbuf, 40 ) )
110
+    {
111
+      struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR (&newbuf);
112
+      if (tc->flags & OPENVPN_TCPH_SYN_MASK)
113
+	    mss_fixup_dowork (&newbuf, (uint16_t) maxmss-20);
114
+    }
115
+}
116
+
117
+/*
118
+ * change TCP MSS option in SYN/SYN-ACK packets, if present
119
+ * this is generic for IPv4 and IPv6, as the TCP header is the same
120
+ */
121
+
72 122
 void
73 123
 mss_fixup_dowork (struct buffer *buf, uint16_t maxmss)
74 124
 {
... ...
@@ -28,7 +28,8 @@
28 28
 #include "proto.h"
29 29
 #include "error.h"
30 30
 
31
-void mss_fixup (struct buffer *buf, int maxmss);
31
+void mss_fixup_ipv4 (struct buffer *buf, int maxmss);
32
+void mss_fixup_ipv6 (struct buffer *buf, int maxmss);
32 33
 void mss_fixup_dowork (struct buffer *buf, uint16_t maxmss);
33 34
 
34 35
 #endif
... ...
@@ -2411,13 +2411,13 @@ multi_get_queue (struct mbuf_set *ms)
2411 2411
 
2412 2412
   if (mbuf_extract_item (ms, &item)) /* cleartext IP packet */
2413 2413
     {
2414
-      unsigned int pipv4_flags = PIPV4_PASSTOS;
2414
+      unsigned int pip_flags = PIPV4_PASSTOS;
2415 2415
 
2416 2416
       set_prefix (item.instance);
2417 2417
       item.instance->context.c2.buf = item.buffer->buf;
2418 2418
       if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */
2419
-	pipv4_flags |= PIPV4_MSSFIX;
2420
-      process_ipv4_header (&item.instance->context, pipv4_flags, &item.instance->context.c2.buf);
2419
+	pip_flags |= PIP_MSSFIX;
2420
+      process_ip_header (&item.instance->context, pip_flags, &item.instance->context.c2.buf);
2421 2421
       encrypt_sign (&item.instance->context, true);
2422 2422
       mbuf_free_buf (item.buffer);
2423 2423
 
... ...
@@ -36,11 +36,12 @@
36 36
 #include "memdbg.h"
37 37
 
38 38
 /*
39
- * If raw tunnel packet is IPv4, return true and increment
39
+ * If raw tunnel packet is IPv<X>, return true and increment
40 40
  * buffer offset to start of IP header.
41 41
  */
42
+static
42 43
 bool
43
-is_ipv4 (int tunnel_type, struct buffer *buf)
44
+is_ipv_X ( int tunnel_type, struct buffer *buf, int ip_ver )
44 45
 {
45 46
   int offset;
46 47
   const struct openvpn_iphdr *ih;
... ...
@@ -68,12 +69,24 @@ is_ipv4 (int tunnel_type, struct buffer *buf)
68 68
 
69 69
   ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset);
70 70
 
71
-  if (OPENVPN_IPH_GET_VER (ih->version_len) == 4)
71
+  /* IP version is stored in the same bits for IPv4 or IPv6 header */
72
+  if (OPENVPN_IPH_GET_VER (ih->version_len) == ip_ver)
72 73
     return buf_advance (buf, offset);
73 74
   else
74 75
     return false;
75 76
 }
76 77
 
78
+bool
79
+is_ipv4 (int tunnel_type, struct buffer *buf)
80
+{
81
+    return is_ipv_X( tunnel_type, buf, 4 );
82
+}
83
+bool
84
+is_ipv6 (int tunnel_type, struct buffer *buf)
85
+{
86
+    return is_ipv_X( tunnel_type, buf, 6 );
87
+}
88
+
77 89
 #ifdef PACKET_TRUNCATION_CHECK
78 90
 
79 91
 void
... ...
@@ -219,10 +219,11 @@ struct ip_tcp_udp_hdr {
219 219
                              - sizeof(struct openvpn_tcphdr))
220 220
 
221 221
 /*
222
- * If raw tunnel packet is IPv4, return true and increment
222
+ * If raw tunnel packet is IPv4 or IPv6, return true and increment
223 223
  * buffer offset to start of IP header.
224 224
  */
225 225
 bool is_ipv4 (int tunnel_type, struct buffer *buf);
226
+bool is_ipv6 (int tunnel_type, struct buffer *buf);
226 227
 
227 228
 #ifdef PACKET_TRUNCATION_CHECK
228 229
 void ipv4_packet_size_verify (const uint8_t *data,