OpenVPN
mss.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2025 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, see <https://www.gnu.org/licenses/>.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#include "syshead.h"
28#include "error.h"
29#include "mss.h"
30#include "crypto.h"
31#include "ssl_common.h"
32#include "memdbg.h"
33#include "forward.h"
34
35/*
36 * Lower MSS on TCP SYN packets to fix MTU
37 * problems which arise from protocol
38 * encapsulation.
39 */
40
41/*
42 * IPv4 packet: find TCP header, check flags for "SYN"
43 * if yes, hand to mss_fixup_dowork()
44 */
45void
46mss_fixup_ipv4(struct buffer *buf, uint16_t maxmss)
47{
48 const struct openvpn_iphdr *pip;
49 int hlen;
50
51 if (BLEN(buf) < (int)sizeof(struct openvpn_iphdr))
52 {
53 return;
54 }
55
56 verify_align_4(buf);
57 pip = (struct openvpn_iphdr *)BPTR(buf);
58
60
61 if (pip->protocol == OPENVPN_IPPROTO_TCP && ntohs(pip->tot_len) == BLEN(buf)
62 && (ntohs(pip->frag_off) & OPENVPN_IP_OFFMASK) == 0 && hlen <= BLEN(buf)
63 && BLEN(buf) - hlen >= (int)sizeof(struct openvpn_tcphdr))
64 {
65 struct buffer newbuf = *buf;
66 if (buf_advance(&newbuf, hlen))
67 {
68 struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *)BPTR(&newbuf);
70 {
71 mss_fixup_dowork(&newbuf, maxmss);
72 }
73 }
74 }
75}
76
77/*
78 * IPv6 packet: find TCP header, check flags for "SYN"
79 * if yes, hand to mss_fixup_dowork()
80 * (IPv6 header structure is sufficiently different from IPv4...)
81 */
82void
83mss_fixup_ipv6(struct buffer *buf, uint16_t maxmss)
84{
85 const struct openvpn_ipv6hdr *pip6;
86 struct buffer newbuf;
87
88 if (BLEN(buf) < (int)sizeof(struct openvpn_ipv6hdr))
89 {
90 return;
91 }
92
93 verify_align_4(buf);
94 pip6 = (struct openvpn_ipv6hdr *)BPTR(buf);
95
96 /* do we have the full IPv6 packet?
97 * "payload_len" does not include IPv6 header (+40 bytes)
98 */
99 if (BLEN(buf) != (int)ntohs(pip6->payload_len) + 40)
100 {
101 return;
102 }
103
104 /* follow header chain until we reach final header, then check for TCP
105 *
106 * An IPv6 packet could, theoretically, have a chain of multiple headers
107 * before the final header (TCP, UDP, ...), so we'd need to walk that
108 * chain (see RFC 2460 and RFC 6564 for details).
109 *
110 * In practice, "most typically used" extension headers (AH, routing,
111 * fragment, mobility) are very unlikely to be seen inside an OpenVPN
112 * tun, so for now, we only handle the case of "single next header = TCP"
113 */
114 if (pip6->nexthdr != OPENVPN_IPPROTO_TCP)
115 {
116 return;
117 }
118
119 /* skip IPv6 header (40 bytes),
120 * verify remainder is large enough to contain a full TCP header
121 */
122 newbuf = *buf;
123 if (buf_advance(&newbuf, 40) && BLEN(&newbuf) >= (int)sizeof(struct openvpn_tcphdr))
124 {
125 struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *)BPTR(&newbuf);
127 {
128 mss_fixup_dowork(&newbuf, maxmss - 20);
129 }
130 }
131}
132
133/*
134 * change TCP MSS option in SYN/SYN-ACK packets, if present
135 * this is generic for IPv4 and IPv6, as the TCP header is the same
136 */
137
138void
139mss_fixup_dowork(struct buffer *buf, uint16_t maxmss)
140{
141 int hlen, olen, optlen;
142 uint8_t *opt;
143 uint16_t mssval;
144 int accumulate;
145 struct openvpn_tcphdr *tc;
146
147 if (BLEN(buf) < (int)sizeof(struct openvpn_tcphdr))
148 {
149 return;
150 }
151
152 verify_align_4(buf);
153 tc = (struct openvpn_tcphdr *)BPTR(buf);
155
156 /* Invalid header length or header without options. */
157 if (hlen <= (int)sizeof(struct openvpn_tcphdr) || hlen > BLEN(buf))
158 {
159 return;
160 }
161
162 for (olen = hlen - (int)sizeof(struct openvpn_tcphdr), opt = (uint8_t *)(tc + 1); olen > 1;
163 olen -= optlen, opt += optlen)
164 {
165 if (*opt == OPENVPN_TCPOPT_EOL)
166 {
167 break;
168 }
169 else if (*opt == OPENVPN_TCPOPT_NOP)
170 {
171 optlen = 1;
172 }
173 else
174 {
175 optlen = *(opt + 1);
176 if (optlen <= 0 || optlen > olen)
177 {
178 break;
179 }
180 if (*opt == OPENVPN_TCPOPT_MAXSEG)
181 {
182 if (optlen != OPENVPN_TCPOLEN_MAXSEG)
183 {
184 continue;
185 }
186 mssval = opt[2] << 8;
187 mssval += opt[3];
188 if (mssval > maxmss)
189 {
190 dmsg(D_MSS, "MSS: %" PRIu16 " -> %" PRIu16, mssval, maxmss);
191 accumulate = htons(mssval);
192 opt[2] = (uint8_t)((maxmss >> 8) & 0xff);
193 opt[3] = (uint8_t)(maxmss & 0xff);
194 accumulate -= htons(maxmss);
195 ADJUST_CHECKSUM(accumulate, tc->check);
196 }
197 }
198 }
199 }
200}
201
202static inline size_t
203adjust_payload_max_cbc(const struct key_type *kt, size_t target)
204{
205 if (!cipher_kt_mode_cbc(kt->cipher))
206 {
207 /* With stream ciphers (or block cipher in stream modes like CFB, AEAD)
208 * we can just use the target as is */
209 return target;
210 }
211 else
212 {
213 /* With CBC we need at least one extra byte for padding and then need
214 * to ensure that the resulting CBC ciphertext length, which is always
215 * a multiple of the block size, is not larger than the target value */
216 size_t block_size = cipher_kt_block_size(kt->cipher);
217 target = round_down_size(target, block_size);
218 return target - 1;
219 }
220}
221
222static size_t
223get_ip_encap_overhead(const struct options *options, const struct link_socket_info *lsi)
224{
225 /* Add the overhead of the encapsulating IP packets */
226 sa_family_t af;
227 int proto;
228
229 if (lsi && lsi->lsa)
230 {
231 af = lsi->lsa->actual.dest.addr.sa.sa_family;
232 proto = lsi->proto;
233 }
234 else
235 {
236 /* In the early init before the connection is established or we
237 * are in listen mode we can only make an educated guess
238 * from the af of the connection entry, in p2mp this will be
239 * later updated */
240 af = options->ce.af;
241 proto = options->ce.proto;
242 }
243 return datagram_overhead(af, proto);
244}
245
246static void
247frame_calculate_fragment(struct frame *frame, struct key_type *kt, const struct options *options,
248 struct link_socket_info *lsi)
249{
250#if defined(ENABLE_FRAGMENT)
251 size_t overhead;
252
253 overhead = frame_calculate_protocol_header_size(kt, options, false);
254
256 {
257 overhead += get_ip_encap_overhead(options, lsi);
258 }
259
260 size_t target = options->ce.fragment - overhead;
261 /* The 4 bytes of header that fragment adds itself. The other extra payload
262 * bytes (Ethernet header/compression) are handled by the fragment code
263 * just as part of the payload and therefore automatically taken into
264 * account if the packet needs to fragmented */
266
267 if (cipher_kt_mode_cbc(kt->cipher))
268 {
269 /* The packet id gets added to *each* fragment in CBC mode, so we need
270 * to account for it */
272 }
273#endif
274}
275
276static void
277frame_calculate_mssfix(struct frame *frame, struct key_type *kt, const struct options *options,
278 struct link_socket_info *lsi)
279{
281 {
282 /* we subtract IPv4 and TCP overhead here, mssfix method will add the
283 * extra 20 for IPv6 */
284 frame->mss_fix = (uint16_t)(options->ce.mssfix - (20 + 20));
285 return;
286 }
287
288 size_t overhead, payload_overhead;
289
290 overhead = frame_calculate_protocol_header_size(kt, options, false);
291
292 /* Calculate the number of bytes that the payload differs from the payload
293 * MTU. This are fragment/compression/ethernet headers */
295
296 /* We are in a "liberal" position with respect to MSS,
297 * i.e. we assume that MSS can be calculated from MTU
298 * by subtracting out only the IP and TCP header sizes
299 * without options.
300 *
301 * (RFC 879, section 7). */
302
304 {
305 /* Add the overhead of the encapsulating IP packets */
306 overhead += get_ip_encap_overhead(options, lsi);
307 }
308
309 /* Add 20 bytes for the IPv4 header and 20 byte for the TCP header of the
310 * payload, the mssfix method will add 20 extra if payload is IPv6 */
311 payload_overhead += 20 + 20;
312
313 /* Calculate the maximum MSS value from the max link layer size specified
314 * by ce.mssfix */
315
316 /* This is the target value our payload needs to be smaller */
317 size_t target = options->ce.mssfix - overhead;
318 frame->mss_fix = (uint16_t)(adjust_payload_max_cbc(kt, target) - payload_overhead);
319}
320
321void
322frame_calculate_dynamic(struct frame *frame, struct key_type *kt, const struct options *options,
323 struct link_socket_info *lsi)
324{
325 if (options->ce.fragment > 0)
326 {
328 }
329
330 if (options->ce.mssfix > 0)
331 {
333 }
334}
335
336/*
337 * Adjust frame structure based on a Path MTU value given
338 * to us by the OS.
339 */
340void
342{
343 struct link_socket_info *lsi = get_link_socket_info(c);
344 struct options *o = &c->options;
345
346 int pmtu = c->c2.link_sockets[0]->mtu;
347 sa_family_t af = lsi->lsa->actual.dest.addr.sa.sa_family;
348 int proto = lsi->proto;
349
350 int encap_overhead = datagram_overhead(af, proto);
351
352 /* check if mssfix and fragment need to be adjusted */
353 if (pmtu < o->ce.mssfix || (o->ce.mssfix_encap && pmtu < o->ce.mssfix + encap_overhead))
354 {
355 const char *mtustr = o->ce.mssfix_encap ? " mtu" : "";
357 "Note adjusting 'mssfix %d%s' to 'mssfix %d mtu' "
358 "according to path MTU discovery",
359 o->ce.mssfix, mtustr, pmtu);
360 o->ce.mssfix = pmtu;
361 o->ce.mssfix_encap = true;
362 frame_calculate_dynamic(&c->c2.frame, &c->c1.ks.key_type, o, lsi);
363 }
364
365#if defined(ENABLE_FRAGMENT)
366 if (pmtu < o->ce.fragment || (o->ce.fragment_encap && pmtu < o->ce.fragment + encap_overhead))
367 {
368 const char *mtustr = o->ce.fragment_encap ? " mtu" : "";
370 "Note adjusting 'fragment %d%s' to 'fragment %d mtu' "
371 "according to path MTU discovery",
372 o->ce.fragment, mtustr, pmtu);
373 o->ce.fragment = pmtu;
374 o->ce.fragment_encap = true;
376 }
377#endif
378}
#define BPTR(buf)
Definition buffer.h:123
static bool buf_advance(struct buffer *buf, int size)
Definition buffer.h:616
#define verify_align_4(ptr)
Definition buffer.h:973
#define BLEN(buf)
Definition buffer.h:126
Data Channel Cryptography Module.
bool cipher_kt_mode_cbc(const char *ciphername)
Check if the supplied cipher is a supported CBC mode cipher.
int cipher_kt_block_size(const char *ciphername)
Returns the block size of the cipher, in bytes.
#define D_MSS
Definition errlevel.h:127
#define D_MTU_INFO
Definition errlevel.h:104
Interface functions to the internal and external multiplexers.
static struct link_socket_info * get_link_socket_info(struct context *c)
Definition forward.h:332
static size_t round_down_size(size_t num, size_t multiple)
Rounds down num to the nearest multiple of multiple.
Definition integer.h:212
static int clamp_size_to_int(size_t size)
Definition integer.h:43
static void frame_calculate_fragment(struct frame *frame, struct key_type *kt, const struct options *options, struct link_socket_info *lsi)
Definition mss.c:247
void mss_fixup_dowork(struct buffer *buf, uint16_t maxmss)
Definition mss.c:139
void frame_calculate_dynamic(struct frame *frame, struct key_type *kt, const struct options *options, struct link_socket_info *lsi)
Set the –mssfix option.
Definition mss.c:322
void mss_fixup_ipv6(struct buffer *buf, uint16_t maxmss)
Definition mss.c:83
void mss_fixup_ipv4(struct buffer *buf, uint16_t maxmss)
Definition mss.c:46
void frame_adjust_path_mtu(struct context *c)
Checks and adjusts the fragment and mssfix value according to the discovered path mtu value.
Definition mss.c:341
static size_t get_ip_encap_overhead(const struct options *options, const struct link_socket_info *lsi)
Definition mss.c:223
static void frame_calculate_mssfix(struct frame *frame, struct key_type *kt, const struct options *options, struct link_socket_info *lsi)
Definition mss.c:277
static size_t adjust_payload_max_cbc(const struct key_type *kt, size_t target)
Definition mss.c:203
size_t frame_calculate_protocol_header_size(const struct key_type *kt, const struct options *options, bool occ)
Calculates the size of the OpenVPN protocol header.
Definition mtu.c:61
unsigned int calc_packet_id_size_dc(const struct options *options, const struct key_type *kt)
Return the size of the packet ID size that is currently in use by cipher and options for the data cha...
Definition mtu.c:51
size_t frame_calculate_payload_overhead(size_t extra_tun, const struct options *options, const struct key_type *kt)
Calculates the size of the payload overhead according to tun-mtu and tap overhead.
Definition mtu.c:98
#define dmsg(flags,...)
Definition error.h:170
#define msg(flags,...)
Definition error.h:150
#define OPENVPN_TCPOPT_NOP
Definition proto.h:191
#define OPENVPN_IPH_GET_LEN(v)
Definition proto.h:92
#define OPENVPN_TCPH_GET_DOFF(d)
Definition proto.h:172
#define OPENVPN_TCPOPT_MAXSEG
Definition proto.h:192
#define OPENVPN_TCPOPT_EOL
Definition proto.h:190
#define OPENVPN_IP_OFFMASK
Definition proto.h:99
#define ADJUST_CHECKSUM(acc, cksum)
Definition proto.h:215
#define OPENVPN_TCPH_SYN_MASK
Definition proto.h:176
#define OPENVPN_TCPOLEN_MAXSEG
Definition proto.h:193
#define OPENVPN_IPPROTO_TCP
Definition proto.h:105
static int datagram_overhead(sa_family_t af, int proto)
Control Channel Common Data Structures.
Wrapper structure for dynamically allocated memory.
Definition buffer.h:60
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:65
int mssfix
Definition options.h:141
bool mssfix_encap
Definition options.h:143
bool fragment_encap
Definition options.h:139
int fragment
Definition options.h:138
int proto
Definition options.h:106
sa_family_t af
Definition options.h:107
bool mssfix_fixed
Definition options.h:145
struct key_schedule ks
Definition openvpn.h:164
struct frame frame
Definition openvpn.h:248
struct frame frame_fragment
Definition openvpn.h:253
struct link_socket ** link_sockets
Definition openvpn.h:237
Contains all state information for one tunnel.
Definition openvpn.h:474
struct context_2 c2
Level 2 context.
Definition openvpn.h:517
struct options options
Options loaded from command line or configuration file.
Definition openvpn.h:475
struct context_1 c1
Level 1 context.
Definition openvpn.h:516
Packet geometry parameters.
Definition mtu.h:103
int extra_tun
Maximum number of bytes in excess of the tun/tap MTU that might be read from or written to the virtua...
Definition mtu.h:151
uint16_t mss_fix
The actual MSS value that should be written to the payload packets.
Definition mtu.h:124
int max_fragment_size
The maximum size of a fragment.
Definition mtu.h:130
struct key_type key_type
Definition openvpn.h:57
const char * cipher
const name of the cipher
Definition crypto.h:142
uint16_t frag_off
Definition proto.h:100
uint8_t protocol
Definition proto.h:108
uint16_t tot_len
Definition proto.h:96
uint8_t version_len
Definition proto.h:93
uint8_t nexthdr
Definition proto.h:124
uint16_t payload_len
Definition proto.h:123
union openvpn_sockaddr::@27 addr
struct sockaddr sa
Definition socket_util.h:42
uint8_t doff_res
Definition proto.h:173
uint16_t check
Definition proto.h:186
uint8_t flags
Definition proto.h:183
struct connection_entry ce
Definition options.h:290
unsigned short sa_family_t
Definition syshead.h:396