X-Git-Url: https://jfr.im/git/irc/evilnet/x3.git/blobdiff_plain/cc5d8f7fd0dd5ef035eb4288f8a1f4045172c8d1..890866b04ff1e3e033b4ab11b276991596481b21:/src/mod-sockcheck.c diff --git a/src/mod-sockcheck.c b/src/mod-sockcheck.c index 42ed8b4..1ba86fb 100644 --- a/src/mod-sockcheck.c +++ b/src/mod-sockcheck.c @@ -3,9 +3,9 @@ * * This file is part of x3. * - * srvx is free software; you can redistribute it and/or modify + * x3 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -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); @@ -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." }, @@ -203,11 +203,11 @@ 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, 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, 1, 1); + } static struct sockcheck_client * @@ -228,11 +228,11 @@ static void 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); + log_module(PC_LOG, LOG_INFO, "Goodbye %s (%p)! I set you free!", client->addr->hostname, (void*)client); } verify(client); - if (client->fd) - ioset_close(client->fd->fd, 1); + ioset_close(client->fd, 1); + client->fd = NULL; sockcheck_list_unref(client->tests); free(client->read); free(client->resp_state); @@ -261,13 +261,14 @@ 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->test_index, client->state, + (void*)client, (void*)client->addr, decs[client->addr->decision], client->addr->last_touched, + client->addr->reason, client->addr->hostname, + client->test_index, (void*)client->state, (client->state ? client->state->port : 0), (client->state ? decs[client->state->type] : "N/A"), (client->state ? client->state->template : "N/A"), - client->fd, (client->fd ? client->fd->fd : 0), - client->read, client->read_size, client->read_used, client->read_pos); + (void*)client->fd, (client->fd ? client->fd->fd : 0), + (void*)client->read, client->read_size, client->read_used, client->read_pos); } static char hexvals[256] = { @@ -287,13 +288,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': @@ -301,7 +298,7 @@ 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; + exp4 = client->addr->addr.in6_32[3]; exp_length = sizeof(exp4); expansion = (char*)&exp4; break; @@ -410,7 +407,7 @@ sockcheck_elaborate_state(struct sockcheck_client *client) /* If it doesn't require reading, take it now. */ if (client->resp_state[nn] && !*client->resp_state[nn]) { if (SOCKCHECK_DEBUG) { - log_module(PC_LOG, LOG_INFO, "Skipping straight to easy option %d for %p.", nn, client); + log_module(PC_LOG, LOG_INFO, "Skipping straight to easy option %d for %p.", nn, (void*)client); } sockcheck_advance(client, nn); return; @@ -435,7 +432,7 @@ sockcheck_decide(struct sockcheck_client *client, enum sockcheck_decision decisi case ACCEPT: /* 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: @@ -443,7 +440,7 @@ sockcheck_decide(struct sockcheck_client *client, enum sockcheck_decision decisi 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. */ @@ -513,7 +510,7 @@ sockcheck_advance(struct sockcheck_client *client, unsigned int next_state) } break; default: - log_module(PC_LOG, LOG_ERROR, "BUG: unknown next-state type %d (after %p).", ns->type, client->state); + log_module(PC_LOG, LOG_ERROR, "BUG: unknown next-state type %d (after %p).", ns->type, (void*)client->state); break; } } @@ -648,7 +645,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); } @@ -661,15 +657,14 @@ sockcheck_begin_test(struct sockcheck_client *client) struct io_fd *io_fd; verify(client); - if (client->fd) { - ioset_close(client->fd->fd, 1); - client->fd = NULL; - } + 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; @@ -677,7 +672,7 @@ sockcheck_begin_test(struct sockcheck_client *client) io_fd->readable_cb = sockcheck_readable; timeq_add(now + client->state->timeout, sockcheck_timeout_client, client); if (SOCKCHECK_DEBUG) { - log_module(PC_LOG, LOG_INFO, "Starting proxy check on %s:%d (test %d) with fd %d (%p).", client->addr->hostname, client->state->port, client->test_index, io_fd->fd, io_fd); + log_module(PC_LOG, LOG_INFO, "Starting proxy check on %s:%d (test %d) with fd %d (%p).", client->addr->hostname, client->state->port, client->test_index, io_fd->fd, (void*)io_fd); } return; } while (client->test_index < client->tests->used); @@ -701,17 +696,17 @@ sockcheck_start_client(unsigned int idx) 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, (void*)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) { @@ -931,7 +926,7 @@ sockcheck_add_test(const char *desc) } static void -sockcheck_shutdown(void) +sockcheck_shutdown(UNUSED_ARG(void *extra)) { unsigned int n; @@ -1017,25 +1012,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 { @@ -1049,14 +1043,14 @@ 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]; @@ -1104,10 +1098,10 @@ static MODCMD_FUNC(cmd_stats_proxycheck) } static int -sockcheck_new_user(struct userNode *user) { +sockcheck_new_user(struct userNode *user, UNUSED_ARG(void *extra)) { /* 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; @@ -1130,6 +1124,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 */ @@ -1154,25 +1149,18 @@ sockcheck_read_conf(void) 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, "bind_address", RECDB_QSTRING); + if (!str) 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); } } } @@ -1182,7 +1170,7 @@ sockcheck_init(void) { PC_LOG = log_register_type("ProxyCheck", "file:proxycheck.log"); conf_register_reload(sockcheck_read_conf); - reg_exit_func(sockcheck_shutdown); + reg_exit_func(sockcheck_shutdown, NULL); _sockcheck_init(); message_register_table(msgtab); @@ -1191,7 +1179,7 @@ sockcheck_init(void) modcmd_register(sockcheck_module, "hostscan", cmd_hostscan, 2, 0, "level", "650", NULL); modcmd_register(sockcheck_module, "clearhost", cmd_clearhost, 2, 0, "level", "650", NULL); modcmd_register(sockcheck_module, "stats proxycheck", cmd_stats_proxycheck, 0, 0, NULL); - reg_new_user_func(sockcheck_new_user); + reg_new_user_func(sockcheck_new_user, NULL); return 1; }