From 1594c3690563f6ebaba83b0adff80479ac636364 Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Tue, 14 Mar 2006 03:45:52 +0000 Subject: [PATCH] Fix /uping on IPv6-enabled FreeBSD builds (#1435373). git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/branches/u2_10_12_branch@1626 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 28 ++++++++++++++++++++++++++++ include/ircd_osdep.h | 2 +- include/res.h | 10 ++++++++++ ircd/ircd_res.c | 6 ++++-- ircd/listener.c | 2 +- ircd/os_generic.c | 39 ++++++++++++++++++++++++++------------- ircd/s_auth.c | 2 +- ircd/s_bsd.c | 9 ++++++--- ircd/uping.c | 20 +++++++++++++------- 9 files changed, 90 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index e1ad25f..6efb7d0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2006-03-02 Michael Poole + + * include/ircd_osdep.h (os_socket): New parameter. + + * include/res.h (irc_in_addr_unspec): New macro. + + * ircd/ircd_res.c (restart_resolver): Set family appropriately. + + * ircd/listener.c (inetport): Let os_ library pick socket family. + + * ircd/os_generic.c: Do not #define _XOPEN_SOURCE on FreeBSD 5+. + (sockaddr_from_irc): New parameter. + (os_sendto_nonb): Use new parameter to sockaddr_from_irc(). + (os_socket): New parameter. Try to turn off IPV6_V6ONLY on + sockets that listen on unspecified addresses. + (os_connect_nonb): Use new parameter to sockaddr_from_irc(). + + * ircd/s_auth.c (start_auth_query): Let os_ library pick socket + family. + + * ircd/s_bsd.c (connect_inet): If we pick the IPv4 vhost, specify + family for os_socket() as AF_INET. + + * ircd/uping.c (uping_init): Set socket family appropriately. + (uping_server): Likewise. + (uping_end): Fix format strings (the ms_* fields are int, not + long, and this causes bad results on LP64 machines). + 2006-02-22 Michael Poole * ircd/m_silence.c (apply_silence): Refuse to apply silences for diff --git a/include/ircd_osdep.h b/include/ircd_osdep.h index 6e53fc9..89579c0 100644 --- a/include/ircd_osdep.h +++ b/include/ircd_osdep.h @@ -32,7 +32,7 @@ extern int os_get_rusage(struct Client* cptr, int uptime, EnumFn enumerator); extern int os_get_sockerr(int fd); extern int os_get_sockname(int fd, struct irc_sockaddr* sin_out); extern int os_get_peername(int fd, struct irc_sockaddr* sin_out); -extern int os_socket(const struct irc_sockaddr* local, int type, const char* port_name); +extern int os_socket(const struct irc_sockaddr* local, int type, const char* port_name, int family); extern int os_accept(int fd, struct irc_sockaddr* peer); extern IOResult os_sendto_nonb(int fd, const char* buf, unsigned int length, unsigned int* length_out, unsigned int flags, diff --git a/include/res.h b/include/res.h index 50f9324..2bf44c3 100644 --- a/include/res.h +++ b/include/res.h @@ -116,6 +116,16 @@ extern void report_dns_servers(struct Client *source_p, const struct StatDesc *s extern void gethost_byname(const char *name, dns_callback_f callback, void *ctx); extern void gethost_byaddr(const struct irc_in_addr *addr, dns_callback_f callback, void *ctx); +/** Evaluate to non-zero if \a ADDR is an unspecified (all zeros) address. */ +#define irc_in_addr_unspec(ADDR) (((ADDR)->in6_16[0] == 0) \ + && ((ADDR)->in6_16[1] == 0) \ + && ((ADDR)->in6_16[2] == 0) \ + && ((ADDR)->in6_16[3] == 0) \ + && ((ADDR)->in6_16[4] == 0) \ + && ((ADDR)->in6_16[6] == 0) \ + && ((ADDR)->in6_16[7] == 0) \ + && ((ADDR)->in6_16[5] == 0 \ + || (ADDR)->in6_16[5] == 65535)) /** Evaluate to non-zero if \a ADDR is a valid address (not all 0s and not all 1s). */ #define irc_in_addr_valid(ADDR) (((ADDR)->in6_16[0] && ~(ADDR)->in6_16[0]) \ || (ADDR)->in6_16[1] != (ADDR)->in6_16[0] \ diff --git a/ircd/ircd_res.c b/ircd/ircd_res.c index 02ca4e4..b7464cd 100644 --- a/ircd/ircd_res.c +++ b/ircd/ircd_res.c @@ -173,19 +173,21 @@ restart_resolver(void) if (!s_active(&res_socket_v4)) { - int fd = os_socket(&VirtualHost_v4, SOCK_DGRAM, "Resolver UDPv4 socket"); + int fd = os_socket(&VirtualHost_v4, SOCK_DGRAM, "Resolver UDPv4 socket", AF_INET); if (fd >= 0) socket_add(&res_socket_v4, res_readreply, NULL, SS_DATAGRAM, SOCK_EVENT_READABLE, fd); } +#ifdef AF_INET6 if (!s_active(&res_socket_v6)) { - int fd = os_socket(&VirtualHost_v6, SOCK_DGRAM, "Resolver UDPv6 socket"); + int fd = os_socket(&VirtualHost_v6, SOCK_DGRAM, "Resolver UDPv6 socket", AF_INET6); if (fd >= 0) socket_add(&res_socket_v6, res_readreply, NULL, SS_DATAGRAM, SOCK_EVENT_READABLE, fd); } +#endif if (s_active(&res_socket_v4) || s_active(&res_socket_v6)) timer_init(&res_timeout); diff --git a/ircd/listener.c b/ircd/listener.c index d51d319..fa188d9 100644 --- a/ircd/listener.c +++ b/ircd/listener.c @@ -187,7 +187,7 @@ static int inetport(struct Listener* listener) /* * At first, open a new socket */ - fd = os_socket(&listener->addr, SOCK_STREAM, get_listener_name(listener)); + fd = os_socket(&listener->addr, SOCK_STREAM, get_listener_name(listener), 0); if (fd < 0) return 0; /* diff --git a/ircd/os_generic.c b/ircd/os_generic.c index c462209..bdcda7c 100644 --- a/ircd/os_generic.c +++ b/ircd/os_generic.c @@ -29,11 +29,13 @@ */ #define _XOPEN_SOURCE 500 #define __EXTENSIONS__ 1 -#else -/* FreeBSD 6.0 requires SUSv3 to support IPv6. Apparently some other - * OS requires SUSv3 to define IOV_MAX, but its identity is lost for - * the time being. +#elif defined(__FreeBSD__) && __FreeBSD__ >= 5 +/* FreeBSD 6.0 requires SUSv3 to support IPv6 -- but if you ask for + * that specifically (by defining _XOPEN_SOURCE to anything at all), + * they cleverly hide IPPROTO_IPV6. If you don't ask for anything, + * they give you everything. */ +#else #define _XOPEN_SOURCE 600 #endif @@ -72,6 +74,10 @@ #include #endif +#if defined(IPV6_BINDV6ONLY) &&!defined(IPV6_V6ONLY) +# define IPV6_V6ONLY IPV6_BINDV6ONLY +#endif + #ifndef IOV_MAX #define IOV_MAX 16 /**< minimum required length of an iovec array */ #endif @@ -131,15 +137,16 @@ void sockaddr_to_irc(const struct sockaddr_in6 *v6, struct irc_sockaddr *irc) * @param[in] compat_fd If non-negative, an FD specifying address family. * @return Length of address written to \a v6. */ -int sockaddr_from_irc(struct sockaddr_in6 *v6, const struct irc_sockaddr *irc, int compat_fd) +int sockaddr_from_irc(struct sockaddr_in6 *v6, const struct irc_sockaddr *irc, int compat_fd, int family) { struct sockaddr_in6 sin6; socklen_t slen; - int family; assert(irc != 0); slen = sizeof(sin6); - if ((0 <= compat_fd) + if (family) { + /* accept whatever user specified */ + } else if ((0 <= compat_fd) && (0 == getsockname(compat_fd, (struct sockaddr*)&sin6, &slen))) family = sin6.sin6_family; else if ((irc == &VirtualHost_v4) || irc_in_addr_is_ipv4(&irc->addr)) @@ -168,7 +175,7 @@ int sockaddr_from_irc(struct sockaddr_in6 *v6, const struct irc_sockaddr *irc, i #define sn_family sin_family #define sockaddr_to_irc sockaddr_in_to_irc -int sockaddr_from_irc(struct sockaddr_in *v4, const struct irc_sockaddr *irc, int compat_fd) +int sockaddr_from_irc(struct sockaddr_in *v4, const struct irc_sockaddr *irc, int compat_fd, int family) { assert(irc != 0); v4->sin_family = AF_INET; @@ -179,7 +186,7 @@ int sockaddr_from_irc(struct sockaddr_in *v4, const struct irc_sockaddr *irc, in } else{ memset(&v4, 0, sizeof(v4)); } - (void)compat_fd; + (void)compat_fd; (void)family; return sizeof(*v4); } @@ -496,7 +503,7 @@ IOResult os_sendto_nonb(int fd, const char* buf, unsigned int length, int res, size; assert(0 != buf); - size = sockaddr_from_irc(&addr, peer, fd); + size = sockaddr_from_irc(&addr, peer, fd, 0); assert((addr.sn_family == AF_INET) == irc_in_addr_is_ipv4(&peer->addr)); if (-1 < (res = sendto(fd, buf, length, flags, (struct sockaddr*)&addr, size))) { if (count_out) @@ -566,15 +573,16 @@ IOResult os_sendv_nonb(int fd, struct MsgQ* buf, unsigned int* count_in, * @param[in] local Local address to bind to. * @param[in] type SOCK_STREAM or SOCK_DGRAM. * @param[in] port_name Port name (used in error diagnostics). + * @param[in] family A specific address family to use, or 0 for automatic. * @return Bound descriptor, or -1 on error. */ -int os_socket(const struct irc_sockaddr* local, int type, const char* port_name) +int os_socket(const struct irc_sockaddr* local, int type, const char* port_name, int family) { struct sockaddr_native addr; int size, fd; assert(local != 0); - size = sockaddr_from_irc(&addr, local, -1); + size = sockaddr_from_irc(&addr, local, -1, family); fd = socket(addr.sn_family, type, 0); if (fd < 0) { report_error(SOCKET_ERROR_MSG, port_name, errno); @@ -596,6 +604,11 @@ int os_socket(const struct irc_sockaddr* local, int type, const char* port_name) return -1; } if (local) { +#if defined(IPV6_V6ONLY) + int on = 0; + if (family == 0 && irc_in_addr_unspec(&local->addr)) + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); +#endif if (bind(fd, (struct sockaddr*)&addr, size)) { report_error(BIND_ERROR_MSG, port_name, errno); close(fd); @@ -635,7 +648,7 @@ IOResult os_connect_nonb(int fd, const struct irc_sockaddr* sin) struct sockaddr_native addr; int size; - size = sockaddr_from_irc(&addr, sin, fd); + size = sockaddr_from_irc(&addr, sin, fd, 0); if (0 == connect(fd, (struct sockaddr*) &addr, size)) return IO_SUCCESS; else if (errno == EINPROGRESS) diff --git a/ircd/s_auth.c b/ircd/s_auth.c index 03a2c26..a233f9b 100644 --- a/ircd/s_auth.c +++ b/ircd/s_auth.c @@ -826,7 +826,7 @@ static void start_auth_query(struct AuthRequest* auth) local_addr.port = 0; memcpy(&remote_addr.addr, &cli_ip(auth->client), sizeof(remote_addr.addr)); remote_addr.port = 113; - fd = os_socket(&local_addr, SOCK_STREAM, "auth query"); + fd = os_socket(&local_addr, SOCK_STREAM, "auth query", 0); if (fd < 0) { ++ServerStats->is_abad; if (IsUserPort(auth->client)) diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c index 6ce4215..b076c0e 100644 --- a/ircd/s_bsd.c +++ b/ircd/s_bsd.c @@ -207,6 +207,8 @@ static int connect_inet(struct ConfItem* aconf, struct Client* cptr) { const struct irc_sockaddr *local; IOResult result; + int family = 0; + assert(0 != aconf); assert(0 != cptr); /* @@ -215,11 +217,12 @@ static int connect_inet(struct ConfItem* aconf, struct Client* cptr) */ if (irc_in_addr_valid(&aconf->origin.addr)) local = &aconf->origin; - else if (irc_in_addr_is_ipv4(&aconf->address.addr)) + else if (irc_in_addr_is_ipv4(&aconf->address.addr)) { local = &VirtualHost_v4; - else + family = AF_INET; + } else local = &VirtualHost_v6; - cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr)); + cli_fd(cptr) = os_socket(local, SOCK_STREAM, cli_name(cptr), family); if (cli_fd(cptr) < 0) return 0; diff --git a/ircd/uping.c b/ircd/uping.c index e9f075b..62b6956 100644 --- a/ircd/uping.c +++ b/ircd/uping.c @@ -135,7 +135,7 @@ int uping_init(void) memcpy(&from, &VirtualHost_v4, sizeof(from)); from.port = atoi(UDP_PORT); - fd = os_socket(&from, SOCK_DGRAM, "IPv4 uping listener"); + fd = os_socket(&from, SOCK_DGRAM, "IPv4 uping listener", AF_INET); if (fd < 0) return -1; if (!socket_add(&upingSock_v4, uping_echo_callback, 0, SS_DATAGRAM, @@ -145,10 +145,11 @@ int uping_init(void) return -1; } +#ifdef AF_INET6 memcpy(&from, &VirtualHost_v6, sizeof(from)); from.port = atoi(UDP_PORT); - fd = os_socket(&from, SOCK_DGRAM, "IPv6 uping listener"); + fd = os_socket(&from, SOCK_DGRAM, "IPv6 uping listener", AF_INET6); if (fd < 0) return -1; if (!socket_add(&upingSock_v6, uping_echo_callback, 0, SS_DATAGRAM, @@ -157,6 +158,7 @@ int uping_init(void) close(fd); return -1; } +#endif return 0; } @@ -368,6 +370,7 @@ void uping_read(struct UPing* pptr) int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int count) { int fd; + int family = 0; struct UPing* pptr; struct irc_sockaddr *local; @@ -383,8 +386,13 @@ int uping_server(struct Client* sptr, struct ConfItem* aconf, int port, int coun if (IsUPing(sptr)) uping_cancel(sptr, sptr); /* Cancel previous ping request */ - local = irc_in_addr_is_ipv4(&aconf->address.addr) ? &VirtualHost_v4 : &VirtualHost_v6; - fd = os_socket(local, SOCK_DGRAM, "Outbound uping socket"); + if (irc_in_addr_is_ipv4(&aconf->address.addr)) { + local = &VirtualHost_v4; + family = AF_INET; + } else { + local = &VirtualHost_v6; + } + fd = os_socket(local, SOCK_DGRAM, "Outbound uping socket", family); if (fd < 0) return 0; @@ -430,7 +438,7 @@ void uping_end(struct UPing* pptr) sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING %s%s", pptr->client, pptr->name, pptr->buf); sendcmdto_one(&me, CMD_NOTICE, pptr->client, "%C :UPING Stats: " - "sent %d recvd %d ; min/avg/max = %1lu/%1lu/%1lu ms", + "sent %d recvd %d ; min/avg/max = %u/%u/%u ms", pptr->client, pptr->sent, pptr->received, pptr->ms_min, (2 * pptr->ms_ave) / (2 * pptr->received), pptr->ms_max); } else @@ -474,5 +482,3 @@ void uping_cancel(struct Client *sptr, struct Client* acptr) } ClearUPing(sptr); } - - -- 2.20.1