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
8
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
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.
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.
19
* You should have received a copy of the GNU General Public License
20
* along with this program (see the file COPYING included with this
21
* distribution); if not, write to the Free Software Foundation, Inc.,
22
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35
/* allocate a buffer for socket or tun layer */
37
alloc_buf_sock_tun (struct buffer *buf,
38
const struct frame *frame,
39
const bool tuntap_buffer,
40
const unsigned int align_mask)
42
/* allocate buffer for overlapped I/O */
43
*buf = alloc_buf (BUF_SIZE (frame));
44
ASSERT (buf_init (buf, FRAME_HEADROOM_ADJ (frame, align_mask)));
45
buf->len = tuntap_buffer ? MAX_RW_SIZE_TUN (frame) : MAX_RW_SIZE_LINK (frame);
46
ASSERT (buf_safe (buf, 0));
50
frame_finalize (struct frame *frame,
51
bool link_mtu_defined,
56
/* Set link_mtu based on command line options */
59
ASSERT (!link_mtu_defined);
60
frame->link_mtu = tun_mtu + TUN_LINK_DELTA (frame);
64
ASSERT (link_mtu_defined);
65
frame->link_mtu = link_mtu;
68
if (TUN_MTU_SIZE (frame) < TUN_MTU_MIN)
70
msg (M_WARN, "TUN MTU value (%d) must be at least %d", TUN_MTU_SIZE (frame), TUN_MTU_MIN);
71
frame_print (frame, M_FATAL, "MTU is too small");
74
frame->link_mtu_dynamic = frame->link_mtu;
76
frame->extra_buffer += PAYLOAD_ALIGN;
80
* Set the tun MTU dynamically.
83
frame_set_mtu_dynamic (struct frame *frame, int mtu, unsigned int flags)
87
const int orig_mtu = mtu;
88
const int orig_link_mtu_dynamic = frame->link_mtu_dynamic;
93
if (flags & SET_MTU_TUN)
94
mtu += TUN_LINK_DELTA (frame);
96
if (!(flags & SET_MTU_UPPER_BOUND) || mtu < frame->link_mtu_dynamic)
98
frame->link_mtu_dynamic = constrain_int (
100
EXPANDED_SIZE_MIN (frame),
101
EXPANDED_SIZE (frame));
104
dmsg (D_MTU_DEBUG, "MTU DYNAMIC mtu=%d, flags=%u, %d -> %d",
107
orig_link_mtu_dynamic,
108
frame->link_mtu_dynamic);
112
* Move extra_frame octets into extra_tun. Used by fragmenting code
113
* to adjust frame relative to its position in the buffer processing
117
frame_subtract_extra (struct frame *frame, const struct frame *src)
119
frame->extra_frame -= src->extra_frame;
120
frame->extra_tun += src->extra_frame;
124
frame_print (const struct frame *frame,
128
struct gc_arena gc = gc_new ();
129
struct buffer out = alloc_buf_gc (256, &gc);
131
buf_printf (&out, "%s ", prefix);
132
buf_printf (&out, "[");
133
buf_printf (&out, " L:%d", frame->link_mtu);
134
buf_printf (&out, " D:%d", frame->link_mtu_dynamic);
135
buf_printf (&out, " EF:%d", frame->extra_frame);
136
buf_printf (&out, " EB:%d", frame->extra_buffer);
137
buf_printf (&out, " ET:%d", frame->extra_tun);
138
buf_printf (&out, " EL:%d", frame->extra_link);
139
if (frame->align_flags && frame->align_adjust)
140
buf_printf (&out, " AF:%u/%d", frame->align_flags, frame->align_adjust);
141
buf_printf (&out, " ]");
143
msg (level, "%s", out.data);
147
#define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS"
150
set_mtu_discover_type (int sd, int mtu_type)
154
#if defined(HAVE_SETSOCKOPT) && defined(SOL_IP) && defined(IP_MTU_DISCOVER)
156
(sd, SOL_IP, IP_MTU_DISCOVER, &mtu_type, sizeof (mtu_type)))
157
msg (M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket",
160
msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG);
166
translate_mtu_discover_type_name (const char *name)
168
#if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO)
169
if (!strcmp (name, "yes"))
170
return IP_PMTUDISC_DO;
171
if (!strcmp (name, "maybe"))
172
return IP_PMTUDISC_WANT;
173
if (!strcmp (name, "no"))
174
return IP_PMTUDISC_DONT;
176
"invalid --mtu-disc type: '%s' -- valid types are 'yes', 'maybe', or 'no'",
179
msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG);
181
return -1; /* NOTREACHED */
184
#if EXTENDED_SOCKET_ERROR_CAPABILITY
193
format_extended_socket_error (int fd, int *mtu, struct gc_arena *gc)
196
struct probehdr rcvbuf;
199
struct cmsghdr *cmsg;
200
struct sock_extended_err *e;
201
struct sockaddr_in addr;
202
struct buffer out = alloc_buf_gc (256, gc);
203
char *cbuf = (char *) gc_malloc (256, false, gc);
209
memset (&rcvbuf, -1, sizeof (rcvbuf));
210
iov.iov_base = &rcvbuf;
211
iov.iov_len = sizeof (rcvbuf);
212
msg.msg_name = (uint8_t *) &addr;
213
msg.msg_namelen = sizeof (addr);
217
msg.msg_control = cbuf;
218
msg.msg_controllen = 256; /* size of cbuf */
220
res = recvmsg (fd, &msg, MSG_ERRQUEUE);
226
for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg))
228
if (cmsg->cmsg_level == SOL_IP)
230
if (cmsg->cmsg_type == IP_RECVERR)
232
e = (struct sock_extended_err *) CMSG_DATA (cmsg);
236
buf_printf (&out ,"CMSG=%d|", cmsg->cmsg_type);
242
buf_printf (&out, "NO-INFO|");
249
buf_printf (&out, "ETIMEDOUT|");
252
buf_printf (&out, "EMSGSIZE Path-MTU=%d|", e->ee_info);
256
buf_printf (&out, "ECONNREFUSED|");
259
buf_printf (&out, "EPROTO|");
262
buf_printf (&out, "EHOSTUNREACH|");
265
buf_printf (&out, "ENETUNREACH|");
268
buf_printf (&out, "EACCES|");
271
buf_printf (&out, "UNKNOWN|");
277
buf_rmtail (&out, '|');
282
set_sock_extended_error_passing (int sd)
285
if (setsockopt (sd, SOL_IP, IP_RECVERR, &on, sizeof (on)))
286
msg (M_WARN | M_ERRNO,
287
"Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)");