summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/modules/m_ident.cpp304
1 files changed, 84 insertions, 220 deletions
diff --git a/src/modules/m_ident.cpp b/src/modules/m_ident.cpp
index 1ba2247fa..1e9933516 100644
--- a/src/modules/m_ident.cpp
+++ b/src/modules/m_ident.cpp
@@ -35,217 +35,102 @@ using namespace std;
/* $ModDesc: Provides support for RFC 1413 ident lookups */
-Server *Srv;
+// Version 1.5.0.0 - Updated to use InspSocket, faster and neater.
-// State engine constants. We have three states,
-// connecting, waiting for data, and finished.
-
-#define IDENT_STATE_CONNECT 1
-#define IDENT_STATE_WAITDATA 2
-#define IDENT_STATE_DONE 3
-
-// Ident lookups are done by attaching an RFC1413 class to the
-// userrec record using the Extensible system.
-// The RFC1413 class is written especially for this module but
-// it should be relatively standalone for anyone else who wishes
-// to have a nonblocking ident lookup in a program :)
-// the class operates on a simple state engine, each state of the
-// connection incrementing a state counter, leading through to
-// a concluding state which terminates the lookup.
-
-class RFC1413
+class RFC1413 : public InspSocket
{
protected:
- int fd; // file descriptor
+ Server* Srv; // Server* class used for core communications
userrec* u; // user record that the lookup is associated with
- sockaddr_in addr; // address we're connecting to
- in_addr addy; // binary ip address
- int state; // state (this class operates on a state engine)
- char ibuf[MAXBUF]; // input buffer
sockaddr_in sock_us; // our port number
sockaddr_in sock_them; // their port number
socklen_t uslen; // length of our port number
socklen_t themlen; // length of their port number
- int nrecv; // how many bytes we've received
- time_t timeout_end; // how long until the operation times out
- bool timeout; // true if we've timed out and should bail
char ident_request[128]; // buffer used to make up the request string
public:
// The destructor makes damn sure the socket is freed :)
-
- ~RFC1413()
+ RFC1413(userrec* user, int maxtime, Server* S) : InspSocket(user->host, 113, false, maxtime)
{
- if (this->fd != -1)
- {
- shutdown(this->fd,2);
- close(this->fd);
- this->fd = -1;
- }
+ Srv->Log(DEBUG,"Ident: associated with user "+std::string(user->nick));
+ u = user;
+ Srv = S;
}
- // establish an ident connection, maxtime is the time to spend trying
- // returns true if successful, false if something was catastrophically wrong.
- // note that failed connects are not reported here but detected in RFC1413::Poll()
- // as the socket is nonblocking
-
- bool Connect(userrec* user, int maxtime)
+ virtual void OnTimeout()
{
- timeout_end = time(NULL)+maxtime;
- timeout = false;
- if ((this->fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- // theres been a boo-boo... no more fd's left for us, woe is me!
- Srv->Log(DEBUG,"Ident: socket failed for: "+std::string(user->ip));
- return false;
- }
- inet_aton(user->ip,&addy);
- addr.sin_family = AF_INET;
- addr.sin_addr = addy;
- addr.sin_port = htons(113);
-
- int flags;
- flags = fcntl(this->fd, F_GETFL, 0);
- fcntl(this->fd, F_SETFL, flags | O_NONBLOCK);
-
- if(connect(this->fd, (sockaddr*)&this->addr,sizeof(this->addr)) == -1)
- {
- // theres been an error, but EINPROGRESS just means 'right, im on it, call me later'
- if (errno != EINPROGRESS)
- {
- // ... so that error isnt fatal, like the rest.
- Srv->Log(DEBUG,"Ident: connect failed for: "+std::string(user->ip));
- shutdown(this->fd,2);
- close(this->fd);
- this->fd = -1;
- return false;
- }
- }
- Srv->Log(DEBUG,"Ident: successful connect associated with user "+std::string(user->nick));
- this->u = user;
- this->state = IDENT_STATE_CONNECT;
- return true;
+ // When we timeout, the connection failed within the allowed timeframe,
+ // so we just display a notice, and tidy off the ident_data.
+ u->Shrink("ident_data");
+ Srv->SendServ(u->fd,"NOTICE "+std::string(u->nick)+" :*** Could not find your ident, using "+std::string(u->ident)+" instead.");
}
- // Poll the socket to see if we have an ident result, and if we do apply it to the user.
- // returns false if we cannot poll for some reason (e.g. timeout).
-
- bool Poll()
+ virtual bool OnDataReady()
{
- if (time(NULL) > timeout_end)
- {
- timeout = true;
- Srv->SendServ(u->fd,"NOTICE "+std::string(u->nick)+" :*** Could not find your ident, using "+std::string(u->ident)+" instead.");
- shutdown(this->fd,2);
- close(this->fd);
- this->fd = -1;
- return false;
- }
- pollfd polls;
- polls.fd = this->fd;
- if (state == IDENT_STATE_CONNECT)
- {
- // during state IDENT_STATE_CONNECT (leading up to the connect)
- // we're watching for writeability
- polls.events = POLLOUT;
- }
- else
+ std::string databuf = this->Read();
+ if (databuf != "")
{
- // the rest of the time we're waiting for data
- // back on the socket, or a socket close
- polls.events = POLLIN;
- }
- int ret = poll(&polls,1,1);
-
- if (ret > 0)
- {
- switch (this->state)
+ char ibuf[1024];
+ strlcpy(ibuf,databuf.c_str(),1024);
+ Srv->Log(DEBUG,"Received ident response");
+ char* savept;
+ char* section = strtok_r(ibuf,":",&savept);
+ while (section)
{
- case IDENT_STATE_CONNECT:
- uslen = sizeof(sock_us);
- themlen = sizeof(sock_them);
- if ((getsockname(this->u->fd,(sockaddr*)&sock_us,&uslen) || getpeername(this->u->fd, (sockaddr*)&sock_them, &themlen)))
- {
- Srv->Log(DEBUG,"Ident: failed to get socket names, bailing to state 3");
- shutdown(this->fd,2);
- close(this->fd);
- this->fd = -1;
- state = IDENT_STATE_DONE;
- }
- else
+ if (strstr(section,"USERID"))
+ {
+ section = strtok_r(NULL,":",&savept);
+ if (section)
{
- // send the request in the following format: theirsocket,oursocket
- snprintf(ident_request,127,"%d,%d\r\n",ntohs(sock_them.sin_port),ntohs(sock_us.sin_port));
- send(this->fd,ident_request,strlen(ident_request),0);
- Srv->Log(DEBUG,"Sent ident request, moving to state 2");
- state = IDENT_STATE_WAITDATA;
- }
- break;
- case IDENT_STATE_WAITDATA:
- nrecv = recv(this->fd,ibuf,sizeof(ibuf),0);
- if (nrecv > 0)
- {
- // we have the response line in the following format:
- // 6193, 23 : USERID : UNIX : stjohns
- // 6195, 23 : ERROR : NO-USER
- ibuf[nrecv] = '\0';
- Srv->Log(DEBUG,"Received ident response: "+std::string(ibuf));
- shutdown(this->fd,2);
- close(this->fd);
- this->fd = -1;
- char* savept;
- char* section = strtok_r(ibuf,":",&savept);
- while (section)
+ // ID type, usually UNIX or OTHER... we dont want it, so read the next token
+ section = strtok_r(NULL,":",&savept);
+ if (section)
{
- if (strstr(section,"USERID"))
- {
- section = strtok_r(NULL,":",&savept);
- if (section)
- {
- // ID type, usually UNIX or OTHER... we dont want it, so read the next token
- section = strtok_r(NULL,":",&savept);
- if (section)
- {
- while ((*section == ' ') && (strlen(section)>0)) section++; // strip leading spaces
- int t = strlen(section);
- for (int j = 0; j < t; j++)
- if ((section[j] < 33) || (section[j]>126))
- section[j] = '\0'; // truncate at invalid chars
- if (strlen(section))
- {
- strlcpy(u->ident,section,IDENTMAX);
- Srv->Log(DEBUG,"IDENT SET: "+std::string(u->ident));
- Srv->SendServ(u->fd,"NOTICE "+std::string(u->nick)+" :*** Found your ident: "+std::string(u->ident));
- }
- break;
- }
- }
- }
- section = strtok_r(NULL,":",&savept);
+ while (*section == ' ') section++; // strip leading spaces
+ int t = strlen(section);
+ for (int j = 0; j < t; j++)
+ if ((section[j] < 33) || (section[j]>126))
+ section[j] = '\0'; // truncate at invalid chars
+ if (strlen(section))
+ {
+ strlcpy(u->ident,section,IDENTMAX);
+ Srv->Log(DEBUG,"IDENT SET: "+std::string(u->ident));
+ Srv->SendServ(u->fd,"NOTICE "+std::string(u->nick)+" :*** Found your ident: "+std::string(u->ident));
+ }
+ return false;
}
- state = IDENT_STATE_DONE;
}
- break;
- case IDENT_STATE_DONE:
- shutdown(this->fd,2);
- close(this->fd);
- this->fd = -1;
- Srv->Log(DEBUG,"Ident lookup is complete!");
- break;
- default:
- Srv->Log(DEBUG,"Ident: invalid ident state!!!");
- break;
+ }
+ section = strtok_r(NULL,":",&savept);
}
}
- return true;
+ return false;
}
- // returns true if the operation is completed,
- // either due to complete request, or a timeout
+ virtual void OnClose()
+ {
+ // tidy up after ourselves when the connection is done.
+ // We receive this event straight after a timeout, too.
+ u->Shrink("ident_data");
+ }
- bool Done()
+ virtual bool OnConnected()
{
- return ((state == IDENT_STATE_DONE) || (timeout == true));
+ uslen = sizeof(sock_us);
+ themlen = sizeof(sock_them);
+ if ((getsockname(this->u->fd,(sockaddr*)&sock_us,&uslen) || getpeername(this->u->fd, (sockaddr*)&sock_them, &themlen)))
+ {
+ Srv->Log(DEBUG,"Ident: failed to get socket names, bailing");
+ return false;
+ }
+ else
+ {
+ // send the request in the following format: theirsocket,oursocket
+ snprintf(ident_request,127,"%d,%d\r\n",ntohs(sock_them.sin_port),ntohs(sock_us.sin_port));
+ this->Write(ident_request);
+ Srv->Log(DEBUG,"Sent ident request, waiting for reply");
+ return true;
+ }
}
};
@@ -253,6 +138,7 @@ class ModuleIdent : public Module
{
ConfigReader* Conf;
+ Server* Srv;
int IdentTimeout;
public:
@@ -283,58 +169,36 @@ class ModuleIdent : public Module
virtual void OnUserRegister(userrec* user)
{
// when the new user connects, before they authenticate with USER/NICK/PASS, we do
- // their ident lookup.
-
- RFC1413* ident = new RFC1413;
+ // their ident lookup. We do this by instantiating an object of type RFC1413, which
+ // is derived from InspSocket, and inserting it into the socket engine using the
+ // Server::AddSocket() call.
Srv->SendServ(user->fd,"NOTICE "+std::string(user->nick)+" :*** Looking up your ident...");
- if (ident->Connect(user,IdentTimeout))
- {
- // attach the object to the user record
- user->Extend("ident_data",(char*)ident);
- // start it off polling (always good to have a head start)
- // because usually connect has completed by now
- ident->Poll();
- }
- else
- {
- // something went wrong, call an irc-ambulance!
- Srv->SendServ(user->fd,"NOTICE "+std::string(user->nick)+" :*** Could not look up your ident.");
- delete ident;
- }
+ RFC1413* ident = new RFC1413(user, IdentTimeout, Srv);
+ user->Extend("ident_data", (char*)ident);
+ Srv->AddSocket(ident);
}
virtual bool OnCheckReady(userrec* user)
{
+ // The socket engine will clean up their ident request for us when it completes,
+ // either due to timeout or due to closing, so, we just hold them until they dont
+ // have an ident field any more.
RFC1413* ident = (RFC1413*)user->GetExt("ident_data");
- if (ident)
- {
- // this user has a pending ident lookup, poll it
- ident->Poll();
- // is it done?
- if (ident->Done())
- {
- // their ident is done, zap the structures
- Srv->Log(DEBUG,"Ident: removing ident gubbins");
- user->Shrink("ident_data");
- delete ident;
- // ...and send them on their way
- return true;
- }
- // nope, we hold them in this state, they dont go anywhere
- return false;
- }
- return true;
+ return (!ident);
}
virtual void OnUserDisconnect(userrec* user)
{
- // when the user quits tidy up any ident lookup they have pending to keep things tidy
- // and to prevent a memory and FD leaks
+ // when the user quits tidy up any ident lookup they have pending to keep things tidy.
+ // When we call RemoveSocket, the abstractions tied into the system evnetually work their
+ // way to RFC1459::OnClose(), which shrinks off the ident_data for us, so we dont need
+ // to do it here. If we don't tidy this up, there may still be lingering idents for users
+ // who have quit, as class RFC1459 is only loosely bound to userrec* via a pair of pointers
+ // and this would leave at least one of the invalid ;)
RFC1413* ident = (RFC1413*)user->GetExt("ident_data");
if (ident)
{
- delete ident;
- user->Shrink("ident_data");
+ Srv->RemoveSocket(ident);
}
}
@@ -344,7 +208,7 @@ class ModuleIdent : public Module
virtual Version GetVersion()
{
- return Version(1,0,0,1,VF_VENDOR);
+ return Version(1,5,0,0,VF_VENDOR);
}
};