From dab1127090fc149e464653d651e235bc20467e25 Mon Sep 17 00:00:00 2001 From: Alexey Sokolov Date: Sat, 19 Apr 2025 22:17:30 +0100 Subject: [PATCH] Add unix listener support to *status addport, delport --- include/znc/znc.h | 1 + src/ClientCommand.cpp | 119 ++++++++++++++++++++++++++---------------- src/znc.cpp | 10 ++++ 3 files changed, 86 insertions(+), 44 deletions(-) diff --git a/include/znc/znc.h b/include/znc/znc.h index 27b851de..e6da2a2e 100644 --- a/include/znc/znc.h +++ b/include/znc/znc.h @@ -202,6 +202,7 @@ class CZNC : private CCoreTranslationMixin { // Listener yummy CListener* FindListener(u_short uPort, const CString& BindHost, EAddrType eAddr); + CListener* FindUnixListener(const CString& sPath); bool AddListener(CListener*); bool AddTCPListener(unsigned short uPort, const CString& sBindHost, const CString& sURIPrefix, bool bSSL, EAddrType eAddr, diff --git a/src/ClientCommand.cpp b/src/ClientCommand.cpp index 1cae443a..40557c30 100644 --- a/src/ClientCommand.cpp +++ b/src/ClientCommand.cpp @@ -1620,6 +1620,10 @@ void CClient::UserCommand(CString& sLine) { } } +namespace { +struct PortCommandUsage {}; +} + void CClient::UserPortCommand(CString& sLine) { const CString sCommand = sLine.Token(0); @@ -1654,7 +1658,7 @@ void CClient::UserPortCommand(CString& sLine) { : t_s("IPv6", "listports"))); } else if (const CUnixListener* pUnixListener = dynamic_cast(pListener)) { - Table.SetCell(t_s("BindHost", "listports"), + Table.SetCell(t_s("Port", "listports"), pUnixListener->GetPath()); } Table.SetCell(t_s("SSL", "listports"), @@ -1680,68 +1684,92 @@ void CClient::UserPortCommand(CString& sLine) { return; } + auto ParseEAddr = [](const CString& sAddr) { + if (sAddr.Equals("IPV4")) { + return ADDR_IPV4ONLY; + } else if (sAddr.Equals("IPV6")) { + return ADDR_IPV6ONLY; + } else if (sAddr.Equals("ALL")) { + return ADDR_ALL; + } else { + throw PortCommandUsage{}; + } + }; + + auto ParseEAccept = [](const CString& sAccept) { + if (sAccept.Equals("WEB")) { + return CListener::ACCEPT_HTTP; + } else if (sAccept.Equals("IRC")) { + return CListener::ACCEPT_IRC; + } else if (sAccept.Equals("ALL")) { + return CListener::ACCEPT_ALL; + } else { + throw PortCommandUsage{}; + } + }; + CString sPort = sLine.Token(1); - CString sAddr = sLine.Token(2); - EAddrType eAddr = ADDR_ALL; - - if (sAddr.Equals("IPV4")) { - eAddr = ADDR_IPV4ONLY; - } else if (sAddr.Equals("IPV6")) { - eAddr = ADDR_IPV6ONLY; - } else if (sAddr.Equals("ALL")) { - eAddr = ADDR_ALL; - } else { - sAddr.clear(); - } - unsigned short uPort = sPort.ToUShort(); if (sCommand.Equals("ADDPORT")) { - CListener::EAcceptType eAccept = CListener::ACCEPT_ALL; - CString sAccept = sLine.Token(3); + try { + if (sPort.empty()) { + throw PortCommandUsage{}; + } - if (sAccept.Equals("WEB")) { - eAccept = CListener::ACCEPT_HTTP; - } else if (sAccept.Equals("IRC")) { - eAccept = CListener::ACCEPT_IRC; - } else if (sAccept.Equals("ALL")) { - eAccept = CListener::ACCEPT_ALL; - } else { - sAccept.clear(); - } + std::unique_ptr pListener; + if (sPort.TrimPrefix("unix:")) { + bool bSSL = sPort.TrimPrefix("+"); + const CString& sPath = sPort; + CListener::EAcceptType eAccept = ParseEAccept(sLine.Token(2)); + CString sURIPrefix = sLine.Token(3); - if (sPort.empty() || sAddr.empty() || sAccept.empty()) { - PutStatus( - t_s("Usage: AddPort <[+]port> " - "[bindhost [uriprefix]]")); - } else { - bool bSSL = (sPort.StartsWith("+")); - const CString sBindHost = sLine.Token(4); - const CString sURIPrefix = sLine.Token(5); + pListener.reset(new CUnixListener(sPath, sURIPrefix, bSSL, eAccept)); + } else { + bool bSSL = sPort.StartsWith("+"); + EAddrType eAddr = ParseEAddr(sLine.Token(2)); + CListener::EAcceptType eAccept = ParseEAccept(sLine.Token(3)); + const CString sBindHost = sLine.Token(4); + const CString sURIPrefix = sLine.Token(5); - CListener* pListener = new CTCPListener(uPort, sBindHost, sURIPrefix, - bSSL, eAddr, eAccept); + pListener.reset(new CTCPListener(uPort, sBindHost, sURIPrefix, + bSSL, eAddr, eAccept)); + } if (!pListener->Listen()) { auto e = errno; - delete pListener; PutStatus(t_f("Unable to bind: {1}")(CString(strerror(e)))); } else { - if (CZNC::Get().AddListener(pListener)) { + if (CZNC::Get().AddListener(pListener.release())) { PutStatus(t_s("Port added")); } else { PutStatus(t_s("Couldn't add port")); } } + } catch (PortCommandUsage) { + PutStatus( + t_s("Usage: AddPort <[+]port> " + "[bindhost [uriprefix]]")); + PutStatus( + t_s("Or: AddPort unix:[+]/path/to/socket " + "[uriprefix]")); + PutStatus(t_s("+ means SSL")); } } else if (sCommand.Equals("DELPORT")) { - if (sPort.empty() || sAddr.empty()) { - PutStatus(t_s("Usage: DelPort [bindhost]")); - } else { - const CString sBindHost = sLine.Token(3); - - CListener* pListener = - CZNC::Get().FindListener(uPort, sBindHost, eAddr); + try { + if (sPort.empty()) { + throw PortCommandUsage{}; + } + CListener* pListener; + if (sPort.TrimPrefix("unix:")) { + sPort.TrimPrefix("+"); + pListener = CZNC::Get().FindUnixListener(sPort); + } else { + CString sAddr = sLine.Token(2); + CString sBindHost = sLine.Token(3); + pListener = CZNC::Get().FindListener( + uPort, sBindHost, ParseEAddr(sAddr)); + } if (pListener) { CZNC::Get().DelListener(pListener); @@ -1749,6 +1777,9 @@ void CClient::UserPortCommand(CString& sLine) { } else { PutStatus(t_s("Unable to find a matching port")); } + } catch (PortCommandUsage) { + PutStatus(t_s("Usage: DelPort [bindhost]")); + PutStatus(t_s("Or: DelPort unix:/path/to/socket")); } } } diff --git a/src/znc.cpp b/src/znc.cpp index 8c233ff6..a7dc3ebc 100644 --- a/src/znc.cpp +++ b/src/znc.cpp @@ -1575,6 +1575,16 @@ CListener* CZNC::FindListener(u_short uPort, const CString& sBindHost, return nullptr; } +CListener* CZNC::FindUnixListener(const CString& sPath) { + for (CListener* pListener : m_vpListeners) { + CUnixListener* pUnixListener = dynamic_cast(pListener); + if (!pUnixListener) continue; + if (pUnixListener->GetPath() != sPath) continue; + return pListener; + } + return nullptr; +} + bool CZNC::AddListener(const CString& sLine, CString& sError) { CString sName = sLine.Token(0); CString sValue = sLine.Token(1, true);