unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
ident_lookup.c (6120B)
1 /* src/modules/ident_lookup.c - Ident lookups (RFC1413) 2 * (C) Copyright 2019 Bram Matthys (Syzop) and the UnrealIRCd team 3 * License: GPLv2 or later 4 */ 5 #include "unrealircd.h" 6 7 ModuleHeader MOD_HEADER 8 = { 9 "ident_lookup", 10 "1.0", 11 "Ident lookups (RFC1413)", 12 "UnrealIRCd Team", 13 "unrealircd-6", 14 }; 15 16 /* Forward declarations */ 17 static EVENT(check_ident_timeout); 18 static int ident_lookup_connect(Client *client); 19 static void ident_lookup_send(int fd, int revents, void *data); 20 static void ident_lookup_receive(int fd, int revents, void *data); 21 static char *ident_lookup_parse(Client *client, char *buf); 22 23 MOD_INIT() 24 { 25 MARK_AS_OFFICIAL_MODULE(modinfo); 26 ModuleSetOptions(modinfo->handle, MOD_OPT_PERM, 1); /* needed? or not? */ 27 EventAdd(NULL, "check_ident_timeout", check_ident_timeout, NULL, 1000, 0); 28 HookAdd(modinfo->handle, HOOKTYPE_IDENT_LOOKUP, 0, ident_lookup_connect); 29 30 return MOD_SUCCESS; 31 } 32 33 MOD_LOAD() 34 { 35 return MOD_SUCCESS; 36 } 37 38 MOD_UNLOAD() 39 { 40 return MOD_SUCCESS; 41 } 42 43 44 static void ident_lookup_failed(Client *client) 45 { 46 ircstats.is_abad++; 47 if (client->local->authfd != -1) 48 { 49 fd_close(client->local->authfd); 50 --OpenFiles; 51 client->local->authfd = -1; 52 } 53 ClearIdentLookupSent(client); 54 ClearIdentLookup(client); 55 if (should_show_connect_info(client)) 56 sendto_one(client, NULL, ":%s %s", me.name, REPORT_FAIL_ID); 57 } 58 59 static EVENT(check_ident_timeout) 60 { 61 Client *client, *next; 62 63 list_for_each_entry_safe(client, next, &unknown_list, lclient_node) 64 { 65 if (IsIdentLookup(client)) 66 { 67 if (IsIdentLookupSent(client)) 68 { 69 /* set::ident::connect-timeout */ 70 if ((TStime() - client->local->creationtime) > IDENT_CONNECT_TIMEOUT) 71 ident_lookup_failed(client); 72 } else 73 { 74 /* set::ident::read-timeout */ 75 if ((TStime() - client->local->creationtime) > IDENT_READ_TIMEOUT) 76 ident_lookup_failed(client); 77 } 78 } 79 } 80 } 81 82 /** Start the ident lookup for this user */ 83 static int ident_lookup_connect(Client *client) 84 { 85 char buf[BUFSIZE]; 86 87 snprintf(buf, sizeof buf, "identd: %s", get_client_name(client, TRUE)); 88 if ((client->local->authfd = fd_socket(IsIPV6(client) ? AF_INET6 : AF_INET, SOCK_STREAM, 0, buf)) == -1) 89 { 90 ident_lookup_failed(client); 91 return 0; 92 } 93 if (++OpenFiles >= maxclients+1) 94 { 95 unreal_log(ULOG_FATAL, "io", "IDENT_ERROR_MAXCLIENTS", client, 96 "Cannot do ident connection for $client.details: All connections in use"); 97 fd_close(client->local->authfd); 98 --OpenFiles; 99 client->local->authfd = -1; 100 return 0; 101 } 102 103 if (should_show_connect_info(client)) 104 sendto_one(client, NULL, ":%s %s", me.name, REPORT_DO_ID); 105 106 set_sock_opts(client->local->authfd, client, IsIPV6(client)); 107 108 /* Bind to the IP the user got in */ 109 unreal_bind(client->local->authfd, client->local->listener->ip, 0, IsIPV6(client)); 110 111 /* And connect... */ 112 if (!unreal_connect(client->local->authfd, client->ip, 113, IsIPV6(client))) 113 { 114 ident_lookup_failed(client); 115 return 0; 116 } 117 SetIdentLookupSent(client); 118 SetIdentLookup(client); 119 120 fd_setselect(client->local->authfd, FD_SELECT_WRITE, ident_lookup_send, client); 121 122 return 0; 123 } 124 125 /** Send the request to the ident server */ 126 static void ident_lookup_send(int fd, int revents, void *data) 127 { 128 char authbuf[32]; 129 Client *client = data; 130 131 ircsnprintf(authbuf, sizeof(authbuf), "%d , %d\r\n", 132 client->local->port, 133 client->local->listener->port); 134 135 if (WRITE_SOCK(client->local->authfd, authbuf, strlen(authbuf)) != strlen(authbuf)) 136 { 137 if (ERRNO == P_EAGAIN) 138 return; /* Not connected yet, try again later */ 139 ident_lookup_failed(client); 140 return; 141 } 142 ClearIdentLookupSent(client); 143 144 fd_setselect(client->local->authfd, FD_SELECT_READ, ident_lookup_receive, client); 145 fd_setselect(client->local->authfd, FD_SELECT_WRITE, NULL, client); 146 147 return; 148 } 149 150 /** Receive the ident response */ 151 static void ident_lookup_receive(int fd, int revents, void *userdata) 152 { 153 Client *client = userdata; 154 char *ident = NULL; 155 char buf[512]; 156 int len; 157 158 len = READ_SOCK(client->local->authfd, buf, sizeof(buf)-1); 159 160 /* We received a response. We don't bother with fragmentation 161 * since that is not going to happen for such a short string. 162 * Other IRCd's think the same and this simplifies things a lot. 163 */ 164 165 /* Before we continue, we can already tear down the connection 166 * and set the appropriate flags that we are finished. 167 */ 168 fd_close(client->local->authfd); 169 --OpenFiles; 170 client->local->authfd = -1; 171 client->local->identbufcnt = 0; 172 ClearIdentLookup(client); 173 174 if (should_show_connect_info(client)) 175 sendto_one(client, NULL, ":%s %s", me.name, REPORT_FIN_ID); 176 177 if (len > 0) 178 { 179 buf[len] = '\0'; /* safe, due to the READ_SOCK() being on sizeof(buf)-1 */ 180 ident = ident_lookup_parse(client, buf); 181 } 182 if (ident) 183 { 184 strlcpy(client->ident, ident, USERLEN + 1); 185 SetIdentSuccess(client); 186 ircstats.is_asuc++; 187 } else { 188 ircstats.is_abad++; 189 } 190 return; 191 } 192 193 static char *ident_lookup_parse(Client *client, char *buf) 194 { 195 /* <port> , <port> : USERID : <OSTYPE>: <username> 196 * Actually the only thing we care about is <username> 197 */ 198 int port1 = 0, port2 = 0; 199 char *ostype = NULL; 200 char *username = NULL; 201 char *p, *p2; 202 203 skip_whitespace(&buf); 204 p = strchr(buf, ','); 205 if (!p) 206 return NULL; 207 *p = '\0'; 208 port1 = atoi(buf); /* port1 is set */ 209 210 /* <port> : USERID : <OSTYPE>: <username> */ 211 buf = p + 1; 212 p = strchr(buf, ':'); 213 if (!p) 214 return NULL; 215 *p = '\0'; 216 port2 = atoi(buf); /* port2 is set */ 217 218 /* USERID : <OSTYPE>: <username> */ 219 buf = p + 1; 220 skip_whitespace(&buf); 221 if (strncmp(buf, "USERID", 6)) 222 return NULL; 223 buf += 6; /* skip over strlen("USERID") */ 224 skip_whitespace(&buf); 225 if (*buf != ':') 226 return NULL; 227 buf++; 228 skip_whitespace(&buf); 229 230 /* <OSTYPE>: <username> */ 231 p = strchr(buf, ':'); 232 if (!p) 233 return NULL; 234 235 /* <username> */ 236 buf = p+1; 237 skip_whitespace(&buf); 238 239 /* Username */ 240 // A) Skip any ~ or ^ at the start 241 for (; *buf; buf++) 242 if (!strchr("~^", *buf) && (*buf > 32)) 243 break; 244 // B) Stop at the end, IOTW stop at newline, space, etc. 245 for (p=buf; *p; p++) 246 { 247 if (strchr("\n\r@:", *p) || (*p <= 32)) 248 { 249 *p = '\0'; 250 break; 251 } 252 } 253 if (*buf == '\0') 254 return NULL; 255 return buf; 256 }