]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/users.cpp
kick_channel -> chanrec::KickUser(), server_kick_channel -> chanrec::ServerKickUser()
[user/henk/code/inspircd.git] / src / users.cpp
index 1e2e3532144d1bd6c5f820041312864651ed8bc1..34c347cb934deac5aaa0a576a1383801fa20e7cd 100644 (file)
 #include "users.h"
 #include "inspircd.h"
 #include <stdio.h>
-#ifdef THREADED_DNS
-#include <pthread.h>
-#include <signal.h>
-#endif
 #include "inspstring.h"
 #include "commands.h"
 #include "helperfuncs.h"
@@ -48,6 +44,7 @@ extern time_t TIME;
 extern userrec* fd_ref_table[MAX_DESCRIPTORS];
 extern ServerConfig *Config;
 extern user_hash clientlist;
+extern Server* MyServer;
 
 whowas_users whowas;
 
@@ -137,6 +134,82 @@ bool userrec::ProcessNoticeMasks(const char *sm)
        return true;
 }
 
+void userrec::StartDNSLookup()
+{
+       log(DEBUG,"Commencing reverse lookup");
+       try
+       {
+               res_reverse = new UserResolver(this, this->GetIPString(), false);
+               MyServer->AddResolver(res_reverse);
+       }
+       catch (ModuleException& e)
+       {
+               log(DEBUG,"Error in resolver: %s",e.GetReason());
+       }
+}
+
+UserResolver::UserResolver(userrec* user, std::string to_resolve, bool forward) : Resolver(to_resolve, forward ? DNS_QUERY_FORWARD : DNS_QUERY_REVERSE), bound_user(user)
+{
+       this->fwd = forward;
+       this->bound_fd = user->fd;
+}
+
+void UserResolver::OnLookupComplete(const std::string &result)
+{
+       if ((!this->fwd) && (fd_ref_table[this->bound_fd] == this->bound_user))
+       {
+               log(DEBUG,"Commencing forward lookup");
+               this->bound_user->stored_host = result;
+               try
+               {
+                       bound_user->res_forward = new UserResolver(this->bound_user, result, true);
+                       MyServer->AddResolver(bound_user->res_forward);
+               }
+               catch (ModuleException& e)
+               {
+                       log(DEBUG,"Error in resolver: %s",e.GetReason());
+               }
+       }
+       else if ((this->fwd) && (fd_ref_table[this->bound_fd] == this->bound_user))
+       {
+               /* Both lookups completed */
+               if (this->bound_user->GetIPString() == result)
+               {
+                       std::string hostname = this->bound_user->stored_host;
+                       if (hostname.length() < 65)
+                       {
+                               /* Hostnames starting with : are not a good thing (tm) */
+                               if (*(hostname.c_str()) == ':')
+                                       hostname = "0" + hostname;
+
+                               WriteServ(this->bound_fd, "NOTICE Auth :*** Found your hostname (%s)", hostname.c_str());
+                               this->bound_user->dns_done = true;
+                               strlcpy(this->bound_user->dhost, hostname.c_str(),64);
+                               strlcpy(this->bound_user->host, hostname.c_str(),64);
+                       }
+                       else
+                       {
+                               WriteServ(this->bound_fd, "NOTICE Auth :*** Your hostname is longer than the maximum of 64 characters, using your IP address (%s) instead.", this->bound_user->GetIPString());
+                       }
+               }
+               else
+               {
+                       WriteServ(this->bound_fd, "NOTICE Auth :*** Your hostname does not match up with your IP address. Sorry, using your IP address (%s) instead.", this->bound_user->GetIPString());
+               }
+       }
+}
+
+void UserResolver::OnError(ResolverError e, const std::string &errormessage)
+{
+       if (fd_ref_table[this->bound_fd] == this->bound_user)
+       {
+               /* Error message here */
+               WriteServ(this->bound_fd, "NOTICE Auth :*** Could not resolve your hostname, using your IP address (%s) instead.", this->bound_user->GetIPString());
+               this->bound_user->dns_done = true;
+       }
+}
+
+
 bool userrec::IsNoticeMaskSet(unsigned char sm)
 {
        return (snomasks[sm-65]);
@@ -194,10 +267,13 @@ userrec::userrec()
        server = (char*)FindServerNamePtr(Config->ServerName);
        reset_due = TIME;
        lines_in = fd = lastping = signon = idle_lastmsg = nping = registered = 0;
-       timeout = flood = port = bytes_in = bytes_out = cmds_in = cmds_out = 0;
+       timeout = flood = bytes_in = bytes_out = cmds_in = cmds_out = 0;
        haspassed = dns_done = false;
        recvq = "";
        sendq = "";
+       WriteError = "";
+       res_forward = res_reverse = NULL;
+       ip = NULL;
        chans.clear();
        invites.clear();
        chans.resize(MAXCHANS);
@@ -217,7 +293,21 @@ userrec::~userrec()
        for (std::vector<ucrec*>::iterator n = chans.begin(); n != chans.end(); n++)
        {
                ucrec* x = (ucrec*)*n;
-               DELETE(x);
+               delete x;
+       }
+
+       if (ip)
+       {
+               if (this->GetProtocolFamily() == AF_INET)
+               {
+                       delete (sockaddr_in*)ip;
+               }
+#ifdef SUPPORT_IP6LINKS
+               else
+               {
+                       delete (sockaddr_in6*)ip;
+               }
+#endif
        }
 }
 
