diff --git a/include/znc/HTTPSock.h b/include/znc/HTTPSock.h index 407c04b0..afdc143a 100644 --- a/include/znc/HTTPSock.h +++ b/include/znc/HTTPSock.h @@ -56,6 +56,7 @@ public: void ParseURI(); void GetPage(); static CString GetDate(time_t tm = 0); + virtual CString GetRemoteIP(); // Cookies CString GetRequestCookie(const CString& sKey) const; diff --git a/include/znc/WebModules.h b/include/znc/WebModules.h index 6e855443..a60c88f9 100644 --- a/include/znc/WebModules.h +++ b/include/znc/WebModules.h @@ -130,7 +130,6 @@ 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 c1dabb51..499aa113 100644 --- a/include/znc/znc.h +++ b/include/znc/znc.h @@ -66,9 +66,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 ClearTrustedProxies(); + bool AddTrustedProxy(const CString& sHost); + bool RemTrustedProxy(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; } @@ -120,7 +120,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 VCString& GetTrustedProxies() const { return m_vsTrustedProxies; } const std::vector& GetListeners() const { return m_vpListeners; } time_t TimeStarted() const { return m_TimeStarted; } unsigned int GetMaxBufferSize() const { return m_uiMaxBufferSize; } @@ -208,7 +208,7 @@ protected: CString m_sPidFile; CString m_sSSLCertFile; VCString m_vsBindHosts; - VCString m_vsAllowProxies; + VCString m_vsTrustedProxies; VCString m_vsMotd; CFile* m_pLockFile; unsigned int m_uiConnectDelay; diff --git a/src/HTTPSock.cpp b/src/HTTPSock.cpp index 471bf5a1..81a905d6 100644 --- a/src/HTTPSock.cpp +++ b/src/HTTPSock.cpp @@ -128,7 +128,37 @@ void CHTTPSock::ReadLine(const CString& sData) { 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:")) { - m_sForwardedIP = sLine.Token(1).TrimRight_n(","); + // X-Forwarded-For: client, proxy1, proxy2 + if (m_sForwardedIP.empty()) { + const VCString& vsTrustedProxies = CZNC::Get().GetTrustedProxies(); + CString sIP = GetRemoteIP(); + + VCString vsIPs; + sLine.Token(1, true).Split(",", vsIPs, false, "", "", false, true); + + while (!vsIPs.empty()) { + // sIP told us that it got connection from vsIPs.back() + // check if sIP is trusted proxy + bool bTrusted = false; + for (VCString::const_iterator it = vsTrustedProxies.begin(); it != vsTrustedProxies.end(); ++it) { + if (sIP.WildCmp(*it)) { + bTrusted = true; + break; + } + } + if (bTrusted) { + // sIP is trusted proxy, so use vsIPs.back() as new sIP + sIP = vsIPs.back(); + vsIPs.pop_back(); + } else { + break; + } + } + + // either sIP is not trusted proxy, or it's in the beginning of the X-Forwarded-For list + // in both cases use it as the endpoind + m_sForwardedIP = sIP; + } } 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); @@ -151,6 +181,14 @@ void CHTTPSock::ReadLine(const CString& sData) { } } +CString CHTTPSock::GetRemoteIP() { + if (!m_sForwardedIP.empty()) { + return m_sForwardedIP; + } + + return CSocket::GetRemoteIP(); +} + CString CHTTPSock::GetDate(time_t stamp) { struct tm tm; std::stringstream stream; diff --git a/src/WebModules.cpp b/src/WebModules.cpp index c1c653d1..3f000f71 100644 --- a/src/WebModules.cpp +++ b/src/WebModules.cpp @@ -866,21 +866,6 @@ 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 d28a89fc..70752843 100644 --- a/src/znc.cpp +++ b/src/znc.cpp @@ -484,8 +484,8 @@ 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()); + for (unsigned int v = 0; v < m_vsTrustedProxies.size(); v++) { + config.AddKeyValuePair("TrustedProxy", m_vsTrustedProxies[v].FirstLine()); } CModules& Mods = GetModules(); @@ -1114,7 +1114,7 @@ bool CZNC::DoRehash(CString& sError) } m_vsBindHosts.clear(); - m_vsAllowProxies.clear(); + m_vsTrustedProxies.clear(); m_vsMotd.clear(); // Delete all listeners @@ -1209,9 +1209,9 @@ bool CZNC::DoRehash(CString& sError) AddBindHost(*vit); } - config.FindStringVector("allowproxy", vsList); + config.FindStringVector("trustedproxy", vsList); for (vit = vsList.begin(); vit != vsList.end(); ++vit) { - AddAllowProxy(*vit); + AddTrustedProxy(*vit); } config.FindStringVector("vhost", vsList); @@ -1437,30 +1437,30 @@ bool CZNC::RemBindHost(const CString& sHost) { return false; } -void CZNC::ClearAllowProxy() { - m_vsAllowProxies.clear(); +void CZNC::ClearTrustedProxies() { + m_vsTrustedProxies.clear(); } -bool CZNC::AddAllowProxy(const CString& sHost) { +bool CZNC::AddTrustedProxy(const CString& sHost) { if (sHost.empty()) { return false; } - for (unsigned int a = 0; a < m_vsAllowProxies.size(); a++) { - if (m_vsAllowProxies[a].Equals(sHost)) { + for (unsigned int a = 0; a < m_vsTrustedProxies.size(); a++) { + if (m_vsTrustedProxies[a].Equals(sHost)) { return false; } } - m_vsAllowProxies.push_back(sHost); + m_vsTrustedProxies.push_back(sHost); return true; } -bool CZNC::RemAllowProxy(const CString& sHost) { +bool CZNC::RemTrustedProxy(const CString& sHost) { VCString::iterator it; - for (it = m_vsAllowProxies.begin(); it != m_vsAllowProxies.end(); ++it) { + for (it = m_vsTrustedProxies.begin(); it != m_vsTrustedProxies.end(); ++it) { if (sHost.Equals(*it)) { - m_vsAllowProxies.erase(it); + m_vsTrustedProxies.erase(it); return true; } }