From 46b70f654dad0a245c2c008e0413f1d8b4634a1f Mon Sep 17 00:00:00 2001 From: psychon Date: Thu, 15 Apr 2010 18:20:12 +0000 Subject: [PATCH] Move the HTTP/IRC switching to CIncomingConnection This new class waits for the first line from the client and checks if it's an HTTP request and then passes the connection on to the irc or http code. Before this, the IRC parser handled this as a special case which wasn't as nice-looking as this is. :) git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@1925 726aef4b-f618-498e-8847-2d620e286838 --- Client.cpp | 19 ------------------- Client.h | 6 +----- Listener.cpp | 45 ++++++++++++++++++++++++++++++++++++++++++-- Listener.h | 7 +++++++ Modules.cpp | 4 ++-- Modules.h | 6 +++--- modules/fail2ban.cpp | 4 ++-- 7 files changed, 58 insertions(+), 33 deletions(-) diff --git a/Client.cpp b/Client.cpp index 1c5badc1..2954de9d 100644 --- a/Client.cpp +++ b/Client.cpp @@ -67,25 +67,6 @@ void CClient::ReadLine(const CString& sData) { if (IsAttached()) { MODULECALL(OnUserRaw(sLine), m_pUser, this, return); } else { - // If it's an HTTP Request - Check the webmods - if (sLine.WildCmp("GET * HTTP/1.?") || sLine.WildCmp("POST * HTTP/1.?")) { - CModule* pMod = new CModule(NULL, "", ""); - pMod->SetFake(true); - - CWebSock* pSock = new CWebSock(pMod); - CZNC::Get().GetManager().SwapSockByAddr(pSock, this); - - // And don't forget to give it some sane name / timeout - pSock->SetSockName("WebMod::Client"); - pSock->SetTimeout(120); - - // TODO can we somehow get rid of this? - pSock->ReadLine(sLine); - pSock->PushBuff("", 0, true); - - return; - } - if (CZNC::Get().GetModules().OnUnknownUserRaw(this, sLine)) { return; } diff --git a/Client.h b/Client.h index 4f80d207..d6902cc1 100644 --- a/Client.h +++ b/Client.h @@ -73,7 +73,7 @@ protected: class CClient : public CZNCSock { public: - CClient(const CString& sHostname, unsigned short uPort) : CZNCSock(sHostname, uPort) { + CClient() : CZNCSock() { m_pUser = NULL; m_bGotPass = false; m_bGotNick = false; @@ -85,10 +85,6 @@ public: // a little more gentle ;) SetMaxBufferThreshold(1024); - // Disable all timeout types. The socket will now time out in 60 - // seconds, no matter what. AcceptLogin() fixes this up. - SetTimeout(60, 0); - SetNick("unknown-nick"); } diff --git a/Listener.cpp b/Listener.cpp index 4b36d3d8..d98818db 100644 --- a/Listener.cpp +++ b/Listener.cpp @@ -38,11 +38,12 @@ bool CRealListener::ConnectionFrom(const CString& sHost, unsigned short uPort) { } Csock* CRealListener::GetSockObj(const CString& sHost, unsigned short uPort) { - CClient *pClient = new CClient(sHost, uPort); + CIncomingConnection *pClient = new CIncomingConnection(sHost, uPort); if (CZNC::Get().AllowConnectionFrom(sHost)) { CZNC::Get().GetModules().OnClientConnect(pClient, sHost, uPort); } else { - pClient->RefuseLogin("Too many anonymous connections from your IP"); + pClient->Write(":irc.znc.in 464 unknown-nick :Too many anonymous connections from your IP\r\n"); + pClient->Close(Csock::CLT_AFTERWRITE); CZNC::Get().GetModules().OnFailedLogin("", sHost); } return pClient; @@ -56,3 +57,43 @@ void CRealListener::SockError(int iErrno) { Close(); } } + +CIncomingConnection::CIncomingConnection(const CString& sHostname, unsigned short uPort) : CZNCSock(sHostname, uPort) { + // The socket will time out in 120 secs, no matter what. + // This has to be fixed up later, if desired. + SetTimeout(120, 0); + + EnableReadLine(); +} + +void CIncomingConnection::ReadLine(const CString& sLine) { + bool bIsHTTP = (sLine.WildCmp("GET * HTTP/1.?\r\n") || sLine.WildCmp("POST * HTTP/1.?\r\n")); + Csock *pSock = NULL; + + if (!bIsHTTP) { + // Let's assume it's an IRC connection + + pSock = new CClient(); + CZNC::Get().GetManager().SwapSockByAddr(pSock, this); + + // And don't forget to give it some sane name / timeout + pSock->SetSockName("USR::???"); + } else { + // This is a HTTP request, let the webmods handle it + + CModule* pMod = new CModule(NULL, "", ""); + pMod->SetFake(true); + + pSock = new CWebSock(pMod); + CZNC::Get().GetManager().SwapSockByAddr(pSock, this); + + // And don't forget to give it some sane name / timeout + pSock->SetSockName("WebMod::Client"); + } + + if (pSock) { + // TODO can we somehow get rid of this? + pSock->ReadLine(sLine); + pSock->PushBuff("", 0, true); + } +} diff --git a/Listener.h b/Listener.h index 0ead18d2..5c220d5f 100644 --- a/Listener.h +++ b/Listener.h @@ -66,4 +66,11 @@ protected: CRealListener* m_pListener; }; +class CIncomingConnection : public CZNCSock { +public: + CIncomingConnection(const CString& sHostname, unsigned short uPort); + virtual ~CIncomingConnection() {} + virtual void ReadLine(const CString& sData); +}; + #endif // !_LISTENER_H diff --git a/Modules.cpp b/Modules.cpp index ad23c732..0aeb9bc7 100644 --- a/Modules.cpp +++ b/Modules.cpp @@ -501,7 +501,7 @@ bool CModule::PutModNotice(const CString& sLine, const CString& sIdent, const CS CModule::EModRet CGlobalModule::OnWriteConfig(CFile& Config) { return CONTINUE; } CModule::EModRet CGlobalModule::OnAddUser(CUser& User, CString& sErrorRet) { return CONTINUE; } CModule::EModRet CGlobalModule::OnDeleteUser(CUser& User) { return CONTINUE; } -void CGlobalModule::OnClientConnect(CClient* pClient, const CString& sHost, unsigned short uPort) {} +void CGlobalModule::OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) {} CModule::EModRet CGlobalModule::OnLoginAttempt(CSmartPtr Auth) { return CONTINUE; } void CGlobalModule::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) {} CModule::EModRet CGlobalModule::OnUnknownUserRaw(CClient* pClient, CString& sLine) { return CONTINUE; } @@ -613,7 +613,7 @@ bool CGlobalModules::OnDeleteUser(CUser& User) { GLOBALMODHALTCHK(OnDeleteUser(User)); } -void CGlobalModules::OnClientConnect(CClient* pClient, const CString& sHost, unsigned short uPort) { +void CGlobalModules::OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) { GLOBALMODCALL(OnClientConnect(pClient, sHost, uPort)); } diff --git a/Modules.h b/Modules.h index 30480efd..e06f128a 100644 --- a/Modules.h +++ b/Modules.h @@ -940,11 +940,11 @@ public: virtual EModRet OnDeleteUser(CUser& User); /** This module hook is called when there is an incoming connection on * any of ZNC's listening sockets. - * @param pClient The incoming client socket. + * @param pSock The incoming client socket. * @param sHost The IP the client is connecting from. * @param uPort The port the client is connecting from. */ - virtual void OnClientConnect(CClient* pClient, const CString& sHost, unsigned short uPort); + virtual void OnClientConnect(CZNCSock* pSock, const CString& sHost, unsigned short uPort); /** This module hook is called when a client tries to login. If your * module wants to handle the login attempt, it must return * CModule::EModRet::HALT; @@ -977,7 +977,7 @@ public: bool OnWriteConfig(CFile& Config); bool OnAddUser(CUser& User, CString& sErrorRet); bool OnDeleteUser(CUser& User); - void OnClientConnect(CClient* pClient, const CString& sHost, unsigned short uPort); + void OnClientConnect(CZNCSock* pSock, const CString& sHost, unsigned short uPort); bool OnLoginAttempt(CSmartPtr Auth); void OnFailedLogin(const CString& sUsername, const CString& sRemoteIP); bool OnUnknownUserRaw(CClient* pClient, CString& sLine); diff --git a/modules/fail2ban.cpp b/modules/fail2ban.cpp index c5be7316..6ee9b7f9 100644 --- a/modules/fail2ban.cpp +++ b/modules/fail2ban.cpp @@ -52,7 +52,7 @@ public: PutModule("is blocked after a failed login."); } - virtual void OnClientConnect(CClient* pClient, const CString& sHost, unsigned short uPort) { + virtual void OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) { unsigned int *pCount = m_Cache.GetItem(sHost); if (sHost.empty() || pCount == NULL || *pCount < m_uiAllowedFailed) { return; @@ -61,7 +61,7 @@ public: // refresh their ban Add(sHost, *pCount); - pClient->PutClient("ERROR :Closing link [Please try again later - reconnecting too fast]"); + pClient->Write("ERROR :Closing link [Please try again later - reconnecting too fast]\r\n"); pClient->Close(Csock::CLT_AFTERWRITE); }