From ca8247058f7644af519cdbf944d5a54db6adc6ca Mon Sep 17 00:00:00 2001 From: prozacx Date: Sat, 11 Feb 2006 10:06:45 +0000 Subject: [PATCH] Added ipv6 support and multiple listen ports git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@641 726aef4b-f618-498e-8847-2d620e286838 --- Server.cpp | 4 +- Server.h | 4 +- User.cpp | 15 +++++-- User.h | 4 +- main.cpp | 4 +- znc.cpp | 130 ++++++++++++++++++++++++++++++++++------------------- znc.h | 66 +++++++++++++++++++++------ 7 files changed, 158 insertions(+), 69 deletions(-) diff --git a/Server.cpp b/Server.cpp index cc9105b0..e7e66645 100644 --- a/Server.cpp +++ b/Server.cpp @@ -1,11 +1,12 @@ #include "main.h" #include "Server.h" -CServer::CServer(const CString& sName, unsigned short uPort, const CString& sPass, bool bSSL) { +CServer::CServer(const CString& sName, unsigned short uPort, const CString& sPass, bool bSSL, bool bIPV6) { m_sName = sName; m_uPort = (uPort) ? uPort : 6667; m_sPass = sPass; m_bSSL = bSSL; + m_bIPV6 = bIPV6; } CServer::~CServer() {} @@ -30,6 +31,7 @@ const CString& CServer::GetName() const { return m_sName; } unsigned short CServer::GetPort() const { return m_uPort; } const CString& CServer::GetPass() const { return m_sPass; } bool CServer::IsSSL() const { return m_bSSL; } +bool CServer::IsIPV6() const { return m_bIPV6; } CString CServer::GetString() const { return m_sName + " " + CString(m_bSSL ? "+" : "") + CString::ToString(m_uPort) + CString(m_sPass.empty() ? CString("") : " " + m_sPass); diff --git a/Server.h b/Server.h index 3a6334ed..c03a1922 100644 --- a/Server.h +++ b/Server.h @@ -5,13 +5,14 @@ class CServer { public: - CServer(const CString& sName, unsigned short uPort = 6667, const CString& sPass = "", bool bSSL = false); + CServer(const CString& sName, unsigned short uPort = 6667, const CString& sPass = "", bool bSSL = false, bool bIPV6 = false); virtual ~CServer(); const CString& GetName() const; unsigned short GetPort() const; const CString& GetPass() const; bool IsSSL() const; + bool IsIPV6() const; CString GetString() const; static bool IsValidHostName(const CString& sHostName); private: @@ -20,6 +21,7 @@ protected: unsigned short m_uPort; CString m_sPass; bool m_bSSL; + bool m_bIPV6; }; #endif // !_SERVER_H diff --git a/User.cpp b/User.cpp index 8e089e8e..9a807f1a 100644 --- a/User.cpp +++ b/User.cpp @@ -597,7 +597,7 @@ bool CUser::DelServer(const CString& sName) { return false; } -bool CUser::AddServer(const CString& sName) { +bool CUser::AddServer(const CString& sName, bool bIPV6) { if (sName.empty()) { return false; } @@ -617,15 +617,22 @@ bool CUser::AddServer(const CString& sName) { unsigned short uPort = strtoul(sPort.c_str(), NULL, 10); CString sPass = sLine.Token(2, true); - return AddServer(sHost, uPort, sPass, bSSL); + return AddServer(sHost, uPort, sPass, bSSL, bIPV6); } -bool CUser::AddServer(const CString& sName, unsigned short uPort, const CString& sPass, bool bSSL) { +bool CUser::AddServer(const CString& sName, unsigned short uPort, const CString& sPass, bool bSSL, bool bIPV6) { #ifndef HAVE_LIBSSL if (bSSL) { return false; } #endif + +#ifndef HAVE_IPV6 + if (bIPV6) { + return false; + } +#endif + if (sName.empty()) { return false; } @@ -634,7 +641,7 @@ bool CUser::AddServer(const CString& sName, unsigned short uPort, const CString& uPort = 6667; } - CServer* pServer = new CServer(sName, uPort, sPass, bSSL); + CServer* pServer = new CServer(sName, uPort, sPass, bSSL, bIPV6); m_vServers.push_back(pServer); return true; diff --git a/User.h b/User.h index 1981a6d5..032a5fa5 100644 --- a/User.h +++ b/User.h @@ -39,8 +39,8 @@ public: void JoinChans(); CServer* FindServer(const CString& sName); bool DelServer(const CString& sName); - bool AddServer(const CString& sName); - bool AddServer(const CString& sName, unsigned short uPort, const CString& sPass = "", bool bSSL = false); + bool AddServer(const CString& sName, bool bIPV6 = false); + bool AddServer(const CString& sName, unsigned short uPort, const CString& sPass = "", bool bSSL = false, bool bIPV6 = false); CServer* GetNextServer(); CServer* GetCurrentServer(); bool CheckPass(const CString& sPass); diff --git a/main.cpp b/main.cpp index e443243a..5fab762e 100644 --- a/main.cpp +++ b/main.cpp @@ -161,8 +161,8 @@ int main(int argc, char** argv, char** envp) { return 1; } - if (!pZNC->GetListenPort()) { - CUtils::PrintError("You must supply a ListenPort in your config."); + if (!pZNC->GetListeners().size()) { + CUtils::PrintError("You must supply at least one Listen port in your config."); delete pZNC; return 1; } diff --git a/znc.cpp b/znc.cpp index 1cfc815d..1d4a1f76 100644 --- a/znc.cpp +++ b/znc.cpp @@ -17,7 +17,6 @@ CZNC::CZNC() { #ifdef _MODULES m_pModules = new CGlobalModules(); #endif - m_uListenPort = 0; m_bISpoofLocked = false; SetISpoofFormat(""); // Set ISpoofFormat to default } @@ -32,6 +31,10 @@ CZNC::~CZNC() { } #endif + for (size_t b = 0; b < m_vpListeners.size(); b++) { + delete m_vpListeners[b]; + } + m_Manager.Cleanup(); DeleteUsers(); } @@ -142,20 +145,26 @@ int CZNC::Loop() { m_bISpoofLocked = true; } - DEBUG_ONLY( cout << "User [" << pUser->GetUserName() << "] is connecting to [" << pServer->GetName() << ":" << pServer->GetPort() << "] ..." << endl); + DEBUG_ONLY(cout << "User [" << pUser->GetUserName() << "] is connecting to [" << pServer->GetName() << ":" << pServer->GetPort() << "] ..." << endl); pUser->PutStatus("Attempting to connect to [" + pServer->GetName() + ":" + CString::ToString(pServer->GetPort()) + "] ..."); pIRCSock = new CIRCSock(pUser); pIRCSock->SetPass(pServer->GetPass()); bool bSSL = false; + bool bIPV6 = false; #ifdef HAVE_LIBSSL if (pServer->IsSSL()) { bSSL = true; pIRCSock->SetPemLocation(GetPemLocation()); } #endif - if (!m_Manager.Connect(pServer->GetName(), pServer->GetPort(), sSockName, 20, bSSL, pUser->GetVHost(), pIRCSock)) { +#ifdef HAVE_IPV6 + if (pServer->IsIPV6()) { + bIPV6 = true; + } +#endif + if (!m_Manager.Connect(pServer->GetName(), pServer->GetPort(), sSockName, 20, bSSL, pUser->GetVHost(), pIRCSock, bIPV6)) { ReleaseISpoof(); pUser->PutStatus("Unable to connect. (Bad host?)"); } @@ -253,24 +262,6 @@ Csock* CZNC::FindSockByName(const CString& sSockName) { return m_Manager.FindSockByName(sSockName); } -bool CZNC::Listen() { - if (!m_uListenPort) { - return false; - } - - CClient* pClient = new CClient; - - bool bSSL = false; -#ifdef HAVE_LIBSSL - if (IsSSL()) { - bSSL = true; - pClient->SetPemLocation(GetPemLocation()); - } -#endif - - return m_Manager.ListenHost(m_uListenPort, "_LISTENER", m_sListenHost, bSSL, SOMAXCONN, pClient); -} - bool CZNC::IsHostAllowed(const CString& sHostMask) { for (map::iterator a = m_msUsers.begin(); a != m_msUsers.end(); a++) { if (a->second->IsHostAllowed(sHostMask)) { @@ -339,12 +330,18 @@ bool CZNC::WriteConfig() { return false; } - CString sHostPortion; - if (!m_sListenHost.empty()) { - sHostPortion = m_sListenHost + ":"; - } + for (size_t l = 0; l < m_vpListeners.size(); l++) { + CListener* pListener = m_vpListeners[l]; + CString sHostPortion = pListener->GetBindHost(); - File.Write("Listen = " + sHostPortion + CString((m_bSSL) ? "+" : "") + CString::ToString(m_uListenPort) + "\r\n"); + if (!sHostPortion.empty()) { + sHostPortion += " "; + } + + CString s6 = (pListener->IsIPV6()) ? "6" : " "; + + File.Write("Listen" + s6 + " = " + sHostPortion + CString((pListener->IsSSL()) ? "+" : "") + CString::ToString(pListener->GetPort()) + "\r\n"); + } if (!m_sISpoofFile.empty()) { File.Write("ISpoofFile = " + m_sISpoofFile + "\r\n"); @@ -400,7 +397,6 @@ bool CZNC::WriteNewConfig(const CString& sConfig) { CString sConfigFile = ExpandConfigPath((sConfig.empty()) ? "znc.conf" : sConfig); CString sAnswer, sUser; vector vsLines; - bool bAnswer = false; if (CFile::Exists(sConfigFile)) { if (!m_LockFile.TryExLock(sConfigFile, 50)) { @@ -423,18 +419,29 @@ bool CZNC::WriteNewConfig(const CString& sConfig) { // Listen unsigned int uPort = 0; while(!CUtils::GetNumInput("What port would you like ZNC to listen on?", uPort, 1, 65535)); + + CString sSSL; #ifdef HAVE_LIBSSL - bAnswer = CUtils::GetBoolInput("Would you like ZNC to listen using SSL?", false); + if (CUtils::GetBoolInput("Would you like ZNC to listen using SSL?", false)) { + sSSL = "+"; + } +#endif + + CString s6 = " "; +#ifdef HAVE_IPV6 + if (CUtils::GetBoolInput("Would you like ZNC to listen using ipv6?", false)) { + s6 = "6"; + } #endif CString sListenHost; CUtils::GetInput("Listen Host", sListenHost, "", "Blank for all ips"); if (!sListenHost.empty()) { - sListenHost += ":"; + sListenHost += " "; } - vsLines.push_back("Listen = " + sListenHost + CString((bAnswer) ? "+" : "") + CString::ToString(uPort)); + vsLines.push_back("Listen" + s6 + " = " + sListenHost + sSSL + CString::ToString(uPort)); // !Listen #ifdef _MODULES @@ -925,6 +932,14 @@ bool CZNC::ParseConfig(const CString& sConfig) { } else if (sName.CaseCmp("Allow") == 0) { pUser->AddAllowedHost(sValue); continue; + } else if (sName.CaseCmp("Server6") == 0) { + CUtils::PrintAction("Adding ipv6 Server [" + sValue + "]"); +#ifdef HAVE_IPV6 + CUtils::PrintStatus(pUser->AddServer(sValue, true)); +#else + CUtils::PrintStatus(false, "ZNC was not compiled with ipv6 support"); +#endif + continue; } else if (sName.CaseCmp("Server") == 0) { CUtils::PrintAction("Adding Server [" + sValue + "]"); CUtils::PrintStatus(pUser->AddServer(sValue)); @@ -956,41 +971,60 @@ bool CZNC::ParseConfig(const CString& sConfig) { } } } else { - if (sName.CaseCmp("Listen") == 0 || sName.CaseCmp("ListenPort") == 0) { - m_bSSL = false; + if (sName.CaseCmp("Listen") == 0 || sName.CaseCmp("ListenPort") == 0 || sName.CaseCmp("Listen6") == 0) { + bool bSSL = false; + bool bIPV6 = (sName.CaseCmp("Listen6") == 0); CString sPort; - if (sValue.find(":") != CString::npos) { - m_sListenHost = sValue.Token(0, false, ":"); - sPort = sValue.Token(1, true, ":"); + CString sBindHost; + + if (!bIPV6) { + sValue.Replace(":", " "); + } + + if (sValue.find(" ") != CString::npos) { + sBindHost = sValue.Token(0, false, " "); + sPort = sValue.Token(1, true, " "); } else { - m_sListenHost = ""; sPort = sValue; } if (sPort.Left(1) == "+") { sPort.LeftChomp(); - m_bSSL = true; + bSSL = true; } CString sHostComment; - if (!m_sListenHost.empty()) { - sHostComment = " on host [" + m_sListenHost + "]"; + if (!sBindHost.empty()) { + sHostComment = " on host [" + sBindHost + "]"; } - m_uListenPort = strtol(sPort.c_str(), NULL, 10); - CUtils::PrintAction("Binding to port [" + CString((m_bSSL) ? "+" : "") + CString::ToString(m_uListenPort) + "]" + sHostComment); + CString sIPV6Comment; + + if (bIPV6) { + sIPV6Comment = " using ipv6"; + } + + unsigned short uPort = strtol(sPort.c_str(), NULL, 10); + CUtils::PrintAction("Binding to port [" + CString((bSSL) ? "+" : "") + CString::ToString(uPort) + "]" + sHostComment + sIPV6Comment); + +#ifndef HAVE_IPV6 + if (bIPV6) { + CUtils::PrintStatus(false, "IPV6 is not enabled"); + return false; + } +#endif #ifndef HAVE_LIBSSL - if (m_bSSL) { + if (bSSL) { CUtils::PrintStatus(false, "SSL is not enabled"); return false; } #else CString sPemFile = GetPemLocation(); - if ((m_bSSL) && (!CFile::Exists(sPemFile))) { + if (bSSL && !CFile::Exists(sPemFile)) { CUtils::PrintStatus(false, "Unable to locate pem file: [" + sPemFile + "]"); if (CUtils::GetBoolInput("Would you like to create a new pem file?", true)) { @@ -999,19 +1033,23 @@ bool CZNC::ParseConfig(const CString& sConfig) { return false; } - CUtils::PrintAction("Binding to port [" + CString((m_bSSL) ? "+" : "") + CString::ToString(m_uListenPort) + "]"); + CUtils::PrintAction("Binding to port [+" + CString::ToString(uPort) + "]" + sHostComment + sIPV6Comment); } #endif - if (!m_uListenPort) { + if (!uPort) { CUtils::PrintStatus(false, "Invalid port"); return false; } - if (!Listen()) { + CListener* pListener = new CListener(uPort, sBindHost, bSSL, bIPV6); + + if (!pListener->Listen()) { CUtils::PrintStatus(false, "Unable to bind"); + delete pListener; return false; } + m_vpListeners.push_back(pListener); CUtils::PrintStatus(true); continue; diff --git a/znc.h b/znc.h index 7cd71527..153652e9 100644 --- a/znc.h +++ b/znc.h @@ -13,6 +13,7 @@ using std::set; class CUser; class CClient; +class CListener; class CZNC { public: @@ -25,7 +26,6 @@ public: bool WritePidFile(int iPid); CUser* GetUser(const CString& sUser); Csock* FindSockByName(const CString& sSockName); - bool Listen(); bool ParseConfig(const CString& sConfig); bool IsHostAllowed(const CString& sHostMask); void InitDirs(const CString& sArgvPath); @@ -51,8 +51,6 @@ public: #ifdef _MODULES CGlobalModules& GetModules() { return *m_pModules; } #endif - unsigned short GetListenPort() const { return m_uListenPort; } - const CString& GetListenHost() const { return m_sListenHost; } const CString& GetStatusPrefix() const { return m_sStatusPrefix; } const CString& GetCurPath() const { if (!CFile::Exists(m_sCurPath)) { CUtils::MakeDir(m_sCurPath); } return m_sCurPath; } const CString& GetModPath() const { if (!CFile::Exists(m_sModPath)) { CUtils::MakeDir(m_sModPath); } return m_sModPath; } @@ -66,13 +64,7 @@ public: const CString& GetISpoofFile() const { return m_sISpoofFile; } const CString& GetISpoofFormat() const { return m_sISpoofFormat; } const VCString& GetVHosts() const { return m_vsVHosts; } - - bool IsSSL() const { -#ifdef HAVE_LIBSSL - return m_bSSL; -#endif - return false; - } + const vector& GetListeners() const { return m_vpListeners; } // !Getters // Static allocator @@ -91,8 +83,7 @@ public: private: protected: - unsigned short m_uListenPort; - CString m_sListenHost; + vector m_vpListeners; map m_msUsers; set m_ssDelUsers; TSocketManager m_Manager; @@ -115,11 +106,60 @@ protected: VCString m_vsMotd; CLockFile m_LockFile; bool m_bISpoofLocked; - bool m_bSSL; map::iterator m_itUserIter; // This needs to be reset to m_msUsers.begin() if anything is added or removed to the map #ifdef _MODULES CGlobalModules* m_pModules; #endif }; +class CListener { +public: + CListener(unsigned short uPort, const CString& sBindHost, bool bSSL, bool bIPV6) { + m_uPort = uPort; + m_sBindHost = sBindHost; + m_bSSL = bSSL; + m_bIPV6 = bIPV6; + } + + virtual ~CListener() {} + + // Setters + void SetSSL(bool b) { m_bSSL = b; } + void SetIPV6(bool b) { m_bIPV6 = b; } + void SetPort(unsigned short u) { m_uPort = u; } + void SetBindHost(const CString& s) { m_sBindHost = s; } + // !Setters + + // Getters + bool IsSSL() const { return m_bSSL; } + bool IsIPV6() const { return m_bIPV6; } + unsigned short GetPort() const { return m_uPort; } + const CString& GetBindHost() const { return m_sBindHost; } + // !Getters + + bool Listen() const { + if (!m_uPort) { + return false; + } + + CClient* pClient = new CClient; + + bool bSSL = false; +#ifdef HAVE_LIBSSL + if (IsSSL()) { + bSSL = true; + pClient->SetPemLocation(CZNC::Get().GetPemLocation()); + } +#endif + + return CZNC::Get().GetManager().ListenHost(m_uPort, "_LISTENER", m_sBindHost, bSSL, SOMAXCONN, pClient, m_bIPV6); + } +private: +protected: + bool m_bSSL; + bool m_bIPV6; + unsigned short m_uPort; + CString m_sBindHost; +}; + #endif // !_ZNC_H