Fix /uping on IPv6-enabled FreeBSD builds (#1435373).
authorMichael Poole <mdpoole@troilus.org>
Tue, 14 Mar 2006 03:45:52 +0000 (03:45 +0000)
committerMichael Poole <mdpoole@troilus.org>
Tue, 14 Mar 2006 03:45:52 +0000 (03:45 +0000)
git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/branches/u2_10_12_branch@1626 c9e4aea6-c8fd-4c43-8297-357d70d61c8c

ChangeLog
include/ircd_osdep.h
include/res.h
ircd/ircd_res.c
ircd/listener.c
ircd/os_generic.c
ircd/s_auth.c
ircd/s_bsd.c
ircd/uping.c

index e1ad25fbffbc73dd41d4120647da25e8533e965d..6efb7d01b0e66040ea3ba72a8344499465b22948 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2006-03-02  Michael Poole <mdpoole@troilus.org>
+
+       * 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 <mdpoole@troilus.org>
 
        * ircd/m_silence.c (apply_silence): Refuse to apply silences for
index 6e53fc95e3f237f9a45c16cff9b308b3087f15f6..89579c01b8f4d0d10c1843b57dab68ab9bdf1d5a 100644 (file)
@@ -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,
index 50f93245daca7e30d470c2e539cd556095598e93..2bf44c3db866af0b30cd7f4f0badf8f6d0877e6f 100644 (file)
@@ -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] \
index 02ca4e47ddd6ccfc7134aae1e55431295badbbc5..b7464cd7dfa5e9afb50f2fc0689aed046af564d3 100644 (file)
@@ -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);
index d51d319d383c7bd30c9837d81fd2379e4436e7ee..fa188d96693111c055a76b65a715ed3866796d9a 100644 (file)
@@ -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;
   /*
index c4622094ebd6a65e9cca9a2588781e49baf1cd06..bdcda7c32a6e7bf75ca1e8a0e28c3f3c75f36268 100644 (file)
  */
 #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
 
 #include <unistd.h>
 #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)
index 03a2c26c5ea273aa93fa77fda5edebe2076e0745..a233f9bd7b45a985584aa4a61c364a1a5f3cb9e2 100644 (file)
@@ -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))
index 6ce42154deed60315319f03f0d949cdfe5be15c0..b076c0ec36f50387c59c7a1973959fb0e0bc30ac 100644 (file)
@@ -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;
 
index e9f075be7c4283c853aa991ceaa87c068ac4b8a4..62b69560db348c636e148f2f967d99e487746c6f 100644 (file)
@@ -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);
 }
-
-