@@ -306,7 +396,6 @@ bool userrec::IsInvited(irc::string &channel)
                        return true;
                }
        }
-       
        return false;
 }
 
@@ -318,7 +407,6 @@ InvitedList* userrec::GetInviteList()
 void userrec::InviteTo(irc::string &channel)
 {
        Invited i;
-       
        i.channel = channel;
        invites.push_back(i);
 }
@@ -397,44 +485,32 @@ bool userrec::HasPermission(const std::string &command)
 bool userrec::AddBuffer(const std::string &a)
 {
        std::string b = "";
-       char* n = (char*)a.c_str();
-       
-       for (char* i = n; *i; i++)
-       {
-               if ((*i != '\r') && (*i != '\0') && (*i != 7))
-                       b = b + *i;
-       }
-       
-       recvq.append(b);
-       unsigned int i = 0;
-       
-       // count the size of the first line in the buffer.
-       while (i < recvq.length())
+
+       /* NB: std::string is arsey about \r and \n and tries to translate them
+        * somehow, so we CANNOT use std::string::find() here :(
+        */
+       for (std::string::const_iterator i = a.begin(); i != a.end(); i++)
        {
-               if (recvq[i++] == '\n')
-                       break;
+               if (*i != '\r')
+                       b += *i;
        }
+
+       if (b.length())
+               recvq.append(b);
+
        if (recvq.length() > (unsigned)this->recvqmax)
        {
                this->SetWriteError("RecvQ exceeded");
                WriteOpers("*** User %s RecvQ of %d exceeds connect class maximum of %d",this->nick,recvq.length(),this->recvqmax);
+               return false;
        }
-       
-       /*
-        * return false if we've had more than 600 characters WITHOUT
-        * a carriage return (this is BAD, drop the socket)
-        */
-       return (i < 600);
+
+       return true;
 }
 
 bool userrec::BufferIsReady()
 {
-       unsigned int t = recvq.length();
-       
-       for (unsigned int i = 0; i < t; i++)
-               if (recvq[i] == '\n')
-                       return true;
-       return false;
+       return (recvq.find('\n') != std::string::npos);
 }
 
 void userrec::ClearBuffer()
