⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tun.c

📁 tun虚拟网卡设备源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  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-2005 OpenVPN Solutions LLC <info@openvpn.net> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License version 2 *  as published by the Free Software Foundation. * *  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 *//* * Support routines for configuring and accessing TUN/TAP * virtual network adapters. * * This file is based on the TUN/TAP driver interface routines * from VTun by Maxim Krasnyansky <max_mk@yahoo.com>. */#ifdef WIN32#include "config-win32.h"#else#include "config.h"#endif#include "syshead.h"#include "tun.h"#include "fdmisc.h"#include "common.h"#include "misc.h"#include "socket.h"#include "manage.h"#include "memdbg.h"#ifdef TARGET_SOLARISstatic void solaris_error_close (struct tuntap *tt, const struct env_set *es, const char *actual);#endifboolis_dev_type (const char *dev, const char *dev_type, const char *match_type){  ASSERT (match_type);  if (!dev)    return false;  if (dev_type)    return !strcmp (dev_type, match_type);  else    return !strncmp (dev, match_type, strlen (match_type));}intdev_type_enum (const char *dev, const char *dev_type){  if (is_dev_type (dev, dev_type, "tun"))    return DEV_TYPE_TUN;  else if (is_dev_type (dev, dev_type, "tap"))    return DEV_TYPE_TAP;  else if (is_dev_type (dev, dev_type, "null"))    return DEV_TYPE_NULL;  else    return DEV_TYPE_UNDEF;}const char *dev_type_string (const char *dev, const char *dev_type){  switch (dev_type_enum (dev, dev_type))    {    case DEV_TYPE_TUN:      return "tun";    case DEV_TYPE_TAP:      return "tap";    case DEV_TYPE_NULL:      return "null";    default:      return "[unknown-dev-type]";    }}const char *dev_component_in_dev_node (const char *dev_node){  const char *ret;  const int dirsep = OS_SPECIFIC_DIRSEP;  if (dev_node)    {      ret = strrchr (dev_node, dirsep);      if (ret && *ret)	++ret;      else	ret = dev_node;      if (*ret)	return ret;    }  return NULL;}/* * Try to predict the actual TUN/TAP device instance name, * before the device is actually opened. */const char *guess_tuntap_dev (const char *dev,		  const char *dev_type,		  const char *dev_node,		  struct gc_arena *gc){#ifdef WIN32  const int dt = dev_type_enum (dev, dev_type);  if (dt == DEV_TYPE_TUN || dt == DEV_TYPE_TAP)    {      return get_netsh_id (dev_node, gc);    }#endif  /* default case */  return dev;}/* * Called by the open_tun function of OSes to check if we * explicitly support IPv6. * * In this context, explicit means that the OS expects us to * do something special to the tun socket in order to support * IPv6, i.e. it is not transparent. * * ipv6_explicitly_supported should be set to false if we don't * have any explicit IPv6 code in the tun device handler. * * If ipv6_explicitly_supported is true, then we have explicit * OS-specific tun dev code for handling IPv6.  If so, tt->ipv6 * is set according to the --tun-ipv6 command line option. */static voidipv6_support (bool ipv6, bool ipv6_explicitly_supported, struct tuntap* tt){  tt->ipv6 = false;  if (ipv6_explicitly_supported)    tt->ipv6 = ipv6;  else if (ipv6)    msg (M_WARN, "NOTE: explicit support for IPv6 tun devices is not provided for this OS");}/* --ifconfig-nowarn disables some options sanity checking */static const char ifconfig_warn_how_to_silence[] = "(silence this warning with --ifconfig-nowarn)";/* * If !tun, make sure ifconfig_remote_netmask looks *  like a netmask. * * If tun, make sure ifconfig_remote_netmask looks *  like an IPv4 address. */static voidifconfig_sanity_check (bool tun, in_addr_t addr){  struct gc_arena gc = gc_new ();  const bool looks_like_netmask = ((addr & 0xFF000000) == 0xFF000000);  if (tun)    {      if (looks_like_netmask)	msg (M_WARN, "WARNING: Since you are using --dev tun, the second argument to --ifconfig must be an IP address.  You are using something (%s) that looks more like a netmask. %s",	     print_in_addr_t (addr, 0, &gc),	     ifconfig_warn_how_to_silence);    }  else /* tap */    {      if (!looks_like_netmask)	msg (M_WARN, "WARNING: Since you are using --dev tap, the second argument to --ifconfig must be a netmask, for example something like 255.255.255.0. %s",	     ifconfig_warn_how_to_silence);    }  gc_free (&gc);}/* * For TAP-style devices, generate a broadcast address. */static in_addr_tgenerate_ifconfig_broadcast_addr (in_addr_t local,				  in_addr_t netmask){  return local | ~netmask;}/* * Check that --local and --remote addresses do not * clash with ifconfig addresses or subnet. */static voidcheck_addr_clash (const char *name,		  int type,		  in_addr_t public,		  in_addr_t local,		  in_addr_t remote_netmask){  struct gc_arena gc = gc_new ();#if 0  msg (M_INFO, "CHECK_ADDR_CLASH type=%d public=%s local=%s, remote_netmask=%s",       type,       print_in_addr_t (public, 0, &gc),       print_in_addr_t (local, 0, &gc),       print_in_addr_t (remote_netmask, 0, &gc));#endif  if (public)    {      if (type == DEV_TYPE_TUN)	{	  const in_addr_t test_netmask = 0xFFFFFF00;	  const in_addr_t public_net = public & test_netmask;	  const in_addr_t local_net = local & test_netmask;	  const in_addr_t remote_net = remote_netmask & test_netmask;	  if (public == local || public == remote_netmask)	    msg (M_WARN,		 "WARNING: --%s address [%s] conflicts with --ifconfig address pair [%s, %s]. %s",		 name,		 print_in_addr_t (public, 0, &gc),		 print_in_addr_t (local, 0, &gc),		 print_in_addr_t (remote_netmask, 0, &gc),		 ifconfig_warn_how_to_silence);	  if (public_net == local_net || public_net == remote_net)	    msg (M_WARN,		 "WARNING: potential conflict between --%s address [%s] and --ifconfig address pair [%s, %s] -- this is a warning only that is triggered when local/remote addresses exist within the same /24 subnet as --ifconfig endpoints. %s",		 name,		 print_in_addr_t (public, 0, &gc),		 print_in_addr_t (local, 0, &gc),		 print_in_addr_t (remote_netmask, 0, &gc),		 ifconfig_warn_how_to_silence);	}      else if (type == DEV_TYPE_TAP)	{	  const in_addr_t public_network = public & remote_netmask;	  const in_addr_t virtual_network = local & remote_netmask;	  if (public_network == virtual_network)	    msg (M_WARN,		 "WARNING: --%s address [%s] conflicts with --ifconfig subnet [%s, %s] -- local and remote addresses cannot be inside of the --ifconfig subnet. %s",		 name,		 print_in_addr_t (public, 0, &gc),		 print_in_addr_t (local, 0, &gc),		 print_in_addr_t (remote_netmask, 0, &gc),		 ifconfig_warn_how_to_silence);	}    }  gc_free (&gc);}/* * Complain if --dev tap and --ifconfig is used on an OS for which * we don't have a custom tap ifconfig template below. */static voidno_tap_ifconfig (){  msg (M_FATAL, "Sorry but you cannot use --dev tap and --ifconfig together on this OS because I have not yet been programmed to understand the appropriate ifconfig syntax to use for TAP-style devices on this OS.  Your best alternative is to use an --up script and do the ifconfig command manually.");}/* * Return a string to be used for options compatibility check * between peers. */const char *ifconfig_options_string (const struct tuntap* tt, bool remote, bool disable, struct gc_arena *gc){  struct buffer out = alloc_buf_gc (256, gc);  if (tt->did_ifconfig_setup && !disable)    {      if (tt->type == DEV_TYPE_TUN)	{	  const char *l, *r;	  if (remote)	    {	      r = print_in_addr_t (tt->local, 0, gc);	      l = print_in_addr_t (tt->remote_netmask, 0, gc);	    }	  else	    {	      l = print_in_addr_t (tt->local, 0, gc);	      r = print_in_addr_t (tt->remote_netmask, 0, gc);	    }	  buf_printf (&out, "%s %s", r, l);	}      else if (tt->type == DEV_TYPE_TAP)	{	  buf_printf (&out, "%s %s",		      print_in_addr_t (tt->local & tt->remote_netmask, 0, gc),		      print_in_addr_t (tt->remote_netmask, 0, gc));	}      else	buf_printf (&out, "[undef]");    }  return BSTR (&out);}/* * Return a status string describing wait state. */const char *tun_stat (const struct tuntap *tt, unsigned int rwflags, struct gc_arena *gc){  struct buffer out = alloc_buf_gc (64, gc);  if (tt)    {      if (rwflags & EVENT_READ)	{	  buf_printf (&out, "T%s",		      (tt->rwflags_debug & EVENT_READ) ? "R" : "r");#ifdef WIN32	  buf_printf (&out, "%s",		      overlapped_io_state_ascii (&tt->reads));#endif	}      if (rwflags & EVENT_WRITE)	{	  buf_printf (&out, "T%s",		      (tt->rwflags_debug & EVENT_WRITE) ? "W" : "w");#ifdef WIN32	  buf_printf (&out, "%s",		      overlapped_io_state_ascii (&tt->writes));#endif	}    }  else    {      buf_printf (&out, "T?");    }  return BSTR (&out);}/* * Init tun/tap object. * * Set up tuntap structure for ifconfig, * but don't execute yet. */struct tuntap *init_tun (const char *dev,       /* --dev option */	  const char *dev_type,  /* --dev-type option */	  const char *ifconfig_local_parm,          /* --ifconfig parm 1 */	  const char *ifconfig_remote_netmask_parm, /* --ifconfig parm 2 */	  in_addr_t local_public,	  in_addr_t remote_public,	  const bool strict_warn,	  struct env_set *es){  struct gc_arena gc = gc_new ();  struct tuntap *tt;  ALLOC_OBJ (tt, struct tuntap);  clear_tuntap (tt);  tt->type = dev_type_enum (dev, dev_type);  if (ifconfig_local_parm && ifconfig_remote_netmask_parm)    {      bool tun = false;      const char *ifconfig_local = NULL;      const char *ifconfig_remote_netmask = NULL;      const char *ifconfig_broadcast = NULL;      /*       * We only handle TUN/TAP devices here, not --dev null devices.       */      if (tt->type == DEV_TYPE_TUN)	tun = true;      else if (tt->type == DEV_TYPE_TAP)	tun = false;      else	msg (M_FATAL, "'%s' is not a TUN/TAP device.  The --ifconfig option works only for TUN/TAP devices.", dev);      /*       * Convert arguments to binary IPv4 addresses.       */      tt->local = getaddr (			   GETADDR_RESOLVE			   | GETADDR_HOST_ORDER			   | GETADDR_FATAL_ON_SIGNAL			   | GETADDR_FATAL,			   ifconfig_local_parm,			   0,			   NULL,			   NULL);      tt->remote_netmask = getaddr (				    (tun ? GETADDR_RESOLVE : 0)				    | GETADDR_HOST_ORDER				    | GETADDR_FATAL_ON_SIGNAL				    | GETADDR_FATAL,				    ifconfig_remote_netmask_parm,				    0,				    NULL,				    NULL);      /*       * Look for common errors in --ifconfig parms       */      if (strict_warn)	{	  ifconfig_sanity_check (tun, tt->remote_netmask);	  /*	   * If local_public or remote_public addresses are defined,	   * make sure they do not clash with our virtual subnet.	   */	  check_addr_clash ("local",			    tt->type,			    local_public,			    tt->local,			    tt->remote_netmask);	  check_addr_clash ("remote",			    tt->type,			    remote_public,			    tt->local,			    tt->remote_netmask);	}      /*       * Set ifconfig parameters       */      ifconfig_local = print_in_addr_t (tt->local, 0, &gc);      ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc);      /*       * If TAP-style interface, generate broadcast address.       */      if (!tun)	{	  tt->broadcast = generate_ifconfig_broadcast_addr (tt->local, tt->remote_netmask);	  ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc);	}      /*       * Set environmental variables with ifconfig parameters.       */      if (es)	{	  setenv_str (es, "ifconfig_local", ifconfig_local);	  if (tun)	    {	      setenv_str (es, "ifconfig_remote", ifconfig_remote_netmask);	    }	  else	    {	      setenv_str (es, "ifconfig_netmask", ifconfig_remote_netmask);	      setenv_str (es, "ifconfig_broadcast", ifconfig_broadcast);	    }	}      tt->did_ifconfig_setup = true;    }  gc_free (&gc);  return tt;}/* * Platform specific tun initializations */voidinit_tun_post (struct tuntap *tt,	       const struct frame *frame,	       const struct tuntap_options *options){  tt->options = *options;#ifdef WIN32  overlapped_io_init (&tt->reads, frame, FALSE, true);  overlapped_io_init (&tt->writes, frame, TRUE, true);  tt->rw_handle.read = tt->reads.overlapped.hEvent;  tt->rw_handle.write = tt->writes.overlapped.hEvent;  tt->adapter_index = ~0;#endif}/* execute the ifconfig command through the shell */voiddo_ifconfig (struct tuntap *tt,	     const char *actual,    /* actual device name */	     int tun_mtu,	     const struct env_set *es){  struct gc_arena gc = gc_new ();  if (tt->did_ifconfig_setup)    {      bool tun = false;      const char *ifconfig_local = NULL;      const char *ifconfig_remote_netmask = NULL;      const char *ifconfig_broadcast = NULL;      char command_line[256];      /*       * We only handle TUN/TAP devices here, not --dev null devices.       */      if (tt->type == DEV_TYPE_TUN)	tun = true;      else if (tt->type == DEV_TYPE_TAP)	tun = false;      else	ASSERT (0); /* should have been caught in init_tun */      /*       * Set ifconfig parameters       */      ifconfig_local = print_in_addr_t (tt->local, 0, &gc);      ifconfig_remote_netmask = print_in_addr_t (tt->remote_netmask, 0, &gc);      /*       * If TAP-style device, generate broadcast address.       */      if (!tun)	ifconfig_broadcast = print_in_addr_t (tt->broadcast, 0, &gc);#ifdef ENABLE_MANAGEMENT  if (management)    {      management_set_state (management,			    OPENVPN_STATE_ASSIGN_IP,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -