diff --git a/include/znc/HTTPSock.h b/include/znc/HTTPSock.h index 82d49daa..30aff7dd 100644 --- a/include/znc/HTTPSock.h +++ b/include/znc/HTTPSock.h @@ -99,6 +99,7 @@ protected: CString m_sPass; CString m_sContentType; CString m_sDocRoot; + CString m_sForwardedIP; std::map m_msvsPOSTParams; std::map m_msvsGETParams; MCString m_msHeaders; diff --git a/include/znc/WebModules.h b/include/znc/WebModules.h index 13bf8fa5..9b5a1168 100644 --- a/include/znc/WebModules.h +++ b/include/znc/WebModules.h @@ -122,6 +122,7 @@ public: CSmartPtr GetSession(); + virtual CString GetRemoteIP(); virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort); static CString GetSkinPath(const CString& sSkinName); CModule* GetModule() const { return (CModule*) m_pModule; } diff --git a/include/znc/znc.h b/include/znc/znc.h index 6b707b1c..fbd61494 100644 --- a/include/znc/znc.h +++ b/include/znc/znc.h @@ -58,6 +58,9 @@ public: void ClearBindHosts(); bool AddBindHost(const CString& sHost); bool RemBindHost(const CString& sHost); + void ClearAllowProxy(); + bool AddAllowProxy(const CString& sHost); + bool RemAllowProxy(const CString& sHost); void Broadcast(const CString& sMessage, bool bAdminOnly = false, CUser* pSkipUser = NULL, CClient* pSkipClient = NULL); void AddBytesRead(unsigned long long u) { m_uBytesRead += u; } @@ -109,6 +112,7 @@ public: const CString& GetConfigFile() const { return m_sConfigFile; } bool WritePemFile(); const VCString& GetBindHosts() const { return m_vsBindHosts; } + const VCString& GetAllowProxies() const { return m_vsAllowProxies; } const std::vector& GetListeners() const { return m_vpListeners; } time_t TimeStarted() const { return m_TimeStarted; } unsigned int GetMaxBufferSize() const { return m_uiMaxBufferSize; } @@ -196,6 +200,7 @@ protected: CString m_sPidFile; CString m_sSSLCertFile; VCString m_vsBindHosts; + VCString m_vsAllowProxies; VCString m_vsMotd; CFile* m_pLockFile; unsigned int m_uiConnectDelay; diff --git a/src/HTTPSock.cpp b/src/HTTPSock.cpp index 92888b0b..9a74bfd8 100644 --- a/src/HTTPSock.cpp +++ b/src/HTTPSock.cpp @@ -113,6 +113,9 @@ void CHTTPSock::ReadLine(const CString& sData) { m_uPostLen = sLine.Token(1).ToULong(); if (m_uPostLen > MAX_POST_SIZE) PrintErrorPage(413, "Request Entity Too Large", "The request you sent was too large."); + } else if (sName.Equals("X-Forwarded-For:")) { + CString sIP = sLine.Token(1, false); + m_sForwardedIP = sIP.TrimRight_n(", "); } else if (sName.Equals("If-None-Match:")) { // this is for proper client cache support (HTTP 304) on static files: m_sIfNoneMatch = sLine.Token(1, true); diff --git a/src/WebModules.cpp b/src/WebModules.cpp index f943a16a..abaf534a 100644 --- a/src/WebModules.cpp +++ b/src/WebModules.cpp @@ -838,6 +838,21 @@ bool CWebSock::OnLogin(const CString& sUser, const CString& sPass) { return IsLoggedIn(); } +CString CWebSock::GetRemoteIP() +{ + const VCString& vsProxies = CZNC::Get().GetAllowProxies(); + CString sIP = CHTTPSock::GetRemoteIP(); + + VCString::const_iterator it; + for (it = vsProxies.begin(); it != vsProxies.end(); ++it) { + if (sIP.WildCmp(*it)) { + return m_sForwardedIP; + } + } + + return sIP; +} + Csock* CWebSock::GetSockObj(const CString& sHost, unsigned short uPort) { // All listening is done by CListener, thus CWebSock should never have // to listen, but since GetSockObj() is pure virtual... diff --git a/src/znc.cpp b/src/znc.cpp index 8421bf51..46397520 100644 --- a/src/znc.cpp +++ b/src/znc.cpp @@ -467,6 +467,10 @@ bool CZNC::WriteConfig() { config.AddKeyValuePair("BindHost", m_vsBindHosts[v].FirstLine()); } + for (unsigned int v = 0; v < m_vsAllowProxies.size(); v++) { + config.AddKeyValuePair("AllowProxy", m_vsAllowProxies[v].FirstLine()); + } + CModules& Mods = GetModules(); for (unsigned int a = 0; a < Mods.size(); a++) { @@ -1093,6 +1097,7 @@ bool CZNC::DoRehash(CString& sError) } m_vsBindHosts.clear(); + m_vsAllowProxies.clear(); m_vsMotd.clear(); // Delete all listeners @@ -1186,6 +1191,12 @@ bool CZNC::DoRehash(CString& sError) for (vit = vsList.begin(); vit != vsList.end(); ++vit) { AddBindHost(*vit); } + + config.FindStringVector("allowproxy", vsList); + for (vit = vsList.begin(); vit != vsList.end(); ++vit) { + AddAllowProxy(*vit); + } + config.FindStringVector("vhost", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { AddBindHost(*vit); @@ -1409,6 +1420,37 @@ bool CZNC::RemBindHost(const CString& sHost) { return false; } +void CZNC::ClearAllowProxy() { + m_vsAllowProxies.clear(); +} + +bool CZNC::AddAllowProxy(const CString& sHost) { + if (sHost.empty()) { + return false; + } + + for (unsigned int a = 0; a < m_vsAllowProxies.size(); a++) { + if (m_vsAllowProxies[a].Equals(sHost)) { + return false; + } + } + + m_vsAllowProxies.push_back(sHost); + return true; +} + +bool CZNC::RemAllowProxy(const CString& sHost) { + VCString::iterator it; + for (it = m_vsAllowProxies.begin(); it != m_vsAllowProxies.end(); ++it) { + if (sHost.Equals(*it)) { + m_vsAllowProxies.erase(it); + return true; + } + } + + return false; +} + void CZNC::Broadcast(const CString& sMessage, bool bAdminOnly, CUser* pSkipUser, CClient *pSkipClient) { for (map::iterator a = m_msUsers.begin(); a != m_msUsers.end(); ++a) {