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

📄 route.c

📁 OpenVPN is a robust and highly flexible tunneling application that uses all of the encryption, authe
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  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 *//* * Support routines for adding/deleting network routes. */#ifdef WIN32#include "config-win32.h"#else#include "config.h"#endif#include "syshead.h"#include "common.h"#include "error.h"#include "route.h"#include "misc.h"#include "socket.h"#include "tun.h"#include "memdbg.h"static void add_route (struct route *r);static void delete_route (const struct route *r);static bool get_default_gateway (in_addr_t *ret);struct route_option_list *new_route_option_list (struct gc_arena *a){  struct route_option_list *ret;  ALLOC_OBJ_CLEAR_GC (ret, struct route_option_list, a);  return ret;}struct route_list *new_route_list (struct gc_arena *a){  struct route_list *ret;  ALLOC_OBJ_CLEAR_GC (ret, struct route_list, a);  return ret;}static const char *route_string (const struct route *r, struct gc_arena *gc){  struct buffer out = alloc_buf_gc (256, gc);  buf_printf (&out, "ROUTE network %s netmask %s gateway %s",	      print_in_addr_t (r->network, false, gc),	      print_in_addr_t (r->netmask, false, gc),	      print_in_addr_t (r->gateway, false, gc)	      );  if (r->metric_defined)    buf_printf (&out, " metric %d", r->metric);  return BSTR (&out);}static boolis_route_parm_defined (const char *parm){  if (!parm)    return false;  if (!strcmp (parm, "default"))    return false;  return true;}static voidsetenv_route_addr (const char *key, const in_addr_t addr, int i){  struct gc_arena gc = gc_new ();  char name[128];  if (i >= 0)    openvpn_snprintf (name, sizeof (name), "route_%s_%d", key, i);  else    openvpn_snprintf (name, sizeof (name), "route_%s", key);  setenv_str (name, print_in_addr_t (addr, false, &gc));  gc_free (&gc);}static boolget_special_addr (const struct route_special_addr *spec,		  const char *string,		  in_addr_t *out,		  bool *status){  *status = true;  if (!strcmp (string, "vpn_gateway"))    {      if (spec->remote_endpoint_defined)	*out = spec->remote_endpoint;      else	{	  msg (M_INFO, PACKAGE_NAME " ROUTE: vpn_gateway undefined");	  *status = false;	}      return true;    }  else if (!strcmp (string, "net_gateway"))    {      if (spec->net_gateway_defined)	*out = spec->net_gateway;      else	{	  msg (M_INFO, PACKAGE_NAME " ROUTE: net_gateway undefined -- unable to get default gateway from system");	  *status = false;	}      return true;    }  else if (!strcmp (string, "remote_host"))    {      if (spec->remote_host_defined)	*out = spec->remote_host;      else	{	  msg (M_INFO, PACKAGE_NAME " ROUTE: remote_host undefined");	  *status = false;	}      return true;    }  return false;}static boolinit_route (struct route *r,	    const struct route_option *ro,	    const struct route_special_addr *spec){  const in_addr_t default_netmask = ~0;  bool status;  r->option = ro;  r->defined = false;  /* network */  if (!is_route_parm_defined (ro->network))    {      goto fail;    }    if (!get_special_addr (spec, ro->network, &r->network, &status))    {      r->network = getaddr (			    GETADDR_RESOLVE			    | GETADDR_HOST_ORDER			    | GETADDR_FATAL_ON_SIGNAL,			    ro->network,			    0,			    &status,			    NULL);    }  if (!status)    goto fail;  /* netmask */  if (is_route_parm_defined (ro->netmask))    {      r->netmask = getaddr (			    GETADDR_HOST_ORDER			    | GETADDR_FATAL_ON_SIGNAL,			    ro->netmask,			    0,			    &status,			    NULL);      if (!status)	goto fail;    }  else    r->netmask = default_netmask;  /* gateway */  if (is_route_parm_defined (ro->gateway))    {      if (!get_special_addr (spec, ro->gateway, &r->gateway, &status))	{	  r->gateway = getaddr (				GETADDR_RESOLVE				| GETADDR_HOST_ORDER				| GETADDR_FATAL_ON_SIGNAL,				ro->gateway,				0,				&status,				NULL);	}      if (!status)	goto fail;    }  else    {      if (spec->remote_endpoint_defined)	r->gateway = spec->remote_endpoint;      else	{	  msg (M_WARN, PACKAGE_NAME " ROUTE: " PACKAGE_NAME " needs a gateway parameter for a --route option and no default was specified by either --route-gateway or --ifconfig options");	  goto fail;	}    }  /* metric */  r->metric_defined = false;  r->metric = 0;  if (is_route_parm_defined (ro->metric))    {      r->metric = atoi (ro->metric);      if (r->metric < 0)	{	  msg (M_WARN, PACKAGE_NAME " ROUTE: route metric for network %s (%s) must be >= 0",	       ro->network,	       ro->metric);	  goto fail;	}      r->metric_defined = true;    }  else    {      r->metric = 0;      r->metric_defined = false;    }  r->defined = true;  return true; fail:  msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve route for host/network: %s",       ro->network);  r->defined = false;  return false;}voidadd_route_to_option_list (struct route_option_list *l,			  const char *network,			  const char *netmask,			  const char *gateway,			  const char *metric){  struct route_option *ro;  if (l->n >= MAX_ROUTES)    msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d routes",	 MAX_ROUTES);  ro = &l->routes[l->n];  ro->network = network;  ro->netmask = netmask;  ro->gateway = gateway;  ro->metric = metric;  ++l->n;}voidclear_route_list (struct route_list *rl){  CLEAR (*rl);}boolinit_route_list (struct route_list *rl,		 const struct route_option_list *opt,		 const char *remote_endpoint,		 in_addr_t remote_host){  int i;  bool ret = true;  clear_route_list (rl);  if (remote_host)    {      rl->spec.remote_host = remote_host;      rl->spec.remote_host_defined = true;    }  rl->spec.net_gateway_defined = get_default_gateway (&rl->spec.net_gateway);  if (rl->spec.net_gateway_defined)    {      setenv_route_addr ("net_gateway", rl->spec.net_gateway, -1);    }  rl->redirect_default_gateway = opt->redirect_default_gateway;  rl->redirect_local = opt->redirect_local;  if (is_route_parm_defined (remote_endpoint))    {      rl->spec.remote_endpoint = getaddr (				     GETADDR_RESOLVE				     | GETADDR_HOST_ORDER				     | GETADDR_FATAL_ON_SIGNAL,				     remote_endpoint,				     0,				     &rl->spec.remote_endpoint_defined,				     NULL);      if (rl->spec.remote_endpoint_defined)	{	  setenv_route_addr ("vpn_gateway", rl->spec.remote_endpoint, -1);	}      else	{	  msg (M_WARN, PACKAGE_NAME " ROUTE: failed to parse/resolve default gateway: %s",	       remote_endpoint);	  ret = false;	}    }  else    rl->spec.remote_endpoint_defined = false;  ASSERT (opt->n >= 0 && opt->n < MAX_ROUTES);  for (i = 0; i < opt->n; ++i)    {      if (!init_route (&rl->routes[i],		       &opt->routes[i],		       &rl->spec))	ret = false;    }  rl->n = i;  return ret;}static voidadd_route3 (in_addr_t network,	    in_addr_t netmask,	    in_addr_t gateway){  struct route r;  CLEAR (r);  r.defined = true;  r.network = network;  r.netmask = netmask;  r.gateway = gateway;  add_route (&r);}static voiddel_route3 (in_addr_t network,	    in_addr_t netmask,	    in_addr_t gateway){  struct route r;  CLEAR (r);  r.defined = true;  r.network = network;  r.netmask = netmask;  r.gateway = gateway;  delete_route (&r);}static voidredirect_default_route_to_vpn (struct route_list *rl){  const char err[] = "NOTE: unable to redirect default gateway --";  if (rl->redirect_default_gateway)    {      if (!rl->spec.remote_endpoint_defined)	{	  msg (M_WARN, "%s VPN gateway parameter (--route-gateway or --ifconfig) is missing", err);	}      else if (!rl->spec.net_gateway_defined)	{	  msg (M_WARN, "%s Cannot read current default gateway from system", err);	}      else if (!rl->spec.remote_host_defined)	{	  msg (M_WARN, "%s Cannot obtain current remote host address", err);	}      else	{	  /* route remote host to original default gateway */	  if (!rl->redirect_local)	    add_route3 (rl->spec.remote_host,			~0,			rl->spec.net_gateway);	  /* delete default route */	  del_route3 (0,		      0,		      rl->spec.net_gateway);	  /* add new default route */	  add_route3 (0,		      0,		      rl->spec.remote_endpoint);	  /* set a flag so we can undo later */	  rl->did_redirect_default_gateway = true;	}    }}static voidundo_redirect_default_route_to_vpn (struct route_list *rl){  if (rl->did_redirect_default_gateway)    {      /* delete remote host route */      if (!rl->redirect_local)	del_route3 (rl->spec.remote_host,		    ~0,		    rl->spec.net_gateway);      /* delete default route */      del_route3 (0,		  0,		  rl->spec.remote_endpoint);      /* restore original default route */      add_route3 (0,		  0,		  rl->spec.net_gateway);      rl->did_redirect_default_gateway = false;    }}voidadd_routes (struct route_list *rl, bool delete_first){  redirect_default_route_to_vpn (rl);  if (!rl->routes_added)    {      int i;      for (i = 0; i < rl->n; ++i)	{	  if (delete_first)	    delete_route (&rl->routes[i]);	  add_route (&rl->routes[i]);	}      rl->routes_added = true;    }}voiddelete_routes (struct route_list *rl){  if (rl->routes_added)    {      int i;      for (i = rl->n - 1; i >= 0; --i)	{	  const struct route *r = &rl->routes[i];	  delete_route (r);	}      rl->routes_added = false;    }  undo_redirect_default_route_to_vpn (rl);}static const char *show_opt (const char *option){  if (!option)    return "nil";  else    return option;}static voidprint_route_option (const struct route_option *ro, int level){  msg (level, "  route %s/%s/%s/%s",       show_opt (ro->network),       show_opt (ro->netmask),       show_opt (ro->gateway),       show_opt (ro->metric));}voidprint_route_options (const struct route_option_list *rol,		     int level){  int i;  if (rol->redirect_default_gateway)    msg (level, "  [redirect_default_gateway local=%d]",	 rol->redirect_local);  for (i = 0; i < rol->n; ++i)    print_route_option (&rol->routes[i], level);}static voidprint_route (const struct route *r, int level){  struct gc_arena gc = gc_new ();  if (r->defined)    msg (level, "%s", route_string (r, &gc));  gc_free (&gc);}voidprint_routes (const struct route_list *rl, int level){  int i;  for (i = 0; i < rl->n; ++i)    print_route (&rl->routes[i], level);}static voidsetenv_route (const struct route *r, int i){  if (r->defined)    {      setenv_route_addr ("network", r->network, i);      setenv_route_addr ("netmask", r->netmask, i);      setenv_route_addr ("gateway", r->gateway, i);      if (r->metric_defined)	{	  char name[128];	  openvpn_snprintf (name, sizeof (name), "route_metric_%d", i);	  setenv_int (name, r->metric);	}    }}voidsetenv_routes (const struct route_list *rl){  int i;  for (i = 0; i < rl->n; ++i)    setenv_route (&rl->routes[i], i + 1);}static voidadd_route (struct route *r){  struct gc_arena gc;  struct buffer buf;  const char *network;  const char *netmask;  const char *gateway;  bool status = false;  if (!r->defined)    return;  gc_init (&gc);  buf = alloc_buf_gc (256, &gc);  network = print_in_addr_t (r->network, false, &gc);  netmask = print_in_addr_t (r->netmask, false, &gc);  gateway = print_in_addr_t (r->gateway, false, &gc);#if defined(TARGET_LINUX)#ifdef CONFIG_FEATURE_IPROUTE  buf_printf (&buf, IPROUTE_PATH " route add %s/%d via %s",	      network,	      count_netmask_bits(netmask),	      gateway);  if (r->metric_defined)    buf_printf (&buf, " metric %d", r->metric);#else  buf_printf (&buf, ROUTE_PATH " add -net %s netmask %s gw %s",	      network,	      netmask,	      gateway);  if (r->metric_defined)    buf_printf (&buf, " metric %d", r->metric);#endif  /*CONFIG_FEATURE_IPROUTE*/  msg (D_ROUTE, "%s", BSTR (&buf));  status = system_check (BSTR (&buf), "ERROR: Linux route add command failed", false);#elif defined (WIN32)  buf_printf (&buf, ROUTE_PATH " ADD %s MASK %s %s",	      network,	      netmask,	      gateway);  if (r->metric_defined)    buf_printf (&buf, " METRIC %d", r->metric);  netcmd_semaphore_lock ();  msg (D_ROUTE, "%s", BSTR (&buf));  status = system_check (BSTR (&buf), "ERROR: Windows route add command failed", false);  netcmd_semaphore_release ();#elif defined (TARGET_SOLARIS)  /* example: route add 192.0.2.32 -netmask 255.255.255.224 somegateway */  buf_printf (&buf, ROUTE_PATH " add");#if 0

⌨️ 快捷键说明

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