{
/*
* The --passtos and --mssfix options require
- * us to examine the IPv4 header.
+ * us to examine the IP header (IPv4 or IPv6).
*/
- process_ipv4_header (c, PIPV4_PASSTOS|PIPV4_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf);
+ process_ip_header (c, PIPV4_PASSTOS|PIP_MSSFIX|PIPV4_CLIENT_NAT, &c->c2.buf);
#ifdef PACKET_TRUNCATION_CHECK
/* if (c->c2.buf.len > 1) --c->c2.buf.len; */
}
void
-process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf)
+process_ip_header (struct context *c, unsigned int flags, struct buffer *buf)
{
if (!c->options.ce.mssfix)
- flags &= ~PIPV4_MSSFIX;
+ flags &= ~PIP_MSSFIX;
#if PASSTOS_CAPABILITY
if (!c->options.passtos)
flags &= ~PIPV4_PASSTOS;
* us to examine the IPv4 header.
*/
#if PASSTOS_CAPABILITY
- if (flags & (PIPV4_PASSTOS|PIPV4_MSSFIX))
+ if (flags & (PIPV4_PASSTOS|PIP_MSSFIX))
#else
- if (flags & PIPV4_MSSFIX)
+ if (flags & PIP_MSSFIX)
#endif
{
struct buffer ipbuf = *buf;
#endif
/* possibly alter the TCP MSS */
- if (flags & PIPV4_MSSFIX)
- mss_fixup (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
+ if (flags & PIP_MSSFIX)
+ mss_fixup_ipv4 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
#ifdef ENABLE_CLIENT_NAT
/* possibly do NAT on packet */
route_list_add_vpn_gateway (c->c1.route_list, c->c2.es, dhcp_router);
}
}
+ else if (is_ipv6 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf))
+ {
+ /* possibly alter the TCP MSS */
+ if (flags & PIP_MSSFIX)
+ mss_fixup_ipv6 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
+ }
}
}
}
/*
* The --mssfix option requires
- * us to examine the IPv4 header.
+ * us to examine the IP header (IPv4 or IPv6).
*/
- process_ipv4_header (c, PIPV4_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun);
+ process_ip_header (c, PIP_MSSFIX|PIPV4_EXTRACT_DHCP_ROUTER|PIPV4_CLIENT_NAT|PIPV4_OUTGOING, &c->c2.to_tun);
if (c->c2.to_tun.len <= MAX_RW_SIZE_TUN (&c->c2.frame))
{
bool send_control_channel_string (struct context *c, const char *str, int msglevel);
#define PIPV4_PASSTOS (1<<0)
-#define PIPV4_MSSFIX (1<<1)
+#define PIP_MSSFIX (1<<1) /* v4 and v6 */
#define PIPV4_OUTGOING (1<<2)
#define PIPV4_EXTRACT_DHCP_ROUTER (1<<3)
#define PIPV4_CLIENT_NAT (1<<4)
-void process_ipv4_header (struct context *c, unsigned int flags, struct buffer *buf);
+void process_ip_header (struct context *c, unsigned int flags, struct buffer *buf);
#if P2MP
void schedule_exit (struct context *c, const int n_seconds, const int signal);
* problems which arise from protocol
* encapsulation.
*/
+
+/*
+ * IPv4 packet: find TCP header, check flags for "SYN"
+ * if yes, hand to mss_fixup_dowork()
+ */
void
-mss_fixup (struct buffer *buf, int maxmss)
+mss_fixup_ipv4 (struct buffer *buf, int maxmss)
{
const struct openvpn_iphdr *pip;
int hlen;
}
}
+/*
+ * IPv6 packet: find TCP header, check flags for "SYN"
+ * if yes, hand to mss_fixup_dowork()
+ * (IPv6 header structure is sufficiently different from IPv4...)
+ */
+void
+mss_fixup_ipv6 (struct buffer *buf, int maxmss)
+{
+ const struct openvpn_ipv6hdr *pip6;
+ struct buffer newbuf;
+
+ if (BLEN (buf) < (int) sizeof (struct openvpn_ipv6hdr))
+ return;
+
+ verify_align_4 (buf);
+ pip6 = (struct openvpn_ipv6hdr *) BPTR (buf);
+
+ /* do we have the full IPv6 packet?
+ * "payload_len" does not include IPv6 header (+40 bytes)
+ */
+ if (BLEN (buf) != (int) ntohs(pip6->payload_len)+40 )
+ return;
+
+ /* follow header chain until we reach final header, then check for TCP
+ *
+ * An IPv6 packet could, theoretically, have a chain of multiple headers
+ * before the final header (TCP, UDP, ...), so we'd need to walk that
+ * chain (see RFC 2460 and RFC 6564 for details).
+ *
+ * In practice, "most typically used" extention headers (AH, routing,
+ * fragment, mobility) are very unlikely to be seen inside an OpenVPN
+ * tun, so for now, we only handle the case of "single next header = TCP"
+ */
+ if ( pip6->nexthdr != OPENVPN_IPPROTO_TCP )
+ return;
+
+ newbuf = *buf;
+ if ( buf_advance( &newbuf, 40 ) )
+ {
+ struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR (&newbuf);
+ if (tc->flags & OPENVPN_TCPH_SYN_MASK)
+ mss_fixup_dowork (&newbuf, (uint16_t) maxmss-20);
+ }
+}
+
+/*
+ * change TCP MSS option in SYN/SYN-ACK packets, if present
+ * this is generic for IPv4 and IPv6, as the TCP header is the same
+ */
+
void
mss_fixup_dowork (struct buffer *buf, uint16_t maxmss)
{
#include "proto.h"
#include "error.h"
-void mss_fixup (struct buffer *buf, int maxmss);
+void mss_fixup_ipv4 (struct buffer *buf, int maxmss);
+void mss_fixup_ipv6 (struct buffer *buf, int maxmss);
void mss_fixup_dowork (struct buffer *buf, uint16_t maxmss);
#endif
if (mbuf_extract_item (ms, &item)) /* cleartext IP packet */
{
- unsigned int pipv4_flags = PIPV4_PASSTOS;
+ unsigned int pip_flags = PIPV4_PASSTOS;
set_prefix (item.instance);
item.instance->context.c2.buf = item.buffer->buf;
if (item.buffer->flags & MF_UNICAST) /* --mssfix doesn't make sense for broadcast or multicast */
- pipv4_flags |= PIPV4_MSSFIX;
- process_ipv4_header (&item.instance->context, pipv4_flags, &item.instance->context.c2.buf);
+ pip_flags |= PIP_MSSFIX;
+ process_ip_header (&item.instance->context, pip_flags, &item.instance->context.c2.buf);
encrypt_sign (&item.instance->context, true);
mbuf_free_buf (item.buffer);
#include "memdbg.h"
/*
- * If raw tunnel packet is IPv4, return true and increment
+ * If raw tunnel packet is IPv<X>, return true and increment
* buffer offset to start of IP header.
*/
+static
bool
-is_ipv4 (int tunnel_type, struct buffer *buf)
+is_ipv_X ( int tunnel_type, struct buffer *buf, int ip_ver )
{
int offset;
const struct openvpn_iphdr *ih;
ih = (const struct openvpn_iphdr *) (BPTR (buf) + offset);
- if (OPENVPN_IPH_GET_VER (ih->version_len) == 4)
+ /* IP version is stored in the same bits for IPv4 or IPv6 header */
+ if (OPENVPN_IPH_GET_VER (ih->version_len) == ip_ver)
return buf_advance (buf, offset);
else
return false;
}
+bool
+is_ipv4 (int tunnel_type, struct buffer *buf)
+{
+ return is_ipv_X( tunnel_type, buf, 4 );
+}
+bool
+is_ipv6 (int tunnel_type, struct buffer *buf)
+{
+ return is_ipv_X( tunnel_type, buf, 6 );
+}
+
#ifdef PACKET_TRUNCATION_CHECK
void
- sizeof(struct openvpn_tcphdr))
/*
- * If raw tunnel packet is IPv4, return true and increment
+ * If raw tunnel packet is IPv4 or IPv6, return true and increment
* buffer offset to start of IP header.
*/
bool is_ipv4 (int tunnel_type, struct buffer *buf);
+bool is_ipv6 (int tunnel_type, struct buffer *buf);
#ifdef PACKET_TRUNCATION_CHECK
void ipv4_packet_size_verify (const uint8_t *data,