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().
This commit is contained in:
Jan Vidar Krey 2009-07-26 04:02:14 +02:00
parent 041ce7a1fb
commit 6358c7f9cd
4 changed files with 79 additions and 2 deletions

View File

@ -139,7 +139,7 @@ const char* command_get_syntax(struct commands_handler* handler)
switch (handler->args[n])
{
case 'n': strcat(args, "<nick>"); break;
case 'c': strcat(args, "<cid>"); break;
case 'c': strcat(args, "<cid>"); break;
case 'a': strcat(args, "<addr>"); 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

View File

@ -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)
{

View File

@ -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.

View File

@ -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
{