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 {