X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fmod-sockcheck.c;h=d5888da4b81e1633cf2d39743aa63789a802b301;hb=7fe401a165cdfb1f102cf3d545e1dffb3896a2e9;hp=0e038221f187ca3972504de184ed5f810c2081ba;hpb=4d6ca4a951af494f04357fec18caaf3eaed0b67a;p=srvx.git diff --git a/src/mod-sockcheck.c b/src/mod-sockcheck.c index 0e03822..d5888da 100644 --- a/src/mod-sockcheck.c +++ b/src/mod-sockcheck.c @@ -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; nnstate->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; (nused) && (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; nread_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; nread_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; nread_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; nread_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; nresponses.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; nresponses.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; nresponses.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; nused; n++) - sockcheck_free_state(tests->list[n]); + for (n=0; nused; 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; nip.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; nip)); + 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); + } } }