From: Arne Schwabe Date: Wed, 9 Nov 2022 15:48:09 +0000 (+0100) Subject: Allow tun-mtu to be pushed X-Git-Tag: v2.6_beta1~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=01aed6a5df193a09d8d3c28c5a1580241e0a5e05;p=thirdparty%2Fopenvpn.git Allow tun-mtu to be pushed This allows tun-mtu to pushed but only up to the size of the preallocated buffers. This is not a perfect solution but should allow most of the use cases where the mtu is close enough to 1500 (or smaller). Signed-off-by: Arne Schwabe Patch v4: rebase for check_session_cipher name change Patch v5: remove mention of change of default mtu, remove leftover code from an earlier approach. Signed-off-by: Arne Schwabe Acked-by: Gert Doering Message-Id: <20221109154810.1268403-1-arne@rfc2549.org> URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg25498.html Signed-off-by: Gert Doering --- diff --git a/Changes.rst b/Changes.rst index 173abf546..f316115f3 100644 --- a/Changes.rst +++ b/Changes.rst @@ -99,6 +99,11 @@ Inline auth username and password missing OpenVPN will prompt for input via stdin. This applies to inline'd http-proxy-user-pass too. +Tun MTU can be pushed + The client can now also dynamically configure its MTU and the server + will try to push the client MTU when the client supports it. The + directive ``--tun-mtu-max`` has been introduced to increase the maximum + pushable MTU size (defaults to 1600). Improved control channel packet size control (``max-packet-size``) The size of control channel is no longer tied to diff --git a/doc/man-sections/client-options.rst b/doc/man-sections/client-options.rst index 5a906895b..07651479f 100644 --- a/doc/man-sections/client-options.rst +++ b/doc/man-sections/client-options.rst @@ -363,6 +363,10 @@ configuration. The client announces the list of supported ciphers configured with the ``--data-ciphers`` option to the server. + :code:`IV_MTU=` + The client announces the support of pushable MTU and the maximum MTU + it is willing to accept. + :code:`IV_GUI_VER= ` The UI version of a UI if one is running, for example :code:`de.blinkt.openvpn 0.5.47` for the Android app. diff --git a/doc/man-sections/vpn-network-options.rst b/doc/man-sections/vpn-network-options.rst index 72cf9064e..4b2c4a7be 100644 --- a/doc/man-sections/vpn-network-options.rst +++ b/doc/man-sections/vpn-network-options.rst @@ -540,6 +540,12 @@ routing. It's best to use the ``--fragment`` and/or ``--mssfix`` options to deal with MTU sizing issues. +--tun-max-mtu maxmtu + This configures the maximum MTU size that a server can push to ``maxmtu``, + by configuring the internal buffers to allow at least this packet size. + The default for ``maxmtu`` is 1600. Currently, only increasing beyond 1600 + is possible, and attempting to reduce max-mtu below 1600 will be ignored. + --tun-mtu-extra n Assume that the TUN/TAP device might return as many as ``n`` bytes more than the ``--tun-mtu`` size on read. This parameter defaults to 0, which diff --git a/src/openvpn/init.c b/src/openvpn/init.c index e7e122863..c2154b8dd 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -2312,7 +2312,8 @@ pull_permission_mask(const struct context *c) | OPT_P_ECHO | OPT_P_PULL_MODE | OPT_P_PEER_ID - | OPT_P_NCP; + | OPT_P_NCP + | OPT_P_PUSH_MTU; if (!c->options.route_nopull) { @@ -2475,6 +2476,23 @@ do_deferred_options(struct context *c, const unsigned int found) } } + if (found & OPT_P_PUSH_MTU) + { + /* MTU has changed, check that the pushed MTU is small enough to + * be able to change it */ + msg(D_PUSH, "OPTIONS IMPORT: tun-mtu set to %d", c->options.ce.tun_mtu); + + struct frame *frame = &c->c2.frame; + + if (c->options.ce.tun_mtu > frame->tun_max_mtu) + { + msg(D_PUSH_ERRORS, "Server-pushed tun-mtu is too large, please add " + "tun-mtu-max %d in the client configuration", + c->options.ce.tun_mtu); + } + frame->tun_mtu = min_int(frame->tun_max_mtu, c->options.ce.tun_mtu); + } + return true; } @@ -2635,10 +2653,16 @@ frame_finalize_options(struct context *c, const struct options *o) struct frame *frame = &c->c2.frame; frame->tun_mtu = get_frame_mtu(c, o); + frame->tun_max_mtu = o->ce.tun_mtu_max; + + /* max mtu needs to be at least as large as the tun mtu */ + frame->tun_max_mtu = max_int(frame->tun_mtu, frame->tun_max_mtu); - /* We always allow at least 1500 MTU packets to be received in our buffer - * space */ - size_t payload_size = max_int(1500, frame->tun_mtu); + /* We always allow at least 1600 MTU packets to be received in our buffer + * space to allow server to push "baby giant" MTU sizes */ + frame->tun_max_mtu = max_int(1600, frame->tun_max_mtu); + + size_t payload_size = frame->tun_max_mtu; /* we need to be also large enough to hold larger control channel packets * if configured */ @@ -2650,9 +2674,9 @@ frame_finalize_options(struct context *c, const struct options *o) payload_size += o->ce.tun_mtu_extra; } - /* Add 100 byte of extra space in the buffer to account for slightly - * mismatched MUTs between peers */ - payload_size += 100; + /* Add 32 byte of extra space in the buffer to account for small errors + * in the calculation */ + payload_size += 32; /* the space that is reserved before the payload to add extra headers to it @@ -3211,6 +3235,10 @@ do_init_frame_tls(struct context *c) c->c2.frame.buf.payload_size); frame_print(&c->c2.tls_multi->opt.frame, D_MTU_INFO, "Control Channel MTU parms"); + + /* Keep the max mtu also in the frame of tls multi so it can access + * it in push_peer_info */ + c->c2.tls_multi->opt.frame.tun_max_mtu = c->c2.frame.tun_max_mtu; } if (c->c2.tls_auth_standalone) { diff --git a/src/openvpn/mtu.c b/src/openvpn/mtu.c index f60f48534..a74a08153 100644 --- a/src/openvpn/mtu.c +++ b/src/openvpn/mtu.c @@ -222,6 +222,7 @@ frame_print(const struct frame *frame, buf_printf(&out, " max_frag:%d", frame->max_fragment_size); #endif buf_printf(&out, " tun_mtu:%d", frame->tun_mtu); + buf_printf(&out, " tun_max_mtu:%d", frame->tun_max_mtu); buf_printf(&out, " headroom:%d", frame->buf.headroom); buf_printf(&out, " payload:%d", frame->buf.payload_size); buf_printf(&out, " tailroom:%d", frame->buf.tailroom); diff --git a/src/openvpn/mtu.h b/src/openvpn/mtu.h index 370806fb5..badb3a6a8 100644 --- a/src/openvpn/mtu.h +++ b/src/openvpn/mtu.h @@ -138,6 +138,9 @@ struct frame { * control frame payload (although most of * code ignores it) */ + int tun_max_mtu; /**< the maximum tun-mtu size the buffers are + * are sized for. This is the upper bound that + * a server can push as MTU */ int extra_tun; /**< Maximum number of bytes in excess of * the tun/tap MTU that might be read diff --git a/src/openvpn/options.c b/src/openvpn/options.c index a86cc5cf1..334fc4118 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -6449,10 +6449,23 @@ add_option(struct options *options, } else if (streq(p[0], "tun-mtu") && p[1] && !p[2]) { - VERIFY_PERMISSION(OPT_P_MTU|OPT_P_CONNECTION); + VERIFY_PERMISSION(OPT_P_PUSH_MTU|OPT_P_CONNECTION); options->ce.tun_mtu = positive_atoi(p[1]); options->ce.tun_mtu_defined = true; } + else if (streq(p[0], "tun-mtu-max") && p[1] && !p[3]) + { + VERIFY_PERMISSION(OPT_P_MTU|OPT_P_CONNECTION); + int max_mtu = positive_atoi(p[1]); + if (max_mtu < 68 || max_mtu > 65536) + { + msg(msglevel, "--tun-mtu-max value '%s' is invalid", p[1]); + } + else + { + options->ce.tun_mtu_max = max_mtu; + } + } else if (streq(p[0], "tun-mtu-extra") && p[1] && !p[2]) { VERIFY_PERMISSION(OPT_P_MTU|OPT_P_CONNECTION); diff --git a/src/openvpn/options.h b/src/openvpn/options.h index b165ee5b7..a2bc13a1c 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -118,6 +118,8 @@ struct connection_entry const char *socks_proxy_authfile; int tun_mtu; /* MTU of tun device */ + int tun_mtu_max; /* maximum MTU that can be pushed */ + bool tun_mtu_defined; /* true if user overriding parm with command line option */ int tun_mtu_extra; bool tun_mtu_extra_defined; @@ -730,6 +732,7 @@ struct options #define OPT_P_CONNECTION (1<<27) #define OPT_P_PEER_ID (1<<28) #define OPT_P_INLINE (1<<29) +#define OPT_P_PUSH_MTU (1<<30) #define OPT_P_DEFAULT (~(OPT_P_INSTANCE|OPT_P_PULL_MODE)) diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c index 01ecc0dba..a73a2b714 100644 --- a/src/openvpn/ssl.c +++ b/src/openvpn/ssl.c @@ -2048,6 +2048,9 @@ push_peer_info(struct buffer *buf, struct tls_session *session) /* support for AUTH_FAIL,TEMP control message */ iv_proto |= IV_PROTO_AUTH_FAIL_TEMP; + + /* support for tun-mtu as part of the push message */ + buf_printf(&out, "IV_MTU=%d\n", session->opt->frame.tun_max_mtu); } /* support for Negotiable Crypto Parameters */