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

📄 socket.c

📁 OpenVPN -- A Secure tunneling daemon
💻 C
字号:
/* *  OpenVPN -- An application to securely tunnel IP networks *             over a single UDP port, with support for SSL/TLS-based *             session authentication and key exchange, *             packet encryption, packet authentication, and *             packet compression. * *  Copyright (C) 2002-2003 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 "socket.h"#include "fdmisc.h"#include "thread.h"#include "misc.h"#include "memdbg.h"/* begin check status */unsigned int x_cs_info_level;unsigned int x_cs_verbose_level;voidreset_check_status (){  x_cs_info_level = 0;  x_cs_verbose_level = 0;}voidset_check_status (unsigned int info_level, unsigned int verbose_level){  x_cs_info_level = info_level;  x_cs_verbose_level = verbose_level;}/* * Called after most socket operations, via the inline function check_status(). * Decide if we should print an error message, and see if we can extract any useful * info from the error, such as a Path MTU hint from the OS. */voidx_check_status (int status, const char *description, struct udp_socket *sock){  const int my_errno = openvpn_errno_socket ();  const char *extended_msg = NULL;  msg (x_cs_verbose_level, "%s returned %d", description, status);  if (status < 0)    {#if EXTENDED_SOCKET_ERROR_CAPABILITY      /* get extended socket error message and possible PMTU hint from OS */      if (sock)	{	  int mtu;	  extended_msg = format_extended_socket_error (sock->sd, &mtu);	  if (mtu > 0 && sock->mtu != mtu)	    {	      sock->mtu = mtu;	      sock->mtu_changed = true;	    }	}#endif      if (my_errno != EAGAIN)	{	  if (extended_msg)	    msg (x_cs_info_level, "%s [%s]: %s",		 description,		 extended_msg,		 strerror_ts (my_errno));	  else	    msg (x_cs_info_level, "%s: %s",		 description,		 strerror_ts (my_errno));	}    }}/* end check status */static const char*h_errno_msg(int h_errno_err){  switch (h_errno_err)    {    case HOST_NOT_FOUND:      return "[HOST_NOT_FOUND] The specified host is unknown.";    case NO_DATA:      return "[NO_DATA] The requested name is valid but does not have an IP address.";    case NO_RECOVERY:      return "[NO_RECOVERY] A non-recoverable name server error occurred.";    case TRY_AGAIN:      return "[TRY_AGAIN] A temporary error occurred on an authoritative name server.";    }  return "[unknown h_errno value]";}/* * Translate IP addr or hostname to in_addr_t. * If resolve error, try again for * resolve_retry_seconds seconds. */static in_addr_tgetaddr (const char *hostname, int resolve_retry_seconds){  struct in_addr ia;  const int status = inet_aton (hostname, &ia);  if (!status)    {      const int fail_wait_interval = 5; /* seconds */      int resolve_retries = resolve_retry_seconds / fail_wait_interval;      /*       * Resolve hostname       */      struct hostent *h;      while ( !(h = gethostbyname (hostname)) )	{	  msg ((resolve_retries > 0  ? D_RESOLVE_ERRORS : M_FATAL),	       "Cannot resolve host address: %s: %s",	       hostname, h_errno_msg (h_errno));	  sleep (fail_wait_interval);	  --resolve_retries;	}      /* potentially more than one address returned, but we take first */      ia.s_addr = *(in_addr_t *) (h->h_addr_list[0]);      if (ia.s_addr)	{	  if (h->h_addr_list[1])	    msg (M_WARN, "Warning: %s has multiple addresses", hostname);	}    }  return ia.s_addr;}/* Create a UDP socket */voidudp_socket_init (struct udp_socket *sock,		 const char *local_host,		 const char *remote_host,		 int local_port,		 int remote_port,		 bool bind_local,		 bool remote_float,		 bool inetd,		 struct udp_socket_addr *usa,		 const char *ipchange_command,		 int resolve_retry_seconds,		 int mtu_discover_type){  CLEAR (*sock);  sock->remote_float = remote_float;  sock->addr = usa;  sock->ipchange_command = ipchange_command;  /* were we started by inetd or xinetd? */  if (inetd)    {      ASSERT (inetd_socket_descriptor >= 0);      sock->sd = inetd_socket_descriptor;    }  else    {      /* create socket */      if ((sock->sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)	msg (M_SOCKERR, "Cannot create socket");      /* resolve local address if undefined */      if (!addr_defined (&usa->local))	{	  usa->local.sin_family = AF_INET;	  usa->local.sin_addr.s_addr =	    (local_host ? getaddr (local_host, resolve_retry_seconds)	     : htonl (INADDR_ANY));	  usa->local.sin_port = htons (local_port);	}      /* bind to local address/port */      if (bind_local)	{	  if (bind (sock->sd, (struct sockaddr *) &usa->local, sizeof (usa->local)))	    {	      const int errnum = openvpn_errno_socket ();	      msg (M_FATAL, "Socket bind failed on local address %s: %s",		   print_sockaddr (&usa->local),		   strerror_ts (errnum));	    }	}    }  /* resolve remote address if undefined */  if (!addr_defined (&usa->remote))    {      usa->remote.sin_family = AF_INET;      usa->remote.sin_addr.s_addr =	(remote_host ? getaddr (remote_host, resolve_retry_seconds) : 0);      usa->remote.sin_port = htons (remote_port);    }  /* should we re-use previous active remote address? */  if (addr_defined (&usa->actual))    msg (M_INFO, "Preserving recently used remote address: %s",	 print_sockaddr (&usa->actual));  else    usa->actual = usa->remote;  /* set socket to non-blocking mode */  set_nonblock (sock->sd);  /* set socket file descriptor to not pass across execs, so that     scripts don't have access to it */  set_cloexec (sock->sd);  /* set Path MTU discovery options on the socket */  set_mtu_discover_type (sock->sd, mtu_discover_type);#if EXTENDED_SOCKET_ERROR_CAPABILITY  /* if the OS supports it, enable extended error passing on the socket */  set_sock_extended_error_passing (sock->sd);#endif  /* print local and active remote address */  if (sock->sd == INETD_SOCKET_DESCRIPTOR)    msg (M_INFO, "UDP link local: [inetd]");  else    msg (M_INFO, "UDP link local%s: %s", (bind_local ? " (bound)" : ""),	 print_sockaddr_ex (&usa->local, bind_local, ":"));  msg (M_INFO, "UDP link remote: %s",       print_sockaddr_ex (&usa->actual, addr_defined (&usa->actual), ":"));}voidudp_socket_set_outgoing_addr (const struct buffer *buf,			      struct udp_socket *sock,			      const struct sockaddr_in *addr){  mutex_lock (L_SOCK);  if (!buf || buf->len > 0)    {      struct udp_socket_addr *usa = sock->addr;      ASSERT (addr_defined (addr));      if ((sock->remote_float	   || !addr_defined (&usa->remote)	   || addr_match (addr, &usa->remote))	  && (!addr_match (addr, &usa->actual)	      || !sock->set_outgoing_initial))	{	  usa->actual = *addr;	  sock->set_outgoing_initial = true;	  mutex_unlock (L_SOCK);	  msg (M_INFO, "Peer Connection Initiated with %s", print_sockaddr (&usa->actual));	  if (sock->ipchange_command)	    {	      char command[256];	      struct buffer out;	      buf_set_write (&out, (uint8_t *)command, sizeof (command));	      buf_printf (&out, "%s %s",			  sock->ipchange_command,			  print_sockaddr_ex (&usa->actual, true, " "));	      msg (D_TLS_DEBUG, "executing ip-change command: %s", command);	      system_check (command, "ip-change command failed", false);	    }	  mutex_lock (L_SOCK);	}    }  mutex_unlock (L_SOCK);}voidudp_socket_incoming_addr (struct buffer *buf,			  const struct udp_socket *sock,			  const struct sockaddr_in *from_addr){  mutex_lock (L_SOCK);  if (buf->len > 0)    {      struct udp_socket_addr *usa = sock->addr;      if (from_addr->sin_family != AF_INET)	goto bad;      if (!addr_defined (from_addr))	goto bad;      if (!addr_defined (&usa->remote) || sock->remote_float)	goto good;      if (addr_match (from_addr, &usa->remote))	goto good;    }bad:  msg (D_LINK_ERRORS,       "IP Address failed from %s (allow this incoming address/port by removing --remote or adding --float)",       print_sockaddr (from_addr));  buf->len = 0;  mutex_unlock (L_SOCK);  return;good:  msg (D_READ_WRITE, "IP Address OK from %s",       print_sockaddr (from_addr));  mutex_unlock (L_SOCK);  return;}voidudp_socket_get_outgoing_addr (struct buffer *buf,			      const struct udp_socket *sock,			      struct sockaddr_in *addr){  mutex_lock (L_SOCK);  if (buf->len > 0)    {      struct udp_socket_addr *usa = sock->addr;      if (addr_defined (&usa->actual))	{	  *addr = usa->actual;	}      else	{	  msg (D_READ_WRITE, "No outgoing address to send packet");	  buf->len = 0;	}    }  mutex_unlock (L_SOCK);}voidudp_socket_close (struct udp_socket *sock){  if (sock->sd >= 0 && sock->sd != INETD_SOCKET_DESCRIPTOR)    {      openvpn_close_socket (sock->sd);      sock->sd = -1;    }}const char *print_sockaddr (const struct sockaddr_in *addr){  return print_sockaddr_ex(addr, true, ":");}const char *print_sockaddr_ex (const struct sockaddr_in *addr, bool do_port, const char* separator){  struct buffer out = alloc_buf_gc (64);  const int port = ntohs (addr->sin_port);  mutex_lock (L_INET_NTOA);  buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sin_addr) : "[undef]"));  mutex_unlock (L_INET_NTOA);  if (do_port && port)    {      if (separator)	buf_printf (&out, "%s", separator);      buf_printf (&out, "%d", port);    }  return BSTR (&out);}

⌨️ 快捷键说明

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