📄 mtu.c
字号:
/* * OpenVPN -- An application to securely tunnel IP networks * over a single TCP/UDP port, with support for SSL/TLS-based * session authentication and key exchange, * packet encryption, packet authentication, and * packet compression. * * Copyright (C) 2002-2004 James Yonan <jim@yonan.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program (see the file COPYING included with this * distribution); if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#ifdef WIN32#include "config-win32.h"#else#include "config.h"#endif#include "syshead.h"#include "common.h"#include "buffer.h"#include "error.h"#include "integer.h"#include "mtu.h"#include "memdbg.h"/* allocate a buffer for socket or tun layer */voidalloc_buf_sock_tun (struct buffer *buf, const struct frame *frame, bool tuntap_buffer){ /* allocate buffer for overlapped I/O */ *buf = alloc_buf (BUF_SIZE (frame)); ASSERT (buf_init (buf, FRAME_HEADROOM (frame))); buf->len = tuntap_buffer ? MAX_RW_SIZE_TUN (frame) : MAX_RW_SIZE_LINK (frame); ASSERT (buf_safe (buf, 0));}voidframe_finalize (struct frame *frame, bool link_mtu_defined, int link_mtu, bool tun_mtu_defined, int tun_mtu){ /* Set link_mtu based on command line options */ if (tun_mtu_defined) { ASSERT (!link_mtu_defined); frame->link_mtu = tun_mtu + TUN_LINK_DELTA (frame); } else { ASSERT (link_mtu_defined); frame->link_mtu = link_mtu; } if (TUN_MTU_SIZE (frame) < TUN_MTU_MIN) { msg (M_WARN, "TUN MTU value (%d) must be at least %d", TUN_MTU_SIZE (frame), TUN_MTU_MIN); frame_print (frame, M_FATAL, "MTU is too small"); } frame->link_mtu_dynamic = frame->link_mtu;}/* * Set the tun MTU dynamically. */voidframe_set_mtu_dynamic (struct frame *frame, int mtu, unsigned int flags){ const int orig_mtu = mtu; const int orig_link_mtu_dynamic = frame->link_mtu_dynamic; ASSERT (mtu >= 0); if (flags & SET_MTU_TUN) mtu += TUN_LINK_DELTA (frame); if (!(flags & SET_MTU_UPPER_BOUND) || mtu < frame->link_mtu_dynamic) { frame->link_mtu_dynamic = constrain_int ( mtu, EXPANDED_SIZE_MIN (frame), EXPANDED_SIZE (frame)); } msg (D_MTU_DEBUG, "MTU DYNAMIC mtu=%d, flags=%u, %d -> %d", orig_mtu, flags, orig_link_mtu_dynamic, frame->link_mtu_dynamic);}/* * Move extra_frame octets into extra_tun. Used by fragmenting code * to adjust frame relative to its position in the buffer processing * queue. */voidframe_subtract_extra (struct frame *frame, const struct frame *src){ frame->extra_frame -= src->extra_frame; frame->extra_tun += src->extra_frame;}voidframe_print (const struct frame *frame, int level, const char *prefix){ struct gc_arena gc = gc_new (); struct buffer out = alloc_buf_gc (256, &gc); if (prefix) buf_printf (&out, "%s ", prefix); buf_printf (&out, "["); buf_printf (&out, " L:%d", frame->link_mtu); buf_printf (&out, " D:%d", frame->link_mtu_dynamic); buf_printf (&out, " EF:%d", frame->extra_frame); buf_printf (&out, " EB:%d", frame->extra_buffer); buf_printf (&out, " ET:%d", frame->extra_tun); buf_printf (&out, " EL:%d", frame->extra_link); buf_printf (&out, " ]"); msg (level, "%s", out.data); gc_free (&gc);}#define MTUDISC_NOT_SUPPORTED_MSG "--mtu-disc is not supported on this OS"voidset_mtu_discover_type (int sd, int mtu_type){ if (mtu_type >= 0) {#if defined(HAVE_SETSOCKOPT) && defined(SOL_IP) && defined(IP_MTU_DISCOVER) if (setsockopt (sd, SOL_IP, IP_MTU_DISCOVER, &mtu_type, sizeof (mtu_type))) msg (M_ERR, "Error setting IP_MTU_DISCOVER type=%d on TCP/UDP socket", mtu_type);#else msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG);#endif }}inttranslate_mtu_discover_type_name (const char *name){#if defined(IP_PMTUDISC_DONT) && defined(IP_PMTUDISC_WANT) && defined(IP_PMTUDISC_DO) if (!strcmp (name, "yes")) return IP_PMTUDISC_DO; if (!strcmp (name, "maybe")) return IP_PMTUDISC_WANT; if (!strcmp (name, "no")) return IP_PMTUDISC_DONT; msg (M_FATAL, "invalid --mtu-disc type: '%s' -- valid types are 'yes', 'maybe', or 'no'", name);#else msg (M_FATAL, MTUDISC_NOT_SUPPORTED_MSG);#endif return -1; /* NOTREACHED */}#if EXTENDED_SOCKET_ERROR_CAPABILITY/* * * The following code is adapted from tracepath * under the terms of the GPL. * Copyright (C) Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>. */struct probehdr{ uint32_t ttl; struct timeval tv;};const char *format_extended_socket_error (int fd, int *mtu, struct gc_arena *gc){ int res; struct probehdr rcvbuf; struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; struct sock_extended_err *e; struct sockaddr_in addr; struct buffer out = alloc_buf_gc (512, gc); char *cbuf = (char *) gc_malloc (512, false, gc); *mtu = 0; while (true) { memset (&rcvbuf, -1, sizeof (rcvbuf)); iov.iov_base = &rcvbuf; iov.iov_len = sizeof (rcvbuf); msg.msg_name = (uint8_t *) &addr; msg.msg_namelen = sizeof (addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = cbuf; msg.msg_controllen = 512; /* size of cbuf */ res = recvmsg (fd, &msg, MSG_ERRQUEUE); if (res < 0) goto exit; e = NULL; for (cmsg = CMSG_FIRSTHDR (&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg)) { if (cmsg->cmsg_level == SOL_IP) { if (cmsg->cmsg_type == IP_RECVERR) { e = (struct sock_extended_err *) CMSG_DATA (cmsg); } else { buf_printf (&out ,"CMSG=%d|", cmsg->cmsg_type); } } } if (e == NULL) { buf_printf (&out, "NO-INFO|"); goto exit; } switch (e->ee_errno) { case ETIMEDOUT: buf_printf (&out, "ETIMEDOUT|"); break; case EMSGSIZE: buf_printf (&out, "EMSGSIZE Path-MTU=%d|", e->ee_info); *mtu = e->ee_info; break; case ECONNREFUSED: buf_printf (&out, "ECONNREFUSED|"); break; case EPROTO: buf_printf (&out, "EPROTO|"); break; case EHOSTUNREACH: buf_printf (&out, "EHOSTUNREACH|"); break; case ENETUNREACH: buf_printf (&out, "ENETUNREACH|"); break; case EACCES: buf_printf (&out, "EACCES|"); break; default: buf_printf (&out, "UNKNOWN|"); break; } } exit: buf_rmtail (&out, '|'); return BSTR (&out);}voidset_sock_extended_error_passing (int sd){ int on = 1; if (setsockopt (sd, SOL_IP, IP_RECVERR, &on, sizeof (on))) msg (M_WARN | M_ERRNO, "Note: enable extended error passing on TCP/UDP socket failed (IP_RECVERR)");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -