From cebc09325435cfc2f75fad1b98bdf2f3ddc4c23a Mon Sep 17 00:00:00 2001 From: Alexey Sokolov Date: Thu, 19 Jul 2012 00:35:07 +0700 Subject: [PATCH] Per-network bind hosts. Fix #147 --- include/znc/IRCNetwork.h | 3 + .../data/webadmin/tmpl/add_edit_network.tmpl | 17 +++++- modules/webadmin.cpp | 38 +++++++++++++ src/Client.cpp | 4 +- src/ClientCommand.cpp | 55 ++++++++++++++++++- src/IRCNetwork.cpp | 26 ++++++++- src/IRCSock.cpp | 2 +- src/Socket.cpp | 10 +++- 8 files changed, 146 insertions(+), 9 deletions(-) diff --git a/include/znc/IRCNetwork.h b/include/znc/IRCNetwork.h index dc944cc7..fbb05391 100644 --- a/include/znc/IRCNetwork.h +++ b/include/znc/IRCNetwork.h @@ -131,11 +131,13 @@ public: const CString& GetAltNick(const bool bAllowDefault = true) const; const CString& GetIdent(const bool bAllowDefault = true) const; const CString& GetRealName() const; + const CString& GetBindHost() const; void SetNick(const CString& s); void SetAltNick(const CString& s); void SetIdent(const CString& s); void SetRealName(const CString& s); + void SetBindHost(const CString& s); double GetFloodRate() const { return m_fFloodRate; } unsigned short int GetFloodBurst() const { return m_uFloodBurst; } @@ -155,6 +157,7 @@ protected: CString m_sAltNick; CString m_sIdent; CString m_sRealName; + CString m_sBindHost; CModules* m_pModules; diff --git a/modules/data/webadmin/tmpl/add_edit_network.tmpl b/modules/data/webadmin/tmpl/add_edit_network.tmpl index e99db870..15c13b76 100644 --- a/modules/data/webadmin/tmpl/add_edit_network.tmpl +++ b/modules/data/webadmin/tmpl/add_edit_network.tmpl @@ -15,7 +15,7 @@

Network Info

