diff --git a/include/znc/HTTPSock.h b/include/znc/HTTPSock.h index 4b80a6e0..407c04b0 100644 --- a/include/znc/HTTPSock.h +++ b/include/znc/HTTPSock.h @@ -111,6 +111,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 a60c88f9..6e855443 100644 --- a/include/znc/WebModules.h +++ b/include/znc/WebModules.h @@ -130,6 +130,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 9be132f2..c1dabb51 100644 --- a/include/znc/znc.h +++ b/include/znc/znc.h @@ -66,6 +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 Broadcast(const CString& sMessage, bool bAdminOnly = false, CUser* pSkipUser = NULL, CClient* pSkipClient = NULL); void AddBytesRead(unsigned long long u) { m_uBytesRead += u; } @@ -117,6 +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 std::vector& GetListeners() const { return m_vpListeners; } time_t TimeStarted() const { return m_TimeStarted; } unsigned int GetMaxBufferSize() const { return m_uiMaxBufferSize; } @@ -204,6 +208,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 c0a2a535..471bf5a1 100644 --- a/src/HTTPSock.cpp +++ b/src/HTTPSock.cpp @@ -127,6 +127,8 @@ 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:")) { + m_sForwardedIP = sLine.Token(1).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 3f000f71..c1c653d1 100644 --- a/src/WebModules.cpp +++ b/src/WebModules.cpp @@ -866,6 +866,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 827b63bf..d28a89fc 100644 --- a/src/znc.cpp +++ b/src/znc.cpp @@ -484,6 +484,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++) { @@ -1110,6 +1114,7 @@ bool CZNC::DoRehash(CString& sError) } m_vsBindHosts.clear(); + m_vsAllowProxies.clear(); m_vsMotd.clear(); // Delete all listeners @@ -1203,6 +1208,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); @@ -1426,6 +1437,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) {