@@ -444,25 +520,29 @@ void userrec::ClearBuffer()
 
 std::string userrec::GetBuffer()
 {
-       if (recvq == "")
+       if (!recvq.length())
                return "";
-               
-       char* line = (char*)recvq.c_str();
-       
-       std::string ret = "";
-       
-       while ((*line != '\n') && (*line))
+
+       /* Strip any leading \r or \n off the string.
+        * Usually there are only one or two of these,
+        * so its is computationally cheap to do.
+        */
+       while ((*recvq.begin() == '\r') || (*recvq.begin() == '\n'))
+               recvq.erase(recvq.begin());
+
+       for (std::string::iterator x = recvq.begin(); x != recvq.end(); x++)
        {
-               ret = ret + *line;
-               line++;
+               /* Find the first complete line, return it as the
+                * result, and leave the recvq as whats left
+                */
+               if (*x == '\n')
+               {
+                       std::string ret = std::string(recvq.begin(), x);
+                       recvq.erase(recvq.begin(), x + 1);
+                       return ret;
+               }
        }
-       
-       while ((*line == '\n') || (*line == '\r'))
-               line++;
-       
-       recvq = line;
-       
-       return ret;
+       return "";
 }
 
 void userrec::AddWriteBuf(const std::string &data)
@@ -482,7 +562,17 @@ void userrec::AddWriteBuf(const std::string &data)
                return;
        }
        
-       sendq.append(data);
+       if (data.length() > 512)
+       {
+               std::string newdata(data);
+               newdata.resize(510);
+               newdata.append("\r\n");
+               sendq.append(newdata);
+       }
+       else
+       {
+               sendq.append(data);
+       }
 }
 
 // send AS MUCH OF THE USERS SENDQ as we are able to (might not be all of it)