- Nick, AltNick, Ident, RealName can be left empty to use the value from the user. + Nick, AltNick, Ident, RealName, BindHost can be left empty to use the value from the user.
@@ -48,6 +48,21 @@ title="Your real name." />
+ +
+
BindHost:
+ + + + + +
+
+ +
Active:
checked="checked" /> diff --git a/modules/webadmin.cpp b/modules/webadmin.cpp index 7a444770..f2e3076e 100644 --- a/modules/webadmin.cpp +++ b/modules/webadmin.cpp @@ -684,6 +684,38 @@ public: } } + // To change BindHosts be admin or don't have DenySetBindHost + if (spSession->IsAdmin() || !spSession->GetUser()->DenySetBindHost()) { + Tmpl["BindHostEdit"] = "true"; + const VCString& vsBindHosts = CZNC::Get().GetBindHosts(); + if (vsBindHosts.empty()) { + if (pNetwork) { + Tmpl["BindHost"] = pNetwork->GetBindHost(); + } + } else { + bool bFoundBindHost = false; + for (unsigned int b = 0; b < vsBindHosts.size(); b++) { + const CString& sBindHost = vsBindHosts[b]; + CTemplate& l = Tmpl.AddRow("BindHostLoop"); + + l["BindHost"] = sBindHost; + + if (pNetwork && pNetwork->GetBindHost() == sBindHost) { + l["Checked"] = "true"; + bFoundBindHost = true; + } + } + + // If our current bindhost is not in the global list... + if (pNetwork && !bFoundBindHost && !pNetwork->GetBindHost().empty()) { + CTemplate& l = Tmpl.AddRow("BindHostLoop"); + + l["BindHost"] = pNetwork->GetBindHost(); + l["Checked"] = "true"; + } + } + } + if (pNetwork) { Tmpl["Action"] = "editnetwork"; Tmpl["Edit"] = "true"; @@ -767,6 +799,12 @@ public: pNetwork->SetIRCConnectEnabled(WebSock.GetParam("doconnect").ToBool()); + sArg = WebSock.GetParam("bindhost"); + // To change BindHosts be admin or don't have DenySetBindHost + if (spSession->IsAdmin() || !spSession->GetUser()->DenySetBindHost()) { + pNetwork->SetBindHost(WebSock.GetParam("bindhost")); + } + if (WebSock.GetParam("floodprotection").ToBool()) { pNetwork->SetFloodRate(WebSock.GetParam("floodrate").ToDouble()); pNetwork->SetFloodBurst(WebSock.GetParam("floodburst").ToUInt()); diff --git a/src/Client.cpp b/src/Client.cpp index b3d03735..20082885 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -783,12 +783,12 @@ CString CClient::GetNickMask() const { return GetIRCSock()->GetNickMask(); } - CString sHost = m_pUser->GetBindHost(); + CString sHost = m_pNetwork ? m_pNetwork->GetBindHost() : m_pUser->GetBindHost(); if (sHost.empty()) { sHost = "irc.znc.in"; } - return GetNick() + "!" + m_pUser->GetIdent() + "@" + sHost; + return GetNick() + "!" + (m_pNetwork ? m_pNetwork->GetBindHost() : m_pUser->GetIdent()) + "@" + sHost; } void CClient::RespondCap(const CString& sResponse) diff --git a/src/ClientCommand.cpp b/src/ClientCommand.cpp index 9ed513f8..16fb8631 100644 --- a/src/ClientCommand.cpp +++ b/src/ClientCommand.cpp @@ -1004,6 +1004,10 @@ void CClient::UserCommand(CString& sLine) { } PutStatus(Table); } else if ((sCommand.Equals("SETBINDHOST") || sCommand.Equals("SETVHOST")) && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { + if (!m_pNetwork) { + PutStatus("You must be connected with a network to use this command. Try SetUserBindHost instead"); + return; + } CString sHost = sLine.Token(1); if (sHost.empty()) { @@ -1011,6 +1015,39 @@ void CClient::UserCommand(CString& sLine) { return; } + if (sHost.Equals(m_pNetwork->GetBindHost())) { + PutStatus("You already have this bind host!"); + return; + } + + const VCString& vsHosts = CZNC::Get().GetBindHosts(); + if (!m_pUser->IsAdmin() && !vsHosts.empty()) { + VCString::const_iterator it; + bool bFound = false; + + for (it = vsHosts.begin(); it != vsHosts.end(); ++it) { + if (sHost.Equals(*it)) { + bFound = true; + break; + } + } + + if (!bFound) { + PutStatus("You may not use this bind host. See [ListBindHosts] for a list"); + return; + } + } + + m_pNetwork->SetBindHost(sHost); + PutStatus("Set bind host for network [" + m_pNetwork->GetName() + "] to [" + m_pNetwork->GetBindHost() + "]"); + } else if (sCommand.Equals("SETUSERBINDHOST") && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { + CString sHost = sLine.Token(1); + + if (sHost.empty()) { + PutStatus("Usage: SetUserBindHost "); + return; + } + if (sHost.Equals(m_pUser->GetBindHost())) { PutStatus("You already have this bind host!"); return; @@ -1037,8 +1074,15 @@ void CClient::UserCommand(CString& sLine) { m_pUser->SetBindHost(sHost); PutStatus("Set bind host to [" + m_pUser->GetBindHost() + "]"); } else if ((sCommand.Equals("CLEARBINDHOST") || sCommand.Equals("CLEARVHOST")) && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { + if (!m_pNetwork) { + PutStatus("You must be connected with a network to use this command. Try ClearUserBindHost instead"); + return; + } + m_pNetwork->SetBindHost(""); + PutStatus("Bind host cleared"); + } else if (sCommand.Equals("CLEARUSERBINDHOST") && (m_pUser->IsAdmin() || !m_pUser->DenySetBindHost())) { m_pUser->SetBindHost(""); - PutStatus("Bind Host Cleared"); + PutStatus("Bind host cleared"); } else if (sCommand.Equals("PLAYBUFFER")) { if (!m_pNetwork) { PutStatus("You must be connected with a network to use this command"); @@ -1419,9 +1463,18 @@ void CClient::HelpUser() { Table.SetCell("Arguments", ""); Table.SetCell("Description", "Set the bind host for this connection"); + Table.AddRow(); + Table.SetCell("Command", "SetUserBindHost"); + Table.SetCell("Arguments", ""); + Table.SetCell("Description", "Set the default bind host for this user"); + Table.AddRow(); Table.SetCell("Command", "ClearBindHost"); Table.SetCell("Description", "Clear the bind host for this connection"); + + Table.AddRow(); + Table.SetCell("Command", "ClearUserBindHost"); + Table.SetCell("Description", "Clear the default bind host for this user"); } Table.AddRow(); diff --git a/src/IRCNetwork.cpp b/src/IRCNetwork.cpp index 18e88e25..9b84367d 100644 --- a/src/IRCNetwork.cpp +++ b/src/IRCNetwork.cpp @@ -88,6 +88,7 @@ void CIRCNetwork::Clone(const CIRCNetwork& Network) { SetAltNick(Network.GetAltNick()); SetIdent(Network.GetIdent()); SetRealName(Network.GetRealName()); + SetBindHost(Network.GetBindHost()); // Servers const vector& vServers = Network.GetServers(); @@ -246,7 +247,8 @@ bool CIRCNetwork::ParseConfig(CConfig *pConfig, CString& sError, bool bUpgrade) { "nick", &CIRCNetwork::SetNick }, { "altnick", &CIRCNetwork::SetAltNick }, { "ident", &CIRCNetwork::SetIdent }, - { "realname", &CIRCNetwork::SetRealName } + { "realname", &CIRCNetwork::SetRealName }, + { "bindhost", &CIRCNetwork::SetBindHost }, }; size_t numStringOptions = sizeof(StringOptions) / sizeof(StringOptions[0]); TOption BoolOptions[] = { @@ -380,6 +382,9 @@ CConfig CIRCNetwork::ToConfig() { if (!m_sRealName.empty()) { config.AddKeyValuePair("RealName", m_sRealName); } + if (!m_sBindHost.empty()) { + config.AddKeyValuePair("BindHost", m_sBindHost); + } config.AddKeyValuePair("IRCConnectEnabled", CString(GetIRCConnectEnabled())); config.AddKeyValuePair("FloodRate", CString(GetFloodRate())); @@ -947,7 +952,7 @@ bool CIRCNetwork::Connect() { ); CString sSockName = "IRC::" + m_pUser->GetUserName() + "::" + m_sName; - CZNC::Get().GetManager().Connect(pServer->GetName(), pServer->GetPort(), sSockName, 120, bSSL, m_pUser->GetBindHost(), pIRCSock); + CZNC::Get().GetManager().Connect(pServer->GetName(), pServer->GetPort(), sSockName, 120, bSSL, GetBindHost(), pIRCSock); return true; } @@ -1034,6 +1039,14 @@ const CString& CIRCNetwork::GetRealName() const { return m_sRealName; } +const CString& CIRCNetwork::GetBindHost() const { + if (m_sBindHost.empty()) { + return m_pUser->GetBindHost(); + } + + return m_sBindHost; +} + void CIRCNetwork::SetNick(const CString& s) { if (m_pUser->GetNick().Equals(s)) { m_sNick = ""; @@ -1066,6 +1079,14 @@ void CIRCNetwork::SetRealName(const CString& s) { } } +void CIRCNetwork::SetBindHost(const CString& s) { + if (m_pUser->GetBindHost().Equals(s)) { + m_sBindHost = ""; + } else { + m_sBindHost = s; + } +} + CString CIRCNetwork::ExpandString(const CString& sStr) const { CString sRet; return ExpandString(sStr, sRet); @@ -1078,6 +1099,7 @@ CString& CIRCNetwork::ExpandString(const CString& sStr, CString& sRet) const { sRet.Replace("%altnick%", GetAltNick()); sRet.Replace("%ident%", GetIdent()); sRet.Replace("%realname%", GetRealName()); + sRet.Replace("%bindhost%", GetBindHost()); return m_pUser->ExpandString(sRet, sRet); } diff --git a/src/IRCSock.cpp b/src/IRCSock.cpp index 37cef69f..279a187a 100644 --- a/src/IRCSock.cpp +++ b/src/IRCSock.cpp @@ -54,7 +54,7 @@ CIRCSock::CIRCSock(CIRCNetwork* pNetwork) : CZNCSock() { m_iSendsAllowed = m_uFloodBurst; EnableReadLine(); m_Nick.SetIdent(m_pNetwork->GetIdent()); - m_Nick.SetHost(m_pNetwork->GetUser()->GetBindHost()); + m_Nick.SetHost(m_pNetwork->GetBindHost()); m_uMaxNickLen = 9; m_uCapPaused = 0; diff --git a/src/Socket.cpp b/src/Socket.cpp index 457b4b34..54591b8d 100644 --- a/src/Socket.cpp +++ b/src/Socket.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -248,7 +249,7 @@ void CSockManager::SetTDNSThreadFinished(TDNSTask* task, bool bBind, addrinfo* a aiTarget = aiTarget4; #endif } else if (!aiBind4 && !aiBind6) { - throw "Can't resolve bind hostname. Try /znc clearbindhost"; + throw "Can't resolve bind hostname. Try /znc clearbindhost and /znc clearuserbindhost"; } else if (aiBind6 && aiTarget6) { aiTarget = aiTarget6; aiBind = aiBind6; @@ -457,7 +458,12 @@ bool CSocket::Connect(const CString& sHostname, unsigned short uPort, bool bSSL, if (pUser) { sSockName += "::" + pUser->GetUserName(); - sBindHost = m_pModule->GetUser()->GetBindHost(); + sBindHost = pUser->GetBindHost(); + CIRCNetwork* pNetwork = m_pModule->GetNetwork(); + if (pNetwork) { + sSockName += "::" + pNetwork->GetName(); + sBindHost = pNetwork->GetBindHost(); + } } // Don't overwrite the socket name if one is already set