📄 socket.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 "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 + -