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-2024 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, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29#include "error.h"
30#include "mss.h"
31#include "crypto.h"
32#include "ssl_common.h"
33#include "memdbg.h"
34#include "forward.h"
35
36/*
37 * Lower MSS on TCP SYN packets to fix MTU
38 * problems which arise from protocol
39 * encapsulation.
40 */
41
42/*
43 * IPv4 packet: find TCP header, check flags for "SYN"
44 * if yes, hand to mss_fixup_dowork()
45 */
46void
47mss_fixup_ipv4(struct buffer *buf, uint16_t maxmss)
48{
49 const struct openvpn_iphdr *pip;
50 int hlen;
51
52 if (BLEN(buf) < (int) sizeof(struct openvpn_iphdr))
53 {
54 return;
55 }
56
57 verify_align_4(buf);
58 pip = (struct openvpn_iphdr *) BPTR(buf);
59
61
63 && ntohs(pip->tot_len) == BLEN(buf)
64 && (ntohs(pip->frag_off) & OPENVPN_IP_OFFMASK) == 0
65 && hlen <= BLEN(buf)
66 && BLEN(buf) - hlen
67 >= (int) sizeof(struct openvpn_tcphdr))
68 {
69 struct buffer newbuf = *buf;
70 if (buf_advance(&newbuf, hlen))
71 {
72 struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR(&newbuf);
74 {
75 mss_fixup_dowork(&newbuf, maxmss);
76 }
77 }
78 }
79}
80
81/*
82 * IPv6 packet: find TCP header, check flags for "SYN"
83 * if yes, hand to mss_fixup_dowork()
84 * (IPv6 header structure is sufficiently different from IPv4...)
85 */
86void
87mss_fixup_ipv6(struct buffer *buf, uint16_t maxmss)
88{
89 const struct openvpn_ipv6hdr *pip6;
90 struct buffer newbuf;
91
92 if (BLEN(buf) < (int) sizeof(struct openvpn_ipv6hdr))
93 {
94 return;
95 }
96
97 verify_align_4(buf);
98 pip6 = (struct openvpn_ipv6hdr *) BPTR(buf);
99
100 /* do we have the full IPv6 packet?
101 * "payload_len" does not include IPv6 header (+40 bytes)
102 */
103 if (BLEN(buf) != (int) ntohs(pip6->payload_len)+40)
104 {
105 return;
106 }
107
108 /* follow header chain until we reach final header, then check for TCP
109 *
110 * An IPv6 packet could, theoretically, have a chain of multiple headers
111 * before the final header (TCP, UDP, ...), so we'd need to walk that
112 * chain (see RFC 2460 and RFC 6564 for details).
113 *
114 * In practice, "most typically used" extension headers (AH, routing,
115 * fragment, mobility) are very unlikely to be seen inside an OpenVPN
116 * tun, so for now, we only handle the case of "single next header = TCP"
117 */
118 if (pip6->nexthdr != OPENVPN_IPPROTO_TCP)
119 {
120 return;
121 }
122
123 /* skip IPv6 header (40 bytes),
124 * verify remainder is large enough to contain a full TCP header
125 */
126 newbuf = *buf;
127 if (buf_advance( &newbuf, 40 )
128 && BLEN(&newbuf) >= (int) sizeof(struct openvpn_tcphdr))
129 {
130 struct openvpn_tcphdr *tc = (struct openvpn_tcphdr *) BPTR(&newbuf);
132 {
133 mss_fixup_dowork(&newbuf, maxmss-20);
134 }
135 }
136}
137
138/*
139 * change TCP MSS option in SYN/SYN-ACK packets, if present
140 * this is generic for IPv4 and IPv6, as the TCP header is the same
141 */
142
143void
144mss_fixup_dowork(struct buffer *buf, uint16_t maxmss)
145{
146 int hlen, olen, optlen;
147 uint8_t *opt;
148 uint16_t mssval;
149 int accumulate;
150 struct openvpn_tcphdr *tc;
151
152 if (BLEN(buf) < (int) sizeof(struct openvpn_tcphdr))
153 {
154 return;
155 }
156
157 verify_align_4(buf);
158 tc = (struct openvpn_tcphdr *) BPTR(buf);
160
161 /* Invalid header length or header without options. */
162 if (hlen <= (int) sizeof(struct openvpn_tcphdr)
163 || hlen > BLEN(buf))
164 {
165 return;
166 }
167
168 for (olen = hlen - (int) sizeof(struct openvpn_tcphdr),
169 opt = (uint8_t *)(tc + 1);
170 olen > 1;
171 olen -= optlen, opt += optlen)
172 {
173 if (*opt == OPENVPN_TCPOPT_EOL)
174 {
175 break;
176 }
177 else if (*opt == OPENVPN_TCPOPT_NOP)
178 {
179 optlen = 1;
180 }
181 else
182 {
183 optlen = *(opt + 1);
184 if (optlen <= 0 || optlen > olen)
185 {
186 break;
187 }
188 if (*opt == OPENVPN_TCPOPT_MAXSEG)
189 {
190 if (optlen != OPENVPN_TCPOLEN_MAXSEG)
191 {
192 continue;
193 }
194 mssval = opt[2] << 8;
195 mssval += opt[3];
196 if (mssval > maxmss)
197 {
198 dmsg(D_MSS, "MSS: %" PRIu16 " -> %" PRIu16, mssval, maxmss);
199 accumulate = htons(mssval);
200 opt[2] = (uint8_t)((maxmss>>8)&0xff);
201 opt[3] = (uint8_t)(maxmss&0xff);
202 accumulate -= htons(maxmss);
203 ADJUST_CHECKSUM(accumulate, tc->check);
204 }
205 }
206 }
207 }
208}
209
210static inline size_t
211adjust_payload_max_cbc(const struct key_type *kt, size_t target)
212{
213 if (!cipher_kt_mode_cbc(kt->cipher))
214 {
215 /* With stream ciphers (or block cipher in stream modes like CFB, AEAD)
216 * we can just use the target as is */
217 return target;
218 }
219 else
220 {
221 /* With CBC we need at least one extra byte for padding and then need
222 * to ensure that the resulting CBC ciphertext length, which is always
223 * a multiple of the block size, is not larger than the target value */
224 size_t block_size = cipher_kt_block_size(kt->cipher);
225 target = round_down_size(target, block_size);
226 return target - 1;
227 }
228}
229
230static size_t
232 const struct link_socket_info *lsi)
233{
234 /* Add the overhead of the encapsulating IP packets */
235 sa_family_t af;
236 int proto;
237
238 if (lsi && lsi->lsa)
239 {
240 af = lsi->lsa->actual.dest.addr.sa.sa_family;
241 proto = lsi->proto;
242 }
243 else
244 {
245 /* In the early init before the connection is established or we
246 * are in listen mode we can only make an educated guess
247 * from the af of the connection entry, in p2mp this will be
248 * later updated */
249 af = options->ce.af;
250 proto = options->ce.proto;
251 }
252 return datagram_overhead(af, proto);
253}
254
255static void
257 const struct options *options,
258 struct link_socket_info *lsi)
259{
260#if defined(ENABLE_FRAGMENT)
261 size_t overhead;
262
263 overhead = frame_calculate_protocol_header_size(kt, options, false);
264
266 {
267 overhead += get_ip_encap_overhead(options, lsi);
268 }
269
270 size_t target = options->ce.fragment - overhead;
271 /* The 4 bytes of header that fragment adds itself. The other extra payload
272 * bytes (Ethernet header/compression) are handled by the fragment code
273 * just as part of the payload and therefore automatically taken into
274 * account if the packet needs to fragmented */
276
277 if (cipher_kt_mode_cbc(kt->cipher))
278 {
279 /* The packet id gets added to *each* fragment in CBC mode, so we need
280 * to account for it */
282 }
283#endif
284}
285
286static void
288 const struct options *options,
289 struct link_socket_info *lsi)
290{
292 {
293 /* we subtract IPv4 and TCP overhead here, mssfix method will add the
294 * extra 20 for IPv6 */
295 frame->mss_fix = (uint16_t)(options->ce.mssfix - (20 + 20));
296 return;
297 }
298
299 size_t overhead, payload_overhead;
300
301 overhead = frame_calculate_protocol_header_size(kt, options, false);
302
303 /* Calculate the number of bytes that the payload differs from the payload
304 * MTU. This are fragment/compression/ethernet headers */
306
307 /* We are in a "liberal" position with respect to MSS,
308 * i.e. we assume that MSS can be calculated from MTU
309 * by subtracting out only the IP and TCP header sizes
310 * without options.
311 *
312 * (RFC 879, section 7). */
313
315 {
316 /* Add the overhead of the encapsulating IP packets */
317 overhead += get_ip_encap_overhead(options, lsi);
318 }
319
320 /* Add 20 bytes for the IPv4 header and 20 byte for the TCP header of the
321 * payload, the mssfix method will add 20 extra if payload is IPv6 */
322 payload_overhead += 20 + 20;
323
324 /* Calculate the maximum MSS value from the max link layer size specified
325 * by ce.mssfix */
326
327 /* This is the target value our payload needs to be smaller */
328 size_t target = options->ce.mssfix - overhead;
329 frame->mss_fix = (uint16_t)(adjust_payload_max_cbc(kt, target) - payload_overhead);
330
331
332}
333
334void
336 const struct options *options,
337 struct link_socket_info *lsi)
338{
339 if (options->ce.fragment > 0)
340 {
342 }
343
344 if (options->ce.mssfix > 0)
345 {
347 }
348}
349
350/*
351 * Adjust frame structure based on a Path MTU value given
352 * to us by the OS.
353 */
354void
356{
357 struct link_socket_info *lsi = get_link_socket_info(c);
358 struct options *o = &c->options;
359
360 int pmtu = c->c2.link_sockets[0]->mtu;
361 sa_family_t af = lsi->lsa->actual.dest.addr.sa.sa_family;
362 int proto = lsi->proto;
363
364 int encap_overhead = datagram_overhead(af, proto);
365
366 /* check if mssfix and fragment need to be adjusted */
367 if (pmtu < o->ce.mssfix
368 || (o->ce.mssfix_encap && pmtu < o->ce.mssfix + encap_overhead))
369 {
370 const char *mtustr = o->ce.mssfix_encap ? " mtu" : "";
371 msg(D_MTU_INFO, "Note adjusting 'mssfix %d%s' to 'mssfix %d mtu' "
372 "according to path MTU discovery", o->ce.mssfix,
373 mtustr, pmtu);
374 o->ce.mssfix = pmtu;
375 o->ce.mssfix_encap = true;
376 frame_calculate_dynamic(&c->c2.frame, &c->c1.ks.key_type, o, lsi);
377 }
378
379#if defined(ENABLE_FRAGMENT)
380 if (pmtu < o->ce.fragment
381 || (o->ce.fragment_encap && pmtu < o->ce.fragment + encap_overhead))
382 {
383 const char *mtustr = o->ce.fragment_encap ? " mtu" : "";
384 msg(D_MTU_INFO, "Note adjusting 'fragment %d%s' to 'fragment %d mtu' "
385 "according to path MTU discovery", o->ce.fragment,
386 mtustr, pmtu);
387 o->ce.fragment = pmtu;
388 o->ce.fragment_encap = true;
390 o, lsi);
391 }
392#endif
393}
#define BPTR(buf)
Definition buffer.h:124
static bool buf_advance(struct buffer *buf, int size)
Definition buffer.h:618
#define verify_align_4(ptr)
Definition buffer.h:991
#define BLEN(buf)
Definition buffer.h:127
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:128
#define D_MTU_INFO
Definition errlevel.h:105
Interface functions to the internal and external multiplexers.
static struct link_socket_info * get_link_socket_info(struct context *c)
Definition forward.h:321
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:40
static void frame_calculate_fragment(struct frame *frame, struct key_type *kt, const struct options *options, struct link_socket_info *lsi)
Definition mss.c:256
void mss_fixup_dowork(struct buffer *buf, uint16_t maxmss)
Definition mss.c:144
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:335
void mss_fixup_ipv6(struct buffer *buf, uint16_t maxmss)
Definition mss.c:87
void mss_fixup_ipv4(struct buffer *buf, uint16_t maxmss)
Definition mss.c:47
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:355
static size_t get_ip_encap_overhead(const struct options *options, const struct link_socket_info *lsi)
Definition mss.c:231
static void frame_calculate_mssfix(struct frame *frame, struct key_type *kt, const struct options *options, struct link_socket_info *lsi)
Definition mss.c:287
static size_t adjust_payload_max_cbc(const struct key_type *kt, size_t target)
Definition mss.c:211
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:63
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:53
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:101
#define dmsg(flags,...)
Definition error.h:148
#define msg(flags,...)
Definition error.h:144
#define OPENVPN_TCPOPT_NOP
Definition proto.h:189
#define OPENVPN_IPH_GET_LEN(v)
Definition proto.h:94
#define OPENVPN_TCPH_GET_DOFF(d)
Definition proto.h:170
#define OPENVPN_TCPOPT_MAXSEG
Definition proto.h:190
#define OPENVPN_TCPOPT_EOL
Definition proto.h:188
#define OPENVPN_IP_OFFMASK
Definition proto.h:101
#define ADJUST_CHECKSUM(acc, cksum)
Definition proto.h:211
#define OPENVPN_TCPH_SYN_MASK
Definition proto.h:174
#define OPENVPN_TCPOLEN_MAXSEG
Definition proto.h:191
#define OPENVPN_IPPROTO_TCP
Definition proto.h:107
static int datagram_overhead(sa_family_t af, int proto)
Definition socket.h:629
Control Channel Common Data Structures.
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:66
int mssfix
Definition options.h:142
bool mssfix_encap
Definition options.h:144
bool fragment_encap
Definition options.h:140
int fragment
Definition options.h:139
int proto
Definition options.h:107
sa_family_t af
Definition options.h:108
bool mssfix_fixed
Definition options.h:146
struct key_schedule ks
Definition openvpn.h:163
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:514
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:513
Packet geometry parameters.
Definition mtu.h:98
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:145
uint16_t mss_fix
The actual MSS value that should be written to the payload packets.
Definition mtu.h:118
int max_fragment_size
The maximum size of a fragment.
Definition mtu.h:124
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:102
uint8_t protocol
Definition proto.h:110
uint16_t tot_len
Definition proto.h:98
uint8_t version_len
Definition proto.h:95
uint8_t nexthdr
Definition proto.h:125
uint16_t payload_len
Definition proto.h:124
union openvpn_sockaddr::@20 addr
struct sockaddr sa
Definition socket.h:69
uint8_t doff_res
Definition proto.h:171
uint16_t check
Definition proto.h:184
uint8_t flags
Definition proto.h:181
struct connection_entry ce
Definition options.h:288
unsigned short sa_family_t
Definition syshead.h:395