1 /* +------------------------------------+
2 * | Inspire Internet Relay Chat Daemon |
3 * +------------------------------------+
5 * InspIRCd: (C) 2002-2007 InspIRCd Development Team
6 * See: http://www.inspircd.org/wiki/index.php/Credits
8 * This program is free but copyrighted software; see
9 * the file COPYING for details.
11 * ---------------------------------------------------
19 /* $ModDesc: Provides support for RFC1413 ident lookups */
21 class IdentRequestSocket : public InspSocket
27 IdentRequestSocket(InspIRCd *Server, userrec *user, int timeout, const std::string &bindip)
28 : InspSocket(Server, user->GetIPString(), 113, false, timeout, bindip), user(user)
30 original_fd = user->GetFd();
31 Instance->Log(DEBUG, "Ident request against user with fd %d", original_fd);
34 virtual bool OnConnected()
36 if (Instance->SE->GetRef(original_fd) == user)
38 Instance->Log(DEBUG,"Oh dear, our user has gone AWOL on fd %d", original_fd);
42 /* Both sockaddr_in and sockaddr_in6 can be safely casted to sockaddr, especially since the
43 * only members we use are in a part of the struct that should always be identical (at the
46 Instance->Log(DEBUG, "Sending ident request to %s", user->GetIPString());
49 sockaddr_in laddr, raddr;
51 sockaddr_in6 laddr, raddr;
54 socklen_t laddrsz = sizeof(laddr);
55 socklen_t raddrsz = sizeof(raddr);
57 if ((getsockname(user->GetFd(), (sockaddr*) &laddr, &laddrsz) != 0) || (getpeername(user->GetFd(), (sockaddr*) &raddr, &raddrsz) != 0))
67 snprintf(req, sizeof(req), "%d,%d\r\n", ntohs(raddr.sin_port), ntohs(laddr.sin_port));
69 snprintf(req, sizeof(req), "%d,%d\r\n", ntohs(raddr.sin6_port), ntohs(laddr.sin6_port));
77 virtual void OnClose()
79 /* There used to be a check against the fd table here, to make sure the user hadn't been
80 * deleted but not yet had their socket closed or something along those lines, dated june
81 * 2006. Since we added the global cull list and such, I don't *think* that is necessary
83 * -- YES IT IS!!!! DO NOT REMOVE IT, THIS IS WHAT THE WARNING ABOVE THE OLD CODE SAID :P
85 if (Instance->SE->GetRef(original_fd) == user)
87 Instance->Log(DEBUG,"Oh dear, our user has gone AWOL on fd %d", original_fd);
91 if (*user->ident == '~' && user->GetExt("ident_socket"))
92 user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead", user->ident);
95 Instance->next_call = Instance->Time();
98 virtual void OnError(InspSocketError e)
100 if (Instance->SE->GetRef(original_fd) == user)
102 Instance->Log(DEBUG,"Oh dear, our user has gone AWOL on fd %d", original_fd);
106 // Quick check to make sure that this hasn't been sent ;)
107 if (*user->ident == '~' && user->GetExt("ident_socket"))
108 user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead", user->ident);
111 Instance->next_call = Instance->Time();
114 virtual bool OnDataReady()
116 if (Instance->SE->GetRef(original_fd) == user)
118 Instance->Log(DEBUG,"Oh dear, our user has gone AWOL on fd %d", original_fd);
122 char *ibuf = this->Read();
129 // We don't really need to buffer for incomplete replies here, since IDENT replies are
130 // extremely short - there is *no* sane reason it'd be in more than one packet
132 irc::sepstream sep(ibuf, ':');
134 for (int i = 0; sep.GetToken(token); i++)
136 // We only really care about the 4th portion
140 char ident[IDENTMAX + 2];
142 // Truncate the ident at any characters we don't like, skip leading spaces
144 for (const char *j = token.c_str(); *j && (k < IDENTMAX + 1); j++)
149 // Rules taken from InspIRCd::IsIdent
150 if (((*j >= 'A') && (*j <= '}')) || ((*j >= '0') && (*j <= '9')) || (*j == '-') || (*j == '.'))
161 // Redundant check with IsIdent, in case that changes and this doesn't (paranoia!)
162 if (*ident && Instance->IsIdent(ident))
164 strlcpy(user->ident, ident, IDENTMAX);
165 user->WriteServ("NOTICE Auth :*** Found your ident: %s", user->ident);
166 Instance->next_call = Instance->Time();
178 user->Shrink("ident_socket");
180 if (user->GetExt("ident_socket_fd", delfd))
183 user->Shrink("ident_socket_fd");
188 class ModuleIdent : public Module
193 ModuleIdent(InspIRCd *Me)
199 virtual ~ModuleIdent()
203 virtual Version GetVersion()
205 return Version(1, 1, 1, 0, VF_VENDOR, API_VERSION);
208 virtual void Implements(char *List)
210 List[I_OnRehash] = List[I_OnUserRegister] = List[I_OnCheckReady] = List[I_OnCleanup] = List[I_OnUserDisconnect] = 1;
213 virtual void OnRehash(userrec *user, const std::string ¶m)
215 ConfigReader MyConf(ServerInstance);
217 RequestTimeout = MyConf.ReadInteger("ident", "timeout", 0, true);
222 virtual int OnUserRegister(userrec *user)
224 /* userrec::ident is currently the username field from USER; with m_ident loaded, that
225 * should be preceded by a ~. The field is actually IDENTMAX+2 characters wide. */
226 memmove(user->ident + 1, user->ident, IDENTMAX);
227 user->ident[0] = '~';
228 // Ensure that it is null terminated
229 user->ident[IDENTMAX + 1] = '\0';
231 user->WriteServ("NOTICE Auth :*** Looking up your ident...");
233 // Get the IP that the user is connected to, and bind to that for the outgoing connection
239 socklen_t laddrsz = sizeof(laddr);
241 if (getsockname(user->GetFd(), (sockaddr*) &laddr, &laddrsz) != 0)
243 user->WriteServ("NOTICE Auth :*** Could not find your ident, using %s instead.", user->ident);
248 const char *ip = inet_ntoa(laddr.sin_addr);
250 char ip[INET6_ADDRSTRLEN + 1];
251 inet_ntop(laddr.sin6_family, &laddr.sin6_addr, ip, INET6_ADDRSTRLEN);
254 IdentRequestSocket *isock = new IdentRequestSocket(ServerInstance, user, RequestTimeout, ip);
255 if (isock->GetFd() > -1)
257 user->Extend("ident_socket_fd", new int(isock->GetFd()));
258 user->Extend("ident_socket", isock);
261 if (ServerInstance->SocketCull.find(isock) == ServerInstance->SocketCull.end())
262 ServerInstance->SocketCull[isock] = isock;
266 virtual bool OnCheckReady(userrec *user)
268 return (!user->GetExt("ident_socket"));
271 virtual void OnCleanup(int target_type, void *item)
273 if (target_type == TYPE_USER)
275 IdentRequestSocket *isock;
276 userrec *user = (userrec*)item;
277 if (user->GetExt("ident_socket", isock))
280 if (user->GetExt("ident_socket_fd", fd) && (ServerInstance->SE->GetRef(*fd) == isock))
282 user->Shrink("ident_socket_fd");
290 virtual void OnUserDisconnect(userrec *user)
292 IdentRequestSocket *isock;
293 if (user->GetExt("ident_socket", isock))
296 if (user->GetExt("ident_socket_fd", fd) && (ServerInstance->SE->GetRef(*fd) == isock))
298 user->Shrink("ident_socket_fd");
306 MODULE_INIT(ModuleIdent);