@@ -105,6 +105,11 @@ Secure renegotiation
previously authenticated peer can do trigger renegotiation and complete
renegotiations. This also closes CVE-2021-3568.
+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 specify 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
@@ -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=<max_mtu>`
+ The client announces the support of pushable MTU and the maximum MTU
+ it is willing to accept.
+
:code:`IV_GUI_VER=<gui_id> <version>`
The UI version of a UI if one is running, for example
:code:`de.blinkt.openvpn 0.5.47` for the Android app.
@@ -516,6 +516,11 @@ 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``.
+ The default for ``maxmtu`` is 1600. This will increase internal buffers
+ allocation for larger packet sizes.
+
--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
@@ -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,25 @@ do_deferred_options(struct context *c, const unsigned int found)
}
}
+ /* Cipher is considered safe, so we can use it to calculate the max
+ * MTU size */
+ 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 a large mtu, 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 +2655,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 +2676,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
@@ -3215,6 +3241,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)
{
@@ -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);
@@ -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
@@ -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);
@@ -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))
@@ -2061,6 +2061,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 */