Improve support for IPv4 vs IPv6 virtual hosts (fixes SF bugs #1087699, #1087668).
[ircu2.10.12-pk.git] / ircd / ircd_res.c
index 0ce4fd60b4c86e32407efd359d3c4c467889d0ef..c9960f6b17780c3a53123e933e38f48009bc42f6 100644 (file)
 #error this code needs to be able to address individual octets 
 #endif
 
-/** Resolver UDP socket. */
-static struct Socket res_socket;
+/** IPv4 resolver UDP socket. */
+static struct Socket res_socket_v4;
+/** IPv6 resolver UDP socket. */
+static struct Socket res_socket_v6;
 /** Next DNS lookup timeout. */
 static struct Timer res_timeout;
 /** Check for whether the resolver has been initialized yet. */
@@ -140,8 +142,6 @@ extern struct irc_sockaddr irc_nsaddr_list[IRCD_MAXNS];
 extern int irc_nscount;
 extern char irc_domain[HOSTLEN];
 
-struct irc_sockaddr ResolverAddr;
-
 /** Check whether \a inp is a nameserver we use.
  * @param[in] inp Nameserver address.
  * @return Non-zero if we trust \a inp; zero if not.
@@ -171,17 +171,24 @@ restart_resolver(void)
   if (!request_list.next)
     request_list.next = request_list.prev = &request_list;
 
-  if (!s_active(&res_socket))
+  if (!s_active(&res_socket_v4))
   {
-    struct irc_sockaddr *local;
-    int fd;
-    local = irc_in_addr_valid(&ResolverAddr.addr) ? &ResolverAddr : &VirtualHost;
-    fd = os_socket(local, SOCK_DGRAM, "Resolver UDP socket");
-    if (fd < 0) return;
-    if (!socket_add(&res_socket, res_readreply, NULL, SS_DATAGRAM,
-                    SOCK_EVENT_READABLE, fd)) return;
-    timer_init(&res_timeout);
+    int fd = os_socket(&VirtualHost_v4, SOCK_DGRAM, "Resolver UDPv4 socket");
+    if (fd >= 0)
+      socket_add(&res_socket_v4, res_readreply, NULL,
+                 SS_DATAGRAM, SOCK_EVENT_READABLE, fd);
+  }
+
+  if (!s_active(&res_socket_v6))
+  {
+    int fd = os_socket(&VirtualHost_v6, SOCK_DGRAM, "Resolver UDPv6 socket");
+    if (fd >= 0)
+      socket_add(&res_socket_v6, res_readreply, NULL,
+                 SS_DATAGRAM, SOCK_EVENT_READABLE, fd);
   }
+
+  if (s_active(&res_socket_v4) || s_active(&res_socket_v6))
+    timer_init(&res_timeout);
 }
 
 /** Append local domain to hostname if needed.
@@ -365,9 +372,11 @@ send_res_msg(const char *msg, int len, int rcount)
   if (max_queries == 0)
     max_queries = 1;
 
-  for (i = 0; i < max_queries; i++)
-    if (os_sendto_nonb(s_fd(&res_socket), msg, len, NULL, 0, &irc_nsaddr_list[i]) == IO_SUCCESS)
+  for (i = 0; i < max_queries; i++) {
+    int fd = irc_in_addr_is_ipv4(&irc_nsaddr_list[i].addr) ? s_fd(&res_socket_v4) : s_fd(&res_socket_v6);
+    if (os_sendto_nonb(fd, msg, len, NULL, 0, &irc_nsaddr_list[i]) == IO_SUCCESS)
       ++sent;
+  }
 
   return(sent);
 }
@@ -733,7 +742,7 @@ res_readreply(struct Event *ev)
   unsigned int rc;
   int answer_count;
 
-  assert(ev_socket(ev) == &res_socket);
+  assert((ev_socket(ev) == &res_socket_v4) || (ev_socket(ev) == &res_socket_v6));
   sock = ev_socket(ev);
 
   if (IO_SUCCESS != os_recvfrom_nonb(s_fd(sock), buf, sizeof(buf), &rc, &lsin)
@@ -919,55 +928,3 @@ cres_mem(struct Client* sptr)
             ":Resolver: requests %d(%d)", request_count, request_mem);
   return request_mem;
 }
-
-/** Check whether an address looks valid.
- * This means not all 0s and not all 1s.
- * @param[in] addr Address to check for validity.
- * @return Non-zero if the address looks valid.
- */
-int irc_in_addr_valid(const struct irc_in_addr *addr)
-{
-  unsigned int ii;
-  unsigned short val;
-
-  val = addr->in6_16[0];
-  if (val != 0 && val != 0xffff)
-    return 1;
-  for (ii = 1; ii < 8; ii++)
-    if (addr->in6_16[ii] != val)
-      return 1;
-  return 0;
-}
-
-/** Compare two IP addresses.
- * @param[in] a First address to compare.
- * @param[in] b Second address to compare.
- * @return Non-zero if the two addresses differ, zero if they are identical.
- */
-int irc_in_addr_cmp(const struct irc_in_addr *a, const struct irc_in_addr *b)
-{
-  if (irc_in_addr_is_ipv4(a))
-    return a->in6_16[6] != b->in6_16[6]
-        || a->in6_16[7] != b->in6_16[7]
-        || !irc_in_addr_is_ipv4(b);
-  else
-    return memcmp(a, b, sizeof(*a));
-}
-
-/** Indicate whether an IP address is a loopback address.
- * @param[in] addr Address to check.
- * @return Non-zero if the address is loopback; zero if not.
- */
-int irc_in_addr_is_loopback(const struct irc_in_addr *addr)
-{
-  if (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)
-    return 0;
-  if ((addr->in6_16[5] == 0xffff) || (addr->in6_16[5] == 0 && addr->in6_16[6] != 0))
-    return (ntohs(addr->in6_16[6]) & 0xff00) == 0x7f00;
-  else
-    return addr->in6_16[5] == 0 && addr->in6_16[6] == 0 && htons(addr->in6_16[7]) == 1;
-}