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

📄 socket.c

📁 OpenVPN is a robust and highly flexible tunneling application that uses all of the encryption, authe
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  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 "socket.h"#include "fdmisc.h"#include "thread.h"#include "misc.h"#include "memdbg.h"/* * Functions related to the translation of DNS names to IP addresses. */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. */in_addr_tgetaddr (unsigned int flags,	 const char *hostname,	 int resolve_retry_seconds,	 bool *succeeded,	 volatile int *signal_received){  struct in_addr ia;  int status;  int sigrec = 0;  const int msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;  CLEAR (ia);  if (succeeded)    *succeeded = false;  if ((flags & (GETADDR_FATAL_ON_SIGNAL|GETADDR_WARN_ON_SIGNAL))      && !signal_received)    signal_received = &sigrec;  status = inet_aton (hostname, &ia);  if (!status)    {      const int fail_wait_interval = 5; /* seconds */      int resolve_retries = resolve_retry_seconds / fail_wait_interval;      struct hostent *h;      const char *fmt;      CLEAR (ia);      fmt = "RESOLVE: Cannot resolve host address: %s: %s";      if ((flags & GETADDR_MENTION_RESOLVE_RETRY)	  && !resolve_retry_seconds)	fmt = "RESOLVE: Cannot resolve host address: %s: %s (I would have retried this name query if you had specified the --resolv-retry option.)";      if (!(flags & GETADDR_RESOLVE))	{	  if (flags & GETADDR_FATAL)	    msg (M_FATAL, "RESOLVE: Cannot parse IP address: %s", hostname);	  else	    goto done;	}      /*       * Resolve hostname       */      while (true)	{	  /* try hostname lookup */	  h = gethostbyname (hostname);	  if (signal_received)	    {	      get_signal (signal_received);	      if (*signal_received)	        goto done;	    }	  /* success? */	  if (h)	    break;	  /* resolve lookup failed, should we	     continue or fail? */	  msg (((resolve_retries > 0		 || !(flags & GETADDR_FATAL))		? D_RESOLVE_ERRORS : M_FATAL),	       fmt,	       hostname,	       h_errno_msg (h_errno));	  if (--resolve_retries <= 0	      && !(flags & GETADDR_FATAL))	    goto done;	  sleep (fail_wait_interval);	}      if (h->h_addrtype != AF_INET || h->h_length != 4)	{	    msg (msglevel, "RESOLVE: Sorry, but we only accept IPv4 DNS names: %s", hostname);	    goto done;	}      ia.s_addr = *(in_addr_t *) (h->h_addr_list[0]);      if (ia.s_addr)	{	  if (h->h_addr_list[1]) /* more than one address returned */	    {	      int n = 0;	      /* count address list */	      while (h->h_addr_list[n])		++n;	      ASSERT (n >= 2);	      msg (D_RESOLVE_ERRORS, "RESOLVE: NOTE: %s resolves to %d addresses, choosing one by random",		   hostname,		   n);	      /* choose address randomly, for basic load-balancing capability */	      ia.s_addr = *(in_addr_t *) (h->h_addr_list[get_random () % n]);	    }	}      /* hostname resolve succeeded */      if (succeeded)	*succeeded = true;    }  else    {      /* IP address parse succeeded */      if (succeeded)	*succeeded = true;    } done:  if (signal_received && *signal_received)    {      int level = 0;      if (flags & GETADDR_FATAL_ON_SIGNAL)	level = M_FATAL;      else if (flags & GETADDR_WARN_ON_SIGNAL)	level = M_WARN;      msg (level, "RESOLVE: signal received during DNS resolution attempt");    }  return (flags & GETADDR_HOST_ORDER) ? ntohl (ia.s_addr) : ia.s_addr;}static voidupdate_remote (const char* host,	       struct sockaddr_in *addr,	       bool *changed){  if (host && addr)    {      const in_addr_t new_addr = getaddr (					  GETADDR_RESOLVE,					  host,					  1,					  NULL,					  NULL);      if (new_addr && addr->sin_addr.s_addr != new_addr)	{	  addr->sin_addr.s_addr = new_addr;	  *changed = true;	}    }}static intsocket_get_sndbuf (int sd){#if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)  int val;  socklen_t len;  len = sizeof (val);  if (getsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &val, &len) == 0      && len == sizeof (val))    return val;#endif  return 0;}static voidsocket_set_sndbuf (int sd, int size){#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_SNDBUF)  if (setsockopt (sd, SOL_SOCKET, SO_SNDBUF, (void *) &size, sizeof (size)) != 0)    {      msg (M_WARN, "NOTE: setsockopt SO_SNDBUF=%d failed", size);    }#endif}static intsocket_get_rcvbuf (int sd){#if defined(HAVE_GETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)  int val;  socklen_t len;  len = sizeof (val);  if (getsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &val, &len) == 0      && len == sizeof (val))    return val;#endif  return 0;}static voidsocket_set_rcvbuf (int sd, int size){#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_RCVBUF)  if (setsockopt (sd, SOL_SOCKET, SO_RCVBUF, (void *) &size, sizeof (size)) != 0)    {      msg (M_WARN, "NOTE: setsockopt SO_RCVBUF=%d failed", size);    }#endif}static voidsocket_set_buffers (int fd, const struct socket_buffer_size *sbs){  if (sbs)    {      const int sndbuf_old = socket_get_sndbuf (fd);      const int rcvbuf_old = socket_get_rcvbuf (fd);      socket_set_sndbuf (fd, sbs->sndbuf);      socket_set_rcvbuf (fd, sbs->rcvbuf);             msg (D_OSBUF, "Socket Buffers: R=[%d->%d] S=[%d->%d]",	   rcvbuf_old,	   socket_get_rcvbuf (fd),	   sndbuf_old,	   socket_get_sndbuf (fd));    }}/* * Remote list code allows clients to specify a list of * potential remote server addresses. */static voidremote_list_next (struct remote_list *l){  if (l)    {      int i;      if (++l->current >= l->len)	l->current = 0;      msg (D_REMOTE_LIST, "REMOTE_LIST len=%d current=%d",	   l->len, l->current);      for (i = 0; i < l->len; ++i)	{	  msg (D_REMOTE_LIST, "[%d] %s:%d",	       i,	       l->array[i].hostname,	       l->array[i].port);	}    }}voidremote_list_randomize (struct remote_list *l){  int i;  for (i = 0; i < l->len; ++i)    {      const int j = get_random () % l->len;      if (i != j)	{	  struct remote_entry tmp;	  tmp = l->array[i];	  l->array[i] = l->array[j];	  l->array[j] = tmp;	}    }}static const char *remote_list_host (const struct remote_list *rl){  if (rl)    return rl->array[rl->current].hostname;  else    return NULL;}static intremote_list_port (const struct remote_list *rl){  if (rl)    return rl->array[rl->current].port;  else    return 0;}/* * SOCKET INITALIZATION CODE. * Create a TCP/UDP socket */static socket_descriptor_tcreate_socket_tcp (void){  socket_descriptor_t sd;  if ((sd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)    msg (M_SOCKERR, "Cannot create TCP socket");  /* set SO_REUSEADDR on socket */  {    int on = 1;    if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR,		    (void *) &on, sizeof (on)) < 0)      msg (M_SOCKERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP socket");  }#if 0  /* set socket linger options */  {    struct linger linger;    linger.l_onoff = 1;    linger.l_linger = 2;    if (setsockopt (sd, SOL_SOCKET, SO_LINGER,		    (void *) &linger, sizeof (linger)) < 0)      msg (M_SOCKERR, "TCP: Cannot setsockopt SO_LINGER on TCP socket");  }#endif  return sd;}static socket_descriptor_tcreate_socket_udp (void){  socket_descriptor_t sd;  if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)    msg (M_SOCKERR, "UDP: Cannot create UDP socket");  return sd;}static voidcreate_socket (struct link_socket *sock){  /* create socket */  if (sock->info.proto == PROTO_UDPv4)    {      sock->sd = create_socket_udp ();      if (sock->socks_proxy)	{	  sock->ctrl_sd = create_socket_tcp ();	}    }  else if (sock->info.proto == PROTO_TCPv4_SERVER	   || sock->info.proto == PROTO_TCPv4_CLIENT)    {      sock->sd = create_socket_tcp ();    }  else    {      ASSERT (0);    }}/* * Functions used for establishing a TCP stream connection. */static voidsocket_do_listen (socket_descriptor_t sd,		  const struct sockaddr_in *local,		  bool do_listen,		  bool do_set_nonblock){  struct gc_arena gc = gc_new ();  if (do_listen)    {      msg (M_INFO, "Listening for incoming TCP connection on %s", 	   print_sockaddr (local, &gc));      if (listen (sd, 1))	msg (M_SOCKERR, "TCP: listen() failed");    }  /* set socket to non-blocking mode */  if (do_set_nonblock)    set_nonblock (sd);  gc_free (&gc);}static socket_descriptor_tsocket_do_accept (socket_descriptor_t sd,		  struct sockaddr_in *remote,		  const bool nowait){  socklen_t remote_len = sizeof (*remote);  socket_descriptor_t new_sd = -1;#ifdef HAVE_GETPEERNAME  if (nowait)    {      new_sd = getpeername (sd, (struct sockaddr *) remote, &remote_len);      if (new_sd == -1)	msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed");      else	new_sd = sd;    }#else  if (nowait)    msg (M_WARN, "TCP: this OS does not provide the getpeername() function");#endif  else    {      new_sd = accept (sd, (struct sockaddr *) remote, &remote_len);    }  if (new_sd == -1)    {      msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept() failed");    }  else if (remote_len != sizeof (*remote))    {      msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len);      openvpn_close_socket (new_sd);

⌨️ 快捷键说明

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