| /* |
| * 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-2018 OpenVPN Inc <sales@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; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #ifndef SOCKET_H |
| #define SOCKET_H |
| |
| #include "buffer.h" |
| #include "common.h" |
| #include "error.h" |
| #include "proto.h" |
| #include "mtu.h" |
| #include "win32.h" |
| #include "event.h" |
| #include "proxy.h" |
| #include "socks.h" |
| #include "misc.h" |
| |
| /* |
| * OpenVPN's default port number as assigned by IANA. |
| */ |
| #define OPENVPN_PORT "1194" |
| |
| /* |
| * Number of seconds that "resolv-retry infinite" |
| * represents. |
| */ |
| #define RESOLV_RETRY_INFINITE 1000000000 |
| |
| /* |
| * packet_size_type is used to communicate packet size |
| * over the wire when stream oriented protocols are |
| * being used |
| */ |
| |
| typedef uint16_t packet_size_type; |
| |
| /* convert a packet_size_type from host to network order */ |
| #define htonps(x) htons(x) |
| |
| /* convert a packet_size_type from network to host order */ |
| #define ntohps(x) ntohs(x) |
| |
| /* OpenVPN sockaddr struct */ |
| struct openvpn_sockaddr |
| { |
| /*int dummy;*/ /* add offset to force a bug if sa not explicitly dereferenced */ |
| union { |
| struct sockaddr sa; |
| struct sockaddr_in in4; |
| struct sockaddr_in6 in6; |
| } addr; |
| }; |
| |
| /* struct to hold preresolved host names */ |
| struct cached_dns_entry { |
| const char *hostname; |
| const char *servname; |
| int ai_family; |
| int flags; |
| struct addrinfo *ai; |
| struct cached_dns_entry *next; |
| }; |
| |
| /* actual address of remote, based on source address of received packets */ |
| struct link_socket_actual |
| { |
| /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */ |
| |
| struct openvpn_sockaddr dest; |
| #if ENABLE_IP_PKTINFO |
| union { |
| #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) |
| struct in_pktinfo in4; |
| #elif defined(IP_RECVDSTADDR) |
| struct in_addr in4; |
| #endif |
| struct in6_pktinfo in6; |
| } pi; |
| #endif |
| }; |
| |
| /* IP addresses which are persistant across SIGUSR1s */ |
| struct link_socket_addr |
| { |
| struct addrinfo *bind_local; |
| struct addrinfo *remote_list; /* complete remote list */ |
| struct addrinfo *current_remote; /* remote used in the |
| * current connection attempt */ |
| struct link_socket_actual actual; /* reply to this address */ |
| }; |
| |
| struct link_socket_info |
| { |
| struct link_socket_addr *lsa; |
| bool connection_established; |
| const char *ipchange_command; |
| const struct plugin_list *plugins; |
| bool remote_float; |
| int proto; /* Protocol (PROTO_x defined below) */ |
| sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/ |
| bool bind_ipv6_only; |
| int mtu_changed; /* Set to true when mtu value is changed */ |
| }; |
| |
| /* |
| * Used to extract packets encapsulated in streams into a buffer, |
| * in this case IP packets embedded in a TCP stream. |
| */ |
| struct stream_buf |
| { |
| struct buffer buf_init; |
| struct buffer residual; |
| int maxlen; |
| bool residual_fully_formed; |
| |
| struct buffer buf; |
| struct buffer next; |
| int len; /* -1 if not yet known */ |
| |
| bool error; /* if true, fatal TCP error has occurred, |
| * requiring that connection be restarted */ |
| #if PORT_SHARE |
| #define PS_DISABLED 0 |
| #define PS_ENABLED 1 |
| #define PS_FOREIGN 2 |
| int port_share_state; |
| #endif |
| }; |
| |
| /* |
| * Used to set socket buffer sizes |
| */ |
| struct socket_buffer_size |
| { |
| int rcvbuf; |
| int sndbuf; |
| }; |
| |
| /* |
| * This is the main socket structure used by OpenVPN. The SOCKET_ |
| * defines try to abstract away our implementation differences between |
| * using sockets on Posix vs. Win32. |
| */ |
| struct link_socket |
| { |
| struct link_socket_info info; |
| |
| socket_descriptor_t sd; |
| socket_descriptor_t ctrl_sd; /* only used for UDP over Socks */ |
| |
| #ifdef _WIN32 |
| struct overlapped_io reads; |
| struct overlapped_io writes; |
| struct rw_handle rw_handle; |
| struct rw_handle listen_handle; /* For listening on TCP socket in server mode */ |
| #endif |
| |
| /* used for printing status info only */ |
| unsigned int rwflags_debug; |
| |
| /* used for long-term queueing of pre-accepted socket listen */ |
| bool listen_persistent_queued; |
| |
| const char *remote_host; |
| const char *remote_port; |
| const char *local_host; |
| const char *local_port; |
| struct cached_dns_entry *dns_cache; |
| bool bind_local; |
| |
| #define INETD_NONE 0 |
| #define INETD_WAIT 1 |
| #define INETD_NOWAIT 2 |
| int inetd; |
| |
| #define LS_MODE_DEFAULT 0 |
| #define LS_MODE_TCP_LISTEN 1 |
| #define LS_MODE_TCP_ACCEPT_FROM 2 |
| int mode; |
| |
| int resolve_retry_seconds; |
| int mtu_discover_type; |
| |
| struct socket_buffer_size socket_buffer_sizes; |
| |
| int mtu; /* OS discovered MTU, or 0 if unknown */ |
| |
| #define SF_USE_IP_PKTINFO (1<<0) |
| #define SF_TCP_NODELAY (1<<1) |
| #define SF_PORT_SHARE (1<<2) |
| #define SF_HOST_RANDOMIZE (1<<3) |
| #define SF_GETADDRINFO_DGRAM (1<<4) |
| unsigned int sockflags; |
| int mark; |
| |
| /* for stream sockets */ |
| struct stream_buf stream_buf; |
| struct buffer stream_buf_data; |
| bool stream_reset; |
| |
| /* HTTP proxy */ |
| struct http_proxy_info *http_proxy; |
| |
| /* Socks proxy */ |
| struct socks_proxy_info *socks_proxy; |
| struct link_socket_actual socks_relay; /* Socks UDP relay address */ |
| |
| /* The OpenVPN server we will use the proxy to connect to */ |
| const char *proxy_dest_host; |
| const char *proxy_dest_port; |
| |
| /* Pointer to the server-poll to trigger the timeout in function which have |
| * their own loop instead of using the main oop */ |
| struct event_timeout *server_poll_timeout; |
| |
| #if PASSTOS_CAPABILITY |
| /* used to get/set TOS. */ |
| #if defined(TARGET_LINUX) |
| uint8_t ptos; |
| #else /* all the BSDs, Solaris, MacOS use plain "int" -> see "man ip" there */ |
| int ptos; |
| #endif |
| bool ptos_defined; |
| #endif |
| |
| #ifdef ENABLE_DEBUG |
| int gremlin; /* --gremlin bits */ |
| #endif |
| }; |
| |
| /* |
| * Some Posix/Win32 differences. |
| */ |
| |
| #ifndef MSG_NOSIGNAL |
| #define MSG_NOSIGNAL 0 |
| #endif |
| |
| #ifdef _WIN32 |
| |
| #define openvpn_close_socket(s) closesocket(s) |
| |
| int socket_recv_queue(struct link_socket *sock, int maxsize); |
| |
| int socket_send_queue(struct link_socket *sock, |
| struct buffer *buf, |
| const struct link_socket_actual *to); |
| |
| int socket_finalize( |
| SOCKET s, |
| struct overlapped_io *io, |
| struct buffer *buf, |
| struct link_socket_actual *from); |
| |
| #else /* ifdef _WIN32 */ |
| |
| #define openvpn_close_socket(s) close(s) |
| |
| #endif |
| |
| struct link_socket *link_socket_new(void); |
| |
| void socket_bind(socket_descriptor_t sd, |
| struct addrinfo *local, |
| int af_family, |
| const char *prefix, |
| bool ipv6only); |
| |
| int openvpn_connect(socket_descriptor_t sd, |
| const struct sockaddr *remote, |
| int connect_timeout, |
| volatile int *signal_received); |
| |
| |
| |
| /* |
| * Initialize link_socket object. |
| */ |
| |
| void |
| link_socket_init_phase1(struct link_socket *sock, |
| const char *local_host, |
| const char *local_port, |
| const char *remote_host, |
| const char *remote_port, |
| struct cached_dns_entry *dns_cache, |
| int proto, |
| sa_family_t af, |
| bool bind_ipv6_only, |
| int mode, |
| const struct link_socket *accept_from, |
| struct http_proxy_info *http_proxy, |
| struct socks_proxy_info *socks_proxy, |
| #ifdef ENABLE_DEBUG |
| int gremlin, |
| #endif |
| bool bind_local, |
| bool remote_float, |
| int inetd, |
| struct link_socket_addr *lsa, |
| const char *ipchange_command, |
| const struct plugin_list *plugins, |
| int resolve_retry_seconds, |
| int mtu_discover_type, |
| int rcvbuf, |
| int sndbuf, |
| int mark, |
| struct event_timeout *server_poll_timeout, |
| unsigned int sockflags); |
| |
| void link_socket_init_phase2(struct link_socket *sock, |
| const struct frame *frame, |
| struct signal_info *sig_info); |
| |
| void do_preresolve(struct context *c); |
| |
| void socket_adjust_frame_parameters(struct frame *frame, int proto); |
| |
| void frame_adjust_path_mtu(struct frame *frame, int pmtu, int proto); |
| |
| void link_socket_close(struct link_socket *sock); |
| |
| void sd_close(socket_descriptor_t *sd); |
| |
| #define PS_SHOW_PORT_IF_DEFINED (1<<0) |
| #define PS_SHOW_PORT (1<<1) |
| #define PS_SHOW_PKTINFO (1<<2) |
| #define PS_DONT_SHOW_ADDR (1<<3) |
| #define PS_DONT_SHOW_FAMILY (1<<4) |
| |
| const char *print_sockaddr_ex(const struct sockaddr *addr, |
| const char *separator, |
| const unsigned int flags, |
| struct gc_arena *gc); |
| |
| static inline |
| const char * |
| print_openvpn_sockaddr_ex(const struct openvpn_sockaddr *addr, |
| const char *separator, |
| const unsigned int flags, |
| struct gc_arena *gc) |
| { |
| return print_sockaddr_ex(&addr->addr.sa, separator, flags, gc); |
| } |
| |
| static inline |
| const char * |
| print_openvpn_sockaddr(const struct openvpn_sockaddr *addr, |
| struct gc_arena *gc) |
| { |
| return print_sockaddr_ex(&addr->addr.sa, ":", PS_SHOW_PORT, gc); |
| } |
| |
| static inline |
| const char * |
| print_sockaddr(const struct sockaddr *addr, |
| struct gc_arena *gc) |
| { |
| return print_sockaddr_ex(addr, ":", PS_SHOW_PORT, gc); |
| } |
| |
| |
| |
| const char *print_link_socket_actual_ex(const struct link_socket_actual *act, |
| const char *separator, |
| const unsigned int flags, |
| struct gc_arena *gc); |
| |
| const char *print_link_socket_actual(const struct link_socket_actual *act, |
| struct gc_arena *gc); |
| |
| |
| #define IA_EMPTY_IF_UNDEF (1<<0) |
| #define IA_NET_ORDER (1<<1) |
| const char *print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc); |
| |
| const char *print_in6_addr(struct in6_addr addr6, unsigned int flags, struct gc_arena *gc); |
| |
| struct in6_addr add_in6_addr( struct in6_addr base, uint32_t add ); |
| |
| #define SA_IP_PORT (1<<0) |
| #define SA_SET_IF_NONZERO (1<<1) |
| void setenv_sockaddr(struct env_set *es, |
| const char *name_prefix, |
| const struct openvpn_sockaddr *addr, |
| const unsigned int flags); |
| |
| void setenv_in_addr_t(struct env_set *es, |
| const char *name_prefix, |
| in_addr_t addr, |
| const unsigned int flags); |
| |
| void setenv_in6_addr(struct env_set *es, |
| const char *name_prefix, |
| const struct in6_addr *addr, |
| const unsigned int flags); |
| |
| void setenv_link_socket_actual(struct env_set *es, |
| const char *name_prefix, |
| const struct link_socket_actual *act, |
| const unsigned int flags); |
| |
| void bad_address_length(int actual, int expected); |
| |
| /* IPV4_INVALID_ADDR: returned by link_socket_current_remote() |
| * to ease redirect-gateway logic for ipv4 tunnels on ipv6 endpoints |
| */ |
| #define IPV4_INVALID_ADDR 0xffffffff |
| in_addr_t link_socket_current_remote(const struct link_socket_info *info); |
| |
| const struct in6_addr *link_socket_current_remote_ipv6 |
| (const struct link_socket_info *info); |
| |
| void link_socket_connection_initiated(const struct buffer *buf, |
| struct link_socket_info *info, |
| const struct link_socket_actual *addr, |
| const char *common_name, |
| struct env_set *es); |
| |
| void link_socket_bad_incoming_addr(struct buffer *buf, |
| const struct link_socket_info *info, |
| const struct link_socket_actual *from_addr); |
| |
| void set_actual_address(struct link_socket_actual *actual, |
| struct addrinfo *ai); |
| |
| void link_socket_bad_outgoing_addr(void); |
| |
| void setenv_trusted(struct env_set *es, const struct link_socket_info *info); |
| |
| bool link_socket_update_flags(struct link_socket *ls, unsigned int sockflags); |
| |
| void link_socket_update_buffer_sizes(struct link_socket *ls, int rcvbuf, int sndbuf); |
| |
| /* |
| * Low-level functions |
| */ |
| |
| /* return values of openvpn_inet_aton */ |
| #define OIA_HOSTNAME 0 |
| #define OIA_IP 1 |
| #define OIA_ERROR -1 |
| int openvpn_inet_aton(const char *dotted_quad, struct in_addr *addr); |
| |
| /* integrity validation on pulled options */ |
| bool ip_addr_dotted_quad_safe(const char *dotted_quad); |
| |
| bool ip_or_dns_addr_safe(const char *addr, const bool allow_fqdn); |
| |
| bool mac_addr_safe(const char *mac_addr); |
| |
| bool ipv6_addr_safe(const char *ipv6_text_addr); |
| |
| socket_descriptor_t create_socket_tcp(struct addrinfo *); |
| |
| socket_descriptor_t socket_do_accept(socket_descriptor_t sd, |
| struct link_socket_actual *act, |
| const bool nowait); |
| |
| /* |
| * proto related |
| */ |
| bool proto_is_net(int proto); |
| |
| bool proto_is_dgram(int proto); |
| |
| bool proto_is_udp(int proto); |
| |
| bool proto_is_tcp(int proto); |
| |
| |
| #if UNIX_SOCK_SUPPORT |
| |
| socket_descriptor_t create_socket_unix(void); |
| |
| void socket_bind_unix(socket_descriptor_t sd, |
| struct sockaddr_un *local, |
| const char *prefix); |
| |
| socket_descriptor_t socket_accept_unix(socket_descriptor_t sd, |
| struct sockaddr_un *remote); |
| |
| int socket_connect_unix(socket_descriptor_t sd, |
| struct sockaddr_un *remote); |
| |
| void sockaddr_unix_init(struct sockaddr_un *local, const char *path); |
| |
| const char *sockaddr_unix_name(const struct sockaddr_un *local, const char *null); |
| |
| void socket_delete_unix(const struct sockaddr_un *local); |
| |
| bool unix_socket_get_peer_uid_gid(const socket_descriptor_t sd, int *uid, int *gid); |
| |
| #endif /* if UNIX_SOCK_SUPPORT */ |
| |
| /* |
| * DNS resolution |
| */ |
| |
| #define GETADDR_RESOLVE (1<<0) |
| #define GETADDR_FATAL (1<<1) |
| #define GETADDR_HOST_ORDER (1<<2) |
| #define GETADDR_MENTION_RESOLVE_RETRY (1<<3) |
| #define GETADDR_FATAL_ON_SIGNAL (1<<4) |
| #define GETADDR_WARN_ON_SIGNAL (1<<5) |
| #define GETADDR_MSG_VIRT_OUT (1<<6) |
| #define GETADDR_TRY_ONCE (1<<7) |
| #define GETADDR_UPDATE_MANAGEMENT_STATE (1<<8) |
| #define GETADDR_RANDOMIZE (1<<9) |
| #define GETADDR_PASSIVE (1<<10) |
| #define GETADDR_DATAGRAM (1<<11) |
| |
| #define GETADDR_CACHE_MASK (GETADDR_DATAGRAM|GETADDR_PASSIVE) |
| |
| /** |
| * Translate an IPv4 addr or hostname from string form to in_addr_t |
| * |
| * In case of resolve error, it will try again for |
| * resolve_retry_seconds seconds. |
| */ |
| in_addr_t getaddr(unsigned int flags, |
| const char *hostname, |
| int resolve_retry_seconds, |
| bool *succeeded, |
| volatile int *signal_received); |
| |
| /** |
| * Translate an IPv6 addr or hostname from string form to in6_addr |
| */ |
| bool get_ipv6_addr(const char *hostname, struct in6_addr *network, |
| unsigned int *netbits, int msglevel); |
| |
| int openvpn_getaddrinfo(unsigned int flags, |
| const char *hostname, |
| const char *servname, |
| int resolve_retry_seconds, |
| volatile int *signal_received, |
| int ai_family, |
| struct addrinfo **res); |
| |
| /* |
| * Transport protocol naming and other details. |
| */ |
| |
| /* |
| * Use enum's instead of #define to allow for easier |
| * optional proto support |
| */ |
| enum proto_num { |
| PROTO_NONE, /* catch for uninitialized */ |
| PROTO_UDP, |
| PROTO_TCP, |
| PROTO_TCP_SERVER, |
| PROTO_TCP_CLIENT, |
| PROTO_N |
| }; |
| |
| int ascii2proto(const char *proto_name); |
| |
| sa_family_t ascii2af(const char *proto_name); |
| |
| const char *proto2ascii(int proto, sa_family_t af, bool display_form); |
| |
| const char *proto2ascii_all(struct gc_arena *gc); |
| |
| const char *proto_remote(int proto, bool remote); |
| |
| const char *addr_family_name(int af); |
| |
| /* |
| * Overhead added to packets by various protocols. |
| */ |
| #define IPv4_UDP_HEADER_SIZE 28 |
| #define IPv4_TCP_HEADER_SIZE 40 |
| #define IPv6_UDP_HEADER_SIZE 48 |
| #define IPv6_TCP_HEADER_SIZE 60 |
| |
| extern const int proto_overhead[]; |
| |
| static inline int |
| datagram_overhead(int proto) |
| { |
| ASSERT(proto >= 0 && proto < PROTO_N); |
| return proto_overhead [proto]; |
| } |
| |
| /* |
| * Misc inline functions |
| */ |
| |
| static inline bool |
| link_socket_proto_connection_oriented(int proto) |
| { |
| return !proto_is_dgram(proto); |
| } |
| |
| static inline bool |
| link_socket_connection_oriented(const struct link_socket *sock) |
| { |
| if (sock) |
| { |
| return link_socket_proto_connection_oriented(sock->info.proto); |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| static inline bool |
| addr_defined(const struct openvpn_sockaddr *addr) |
| { |
| if (!addr) |
| { |
| return 0; |
| } |
| switch (addr->addr.sa.sa_family) |
| { |
| case AF_INET: return addr->addr.in4.sin_addr.s_addr != 0; |
| |
| case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6.sin6_addr); |
| |
| default: return 0; |
| } |
| } |
| |
| static inline bool |
| addr_local(const struct sockaddr *addr) |
| { |
| if (!addr) |
| { |
| return false; |
| } |
| switch (addr->sa_family) |
| { |
| case AF_INET: |
| return ((const struct sockaddr_in *)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK); |
| |
| case AF_INET6: |
| return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6 *)addr)->sin6_addr); |
| |
| default: |
| return false; |
| } |
| } |
| |
| |
| static inline bool |
| addr_defined_ipi(const struct link_socket_actual *lsa) |
| { |
| #if ENABLE_IP_PKTINFO |
| if (!lsa) |
| { |
| return 0; |
| } |
| switch (lsa->dest.addr.sa.sa_family) |
| { |
| #if defined(HAVE_IN_PKTINFO) && defined(HAVE_IPI_SPEC_DST) |
| case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0; |
| |
| #elif defined(IP_RECVDSTADDR) |
| case AF_INET: return lsa->pi.in4.s_addr != 0; |
| |
| #endif |
| case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&lsa->pi.in6.ipi6_addr); |
| |
| default: return 0; |
| } |
| #else /* if ENABLE_IP_PKTINFO */ |
| ASSERT(0); |
| #endif |
| return false; |
| } |
| |
| static inline bool |
| link_socket_actual_defined(const struct link_socket_actual *act) |
| { |
| return act && addr_defined(&act->dest); |
| } |
| |
| static inline bool |
| addr_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) |
| { |
| switch (a1->addr.sa.sa_family) |
| { |
| case AF_INET: |
| return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr; |
| |
| case AF_INET6: |
| return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr); |
| } |
| ASSERT(0); |
| return false; |
| } |
| |
| static inline bool |
| addrlist_match(const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist) |
| { |
| const struct addrinfo *curele; |
| for (curele = addrlist; curele; curele = curele->ai_next) |
| { |
| switch (a1->addr.sa.sa_family) |
| { |
| case AF_INET: |
| if (a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr) |
| { |
| return true; |
| } |
| break; |
| |
| case AF_INET6: |
| if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6 *) curele->ai_addr)->sin6_addr)) |
| { |
| return true; |
| } |
| break; |
| |
| default: |
| ASSERT(0); |
| } |
| } |
| return false; |
| } |
| |
| static inline in_addr_t |
| addr_host(const struct openvpn_sockaddr *addr) |
| { |
| /* |
| * "public" addr returned is checked against ifconfig for |
| * possible clash: non sense for now given |
| * that we do ifconfig only IPv4 |
| */ |
| if (addr->addr.sa.sa_family != AF_INET) |
| { |
| return 0; |
| } |
| return ntohl(addr->addr.in4.sin_addr.s_addr); |
| } |
| |
| |
| static inline bool |
| addrlist_port_match(const struct openvpn_sockaddr *a1, const struct addrinfo *a2) |
| { |
| const struct addrinfo *curele; |
| for (curele = a2; curele; curele = curele->ai_next) |
| { |
| switch (a1->addr.sa.sa_family) |
| { |
| case AF_INET: |
| if (curele->ai_family == AF_INET |
| && a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in *)curele->ai_addr)->sin_addr.s_addr |
| && a1->addr.in4.sin_port == ((struct sockaddr_in *)curele->ai_addr)->sin_port) |
| { |
| return true; |
| } |
| break; |
| |
| case AF_INET6: |
| if (curele->ai_family == AF_INET6 |
| && IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6 *) curele->ai_addr)->sin6_addr) |
| && a1->addr.in6.sin6_port == ((struct sockaddr_in6 *) curele->ai_addr)->sin6_port) |
| { |
| return true; |
| } |
| break; |
| |
| default: |
| ASSERT(0); |
| } |
| } |
| return false; |
| } |
| |
| |
| |
| static inline bool |
| addr_port_match(const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2) |
| { |
| switch (a1->addr.sa.sa_family) |
| { |
| case AF_INET: |
| return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr |
| && a1->addr.in4.sin_port == a2->addr.in4.sin_port; |
| |
| case AF_INET6: |
| return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr) |
| && a1->addr.in6.sin6_port == a2->addr.in6.sin6_port; |
| } |
| ASSERT(0); |
| return false; |
| } |
| |
| static inline bool |
| addr_match_proto(const struct openvpn_sockaddr *a1, |
| const struct openvpn_sockaddr *a2, |
| const int proto) |
| { |
| return link_socket_proto_connection_oriented(proto) |
| ? addr_match(a1, a2) |
| : addr_port_match(a1, a2); |
| } |
| |
| |
| static inline bool |
| addrlist_match_proto(const struct openvpn_sockaddr *a1, |
| struct addrinfo *addr_list, |
| const int proto) |
| { |
| return link_socket_proto_connection_oriented(proto) |
| ? addrlist_match(a1, addr_list) |
| : addrlist_port_match(a1, addr_list); |
| } |
| |
| static inline void |
| addr_zero_host(struct openvpn_sockaddr *addr) |
| { |
| switch (addr->addr.sa.sa_family) |
| { |
| case AF_INET: |
| addr->addr.in4.sin_addr.s_addr = 0; |
| break; |
| |
| case AF_INET6: |
| memset(&addr->addr.in6.sin6_addr, 0, sizeof(struct in6_addr)); |
| break; |
| } |
| } |
| |
| static inline void |
| addr_copy_sa(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src) |
| { |
| dst->addr = src->addr; |
| } |
| |
| static inline bool |
| addr_inet4or6(struct sockaddr *addr) |
| { |
| return addr->sa_family == AF_INET || addr->sa_family == AF_INET6; |
| } |
| |
| int addr_guess_family(sa_family_t af,const char *name); |
| |
| static inline int |
| af_addr_size(sa_family_t af) |
| { |
| switch (af) |
| { |
| case AF_INET: return sizeof(struct sockaddr_in); |
| |
| case AF_INET6: return sizeof(struct sockaddr_in6); |
| |
| default: |
| #if 0 |
| /* could be called from socket_do_accept() with empty addr */ |
| msg(M_ERR, "Bad address family: %d\n", af); |
| ASSERT(0); |
| #endif |
| return 0; |
| } |
| } |
| |
| static inline bool |
| link_socket_actual_match(const struct link_socket_actual *a1, const struct link_socket_actual *a2) |
| { |
| return addr_port_match(&a1->dest, &a2->dest); |
| } |
| |
| #if PORT_SHARE |
| |
| static inline bool |
| socket_foreign_protocol_detected(const struct link_socket *sock) |
| { |
| return link_socket_connection_oriented(sock) |
| && sock->stream_buf.port_share_state == PS_FOREIGN; |
| } |
| |
| static inline const struct buffer * |
| socket_foreign_protocol_head(const struct link_socket *sock) |
| { |
| return &sock->stream_buf.buf; |
| } |
| |
| static inline int |
| socket_foreign_protocol_sd(const struct link_socket *sock) |
| { |
| return sock->sd; |
| } |
| |
| #endif /* if PORT_SHARE */ |
| |
| static inline bool |
| socket_connection_reset(const struct link_socket *sock, int status) |
| { |
| if (link_socket_connection_oriented(sock)) |
| { |
| if (sock->stream_reset || sock->stream_buf.error) |
| { |
| return true; |
| } |
| else if (status < 0) |
| { |
| const int err = openvpn_errno(); |
| #ifdef _WIN32 |
| return err == WSAECONNRESET || err == WSAECONNABORTED; |
| #else |
| return err == ECONNRESET; |
| #endif |
| } |
| } |
| return false; |
| } |
| |
| static inline bool |
| link_socket_verify_incoming_addr(struct buffer *buf, |
| const struct link_socket_info *info, |
| const struct link_socket_actual *from_addr) |
| { |
| if (buf->len > 0) |
| { |
| switch (from_addr->dest.addr.sa.sa_family) |
| { |
| case AF_INET6: |
| case AF_INET: |
| if (!link_socket_actual_defined(from_addr)) |
| { |
| return false; |
| } |
| if (info->remote_float || (!info->lsa->remote_list)) |
| { |
| return true; |
| } |
| if (addrlist_match_proto(&from_addr->dest, info->lsa->remote_list, info->proto)) |
| { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| static inline void |
| link_socket_get_outgoing_addr(struct buffer *buf, |
| const struct link_socket_info *info, |
| struct link_socket_actual **act) |
| { |
| if (buf->len > 0) |
| { |
| struct link_socket_addr *lsa = info->lsa; |
| if (link_socket_actual_defined(&lsa->actual)) |
| { |
| *act = &lsa->actual; |
| } |
| else |
| { |
| link_socket_bad_outgoing_addr(); |
| buf->len = 0; |
| *act = NULL; |
| } |
| } |
| } |
| |
| static inline void |
| link_socket_set_outgoing_addr(const struct buffer *buf, |
| struct link_socket_info *info, |
| const struct link_socket_actual *act, |
| const char *common_name, |
| struct env_set *es) |
| { |
| if (!buf || buf->len > 0) |
| { |
| struct link_socket_addr *lsa = info->lsa; |
| if ( |
| /* new or changed address? */ |
| (!info->connection_established |
| || !addr_match_proto(&act->dest, &lsa->actual.dest, info->proto) |
| ) |
| && |
| /* address undef or address == remote or --float */ |
| (info->remote_float |
| || (!lsa->remote_list || addrlist_match_proto(&act->dest, lsa->remote_list, info->proto)) |
| ) |
| ) |
| { |
| link_socket_connection_initiated(buf, info, act, common_name, es); |
| } |
| } |
| } |
| |
| /* |
| * Stream buffer handling -- stream_buf is a helper class |
| * to assist in the packetization of stream transport protocols |
| * such as TCP. |
| */ |
| |
| void stream_buf_init(struct stream_buf *sb, |
| struct buffer *buf, |
| const unsigned int sockflags, |
| const int proto); |
| |
| void stream_buf_close(struct stream_buf *sb); |
| |
| bool stream_buf_added(struct stream_buf *sb, int length_added); |
| |
| static inline bool |
| stream_buf_read_setup(struct link_socket *sock) |
| { |
| bool stream_buf_read_setup_dowork(struct link_socket *sock); |
| |
| if (link_socket_connection_oriented(sock)) |
| { |
| return stream_buf_read_setup_dowork(sock); |
| } |
| else |
| { |
| return true; |
| } |
| } |
| |
| /* |
| * Socket Read Routines |
| */ |
| |
| int link_socket_read_tcp(struct link_socket *sock, |
| struct buffer *buf); |
| |
| #ifdef _WIN32 |
| |
| static inline int |
| link_socket_read_udp_win32(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *from) |
| { |
| return socket_finalize(sock->sd, &sock->reads, buf, from); |
| } |
| |
| #else /* ifdef _WIN32 */ |
| |
| int link_socket_read_udp_posix(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *from); |
| |
| #endif |
| |
| /* read a TCP or UDP packet from link */ |
| static inline int |
| link_socket_read(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *from) |
| { |
| if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ |
| { |
| int res; |
| |
| #ifdef _WIN32 |
| res = link_socket_read_udp_win32(sock, buf, from); |
| #else |
| res = link_socket_read_udp_posix(sock, buf, from); |
| #endif |
| return res; |
| } |
| else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ |
| { |
| /* from address was returned by accept */ |
| addr_copy_sa(&from->dest, &sock->info.lsa->actual.dest); |
| return link_socket_read_tcp(sock, buf); |
| } |
| else |
| { |
| ASSERT(0); |
| return -1; /* NOTREACHED */ |
| } |
| } |
| |
| /* |
| * Socket Write routines |
| */ |
| |
| int link_socket_write_tcp(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *to); |
| |
| #ifdef _WIN32 |
| |
| static inline int |
| link_socket_write_win32(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *to) |
| { |
| int err = 0; |
| int status = 0; |
| if (overlapped_io_active(&sock->writes)) |
| { |
| status = socket_finalize(sock->sd, &sock->writes, NULL, NULL); |
| if (status < 0) |
| { |
| err = WSAGetLastError(); |
| } |
| } |
| socket_send_queue(sock, buf, to); |
| if (status < 0) |
| { |
| WSASetLastError(err); |
| return status; |
| } |
| else |
| { |
| return BLEN(buf); |
| } |
| } |
| |
| #else /* ifdef _WIN32 */ |
| |
| static inline size_t |
| link_socket_write_udp_posix(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *to) |
| { |
| #if ENABLE_IP_PKTINFO |
| size_t link_socket_write_udp_posix_sendmsg(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *to); |
| |
| if (proto_is_udp(sock->info.proto) && (sock->sockflags & SF_USE_IP_PKTINFO) |
| && addr_defined_ipi(to)) |
| { |
| return link_socket_write_udp_posix_sendmsg(sock, buf, to); |
| } |
| else |
| #endif |
| return sendto(sock->sd, BPTR(buf), BLEN(buf), 0, |
| (struct sockaddr *) &to->dest.addr.sa, |
| (socklen_t) af_addr_size(to->dest.addr.sa.sa_family)); |
| } |
| |
| static inline size_t |
| link_socket_write_tcp_posix(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *to) |
| { |
| return send(sock->sd, BPTR(buf), BLEN(buf), MSG_NOSIGNAL); |
| } |
| |
| #endif /* ifdef _WIN32 */ |
| |
| static inline size_t |
| link_socket_write_udp(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *to) |
| { |
| #ifdef _WIN32 |
| return link_socket_write_win32(sock, buf, to); |
| #else |
| return link_socket_write_udp_posix(sock, buf, to); |
| #endif |
| } |
| |
| /* write a TCP or UDP packet to link */ |
| static inline int |
| link_socket_write(struct link_socket *sock, |
| struct buffer *buf, |
| struct link_socket_actual *to) |
| { |
| if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */ |
| { |
| return link_socket_write_udp(sock, buf, to); |
| } |
| else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */ |
| { |
| return link_socket_write_tcp(sock, buf, to); |
| } |
| else |
| { |
| ASSERT(0); |
| return -1; /* NOTREACHED */ |
| } |
| } |
| |
| #if PASSTOS_CAPABILITY |
| |
| /* |
| * Extract TOS bits. Assumes that ipbuf is a valid IPv4 packet. |
| */ |
| static inline void |
| link_socket_extract_tos(struct link_socket *ls, const struct buffer *ipbuf) |
| { |
| if (ls && ipbuf) |
| { |
| struct openvpn_iphdr *iph = (struct openvpn_iphdr *) BPTR(ipbuf); |
| ls->ptos = iph->tos; |
| ls->ptos_defined = true; |
| } |
| } |
| |
| /* |
| * Set socket properties to reflect TOS bits which were extracted |
| * from tunnel packet. |
| */ |
| static inline void |
| link_socket_set_tos(struct link_socket *ls) |
| { |
| if (ls && ls->ptos_defined) |
| { |
| setsockopt(ls->sd, IPPROTO_IP, IP_TOS, (const void *)&ls->ptos, sizeof(ls->ptos)); |
| } |
| } |
| |
| #endif /* if PASSTOS_CAPABILITY */ |
| |
| /* |
| * Socket I/O wait functions |
| */ |
| |
| static inline bool |
| socket_read_residual(const struct link_socket *s) |
| { |
| return s && s->stream_buf.residual_fully_formed; |
| } |
| |
| static inline event_t |
| socket_event_handle(const struct link_socket *s) |
| { |
| #ifdef _WIN32 |
| return &s->rw_handle; |
| #else |
| return s->sd; |
| #endif |
| } |
| |
| event_t socket_listen_event_handle(struct link_socket *s); |
| |
| unsigned int |
| socket_set(struct link_socket *s, |
| struct event_set *es, |
| unsigned int rwflags, |
| void *arg, |
| unsigned int *persistent); |
| |
| static inline void |
| socket_set_listen_persistent(struct link_socket *s, |
| struct event_set *es, |
| void *arg) |
| { |
| if (s && !s->listen_persistent_queued) |
| { |
| event_ctl(es, socket_listen_event_handle(s), EVENT_READ, arg); |
| s->listen_persistent_queued = true; |
| } |
| } |
| |
| static inline void |
| socket_reset_listen_persistent(struct link_socket *s) |
| { |
| #ifdef _WIN32 |
| reset_net_event_win32(&s->listen_handle, s->sd); |
| #endif |
| } |
| |
| const char *socket_stat(const struct link_socket *s, unsigned int rwflags, struct gc_arena *gc); |
| |
| #endif /* SOCKET_H */ |