@@ -490,7 +580,7 @@ void userrec::FlushWriteBuf()
 {
        if ((sendq.length()) && (this->fd != FD_MAGIC_NUMBER))
        {
-               char* tb = (char*)this->sendq.c_str();
+               const char* tb = this->sendq.c_str();
                int n_sent = write(this->fd,tb,this->sendq.length());
                if (n_sent == -1)
                {
@@ -511,10 +601,13 @@ void userrec::FlushWriteBuf()
 
 void userrec::SetWriteError(const std::string &error)
 {
-       log(DEBUG,"Setting error string for %s to '%s'",this->nick,error.c_str());
+       log(DEBUG,"SetWriteError: %s",error.c_str());
        // don't try to set the error twice, its already set take the first string.
-       if (this->WriteError == "")
+       if (!this->WriteError.length())
+       {
+               log(DEBUG,"Setting error string for %s to '%s'",this->nick,error.c_str());
                this->WriteError = error;
+       }
 }
 
 const char* userrec::GetWriteError()
@@ -564,7 +657,7 @@ void kill_link(userrec *user,const char* r)
        if (IS_LOCAL(user))
                Write(user->fd,"ERROR :Closing link (%s@%s) [%s]",user->ident,user->host,reason);
 
-       if (user->registered == 7)
+       if (user->registered == REG_ALL)
        {
                purge_empty_chans(user);
                FOREACH_MOD(I_OnUserQuit,OnUserQuit(user,reason));
@@ -578,11 +671,11 @@ void kill_link(userrec *user,const char* r)
 
        if (IS_LOCAL(user))
        {
-               if (Config->GetIOHook(user->port))
+               if (Config->GetIOHook(user->GetPort()))
                {
                        try
                        {
-                               Config->GetIOHook(user->port)->OnRawSocketClose(user->fd);
+                               Config->GetIOHook(user->GetPort())->OnRawSocketClose(user->fd);
                        }
                        catch (ModuleException& modexcept)
                        {
@@ -602,7 +695,7 @@ void kill_link(userrec *user,const char* r)
         * In the current implementation, we only show local quits, as we only show local connects. With 
         * the proposed implmentation of snomasks however, this will likely change in the (near?) future.
         */
-       if (user->registered == 7)
+       if (user->registered == REG_ALL)
        {
                if (IS_LOCAL(user))
                        WriteOpers("*** Client exiting: %s!%s@%s [%s]",user->nick,user->ident,user->host,reason);
@@ -694,11 +787,12 @@ void MaintainWhoWas(time_t TIME)
 }
 
 /* add a client connection to the sockets list */
-void AddClient(int socket, int port, bool iscached, in_addr ip4)
+void AddClient(int socket, int port, bool iscached, insp_inaddr ip)
 {
        std::string tempnick = ConvToStr(socket) + "-unknown";
        user_hash::iterator iter = clientlist.find(tempnick);
-       const char *ipaddr = inet_ntoa(ip4);
+       const char *ipaddr = insp_ntoa(ip);
+       userrec* _new;
        int j = 0;
 
        /*
@@ -719,25 +813,28 @@ void AddClient(int socket, int port, bool iscached, in_addr ip4)
 
        log(DEBUG,"AddClient: %d %d %s",socket,port,ipaddr);
        
-       clientlist[tempnick] = new userrec();
-       clientlist[tempnick]->fd = socket;
-       strlcpy(clientlist[tempnick]->nick,tempnick.c_str(),NICKMAX-1);
-
-       /* Smarter than your average bear^H^H^H^Hset of strlcpys. */
-       for (char* temp = (char*)ipaddr; *temp && j < 64; temp++, j++)
-               clientlist[tempnick]->dhost[j] = clientlist[tempnick]->host[j] = *temp;
-       clientlist[tempnick]->dhost[j] = clientlist[tempnick]->host[j] = 0;
+       _new = new userrec();
+       clientlist[tempnick] = _new;
+       _new->fd = socket;
+       strlcpy(_new->nick,tempnick.c_str(),NICKMAX-1);
 
-       clientlist[tempnick]->server = (char*)FindServerNamePtr(Config->ServerName);
+       _new->server = FindServerNamePtr(Config->ServerName);
        /* We don't need range checking here, we KNOW 'unknown\0' will fit into the ident field. */
-       strcpy(clientlist[tempnick]->ident, "unknown");
+       strcpy(_new->ident, "unknown");
 
-       clientlist[tempnick]->registered = 0;
-       clientlist[tempnick]->signon = TIME + Config->dns_timeout;
-       clientlist[tempnick]->lastping = 1;
-       clientlist[tempnick]->ip4 = ip4;
-       clientlist[tempnick]->port = port;
+       _new->registered = REG_NONE;
+       _new->signon = TIME + Config->dns_timeout;
+       _new->lastping = 1;
 
+       log(DEBUG,"Setting socket addresses");
+       _new->SetSockAddr(AF_FAMILY, ipaddr, port);
+       log(DEBUG,"Socket addresses set.");
+
+       /* Smarter than your average bear^H^H^H^Hset of strlcpys. */
+        for (const char* temp = _new->GetIPString(); *temp && j < 64; temp++, j++)
+               _new->dhost[j] = _new->host[j] = *temp;
+       _new->dhost[j] = _new->host[j] = 0;
+                       
        // set the registration timeout for this user
        unsigned long class_regtimeout = 90;
        int class_flood = 0;
@@ -747,11 +844,11 @@ void AddClient(int socket, int port, bool iscached, in_addr ip4)
 
        for (ClassVector::iterator i = Config->Classes.begin(); i != Config->Classes.end(); i++)
        {
-               if ((i->type == CC_ALLOW) && (match(ipaddr,i->host.c_str())))
+               if ((i->type == CC_ALLOW) && (match(ipaddr,i->host.c_str(),true)))
                {
                        class_regtimeout = (unsigned long)i->registration_timeout;
                        class_flood = i->flood;
-                       clientlist[tempnick]->pingmax = i->pingtime;
+                       _new->pingmax = i->pingtime;
                        class_threshold = i->threshold;
                        class_sqmax = i->sendqmax;
                        class_rqmax = i->recvqmax;
@@ -759,25 +856,25 @@ void AddClient(int socket, int port, bool iscached, in_addr ip4)
                }
        }
 
-       clientlist[tempnick]->nping = TIME+clientlist[tempnick]->pingmax + Config->dns_timeout;
-       clientlist[tempnick]->timeout = TIME+class_regtimeout;
-       clientlist[tempnick]->flood = class_flood;
-       clientlist[tempnick]->threshold = class_threshold;
-       clientlist[tempnick]->sendqmax = class_sqmax;
-       clientlist[tempnick]->recvqmax = class_rqmax;
+       _new->nping = TIME + _new->pingmax + Config->dns_timeout;
+       _new->timeout = TIME+class_regtimeout;
+       _new->flood = class_flood;
+       _new->threshold = class_threshold;
+       _new->sendqmax = class_sqmax;
+       _new->recvqmax = class_rqmax;
 
-       fd_ref_table[socket] = clientlist[tempnick];
-       local_users.push_back(clientlist[tempnick]);
+       fd_ref_table[socket] = _new;
+       local_users.push_back(_new);
 
        if (local_users.size() > Config->SoftLimit)
        {
-               kill_link(clientlist[tempnick],"No more connections allowed");
+               kill_link(_new,"No more connections allowed");
                return;
        }
 
        if (local_users.size() >= MAXCLIENTS)
        {
-               kill_link(clientlist[tempnick],"No more connections allowed");
+               kill_link(_new,"No more connections allowed");
                return;
        }
 
@@ -793,7 +890,7 @@ void AddClient(int socket, int port, bool iscached, in_addr ip4)
         */
        if ((unsigned)socket >= MAX_DESCRIPTORS)
        {
-               kill_link(clientlist[tempnick],"Server is full");
+               kill_link(_new,"Server is full");
                return;
        }
        char* e = matches_exception(ipaddr);
@@ -804,26 +901,35 @@ void AddClient(int socket, int port, bool iscached, in_addr ip4)
                {
                        char reason[MAXBUF];
                        snprintf(reason,MAXBUF,"Z-Lined: %s",r);
-                       kill_link(clientlist[tempnick],reason);
+                       kill_link(_new,reason);
                        return;
                }
        }
 
        if (socket > -1)
        {
-               ServerInstance->SE->AddFd(socket,true,X_ESTAB_CLIENT);
+               if (!ServerInstance->SE->AddFd(socket,true,X_ESTAB_CLIENT))
+               {
+                       kill_link(_new, "Internal error handling connection");
+                       return;
+               }
        }
 
-       WriteServ(clientlist[tempnick]->fd,"NOTICE Auth :*** Looking up your hostname...");
+       WriteServ(_new->fd,"NOTICE Auth :*** Looking up your hostname...");
 }
 
 long FindMatchingGlobal(userrec* user)
 {
+       char u1[1024];
+       char u2[1024];
        long x = 0;
        for (user_hash::const_iterator a = clientlist.begin(); a != clientlist.end(); a++)
        {
-               if (a->second->ip4.s_addr == user->ip4.s_addr)
-                       x++;
+               /* We have to match ip's as strings - we don't know what protocol
+                * a remote user may be using
+                */
+               if (!strcasecmp(a->second->GetIPString(u1), user->GetIPString(u2)))
+                               x++;
        }
        return x;
 }
@@ -833,9 +939,19 @@ long FindMatchingLocal(userrec* user)
        long x = 0;
        for (std::vector<userrec*>::const_iterator a = local_users.begin(); a != local_users.end(); a++)
        {
-               userrec* comp = (userrec*)(*a);
-               if (comp->ip4.s_addr == user->ip4.s_addr)
+               userrec* comp = *a;
+#ifdef IPV6
+               /* I dont think theres any faster way of matching two ipv6 addresses than memcmp */
+               in6_addr* s1 = &(((sockaddr_in6*)comp->ip)->sin6_addr);
+               in6_addr* s2 = &(((sockaddr_in6*)user->ip)->sin6_addr);
+               if (!memcmp(s1->s6_addr, s2->s6_addr, sizeof(in6_addr)))
+                       x++;
+#else
+               in_addr* s1 = &((sockaddr_in*)comp->ip)->sin_addr;
+               in_addr* s2 = &((sockaddr_in*)user->ip)->sin_addr;
+               if (s1->s_addr == s2->s_addr)
                        x++;
+#endif
        }
        return x;
 }
@@ -863,13 +979,13 @@ void FullConnectUser(userrec* user, CullList* Goners)
        if (FindMatchingLocal(user) > a.maxlocal)
        {
                Goners->AddItem(user,"No more connections allowed from your host via this connect class (local)");
-               WriteOpers("*** WARNING: maximum LOCAL connections (%ld) exceeded for IP %s",a.maxlocal,(char*)inet_ntoa(user->ip4));
+               WriteOpers("*** WARNING: maximum LOCAL connections (%ld) exceeded for IP %s",a.maxlocal,user->GetIPString());
                return;
        }
        else if (FindMatchingGlobal(user) > a.maxglobal)
        {
                Goners->AddItem(user,"No more connections allowed from your host via this connect class (global)");
-               WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s",a.maxglobal,(char*)inet_ntoa(user->ip4));
+               WriteOpers("*** WARNING: maximum GLOBAL connections (%ld) exceeded for IP %s",a.maxglobal,user->GetIPString());
                return;
        }
 
@@ -905,7 +1021,7 @@ void FullConnectUser(userrec* user, CullList* Goners)
        WriteServ(user->fd,"001 %s :Welcome to the %s IRC Network %s!%s@%s",user->nick,Config->Network,user->nick,user->ident,user->host);
        WriteServ(user->fd,"002 %s :Your host is %s, running version %s",user->nick,Config->ServerName,VERSION);
        WriteServ(user->fd,"003 %s :This server was created %s %s",user->nick,__TIME__,__DATE__);
-       WriteServ(user->fd,"004 %s %s %s iowghrasxRVSCWBG lvhopsmntikrcaqbegIOLQRSKVHGCNT vhobeIaqglk",user->nick,Config->ServerName,VERSION);
+       WriteServ(user->fd,"004 %s %s %s %s %s %s",user->nick,Config->ServerName,VERSION,ServerInstance->ModeGrok->UserModeList().c_str(),ServerInstance->ModeGrok->ChannelModeList().c_str(),+ServerInstance->ModeGrok->ParaModeList().c_str());
        
        // anfl @ #ratbox, efnet reminded me that according to the RFC this cant contain more than 13 tokens per line...
        // so i'd better split it :)
@@ -936,8 +1052,8 @@ void FullConnectUser(userrec* user, CullList* Goners)
         */
        FOREACH_MOD(I_OnUserConnect,OnUserConnect(user));
        FOREACH_MOD(I_OnGlobalConnect,OnGlobalConnect(user));
-       user->registered = 7;
-       WriteOpers("*** Client connecting on port %lu: %s!%s@%s [%s]",(unsigned long)user->port,user->nick,user->ident,user->host,(char*)inet_ntoa(user->ip4));
+       user->registered = REG_ALL;
+       WriteOpers("*** Client connecting on port %d: %s!%s@%s [%s]",user->GetPort(),user->nick,user->ident,user->host,user->GetIPString());
 }
 
 /** ReHashNick()
@@ -1001,7 +1117,7 @@ void force_nickchange(userrec* user,const char* newnick)
                        strlcpy(nick,newnick,MAXBUF-1);
                }
 
-               if (user->registered == 7)
+               if (user->registered == REG_ALL)
                {
                        const char* pars[1];
                        pars[0] = nick;
@@ -1011,3 +1127,156 @@ void force_nickchange(userrec* user,const char* newnick)
                }
        }
 }
+
+void userrec::SetSockAddr(int protocol_family, const char* ip, int port)
+{
+       switch (protocol_family)
+       {
+#ifdef SUPPORT_IP6LINKS
+               case AF_INET6:
+               {
+                       log(DEBUG,"Set inet6 protocol address");
+                       sockaddr_in6* sin = new sockaddr_in6;
+                       sin->sin6_family = AF_INET6;
+                       sin->sin6_port = port;
+                       inet_pton(AF_INET6, ip, &sin->sin6_addr);
+                       this->ip = (sockaddr*)sin;
+               }
+               break;
+#endif
+               case AF_INET:
+               {
+                       log(DEBUG,"Set inet4 protocol address");
+                       sockaddr_in* sin = new sockaddr_in;
+                       sin->sin_family = AF_INET;
+                       sin->sin_port = port;
+                       inet_pton(AF_INET, ip, &sin->sin_addr);
+                       this->ip = (sockaddr*)sin;
+               }
+               break;
+               default:
+                       log(DEBUG,"Ut oh, I dont know protocol %d to be set on '%s'!", protocol_family, this->nick);
+               break;
+       }
+}
+
+int userrec::GetPort()
+{
+       if (this->ip == NULL)
+               return 0;
+
+       switch (this->GetProtocolFamily())
+       {
+#ifdef SUPPORT_IP6LINKS
+               case AF_INET6:
+               {
+                       sockaddr_in6* sin = (sockaddr_in6*)this->ip;
+                       return sin->sin6_port;
+               }
+               break;
+#endif
+               case AF_INET:
+               {
+                       sockaddr_in* sin = (sockaddr_in*)this->ip;
+                       return sin->sin_port;
+               }
+               break;
+               default:
+                       log(DEBUG,"Ut oh, '%s' has an unknown protocol family!",this->nick);
+               break;
+       }
+       return 0;
+}
+
+int userrec::GetProtocolFamily()
+{
+       if (this->ip == NULL)
+               return 0;
+
+       sockaddr_in* sin = (sockaddr_in*)this->ip;
+       return sin->sin_family;
+}
+
+const char* userrec::GetIPString()
+{
+       static char buf[1024];
+       static char temp[1024];
+
+       if (this->ip == NULL)
+               return "";
+
+       switch (this->GetProtocolFamily())
+       {
+#ifdef SUPPORT_IP6LINKS
+               case AF_INET6:
+               {
+                       sockaddr_in6* sin = (sockaddr_in6*)this->ip;
+                       inet_ntop(sin->sin6_family, &sin->sin6_addr, buf, sizeof(buf));
+                       /* IP addresses starting with a : on irc are a Bad Thing (tm) */
+                       if (*buf == ':')
+                       {
+                               strlcpy(&temp[1], buf, sizeof(temp));
+                               *temp = '0';
+                               return temp;
+                       }
+                       return buf;
+               }
+               break;
+#endif
+               case AF_INET:
+               {
+                       sockaddr_in* sin = (sockaddr_in*)this->ip;
+                       inet_ntop(sin->sin_family, &sin->sin_addr, buf, sizeof(buf));
+                       return buf;
+               }
+               break;
+               default:
+                       log(DEBUG,"Ut oh, '%s' has an unknown protocol family!",this->nick);
+               break;
+       }
+       return "";
+}
+
+const char* userrec::GetIPString(char* buf)
+{
+       static char temp[1024];
+
+       if (this->ip == NULL)
+       {
+               *buf = 0;
+               return buf;
+       }
+
+       switch (this->GetProtocolFamily())
+       {
+#ifdef SUPPORT_IP6LINKS
+               case AF_INET6:
+               {
+                       sockaddr_in6* sin = (sockaddr_in6*)this->ip;
+                       inet_ntop(sin->sin6_family, &sin->sin6_addr, buf, sizeof(buf));
+                       /* IP addresses starting with a : on irc are a Bad Thing (tm) */
+                       if (*buf == ':')
+                       {
+                               strlcpy(&temp[1], buf, sizeof(temp));
+                               *temp = '0';
+                               strlcpy(buf, temp, sizeof(temp));
+                       }
+                       return buf;
+               }
+               break;
+#endif
+               case AF_INET:
+               {
+                       sockaddr_in* sin = (sockaddr_in*)this->ip;
+                       inet_ntop(sin->sin_family, &sin->sin_addr, buf, sizeof(buf));
+                       return buf;
+               }
+               break;
+
+               default:
+                       log(DEBUG,"Ut oh, '%s' has an unknown protocol family!",this->nick);
+               break;
+       }
+       return "";
+}
+