Clarify some log messages.
[srvx.git] / src / mod-sockcheck.c
index 0e038221f187ca3972504de184ed5f810c2081ba..d5888da4b81e1633cf2d39743aa63789a802b301 100644 (file)
@@ -1,5 +1,5 @@
 /* mod-sockcheck.c - insecure proxy checking
- * Copyright 2000-2004 srvx Development Team
+ * Copyright 2000-2006 srvx Development Team
  *
  * This file is part of srvx.
  *
@@ -51,11 +51,11 @@ enum sockcheck_decision {
 };
 
 typedef struct {
-    enum sockcheck_decision decision;
-    time_t last_touched;
+    irc_in_addr_t addr;
     const char *reason;
-    struct in_addr addr;
-    char hostname[16];
+    time_t last_touched;
+    enum sockcheck_decision decision;
+    char hostname[IRC_NTOP_MAX_SIZE]; /* acts as key for checked_ip_dict */
 } *sockcheck_cache_info;
 
 DECLARE_LIST(sci_list, sockcheck_cache_info);
@@ -75,7 +75,7 @@ static dict_t checked_ip_dict;
  * state and the input).  Mealy state machines require fewer states to
  * match the same input than Moore machines (where the output is only
  * a function of the current state).
- * 
+ *
  * A state is characterized by sending some data (possibly nothing),
  * waiting a certain amount of time to receive one of zero or more
  * responses, and a decision (accept, reject, continue to another
@@ -129,7 +129,7 @@ static struct {
     unsigned int max_read;
     unsigned int gline_duration;
     unsigned int max_cache_age;
-    struct sockaddr_in *local_addr;
+    struct sockaddr *local_addr;
     int local_addr_len;
 } sockcheck_conf;
 
@@ -152,7 +152,7 @@ static const struct message_entry msgtab[] = {
     { "PCMSG_DISABLED", "Proxy scanning is $bdisabled$b." },
     { "PCMSG_NOT_CACHED", "No proxycheck records exist for IP %s." },
     { "PCMSG_STATUS_CHECKING", "IP %s proxycheck state: last touched %s ago, still checking" },
-    { "PCMSG_STATUS_ACCEPTED", "IP %s proxycheck state: last touched %s ago, acepted" },
+    { "PCMSG_STATUS_ACCEPTED", "IP %s proxycheck state: last touched %s ago, accepted" },
     { "PCMSG_STATUS_REJECTED", "IP %s proxycheck state: last touched %s ago, rejected: %s" },
     { "PCMSG_STATUS_UNKNOWN", "IP %s proxycheck state: last touched %s ago, invalid status" },
     { "PCMSG_STATISTICS", "Since booting, I have checked %d clients for illicit proxies, and detected %d proxy hosts.\nI am currently checking %d clients (out of %d max) and have a backlog of %d more to start on.\nI currently have %d hosts cached.\nI know how to detect %d kinds of proxies." },
@@ -174,8 +174,8 @@ static void
 sockcheck_list_append(struct sockcheck_list *list, struct sockcheck_state *new_item)
 {
     if (list->used == list->size) {
-       list->size <<= 1;
-       list->list = realloc(list->list, list->size*sizeof(list->list[0]));
+        list->size <<= 1;
+        list->list = realloc(list->list, list->size*sizeof(list->list[0]));
     }
     list->list[list->used++] = new_item;
 }
@@ -203,11 +203,10 @@ sockcheck_list_unref(struct sockcheck_list *list)
 static void
 sockcheck_issue_gline(sockcheck_cache_info sci)
 {
-    char *target = alloca(3+strlen(sci->hostname));
-    strcpy(target, "*@");
-    strcpy(target+2, sci->hostname);
-    log_module(PC_LOG, LOG_INFO, "Issuing gline for client at IP %s hostname %s: %s", inet_ntoa(sci->addr), sci->hostname, sci->reason);
-    gline_add("ProxyCheck", target, sockcheck_conf.gline_duration, sci->reason, now, 1);
+    char addr[IRC_NTOP_MAX_SIZE + 2] = {'*', '@', '\0'};
+    irc_ntop(addr + 2, sizeof(addr) - 2, &sci->addr);
+    log_module(PC_LOG, LOG_INFO, "Issuing gline for client at %s: %s", addr + 2, sci->reason);
+    gline_add("ProxyCheck", addr, sockcheck_conf.gline_duration, sci->reason, now, now, 1);
 }
 
 static struct sockcheck_client *
@@ -230,7 +229,9 @@ sockcheck_free_client(struct sockcheck_client *client)
     if (SOCKCHECK_DEBUG) {
         log_module(PC_LOG, LOG_INFO, "Goodbye %s (%p)!  I set you free!", client->addr->hostname, client);
     }
-    if (client->fd) ioset_close(client->fd->fd, 1);
+    verify(client);
+    ioset_close(client->fd, 1);
+    client->fd = NULL;
     sockcheck_list_unref(client->tests);
     free(client->read);
     free(client->resp_state);
@@ -248,6 +249,7 @@ sockcheck_timeout_client(void *data)
     if (SOCKCHECK_DEBUG) {
         log_module(PC_LOG, LOG_INFO, "Client %s timed out.", client->addr->hostname);
     }
+    verify(client);
     sockcheck_advance(client, client->state->responses.used-1);
 }
 
@@ -258,7 +260,8 @@ sockcheck_print_client(const struct sockcheck_client *client)
     log_module(PC_LOG, LOG_INFO, "client %p: { addr = %p { decision = %s; last_touched = "FMT_TIME_T"; reason = %s; hostname = \"%s\" }; "
         "test_index = %d; state = %p { port = %d; type = %s; template = \"%s\"; ... }; "
         "fd = %p(%d); read = %p; read_size = %d; read_used = %d; read_pos = %d; }",
-        client, client->addr, decs[client->addr->decision], client->addr->last_touched, client->addr->reason, client->addr->hostname,
+        client, client->addr, decs[client->addr->decision], client->addr->last_touched,
+        client->addr->reason, client->addr->hostname,
         client->test_index, client->state,
         (client->state ? client->state->port : 0),
         (client->state ? decs[client->state->type] : "N/A"),
@@ -284,13 +287,9 @@ expand_var(const struct sockcheck_client *client, char var, char **p_expansion,
     extern struct cManagerNode cManager;
     const char *expansion;
     unsigned int exp_length;
-#ifndef __SOLARIS__
-    u_int32_t exp4;
-    u_int16_t exp2;
-#else
     uint32_t exp4;
     uint16_t exp2;
-#endif
+
     /* expand variable */
     switch (var) {
     case 'c':
@@ -298,30 +297,30 @@ expand_var(const struct sockcheck_client *client, char var, char **p_expansion,
         exp_length = strlen(expansion);
         break;
     case 'i':
-       exp4 = client->addr->addr.s_addr;
-       exp_length = sizeof(exp4);
-       expansion = (char*)&exp4;
-       break;
+        exp4 = client->addr->addr.in6_32[3];
+        exp_length = sizeof(exp4);
+        expansion = (char*)&exp4;
+        break;
     case 'p':
-       exp2 = htons(client->state->port);
-       exp_length = sizeof(exp2);
-       expansion = (char*)&exp2;
-       break;
+        exp2 = htons(client->state->port);
+        exp_length = sizeof(exp2);
+        expansion = (char*)&exp2;
+        break;
     case 'u':
-       expansion = cManager.uplink->host;
-       exp_length = strlen(expansion);
-       break;
+        expansion = cManager.uplink->host;
+        exp_length = strlen(expansion);
+        break;
     default:
         log_module(PC_LOG, LOG_WARNING, "Request to expand unknown sockcheck variable $%c, using empty expansion.", var);
-       expansion = "";
-       exp_length = 0;
+        expansion = "";
+        exp_length = 0;
     }
     if (p_expansion) {
-       *p_expansion = malloc(exp_length);
-       memcpy(*p_expansion, expansion, exp_length);
+        *p_expansion = malloc(exp_length);
+        memcpy(*p_expansion, expansion, exp_length);
     }
     if (p_exp_length) {
-       *p_exp_length = exp_length;
+        *p_exp_length = exp_length;
     }
 }
 
@@ -403,7 +402,7 @@ sockcheck_elaborate_state(struct sockcheck_client *client)
     }
     for (nn=0; nn<client->state->responses.used; nn++) {
         /* Set their resp_state to the start of the response. */
-       client->resp_state[nn] = client->state->responses.list[nn]->template;
+        client->resp_state[nn] = client->state->responses.list[nn]->template;
         /* If it doesn't require reading, take it now. */
         if (client->resp_state[nn] && !*client->resp_state[nn]) {
             if (SOCKCHECK_DEBUG) {
@@ -430,32 +429,32 @@ sockcheck_decide(struct sockcheck_client *client, enum sockcheck_decision decisi
     client->addr->last_touched = now;
     switch (decision) {
     case ACCEPT:
-       /* do nothing */
+        /* do nothing */
         if (SOCKCHECK_DEBUG) {
-            log_module(PC_LOG, LOG_INFO, "Proxy check passed for client at IP %s hostname %s.", inet_ntoa(client->addr->addr), client->addr->hostname);
+            log_module(PC_LOG, LOG_INFO, "Proxy check passed for client at %s.", client->addr->hostname);
         }
         break;
     case REJECT:
-       client->addr->reason = client->state->template;
-       proxies_detected++;
-       sockcheck_issue_gline(client->addr);
+        client->addr->reason = client->state->template;
+        proxies_detected++;
+        sockcheck_issue_gline(client->addr);
         if (SOCKCHECK_DEBUG) {
-            log_module(PC_LOG, LOG_INFO, "Proxy check rejects client at IP %s hostname %s (%s)", inet_ntoa(client->addr->addr), client->addr->hostname, client->addr->reason);
+            log_module(PC_LOG, LOG_INFO, "Proxy check rejects client at %s (%s)", client->addr->hostname, client->addr->reason);
         }
-       /* Don't compare test_index != 0 directly, because somebody
-        * else may have reordered the tests already. */
-       if (client->tests->list[client->test_index] != tests->list[0]) {
-           struct sockcheck_list *new_tests = sockcheck_list_clone(tests);
-           struct sockcheck_state *new_first = client->tests->list[client->test_index];
+        /* Don't compare test_index != 0 directly, because somebody
+         * else may have reordered the tests already. */
+        if (client->tests->list[client->test_index] != tests->list[0]) {
+            struct sockcheck_list *new_tests = sockcheck_list_clone(tests);
+            struct sockcheck_state *new_first = client->tests->list[client->test_index];
             for (n=0; (n<tests->used) && (tests->list[n] != new_first); n++) ;
             for (; n>0; n--) new_tests->list[n] = new_tests->list[n-1];
-           new_tests->list[0] = new_first;
-           sockcheck_list_unref(tests);
-           tests = new_tests;
-       }
+            new_tests->list[0] = new_first;
+            sockcheck_list_unref(tests);
+            tests = new_tests;
+        }
         break;
     default:
-       log_module(PC_LOG, LOG_ERROR, "BUG: sockcheck_decide(\"%s\", %d): unrecognized decision.", client->addr->hostname, decision);
+        log_module(PC_LOG, LOG_ERROR, "BUG: sockcheck_decide(\"%s\", %d): unrecognized decision.", client->addr->hostname, decision);
     }
     n = client->client_index;
     sockcheck_free_client(client);
@@ -472,21 +471,22 @@ sockcheck_advance(struct sockcheck_client *client, unsigned int next_state)
 {
     struct sockcheck_state *ns;
 
+    verify(client);
     timeq_del(0, sockcheck_timeout_client, client, TIMEQ_IGNORE_WHEN);
     if (SOCKCHECK_DEBUG) {
         unsigned int n, m;
         char buffer[201];
         static const char *hexmap = "0123456789ABCDEF";
-       log_module(PC_LOG, LOG_INFO, "sockcheck_advance(%s) following response %d (type %d) of %d.", client->addr->hostname, next_state, client->state->responses.list[next_state]->next->type, client->state->responses.used);
-       for (n=0; n<client->read_used; n++) {
-           for (m=0; (m<(sizeof(buffer)-1)>>1) && ((n+m) < client->read_used); m++) {
-               buffer[m << 1] = hexmap[client->read[n+m] >> 4];
-               buffer[m << 1 | 1] = hexmap[client->read[n+m] & 15];
-           }
-           buffer[m<<1] = 0;
-           log_module(PC_LOG, LOG_INFO, " .. read data: %s", buffer);
-           n += m;
-       }
+        log_module(PC_LOG, LOG_INFO, "sockcheck_advance(%s) following response %d (type %d) of %d.", client->addr->hostname, next_state, client->state->responses.list[next_state]->next->type, client->state->responses.used);
+        for (n=0; n<client->read_used; n++) {
+            for (m=0; (m<(sizeof(buffer)-1)>>1) && ((n+m) < client->read_used); m++) {
+                buffer[m << 1] = hexmap[client->read[n+m] >> 4];
+                buffer[m << 1 | 1] = hexmap[client->read[n+m] & 15];
+            }
+            buffer[m<<1] = 0;
+            log_module(PC_LOG, LOG_INFO, " .. read data: %s", buffer);
+            n += m;
+        }
         sockcheck_print_client(client);
     }
 
@@ -522,70 +522,71 @@ sockcheck_readable(struct io_fd *fd)
     unsigned int nn;
     int res;
 
+    verify(client);
     res = read(fd->fd, client->read + client->read_used, client->read_size - client->read_used);
     if (res < 0) {
         switch (res = errno) {
         default:
-           log_module(PC_LOG, LOG_ERROR, "BUG: sockcheck_readable(%d/%s): read() returned errno %d (%s)", fd->fd, client->addr->hostname, errno, strerror(errno));
+            log_module(PC_LOG, LOG_ERROR, "BUG: sockcheck_readable(%d/%s): read() returned errno %d (%s)", fd->fd, client->addr->hostname, errno, strerror(errno));
         case EAGAIN:
             return;
         case ECONNRESET:
             sockcheck_advance(client, client->state->responses.used - 1);
             return;
-       }
+        }
     } else if (res == 0) {
         sockcheck_advance(client, client->state->responses.used - 1);
         return;
     } else {
-       client->read_used += res;
+        client->read_used += res;
     }
     if (SOCKCHECK_DEBUG) {
         unsigned int n, m;
         char buffer[201];
         static const char *hexmap = "0123456789ABCDEF";
-       for (n=0; n<client->read_used; n++) {
-           for (m=0; (m<(sizeof(buffer)-1)>>1) && ((n+m) < client->read_used); m++) {
-               buffer[m << 1] = hexmap[client->read[n+m] >> 4];
-               buffer[m << 1 | 1] = hexmap[client->read[n+m] & 15];
-           }
-           buffer[m<<1] = 0;
-           log_module(PC_LOG, LOG_INFO, "read %d bytes data: %s", client->read_used, buffer);
-           n += m;
-       }
+        for (n=0; n<client->read_used; n++) {
+            for (m=0; (m<(sizeof(buffer)-1)>>1) && ((n+m) < client->read_used); m++) {
+                buffer[m << 1] = hexmap[client->read[n+m] >> 4];
+                buffer[m << 1 | 1] = hexmap[client->read[n+m] & 15];
+            }
+            buffer[m<<1] = 0;
+            log_module(PC_LOG, LOG_INFO, "read %d bytes data: %s", client->read_used, buffer);
+            n += m;
+        }
     }
 
     /* See if what's been read matches any of the expected responses */
     while (client->read_pos < client->read_used) {
         unsigned int last_pos = client->read_pos;
-       char bleh;
-       const char *resp_state;
+        char bleh;
+        const char *resp_state;
 
-       for (nn=0; nn<(client->state->responses.used-1); nn++) {
+        for (nn=0; nn<(client->state->responses.used-1); nn++) {
             char *expected;
             unsigned int exp_length = 1, free_exp = 0;
-           /* compare against possible target */
-           resp_state = client->resp_state[nn];
-           if (resp_state == NULL) continue;
-           switch (*resp_state) {
-           case '=': 
+            /* compare against possible target */
+            resp_state = client->resp_state[nn];
+            if (resp_state == NULL) continue;
+            switch (*resp_state) {
+            case '=':
                 bleh = resp_state[1];
                 expected = &bleh;
                 break;
-           case '.':
+            case '.':
                 /* any character passes */
                 client->read_pos++;
                 exp_length = 0;
                 break;
-           case '0': case '1': case '2': case '3': case '4':
-           case '5': case '6': case '7': case '8': case '9':
-           case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-           case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-               bleh = hexvals[(unsigned char)resp_state[0]] << 4
+            case '0': case '1': case '2': case '3': case '4':
+            case '5': case '6': case '7': case '8': case '9':
+            case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+            case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+                bleh = hexvals[(unsigned char)resp_state[0]] << 4
                     | hexvals[(unsigned char)resp_state[1]];
                 expected = &bleh;
-               break;
-           case '$':
-               expand_var(client, resp_state[1], &expected, &exp_length);
+                break;
+            case '$':
+                expand_var(client, resp_state[1], &expected, &exp_length);
                 free_exp = 1;
                 break;
             }
@@ -600,27 +601,27 @@ sockcheck_readable(struct io_fd *fd)
                 resp_state -= 2;
             }
             if (free_exp) free(expected);
-           if (resp_state) {
-               client->resp_state[nn] = resp_state = resp_state + 2;
-               if (!*resp_state) {
+            if (resp_state) {
+                client->resp_state[nn] = resp_state = resp_state + 2;
+                if (!*resp_state) {
                     sockcheck_advance(client, nn);
-                   return;
-               }
-           } else {
-               client->resp_state[nn] = NULL;
-           }
-       }
+                    return;
+                }
+            } else {
+                client->resp_state[nn] = NULL;
+            }
+        }
         if (last_pos == client->read_pos) break;
     }
 
     /* nothing seemed to match.  what now? */
     if (client->read_used >= client->read_size) {
-       /* we got more data than we expected to get .. don't read any more */
+        /* we got more data than we expected to get .. don't read any more */
         if (SOCKCHECK_DEBUG) {
             log_module(PC_LOG, LOG_INFO, "Buffer filled (unmatched) for client %s", client->addr->hostname);
         }
         sockcheck_advance(client, client->state->responses.used-1);
-       return;
+        return;
     }
 }
 
@@ -628,6 +629,7 @@ static void
 sockcheck_connected(struct io_fd *fd, int rc)
 {
     struct sockcheck_client *client = fd->data;
+    verify(client);
     client->fd = fd;
     switch (rc) {
     default:
@@ -642,7 +644,6 @@ sockcheck_connected(struct io_fd *fd, int rc)
         return;
     case 0: break;
     }
-    fd->wants_reads = 1;
     if (SOCKCHECK_DEBUG) {
         log_module(PC_LOG, LOG_INFO, "Connected: to %s port %d.", client->addr->hostname, client->state->port);
     }
@@ -654,15 +655,15 @@ sockcheck_begin_test(struct sockcheck_client *client)
 {
     struct io_fd *io_fd;
 
-    if (client->fd) {
-        ioset_close(client->fd->fd, 1);
-        client->fd = NULL;
-    }
+    verify(client);
+    ioset_close(client->fd, 1);
+    client->fd = NULL;
     do {
         client->state = client->tests->list[client->test_index];
         client->read_pos = 0;
         client->read_used = 0;
-        client->fd = io_fd = ioset_connect((struct sockaddr*)sockcheck_conf.local_addr, sizeof(struct sockaddr), client->addr->hostname, client->state->port, 0, client, sockcheck_connected);
+        io_fd = ioset_connect(sockcheck_conf.local_addr, sockcheck_conf.local_addr_len, client->addr->hostname, client->state->port, 0, client, sockcheck_connected);
+        client->fd = io_fd;
         if (!io_fd) {
             client->test_index++;
             continue;
@@ -690,24 +691,25 @@ sockcheck_start_client(unsigned int idx)
         return;
     }
     memmove(pending_sci_list.list, pending_sci_list.list+1,
-           (--pending_sci_list.used)*sizeof(pending_sci_list.list[0]));
+            (--pending_sci_list.used)*sizeof(pending_sci_list.list[0]));
     sockcheck_num_clients++;
     if (!tests) return;
     client = client_list[idx] = sockcheck_alloc_client(sci);
-    log_module(PC_LOG, LOG_INFO, "Proxy-checking client at %s (%s) as client %d (%p) of %d.", inet_ntoa(sci->addr), sci->hostname, idx, client, sockcheck_num_clients);
+    log_module(PC_LOG, LOG_INFO, "Proxy-checking client at %s as client %d (%p) of %d.", sci->hostname, idx, client, sockcheck_num_clients);
     client->test_rep = 0;
     client->client_index = idx;
     sockcheck_begin_test(client);
 }
 
 void
-sockcheck_queue_address(struct in_addr addr)
+sockcheck_queue_address(irc_in_addr_t addr)
 {
     sockcheck_cache_info sci;
-    char *ipstr=inet_ntoa(addr);
+    const char *ipstr = irc_ntoa(&addr);
 
     sci = dict_find(checked_ip_dict, ipstr, NULL);
     if (sci) {
+        verify(sci);
         switch (sci->decision) {
         case CHECKING:
             /* We are already checking this host. */
@@ -770,29 +772,29 @@ sockcheck_create_response(const char *key, void *data, void *extra)
     response_list_append(&parent->responses, resp);
     /* now figure out how to create resp->next */
     if ((str = GET_RECORD_QSTRING(rd))) {
-       if (!ircncasecmp(str, "reject", 6)) {
-           resp->next->type = REJECT;
-       } else if (!ircncasecmp(str, "accept", 6)) {
-           resp->next->type = ACCEPT;
-       } else {
-           log_module(PC_LOG, LOG_ERROR, "Error: unknown sockcheck decision `%s', defaulting to accept.", str);
-           resp->next->type = ACCEPT;
-       }
-       if (str[6]) {
-           resp->next->template = strdup(str+7);
-       } else {
-           resp->next->template = strdup("No explanation given");
-       }
+        if (!ircncasecmp(str, "reject", 6)) {
+            resp->next->type = REJECT;
+        } else if (!ircncasecmp(str, "accept", 6)) {
+            resp->next->type = ACCEPT;
+        } else {
+            log_module(PC_LOG, LOG_ERROR, "Error: unknown sockcheck decision `%s', defaulting to accept.", str);
+            resp->next->type = ACCEPT;
+        }
+        if (str[6]) {
+            resp->next->template = strdup(str+7);
+        } else {
+            resp->next->template = strdup("No explanation given");
+        }
     } else if ((resps = GET_RECORD_OBJECT(rd))) {
-       resp->next->type = CHECKING;
-       response_list_init(&resp->next->responses);
-       if (*end == ':') {
-           resp->next->template = strdup(end+1);
+        resp->next->type = CHECKING;
+        response_list_init(&resp->next->responses);
+        if (*end == ':') {
+            resp->next->template = strdup(end+1);
             if (!sockcheck_check_template(resp->next->template, 0)) _exit(1);
-       } else {
-           resp->next->template = strdup("");
-       }
-       dict_foreach(resps, sockcheck_create_response, resp->next);
+        } else {
+            resp->next->template = strdup("");
+        }
+        dict_foreach(resps, sockcheck_create_response, resp->next);
     }
     return 0;
 }
@@ -819,7 +821,7 @@ sockcheck_create_test(const char *key, void *data, void *extra)
     new_test->type = CHECKING;
     response_list_init(&new_test->responses);
     if (!(object = GET_RECORD_OBJECT(rd))) {
-       log_module(PC_LOG, LOG_ERROR, "Error: misformed sockcheck test `%s', skipping it.", key);
+        log_module(PC_LOG, LOG_ERROR, "Error: misformed sockcheck test `%s', skipping it.", key);
         free(new_test);
         return 1;
     }
@@ -839,29 +841,29 @@ sockcheck_create_test(const char *key, void *data, void *extra)
         }
     }
     if (!new_test->template) {
-       log_module(PC_LOG, LOG_ERROR, "Error: misformed sockcheck test `%s', skipping it.", key);
-       free(new_test);
-       return 1;
+        log_module(PC_LOG, LOG_ERROR, "Error: misformed sockcheck test `%s', skipping it.", key);
+        free(new_test);
+        return 1;
     }
     dict_foreach(object, sockcheck_create_response, new_test);
     /* If none of the responses have template "other", create a
      * default response that goes to accept. */
     for (n=0; n<new_test->responses.used; n++) {
-       if (!strcmp(new_test->responses.list[n]->template, "other")) break;
+        if (!strcmp(new_test->responses.list[n]->template, "other")) break;
     }
     if (n == new_test->responses.used) {
-       rd = alloc_record_data_qstring("accept");
-       sockcheck_create_response("other", rd, new_test);
-       free_record_data(rd);
+        rd = alloc_record_data_qstring("accept");
+        sockcheck_create_response("other", rd, new_test);
+        free_record_data(rd);
     } else if (n != (new_test->responses.used - 1)) {
-       struct sockcheck_response *tmp;
-       /* switch the response for "other" to the end */
-       tmp = new_test->responses.list[new_test->responses.used - 1];
-       new_test->responses.list[new_test->responses.used - 1] = new_test->responses.list[n];
-       new_test->responses.list[n] = tmp;
+        struct sockcheck_response *tmp;
+        /* switch the response for "other" to the end */
+        tmp = new_test->responses.list[new_test->responses.used - 1];
+        new_test->responses.list[new_test->responses.used - 1] = new_test->responses.list[n];
+        new_test->responses.list[n] = tmp;
     }
     if (new_test->responses.used > max_responses) {
-       max_responses = new_test->responses.used;
+        max_responses = new_test->responses.used;
     }
     sockcheck_list_append(extra, new_test);
     return 0;
@@ -874,14 +876,14 @@ sockcheck_read_tests(void)
     struct sockcheck_list *new_tests;
     test_db = parse_database(SOCKCHECK_TEST_DB);
     if (!test_db)
-       return;
+        return;
     if (dict_size(test_db) > 0) {
-       new_tests = sockcheck_list_alloc(dict_size(test_db));
-       dict_foreach(test_db, sockcheck_create_test, new_tests);
-       if (tests) sockcheck_list_unref(tests);
-       tests = new_tests;
+        new_tests = sockcheck_list_alloc(dict_size(test_db));
+        dict_foreach(test_db, sockcheck_create_test, new_tests);
+        if (tests) sockcheck_list_unref(tests);
+        tests = new_tests;
     } else {
-       log_module(PC_LOG, LOG_ERROR, "%s was empty - disabling sockcheck.", SOCKCHECK_TEST_DB);
+        log_module(PC_LOG, LOG_ERROR, "%s was empty - disabling sockcheck.", SOCKCHECK_TEST_DB);
     }
     free_database(test_db);
 }
@@ -891,12 +893,12 @@ sockcheck_free_state(struct sockcheck_state *state)
 {
     unsigned int n;
     if (state->type == CHECKING) {
-       for (n=0; n<state->responses.used; n++) {
-           free((char*)state->responses.list[n]->template);
-           sockcheck_free_state(state->responses.list[n]->next);
-           free(state->responses.list[n]);
-       }
-       response_list_clean(&state->responses);
+        for (n=0; n<state->responses.used; n++) {
+            free((char*)state->responses.list[n]->template);
+            sockcheck_free_state(state->responses.list[n]->next);
+            free(state->responses.list[n]);
+        }
+        response_list_clean(&state->responses);
     }
     free((char*)state->template);
     free(state);
@@ -914,8 +916,8 @@ sockcheck_add_test(const char *desc)
         return reason;
     new_tests = sockcheck_list_clone(tests);
     if (sockcheck_create_test(name, rd, new_tests)) {
-       sockcheck_list_unref(new_tests);
-       return "Sockcheck test parse error";
+        sockcheck_list_unref(new_tests);
+        return "Sockcheck test parse error";
     }
     sockcheck_list_unref(tests);
     tests = new_tests;
@@ -938,12 +940,12 @@ sockcheck_shutdown(void)
     dict_delete(checked_ip_dict);
     sci_list_clean(&pending_sci_list);
     if (tests)
-       for (n=0; n<tests->used; n++)
-           sockcheck_free_state(tests->list[n]);
+        for (n=0; n<tests->used; n++)
+            sockcheck_free_state(tests->list[n]);
     sockcheck_list_unref(tests);
     if (sockcheck_conf.local_addr) {
-       free(sockcheck_conf.local_addr);
-       sockcheck_conf.local_addr_len = 0;
+        free(sockcheck_conf.local_addr);
+        sockcheck_conf.local_addr_len = 0;
     }
 }
 
@@ -999,8 +1001,8 @@ static MODCMD_FUNC(cmd_defproxy)
     const char *reason;
 
     if ((reason = sockcheck_add_test(unsplit_string(argv+1, argc-1, NULL)))) {
-       reply("PCMSG_PROXY_DEFINITION_FAILED", reason);
-       return 0;
+        reply("PCMSG_PROXY_DEFINITION_FAILED", reason);
+        return 0;
     }
     reply("PCMSG_PROXY_DEFINITION_SUCCEEDED");
     return 1;
@@ -1009,25 +1011,24 @@ static MODCMD_FUNC(cmd_defproxy)
 static MODCMD_FUNC(cmd_hostscan)
 {
     unsigned int n;
-    unsigned long addr;
-    struct in_addr ipaddr;
-    char hnamebuf[64];
+    irc_in_addr_t ipaddr;
+    char hnamebuf[IRC_NTOP_MAX_SIZE];
 
     for (n=1; n<argc; n++) {
-       struct userNode *un = GetUserH(argv[n]);
+        struct userNode *un = GetUserH(argv[n]);
 
         if (un) {
-            if ((un->ip.s_addr == 0) || (ntohl(un->ip.s_addr) == INADDR_LOOPBACK)) {
+            if (!irc_in_addr_is_valid(un->ip)
+                || irc_in_addr_is_loopback(un->ip)) {
                 reply("PCMSG_UNSCANNABLE_IP", un->nick);
             } else {
-                strcpy(hnamebuf, inet_ntoa(un->ip));
+                irc_ntop(hnamebuf, sizeof(hnamebuf), &un->ip);
                 sockcheck_queue_address(un->ip);
                 reply("PCMSG_ADDRESS_QUEUED", hnamebuf);
             }
         } else {
             char *scanhost = argv[n];
-            if (getipbyname(scanhost, &addr)) {
-                ipaddr.s_addr = htonl(addr);
+            if (irc_pton(&ipaddr, NULL, scanhost)) {
                 sockcheck_queue_address(ipaddr);
                 reply("PCMSG_ADDRESS_QUEUED", scanhost);
             } else {
@@ -1041,24 +1042,24 @@ static MODCMD_FUNC(cmd_hostscan)
 static MODCMD_FUNC(cmd_clearhost)
 {
     unsigned int n;
-    char hnamebuf[64];
+    char hnamebuf[IRC_NTOP_MAX_SIZE];
 
     for (n=1; n<argc; n++) {
         struct userNode *un = GetUserH(argv[n]);
         const char *scanhost;
 
         if (un) {
-            strcpy(hnamebuf, inet_ntoa(un->ip));
+            irc_ntop(hnamebuf, sizeof(hnamebuf), &un->ip);
             scanhost = hnamebuf;
         } else {
             scanhost = argv[n];
         }
         switch (sockcheck_uncache_host(scanhost)) {
         case -1:
-           reply("PCMSG_CHECKING_ADDRESS", scanhost);
+            reply("PCMSG_CHECKING_ADDRESS", scanhost);
             break;
         case 0:
-           reply("PCMSG_NOT_REMOVED_FROM_CACHE", scanhost);
+            reply("PCMSG_NOT_REMOVED_FROM_CACHE", scanhost);
             break;
         default:
             reply("PCMSG_REMOVED_FROM_CACHE", scanhost);
@@ -1098,8 +1099,8 @@ static MODCMD_FUNC(cmd_stats_proxycheck)
 static int
 sockcheck_new_user(struct userNode *user) {
     /* If they have a bum IP, or are bursting in, don't proxy-check or G-line them. */
-    if (user->ip.s_addr
-        && (ntohl(user->ip.s_addr) != INADDR_LOOPBACK)
+    if (irc_in_addr_is_valid(user->ip)
+        && !irc_in_addr_is_loopback(user->ip)
         && !user->uplink->burst)
         sockcheck_queue_address(user->ip);
     return 0;
@@ -1122,6 +1123,7 @@ static void
 sockcheck_read_conf(void)
 {
     dict_t my_node;
+    struct addrinfo *ai;
     const char *str;
 
     /* set the defaults here in case the entire record is missing */
@@ -1135,37 +1137,28 @@ sockcheck_read_conf(void)
     }
     /* now try to read from the conf database */
     if ((my_node = conf_get_data("modules/sockcheck", RECDB_OBJECT))) {
-       str = database_get_data(my_node, "max_sockets", RECDB_QSTRING);
-       if (str) sockcheck_conf.max_clients = strtoul(str, NULL, 0);
-       str = database_get_data(my_node, "max_clients", RECDB_QSTRING);
-       if (str) sockcheck_conf.max_clients = strtoul(str, NULL, 0);
-       str = database_get_data(my_node, "max_read", RECDB_QSTRING);
-       if (str) sockcheck_conf.max_read = strtoul(str, NULL, 0);
-       str = database_get_data(my_node, "max_cache_age", RECDB_QSTRING);
-       if (str) sockcheck_conf.max_cache_age = ParseInterval(str);
+        str = database_get_data(my_node, "max_sockets", RECDB_QSTRING);
+        if (str) sockcheck_conf.max_clients = strtoul(str, NULL, 0);
+        str = database_get_data(my_node, "max_clients", RECDB_QSTRING);
+        if (str) sockcheck_conf.max_clients = strtoul(str, NULL, 0);
+        str = database_get_data(my_node, "max_read", RECDB_QSTRING);
+        if (str) sockcheck_conf.max_read = strtoul(str, NULL, 0);
+        str = database_get_data(my_node, "max_cache_age", RECDB_QSTRING);
+        if (str) sockcheck_conf.max_cache_age = ParseInterval(str);
         str = database_get_data(my_node, "gline_duration", RECDB_QSTRING);
         if (str) sockcheck_conf.gline_duration = ParseInterval(str);
-       str = database_get_data(my_node, "address", RECDB_QSTRING);
-       if (str) {
-           struct sockaddr_in *sin;
-           unsigned long addr;
-
-           sockcheck_conf.local_addr_len = sizeof(*sin);
-           if (getipbyname(str, &addr)) {
-               sin = malloc(sockcheck_conf.local_addr_len);
-               sin->sin_family = AF_INET;
-               sin->sin_port = 0;
-               sin->sin_addr.s_addr = addr;
-#ifdef HAVE_SIN_LEN
-               sin->sin_len = 0;
-#endif
-               memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
-               sockcheck_conf.local_addr = sin;
-           } else {
-               log_module(PC_LOG, LOG_ERROR, "Error: Unable to get host named `%s', not checking a specific address.", str);
-               sockcheck_conf.local_addr = NULL;
-           }
-       }
+        str = database_get_data(my_node, "address", RECDB_QSTRING);
+        if (!getaddrinfo(str, NULL, NULL, &ai)) {
+            sockcheck_conf.local_addr_len = ai->ai_addrlen;
+            sockcheck_conf.local_addr = calloc(1, ai->ai_addrlen);
+            memcpy(sockcheck_conf.local_addr, ai->ai_addr, ai->ai_addrlen);
+            freeaddrinfo(ai);
+        } else {
+            sockcheck_conf.local_addr_len = 0;
+            sockcheck_conf.local_addr = NULL;
+            if (str)
+                log_module(PC_LOG, LOG_ERROR, "Error: Unable to get host named `%s', not checking from a specific address.", str);
+        }
     }
 }