1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-07-01 22:06:37 +02:00
Files
unrealircd/src/modules/ident_lookup.c
T
Bram Matthys 00aee86b66 Clean up and document all functions in src/socket.c. Also,
remove calls to and the finish_auth() function, which did nothing.
2019-10-25 10:51:18 +02:00

233 lines
5.5 KiB
C

/* src/modules/ident_lookup.c - Ident lookups (RFC1413)
* (C) Copyright 2019 Bram Matthys (Syzop) and the UnrealIRCd team
* License: GPLv2
*/
#include "unrealircd.h"
ModuleHeader MOD_HEADER
= {
"ident_lookup",
"1.0",
"Ident lookups (RFC1413)",
"UnrealIRCd Team",
"unrealircd-5",
};
/* Forward declarations */
static EVENT(check_ident_timeout);
static int ident_lookup_connect(Client *client);
static void ident_lookup_send(int fd, int revents, void *data);
static void ident_lookup_receive(int fd, int revents, void *data);
static char *ident_lookup_parse(Client *client, char *buf);
MOD_INIT()
{
MARK_AS_OFFICIAL_MODULE(modinfo);
ModuleSetOptions(modinfo->handle, MOD_OPT_PERM, 1); /* needed? or not? */
EventAdd(NULL, "check_ident_timeout", check_ident_timeout, NULL, 1000, 0);
HookAdd(modinfo->handle, HOOKTYPE_IDENT_LOOKUP, 0, ident_lookup_connect);
return MOD_SUCCESS;
}
MOD_LOAD()
{
return MOD_SUCCESS;
}
MOD_UNLOAD()
{
return MOD_SUCCESS;
}
static void ident_lookup_failed(Client *client)
{
Debug((DEBUG_NOTICE, "ident_lookup_failed() for %p", client));
ircstats.is_abad++;
if (client->local->authfd != -1)
{
fd_close(client->local->authfd);
--OpenFiles;
client->local->authfd = -1;
}
ClearIdentLookupSent(client);
ClearIdentLookup(client);
if (should_show_connect_info(client))
sendto_one(client, NULL, ":%s %s", me.name, REPORT_FAIL_ID);
}
static EVENT(check_ident_timeout)
{
Client *client, *next;
list_for_each_entry_safe(client, next, &unknown_list, lclient_node)
{
if (IsIdentLookup(client) && ((TStime() - client->local->firsttime) > IDENT_CONNECT_TIMEOUT))
ident_lookup_failed(client);
}
}
/** Start the ident lookup for this user */
static int ident_lookup_connect(Client *client)
{
char buf[BUFSIZE];
snprintf(buf, sizeof buf, "identd: %s", get_client_name(client, TRUE));
if ((client->local->authfd = fd_socket(IsIPV6(client) ? AF_INET6 : AF_INET, SOCK_STREAM, 0, buf)) == -1)
{
ident_lookup_failed(client);
return 0;
}
if (++OpenFiles >= maxclients+1)
{
sendto_ops("Can't allocate fd, too many connections.");
fd_close(client->local->authfd);
--OpenFiles;
client->local->authfd = -1;
return 0;
}
if (should_show_connect_info(client))
sendto_one(client, NULL, ":%s %s", me.name, REPORT_DO_ID);
set_sock_opts(client->local->authfd, client, IsIPV6(client));
/* Bind to the IP the user got in */
unreal_bind(client->local->authfd, client->local->listener->ip, 0, IsIPV6(client));
/* And connect... */
if (!unreal_connect(client->local->authfd, client->ip, 113, IsIPV6(client)))
{
ident_lookup_failed(client);
return 0;
}
SetIdentLookupSent(client);
SetIdentLookup(client);
fd_setselect(client->local->authfd, FD_SELECT_WRITE, ident_lookup_send, client);
return 0;
}
/** Send the request to the ident server */
static void ident_lookup_send(int fd, int revents, void *data)
{
char authbuf[32];
Client *client = data;
ircsnprintf(authbuf, sizeof(authbuf), "%d , %d\r\n",
client->local->port,
client->local->listener->port);
if (WRITE_SOCK(client->local->authfd, authbuf, strlen(authbuf)) != strlen(authbuf))
{
if (ERRNO == P_EAGAIN)
return; /* Not connected yet, try again later */
ident_lookup_failed(client);
return;
}
ClearIdentLookupSent(client);
fd_setselect(client->local->authfd, FD_SELECT_READ, ident_lookup_receive, client);
fd_setselect(client->local->authfd, FD_SELECT_WRITE, NULL, client);
return;
}
/** Receive the ident response */
static void ident_lookup_receive(int fd, int revents, void *userdata)
{
Client *client = userdata;
char *ident = NULL;
char buf[512];
int len;
len = READ_SOCK(client->local->authfd, buf, sizeof(buf)-1);
if (ERRNO == P_EAGAIN)
return; /* Try again later */
/* We received a response. We don't bother with fragmentation
* since that is not going to happen for such a short string.
* Other IRCd's think the same and this simplifies things a lot.
*/
/* Before we continue, we can already tear down the connection
* and set the appropriate flags that we are finished.
*/
fd_close(client->local->authfd);
--OpenFiles;
client->local->authfd = -1;
client->local->identbufcnt = 0;
ClearIdentLookup(client);
if (should_show_connect_info(client))
sendto_one(client, NULL, ":%s %s", me.name, REPORT_FIN_ID);
if (len > 0)
{
buf[len] = '\0'; /* safe, due to the READ_SOCK() being on sizeof(buf)-1 */
ident = ident_lookup_parse(client, buf);
}
if (ident)
{
strlcpy(client->ident, ident, USERLEN + 1);
SetIdentSuccess(client);
ircstats.is_asuc++;
} else {
ircstats.is_abad++;
}
return;
}
static char *ident_lookup_parse(Client *client, char *buf)
{
/* <port> , <port> : USERID : <OSTYPE>: <username>
* Actually the only thing we care about is <username>
*/
int port1 = 0, port2 = 0;
char *ostype = NULL;
char *username = NULL;
char *p, *p2;
/* First port */
p = strstr(buf, " , ");
if (!p)
return NULL;
*p = '\0';
port1 = atoi(buf);
buf = p+ strlen(" , ");
/* Second port */
p = strstr(buf, " : USERID : ");
if (!p)
return NULL;
*p = '\0';
port2 = atoi(buf);
buf = p+ strlen(" : USERID : ");
/* USERID */
p = strstr(buf, " : ");
if (!p)
return NULL;
*p = '\0';
ostype = buf;
buf = p+ strlen(" : ");
/* Username */
// A) Skip any ~ or ^ at the start
for (; *buf; buf++)
if (!strchr("~^", *buf) && (*buf > 32))
break;
// B) Stop at the end, IOTW stop at newline, space, etc.
for (p=buf; *p; p++)
if (strchr("\n\r@:", *p) || (*p <= 32))
{
*p = '\0';
break;
}
if (*buf == '\0')
return NULL;
return buf;
}