Add IPv6 support.
[srvx.git] / src / proto-common.c
index 22334026c9e412cebe6b658ef78dbcb7d942f95d..b5e5118a02e246706df003fbfdc5f21fb122dd52 100644 (file)
@@ -134,7 +134,7 @@ create_socket_client(struct uplinkNode *target)
 
     log_module(MAIN_LOG, LOG_INFO, "Connecting to %s:%i...", addr, port);
 
-    socket_io_fd = ioset_connect((struct sockaddr*)cManager.uplink->bind_addr, sizeof(struct sockaddr), addr, port, 1, 0, NULL);
+    socket_io_fd = ioset_connect(cManager.uplink->bind_addr, cManager.uplink->bind_addr_len, addr, port, 1, 0, NULL);
     if (!socket_io_fd) {
         log_module(MAIN_LOG, LOG_ERROR, "Connection to uplink failed: %s (%d)", strerror(errno), errno);
         target->state = DISCONNECTED;
@@ -440,16 +440,17 @@ privmsg_chan_helper(struct chanNode *cn, void *data)
         mn->idle_since = now;
 
     /* Never send a NOTICE to a channel to one of the services */
-    if (!pd->is_notice && cf->func && GetUserMode(cn, cf->service))
+    if (!pd->is_notice && cf->func
+        && ((cn->modes & MODE_REGISTERED) || GetUserMode(cn, cf->service)))
         cf->func(pd->user, cn, pd->text+1, cf->service);
 
     /* This catches *all* text sent to the channel that the services server sees */
     for (x = 0; x < ALLCHANMSG_FUNCS_MAX; x++) {
        cf = (struct chanmsg_func *)&allchanmsg_funcs[x];
        if (!cf->func)
-         break; /* end of list */
+           break; /* end of list */
        else
-       cf->func(pd->user, cn, pd->text, cf->service);
+           cf->func(pd->user, cn, pd->text, cf->service);
     }
 }
 
@@ -568,9 +569,10 @@ mod_chanmode_apply(struct userNode *who, struct chanNode *channel, struct mod_ch
              * to be more specific than an existing ban.
              */
             for (jj=0; jj<channel->banlist.used; ++jj) {
-                if (match_ircglobs(change->args[ii].u.hostmask, channel->banlist.list[jj]->ban)) {
-                    banList_remove(&channel->banlist, channel->banlist.list[jj]);
-                    free(channel->banlist.list[jj]);
+                bn = channel->banlist.list[jj];
+                if (match_ircglobs(change->args[ii].u.hostmask, bn->ban)) {
+                    banList_remove(&channel->banlist, bn);
+                    free(bn);
                     jj--;
                 }
             }
@@ -585,10 +587,11 @@ mod_chanmode_apply(struct userNode *who, struct chanNode *channel, struct mod_ch
             break;
         case MODE_REMOVE|MODE_BAN:
             for (jj=0; jj<channel->banlist.used; ++jj) {
-                if (strcmp(channel->banlist.list[jj]->ban, change->args[ii].u.hostmask))
+                bn = channel->banlist.list[jj];
+                if (strcmp(bn->ban, change->args[ii].u.hostmask))
                     continue;
-                free(channel->banlist.list[jj]);
-                banList_remove(&channel->banlist, channel->banlist.list[jj]);
+                free(bn);
+                banList_remove(&channel->banlist, bn);
                 break;
             }
             break;
@@ -651,8 +654,8 @@ irc_make_chanmode(struct chanNode *chan, char *out)
 char *
 generate_hostmask(struct userNode *user, int options)
 {
-    char *nickname, *ident, *hostname;
-    char *mask;
+    irc_in_addr_t ip;
+    char *nickname, *ident, *hostname, *mask;
     int len, ii;
 
     /* figure out string parts */
@@ -677,32 +680,21 @@ generate_hostmask(struct userNode *user, int options)
     } else if (IsHiddenHost(user) && user->handle_info && hidden_host_suffix && !(options & GENMASK_NO_HIDING)) {
         hostname = alloca(strlen(user->handle_info->handle) + strlen(hidden_host_suffix) + 2);
         sprintf(hostname, "%s.%s", user->handle_info->handle, hidden_host_suffix);
-    } else if (options & GENMASK_STRICT_HOST) {
-        if (options & GENMASK_BYIP)
-            hostname = inet_ntoa(user->ip);
-    } else if ((options & GENMASK_BYIP) || !hostname[strspn(hostname, "0123456789.")]) {
-        /* Should generate an IP-based hostmask.  By popular acclaim, a /16
-         * hostmask is used by default. */
-        unsigned masked_ip, mask, masklen;
-        masklen = 16;
-        mask = ~0 << masklen;
-        masked_ip = ntohl(user->ip.s_addr) & mask;
-        hostname = alloca(32);
-        if (options & GENMASK_SRVXMASK) {
-            sprintf(hostname, "%d.%d.%d.%d/%d", (masked_ip>>24)&0xFF, (masked_ip>>16)&0xFF, (masked_ip>>8)&0xFF, masked_ip&0xFF, masklen);
+    } else if (options & GENMASK_STRICT_HOST && options & GENMASK_BYIP) {
+        hostname = (char*)irc_ntoa(&user->ip);
+    } else if ((options & GENMASK_BYIP) || irc_pton(&ip, NULL, hostname)) {
+        /* Should generate an IP-based hostmask. */
+        hostname = alloca(IRC_NTOP_MAX_SIZE);
+        hostname[IRC_NTOP_MAX_SIZE-1] = '\0';
+        if (irc_in_addr_is_ipv4(user->ip)) {
+            /* By popular acclaim, a /16 hostmask is used. */
+            sprintf(hostname, "%d.%d.*", user->ip.in6_8[12], user->ip.in6_8[13]);
+        } else if (irc_in_addr_is_ipv6(user->ip)) {
+            /* Who knows what the default mask should be?  Use a /48 to start with. */
+            sprintf(hostname, "%x:%x:%x:*", user->ip.in6[0], user->ip.in6[1], user->ip.in6[2]);
         } else {
-            int ofs = 0;
-            for (ii=0; ii<4; ii++) {
-                if (masklen) {
-                    ofs += sprintf(hostname+ofs, "%d.", (masked_ip>>24)&0xFF);
-                    masklen -= 8;
-                    masked_ip <<= 8;
-                } else {
-                    ofs += sprintf(hostname+ofs, "*.");
-                }
-            }
-            /* Truncate the last . */
-            hostname[ofs-1] = 0;
+            /* Unknown type; just copy IP directly. */
+            irc_ntop(hostname, IRC_NTOP_MAX_SIZE, &user->ip);
         }
     } else {
         int cnt;