/* * Open a socket TO the given IP and port. */ int fr_tcp_client_socket(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port) { int sockfd; struct sockaddr_storage salocal; socklen_t salen; if (!dst_ipaddr) return -1; sockfd = socket(dst_ipaddr->af, SOCK_STREAM, 0); if (sockfd < 0) { return sockfd; } /* * Allow the caller to bind us to a specific source IP. */ if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) { if (!fr_ipaddr2sockaddr(src_ipaddr, 0, &salocal, &salen)) { close(sockfd); return -1; } if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) { fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno)); close(sockfd); return -1; } } if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &salocal, &salen)) { close(sockfd); return -1; } /* * FIXME: If EINPROGRESS, then tell the caller that * somehow. The caller can then call connect() when the * socket is ready... */ if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) { fr_strerror_printf("Failed in connect(): %s", fr_syserror(errno)); close(sockfd); return -1; } return sockfd; }
/* * Wrapper for sendto which handles sendfromto, IPv6, and all * possible combinations. * * FIXME: This is just a copy of rad_sendto(). * Duplicate code is bad. */ static int vqp_sendto(int sockfd, void *data, size_t data_len, int flags, fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, int dst_port) { struct sockaddr_storage dst; socklen_t sizeof_dst; #ifdef WITH_UDPFROMTO struct sockaddr_storage src; socklen_t sizeof_src; fr_ipaddr2sockaddr(src_ipaddr, 0, &src, &sizeof_src); #else src_ipaddr = src_ipaddr; /* -Wunused */ #endif if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &dst, &sizeof_dst)) { return -1; /* Unknown address family, Die Die Die! */ } #ifdef WITH_UDPFROMTO /* * Only IPv4 is supported for udpfromto. * * And if they don't specify a source IP address, don't * use udpfromto. */ if ((dst_ipaddr->af == AF_INET) || (src_ipaddr->af != AF_UNSPEC)) { return sendfromto(sockfd, data, data_len, flags, (struct sockaddr *)&src, sizeof_src, (struct sockaddr *)&dst, sizeof_dst); } #else src_ipaddr = src_ipaddr; /* -Wunused */ #endif /* * No udpfromto, OR an IPv6 socket, fail gracefully. */ return sendto(sockfd, data, data_len, flags, (struct sockaddr *)&dst, sizeof_dst); }
/* * Open a socket on the given IP and port. */ int fr_tcp_socket(fr_ipaddr_t *ipaddr, int port) { int sockfd; int on = 1; struct sockaddr_storage salocal; socklen_t salen; if ((port < 0) || (port > 65535)) { fr_strerror_printf("Port %d is out of allowed bounds", port); return -1; } sockfd = socket(ipaddr->af, SOCK_STREAM, 0); if (sockfd < 0) { return sockfd; } if (fr_nonblock(sockfd) < 0) { close(sockfd); return -1; } if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) { close(sockfd); return -1; } #ifdef HAVE_STRUCT_SOCKADDR_IN6 if (ipaddr->af == AF_INET6) { /* * Listening on '::' does NOT get you IPv4 to * IPv6 mapping. You've got to listen on an IPv4 * address, too. This makes the rest of the server * design a little simpler. */ #ifdef IPV6_V6ONLY if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) { if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)) < 0) { fr_strerror_printf("Failed in setsockopt(): %s", fr_syserror(errno)); close(sockfd); return -1; } } #endif /* IPV6_V6ONLY */ } #endif /* HAVE_STRUCT_SOCKADDR_IN6 */ if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { fr_strerror_printf("Failed in setsockopt(): %s", fr_syserror(errno)); close(sockfd); return -1; } if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) { fr_strerror_printf("Failed in bind(): %s", fr_syserror(errno)); close(sockfd); return -1; } if (listen(sockfd, 8) < 0) { fr_strerror_printf("Failed in listen(): %s", fr_syserror(errno)); close(sockfd); return -1; } return sockfd; }
/* * Open a socket TO the given IP and port. */ int fr_tcp_client_socket(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, int dst_port) { int sockfd; struct sockaddr_storage salocal; socklen_t salen; if ((dst_port < 0) || (dst_port > 65535)) { fr_strerror_printf("Port %d is out of allowed bounds", dst_port); return -1; } if (!dst_ipaddr) return -1; sockfd = socket(dst_ipaddr->af, SOCK_STREAM, 0); if (sockfd < 0) { return sockfd; } #if 0 #ifdef O_NONBLOCK { int flags; if ((flags = fcntl(sockfd, F_GETFL, NULL)) < 0) { fr_strerror_printf("Failure getting socket flags: %s", fr_syserror(errno)); close(sockfd); return -1; } flags |= O_NONBLOCK; if( fcntl(sockfd, F_SETFL, flags) < 0) { fr_strerror_printf("Failure setting socket flags: %s", fr_syserror(errno)); close(sockfd); return -1; } } #endif #endif /* * Allow the caller to bind us to a specific source IP. */ if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) { if (!fr_ipaddr2sockaddr(src_ipaddr, 0, &salocal, &salen)) { close(sockfd); return -1; } if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) { fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno)); close(sockfd); return -1; } } if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &salocal, &salen)) { close(sockfd); return -1; } /* * FIXME: If EINPROGRESS, then tell the caller that * somehow. The caller can then call connect() when the * socket is ready... */ if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) { fr_strerror_printf("Failed in connect(): %s", fr_syserror(errno)); close(sockfd); return -1; } return sockfd; }
/* * Open a socket on the given IP and port. */ int fr_socket(fr_ipaddr_t *ipaddr, int port) { int sockfd; struct sockaddr_storage salocal; socklen_t salen; if ((port < 0) || (port > 65535)) { fr_strerror_printf("Port %d is out of allowed bounds", port); return -1; } sockfd = socket(ipaddr->af, SOCK_DGRAM, 0); if (sockfd < 0) { fr_strerror_printf("cannot open socket: %s", strerror(errno)); return sockfd; } #ifdef WITH_UDPFROMTO /* * Initialize udpfromto for all sockets. */ if (udpfromto_init(sockfd) != 0) { close(sockfd); fr_strerror_printf("cannot initialize udpfromto: %s", strerror(errno)); return -1; } #endif if (!fr_ipaddr2sockaddr(ipaddr, port, &salocal, &salen)) { return sockfd; } #ifdef HAVE_STRUCT_SOCKADDR_IN6 if (ipaddr->af == AF_INET6) { /* * Listening on '::' does NOT get you IPv4 to * IPv6 mapping. You've got to listen on an IPv4 * address, too. This makes the rest of the server * design a little simpler. */ #ifdef IPV6_V6ONLY if (IN6_IS_ADDR_UNSPECIFIED(&ipaddr->ipaddr.ip6addr)) { int on = 1; setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&on, sizeof(on)); } #endif /* IPV6_V6ONLY */ } #endif /* HAVE_STRUCT_SOCKADDR_IN6 */ if (ipaddr->af == AF_INET) { UNUSED int flag; #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) /* * Disable PMTU discovery. On Linux, this * also makes sure that the "don't fragment" * flag is zero. */ flag = IP_PMTUDISC_DONT; setsockopt(sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &flag, sizeof(flag)); #endif #if defined(IP_DONTFRAG) /* * Ensure that the "don't fragment" flag is zero. */ flag = 0; setsockopt(sockfd, IPPROTO_IP, IP_DONTFRAG, &flag, sizeof(flag)); #endif } if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) { close(sockfd); fr_strerror_printf("cannot bind socket: %s", strerror(errno)); return -1; } return sockfd; }
/* * Open a socket TO the given IP and port. */ int fr_tcp_client_socket(fr_ipaddr_t *src_ipaddr, fr_ipaddr_t *dst_ipaddr, int dst_port) { int sockfd; struct sockaddr_storage salocal; socklen_t salen; if ((dst_port < 0) || (dst_port > 65535)) { fr_strerror_printf("Port %d is out of allowed bounds", dst_port); return -1; } if (!dst_ipaddr) return -1; sockfd = socket(dst_ipaddr->af, SOCK_STREAM, 0); if (sockfd < 0) { return sockfd; } /* * Allow the caller to bind us to a specific source IP. */ if (src_ipaddr && (src_ipaddr->af != AF_UNSPEC)) { if (!fr_ipaddr2sockaddr(src_ipaddr, 0, &salocal, &salen)) { close(sockfd); return -1; } if (bind(sockfd, (struct sockaddr *) &salocal, salen) < 0) { fr_strerror_printf("Failure binding to IP: %s", fr_syserror(errno)); close(sockfd); return -1; } } if (!fr_ipaddr2sockaddr(dst_ipaddr, dst_port, &salocal, &salen)) { close(sockfd); return -1; } /* * FIXME: If EINPROGRESS, then tell the caller that * somehow. The caller can then call connect() when the * socket is ready... */ if (connect(sockfd, (struct sockaddr *) &salocal, salen) < 0) { fr_strerror_printf("Failed in connect(): %s", fr_syserror(errno)); close(sockfd); return -1; } /* * Set non-block *AFTER* connecting to the remote server * so it doesn't return immediately. */ if (fr_nonblock(sockfd) < 0) { close(sockfd); return -1; } return sockfd; }