From: Lev Stipakov <[email protected]> create_socket() creates the UDP socket and then applies the link socket's options and local bind in place. Pull that sequence into create_socket_udp_configured(), taking the address family and the option values rather than a struct link_socket, and have create_socket() call it; the TCP path keeps its own sequence through the shared socket_apply_options().
--server-probe will open its probe sockets through the same function, so a probe socket is set up and bound exactly like the connection socket it may later become. Its "optional" argument lets that caller treat a socket the host cannot create as "do not probe this address family" instead of dying; the connection path passes false and keeps the fatal error. No behaviour change for existing callers. Change-Id: I8f2bd694146aacd244a1d385ddfe9bb84ec29334 Signed-off-by: Lev Stipakov <[email protected]> Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1910 --- This change was reviewed on Gerrit and approved by at least one developer. I request to merge it to master. Gerrit URL: https://gerrit.openvpn.net/c/openvpn/+/1910 This mail reflects revision 4 of this Change. Acked-by according to Gerrit (reflected above): diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 7c6217a..e9181c8 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -565,7 +565,7 @@ } static socket_descriptor_t -create_socket_udp(struct addrinfo *addrinfo, const unsigned int flags) +create_socket_udp(struct addrinfo *addrinfo, const unsigned int flags, bool optional) { socket_descriptor_t sd; @@ -575,7 +575,8 @@ if ((sd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) == SOCKET_UNDEFINED) { - msg(M_ERR, "UDP: Cannot create UDP/UDP6 socket"); + msg(optional ? D_LOW | M_ERRNO : M_ERR, "UDP: Cannot create UDP/UDP6 socket"); + return SOCKET_UNDEFINED; } #if ENABLE_IP_PKTINFO else if (flags & SF_USE_IP_PKTINFO) @@ -636,12 +637,70 @@ } } +/* The per-socket options every link socket gets right after creation. */ +static void +socket_apply_options(socket_descriptor_t sd, const struct socket_buffer_size *sbs, int mark, + const char *bind_dev) +{ + /* set socket buffers based on --sndbuf and --rcvbuf options */ + socket_set_buffers(sd, sbs, true); + + /* set socket to --mark packets with given value */ + socket_set_mark(sd, mark); + +#if defined(TARGET_LINUX) + if (bind_dev) + { + msg(M_INFO, "Using bind-dev %s", bind_dev); + /* Note: We verify strlen of bind_dev in options parsing */ + if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, bind_dev, (socklen_t)(strlen(bind_dev) + 1)) + != 0) + { + msg(M_WARN | M_ERRNO, "WARN: setsockopt SO_BINDTODEVICE=%s failed", bind_dev); + } + } +#else + (void)bind_dev; +#endif +} + +socket_descriptor_t +create_socket_udp_configured(sa_family_t af, unsigned int sockflags, const struct socket_buffer_size *sbs, + int mark, const char *bind_dev, struct addrinfo *bind_addr, + bool bind_ipv6_only, bool optional) +{ + struct addrinfo ai = { .ai_family = af, .ai_socktype = SOCK_DGRAM, .ai_protocol = IPPROTO_UDP }; + socket_descriptor_t sd = create_socket_udp(&ai, sockflags, optional); + + if (sd == SOCKET_UNDEFINED) + { + return SOCKET_UNDEFINED; + } + + socket_apply_options(sd, sbs, mark, bind_dev); + if (bind_addr) + { + socket_bind(sd, bind_addr, af, "TCP/UDP", bind_ipv6_only); + } + return sd; +} + static void create_socket(struct link_socket *sock, struct addrinfo *addr) { + /* Set af field of sock->info, so it always reflects the address family + * of the created socket */ + sock->info.af = (sa_family_t)addr->ai_family; + if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM) { - sock->sd = create_socket_udp(addr, sock->sockflags); + /* With a SOCKS proxy the local bind goes on the control socket instead + * (see bind_local()), so the UDP socket is created unbound then. */ + struct addrinfo *bind_addr = + (sock->bind_local && !sock->socks_proxy) ? sock->info.lsa->bind_local : NULL; + sock->sd = create_socket_udp_configured(sock->info.af, sock->sockflags, &sock->socket_buffer_sizes, + sock->mark, sock->bind_dev, bind_addr, + sock->info.bind_ipv6_only, false); sock->sockflags |= SF_GETADDRINFO_DGRAM; /* Assume that control socket and data socket to the socks proxy @@ -655,41 +714,19 @@ addrinfo_tmp.ai_socktype = SOCK_STREAM; addrinfo_tmp.ai_protocol = IPPROTO_TCP; sock->ctrl_sd = create_socket_tcp(&addrinfo_tmp); + bind_local(sock); } } else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM) { sock->sd = create_socket_tcp(addr); + socket_apply_options(sock->sd, &sock->socket_buffer_sizes, sock->mark, sock->bind_dev); + bind_local(sock); } else { ASSERT(0); } - /* Set af field of sock->info, so it always reflects the address family - * of the created socket */ - sock->info.af = (sa_family_t)addr->ai_family; - - /* set socket buffers based on --sndbuf and --rcvbuf options */ - socket_set_buffers(sock->sd, &sock->socket_buffer_sizes, true); - - /* set socket to --mark packets with given value */ - socket_set_mark(sock->sd, sock->mark); - -#if defined(TARGET_LINUX) - if (sock->bind_dev) - { - msg(M_INFO, "Using bind-dev %s", sock->bind_dev); - /* Note: We verify strlen of bind_dev in options parsing */ - if (setsockopt(sock->sd, SOL_SOCKET, SO_BINDTODEVICE, sock->bind_dev, - (socklen_t)(strlen(sock->bind_dev) + 1)) - != 0) - { - msg(M_WARN | M_ERRNO, "WARN: setsockopt SO_BINDTODEVICE=%s failed", sock->bind_dev); - } - } -#endif - - bind_local(sock); } #ifdef TARGET_ANDROID diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 89465bc..d296d3b 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -401,6 +401,19 @@ socket_descriptor_t create_socket_tcp(struct addrinfo *); +/** + * Create a UDP socket for @p af set up the way a link socket is: --sndbuf/--rcvbuf, + * --mark, --bind-dev and, when @p bind_addr is given, the local bind (IPV6_V6ONLY + * per @p bind_ipv6_only). Shared by create_socket() and the --server-probe sockets, + * so a probe socket is the connection socket it may become. A failed bind is + * fatal; with @p optional a socket the host cannot create is not, so + * --server-probe can skip that address family (SOCKET_UNDEFINED is returned). + */ +socket_descriptor_t create_socket_udp_configured(sa_family_t af, unsigned int sockflags, + const struct socket_buffer_size *sbs, int mark, + const char *bind_dev, struct addrinfo *bind_addr, + bool bind_ipv6_only, bool optional); + socket_descriptor_t socket_do_accept(socket_descriptor_t sd, struct link_socket_actual *act, const bool nowait); _______________________________________________ Openvpn-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openvpn-devel
