From 6358c7f9cd003529e463e66216f4339c045ab500 Mon Sep 17 00:00:00 2001 From: Jan Vidar Krey Date: Sun, 26 Jul 2009 04:02:14 +0200 Subject: [PATCH] Fix bug #45: [Request] Whoip command. Rewrote patches from Zoltan to support ip ranges and multiple results per IP. Needed to make sure IPv6 mapped IPv4 addresses were converted to proper IPv4 addresses after accept(). --- src/core/commands.c | 46 +++++++++++++++++++++++++++++++++++++++++- src/core/usermanager.c | 15 ++++++++++++++ src/core/usermanager.h | 7 +++++++ src/network/network.c | 13 +++++++++++- 4 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/core/commands.c b/src/core/commands.c index bbaeed1..16c010a 100644 --- a/src/core/commands.c +++ b/src/core/commands.c @@ -139,7 +139,7 @@ const char* command_get_syntax(struct commands_handler* handler) switch (handler->args[n]) { case 'n': strcat(args, ""); break; - case 'c': strcat(args, ""); break; + case 'c': strcat(args, ""); break; case 'a': strcat(args, ""); break; } } @@ -307,6 +307,49 @@ static int command_getip(struct hub_info* hub, struct hub_user* user, struct hub return command_status(hub, user, cmd, tmp); } +static int command_whoip(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) +{ + char* address = list_get_first(cmd->args); + struct ip_range range; + struct linked_list* users; + struct hub_user* u; + int ret = 0; + + ret = ip_convert_address_to_range(address, &range); + if (!ret) + return command_status(hub, user, cmd, "Invalid IP address/range/mask"); + + users = (struct linked_list*) list_create(); + ret = uman_get_user_by_addr(hub, users, &range); + + if (!ret) + { + list_destroy(users); + return command_status(hub, user, cmd, "No users found."); + } + + char tmp[128]; + snprintf(tmp, 128, "Found %d match%s:", (int) ret, ((ret != 1) ? "es" : "")); + + char* buffer = hub_malloc(((MAX_NICK_LEN + 1) * ret) + strlen(tmp) + 2); + buffer[0] = 0; + strcat(buffer, tmp); + strcat(buffer, "\n"); + + u = (struct hub_user*) list_get_first(users); + while (u) + { + strcat(buffer, u->id.nick); + strcat(buffer, "\n"); + u = (struct hub_user*) list_get_next(users); + } + + ret = command_status(hub, user, cmd, buffer); + hub_free(buffer); + return ret; +} + + #ifdef CRASH_DEBUG static int command_crash(struct hub_info* hub, struct hub_user* user, struct hub_command* cmd) { @@ -372,6 +415,7 @@ static struct commands_handler command_handlers[] = { { "shutdown", 8, 0, cred_admin, command_shutdown, "Shutdown hub." }, { "myip", 4, 0, cred_guest, command_myip, "Show your own IP." }, { "getip", 5, "n", cred_operator, command_getip, "Show IP address for a user" }, + { "whoip", 5, "a", cred_operator, command_whoip, "Show users matching IP range" }, #ifdef CRASH_DEBUG { "crash", 5, 0, cred_admin, command_crash, "Crash the hub (DEBUG)." }, #endif diff --git a/src/core/usermanager.c b/src/core/usermanager.c index 1265677..8f850b4 100644 --- a/src/core/usermanager.c +++ b/src/core/usermanager.c @@ -223,6 +223,21 @@ struct hub_user* uman_get_user_by_nick(struct hub_info* hub, const char* nick) return NULL; } +size_t uman_get_user_by_addr(struct hub_info* hub, struct linked_list* users, struct ip_range* range) +{ + size_t num = 0; + struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */ + while (user) + { + if (ip_in_range(&user->net.ipaddr, range)) + { + list_append(users, user); + num++; + } + user = (struct hub_user*) list_get_next(hub->users->list); + } + return num; +} int uman_send_user_list(struct hub_info* hub, struct hub_user* target) { diff --git a/src/core/usermanager.h b/src/core/usermanager.h index 17b3390..8832270 100644 --- a/src/core/usermanager.h +++ b/src/core/usermanager.h @@ -99,6 +99,13 @@ extern struct hub_user* uman_get_user_by_cid(struct hub_info* hub, const char* c */ extern struct hub_user* uman_get_user_by_nick(struct hub_info* hub, const char* nick); +/** + * Lookup users based on an ip address range. + * + * @return The number of users matching the addressess, or -1 on error (mask is wrong). + */ +extern size_t uman_get_user_by_addr(struct hub_info* hub, struct linked_list* users, struct ip_range* range); + /** * Send the user list of connected clients to 'user'. * Usually part of the login process. diff --git a/src/network/network.c b/src/network/network.c index 924e967..e68bb8b 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -337,7 +337,18 @@ int net_accept(int fd, struct ip_addr_encap* ipaddr) ipaddr->af = addr4->sin_family; if (ipaddr->af == AF_INET6) { - memcpy(&ipaddr->internal_ip_data.in6, &addr6->sin6_addr, sizeof(struct in6_addr)); + char address[INET6_ADDRSTRLEN+1] = { 0, }; + net_address_to_string(AF_INET6, (void*) &addr6->sin6_addr, address, INET6_ADDRSTRLEN+1); + if (!strncmp(address, "::ffff:", 7)) + { + /* Hack to convert IPv6 mapped IPv4 addresses to true IPv4 addresses */ + net_string_to_address(AF_INET, address + 7, (void*) &ipaddr->internal_ip_data.in); + ipaddr->af = AF_INET; + } + else + { + memcpy(&ipaddr->internal_ip_data.in6, &addr6->sin6_addr, sizeof(struct in6_addr)); + } } else {