]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/listensocket.cpp
Fix problem with autoconnects: don't reset NextConnectTime to a higher value than...
[user/henk/code/inspircd.git] / src / listensocket.cpp
index 7c679c1d3fe9b650dba2e6c6080f693943e35284..e4b568235b69849f0b9c72d99c36171775de7643 100644 (file)
 
 
 /* Private static member data must be initialized in this manner */
-unsigned int ListenSocket::socketcount = 0;
-sockaddr* ListenSocket::sock_us = NULL;
-sockaddr* ListenSocket::client = NULL;
-sockaddr* ListenSocket::raddr = NULL;
+unsigned int ListenSocketBase::socketcount = 0;
+sockaddr* ListenSocketBase::sock_us = NULL;
+sockaddr* ListenSocketBase::client = NULL;
+sockaddr* ListenSocketBase::raddr = NULL;
 
-ListenSocket::ListenSocket(InspIRCd* Instance, int port, char* addr) : ServerInstance(Instance), desc("plaintext"), bind_addr(addr), bind_port(port)
+ListenSocketBase::ListenSocketBase(InspIRCd* Instance, int port, const std::string &addr) : ServerInstance(Instance), desc("plaintext"), bind_addr(addr), bind_port(port)
 {
-       this->SetFd(irc::sockets::OpenTCPSocket(addr));
+       this->SetFd(irc::sockets::OpenTCPSocket(addr.c_str()));
        if (this->GetFd() > -1)
        {
-               if (!Instance->BindSocket(this->fd,port,addr))
+               if (!Instance->BindSocket(this->fd,port,addr.c_str()))
                        this->fd = -1;
 #ifdef IPV6
-               if ((!*addr) || (strchr(addr,':')))
+               if ((!*addr.c_str()) || (strchr(addr.c_str(),':')))
                        this->family = AF_INET6;
                else
 #endif
@@ -51,7 +51,7 @@ ListenSocket::ListenSocket(InspIRCd* Instance, int port, char* addr) : ServerIns
        socketcount++;
 }
 
-ListenSocket::~ListenSocket()
+ListenSocketBase::~ListenSocketBase()
 {
        if (this->GetFd() > -1)
        {
@@ -71,7 +71,7 @@ ListenSocket::~ListenSocket()
 }
 
 /* Just seperated into another func for tidiness really.. */
-void ListenSocket::AcceptInternal()
+void ListenSocketBase::AcceptInternal()
 {
        ServerInstance->Logs->Log("SOCKET",DEBUG,"HandleEvent for Listensoket");
        socklen_t uslen, length;                // length of our port number
@@ -100,9 +100,27 @@ void ListenSocket::AcceptInternal()
                ServerInstance->stats->statsRefused++;
                return;
        }
+       /*
+        * XXX -
+        * this is done as a safety check to keep the file descriptors within range of fd_ref_table.
+        * its a pretty big but for the moment valid assumption:
+        * file descriptors are handed out starting at 0, and are recycled as theyre freed.
+        * therefore if there is ever an fd over 65535, 65536 clients must be connected to the
+        * irc server at once (or the irc server otherwise initiating this many connections, files etc)
+        * which for the time being is a physical impossibility (even the largest networks dont have more
+        * than about 10,000 users on ONE server!)
+        */
+       if (incomingSockfd >= ServerInstance->SE->GetMaxFds())
+       {
+               ServerInstance->Logs->Log("SOCKET", DEBUG, "Server is full");
+               ServerInstance->SE->Shutdown(incomingSockfd, 2);
+               ServerInstance->SE->Close(incomingSockfd);
+               ServerInstance->stats->statsRefused++;
+               return;
+       }
 
        static char buf[MAXBUF];
-       static char target[MAXBUF];     
+       static char target[MAXBUF];
 
        *target = *buf = '\0';
 
@@ -115,6 +133,33 @@ void ListenSocket::AcceptInternal()
                        inet_ntop(AF_INET6, &((const sockaddr_in6*)raddr)->sin6_addr, target, sizeof(target));
                else
                        ServerInstance->Logs->Log("SOCKET", DEBUG, "Can't get peername: %s", strerror(errno));
+
+               /*
+                * This case is the be all and end all patch to catch and nuke 4in6
+                * instead of special-casing shit all over the place and wreaking merry
+                * havoc with crap, instead, we just recreate sockaddr and strip ::ffff: prefix
+                * if it's a 4in6 IP.
+                *
+                * This is, of course, much improved over the older way of handling this
+                * (pretend it doesn't exist + hack around it -- yes, both were done!)
+                *
+                * Big, big thanks to danieldg for his work on this.
+                * -- w00t
+                */
+               static const unsigned char prefix4in6[12] = { 0,0,0,0,  0,0,0,0, 0,0,0xFF,0xFF };
+               if (!memcmp(prefix4in6, &((const sockaddr_in6*)client)->sin6_addr, 12))
+               {
+                       // strip leading ::ffff: from the IPs
+                       memmove(buf, buf+7, sizeof(buf)-7);
+                       memmove(target, target+7, sizeof(target)-7);
+
+                       // recreate as a sockaddr_in using the IPv4 IP
+                       uint16_t sport = ((const sockaddr_in6*)client)->sin6_port;
+                       struct sockaddr_in* clientv4 = (struct sockaddr_in*)client;
+                       clientv4->sin_family = AF_INET;
+                       clientv4->sin_port = sport;
+                       inet_pton(AF_INET, buf, &clientv4->sin_addr);
+               }
        }
        else
 #endif
@@ -127,31 +172,12 @@ void ListenSocket::AcceptInternal()
                        ServerInstance->Logs->Log("SOCKET", DEBUG, "Can't get peername: %s", strerror(errno));
        }
 
-       /*
-        * XXX -
-        * this is done as a safety check to keep the file descriptors within range of fd_ref_table.
-        * its a pretty big but for the moment valid assumption:
-        * file descriptors are handed out starting at 0, and are recycled as theyre freed.
-        * therefore if there is ever an fd over 65535, 65536 clients must be connected to the
-        * irc server at once (or the irc server otherwise initiating this many connections, files etc)
-        * which for the time being is a physical impossibility (even the largest networks dont have more
-        * than about 10,000 users on ONE server!)
-        */
-       if (incomingSockfd >= ServerInstance->SE->GetMaxFds())
-       {
-               ServerInstance->Logs->Log("SOCKET", DEBUG, "Server is full");
-               ServerInstance->SE->Shutdown(incomingSockfd, 2);
-               ServerInstance->SE->Close(incomingSockfd);
-               ServerInstance->stats->statsRefused++;
-               return;
-       }
-
        ServerInstance->SE->NonBlocking(incomingSockfd);
        ServerInstance->stats->statsAccept++;
-       this->OnAcceptReady(target, incomingSockfd);
+       this->OnAcceptReady(target, incomingSockfd, buf);
 }
 
-void ListenSocket::HandleEvent(EventType e, int err)
+void ListenSocketBase::HandleEvent(EventType e, int err)
 {
        switch (e)
        {
@@ -167,7 +193,7 @@ void ListenSocket::HandleEvent(EventType e, int err)
        }
 }
 
-void ListenSocket::OnAcceptReady(const std::string &ipconnectedto, int nfd)
+void ClientListenSocket::OnAcceptReady(const std::string &ipconnectedto, int nfd, const std::string &incomingip)
 {
-               ServerInstance->Users->AddUser(ServerInstance, nfd, bind_port, false, this->family, client, ipconnectedto);
+       ServerInstance->Users->AddUser(ServerInstance, nfd, bind_port, false, client, ipconnectedto);
 }