diff --git a/modules/bouncedcc.cpp b/modules/bouncedcc.cpp index cf0b5093..72a647df 100644 --- a/modules/bouncedcc.cpp +++ b/modules/bouncedcc.cpp @@ -163,6 +163,17 @@ class CBounceDCCMod : public CModule { bool UseClientIP() { return GetNV("UseClientIP").ToBool(); } + // The address in a DCC request from IRC is chosen by the remote peer, and + // ZNC is the one connecting to it, so don't let it point at ZNC's own + // host or at link-local services. + static bool IsAllowedPeerIP(unsigned long uLongIP) { + if (uLongIP > 0xFFFFFFFFUL) return false; + const unsigned long uFirst = uLongIP >> 24; + if (uFirst == 0 || uFirst == 127 || uFirst >= 224) return false; + if ((uLongIP >> 16) == 0xA9FE) return false; // 169.254.0.0/16 + return true; + } + EModRet OnUserCTCPMessage(CCTCPMessage& Message) override { CString sTarget = Message.GetTarget(); CString sMessage = Message.GetText(); @@ -255,6 +266,13 @@ class CBounceDCCMod : public CModule { unsigned long uFileSize = sMessage.Token(5, false, " ", false, "\"", "\"", true).ToULong(); + if ((sType.Equals("CHAT") || sType.Equals("SEND")) && + !IsAllowedPeerIP(uLongIP)) { + PutModule(t_f("DCC {1} from {2} refused: bad address {3}")( + sType, Nick.GetNick(), CString(uLongIP))); + return HALTCORE; + } + if (sType.Equals("CHAT")) { CNick FromNick(Nick.GetNickMask()); unsigned short uBNCPort = CDCCBounce::DCCRequest( diff --git a/test/integration/tests/modules.cpp b/test/integration/tests/modules.cpp index fe315901..c90efd86 100644 --- a/test/integration/tests/modules.cpp +++ b/test/integration/tests/modules.cpp @@ -765,6 +765,14 @@ TEST_F(ZNCTest, BounceDCCModule) { QByteArray line2; client.ReadUntilAndGet(":friend!user@host PRIVMSG nick :\001DCC CHAT chat", line2); EXPECT_THAT(line2.toStdString(), Not(HasSubstr("3232235521 54321"))); + + // Peer must not be able to make ZNC connect to its own loopback + ircd.Write(":friend!user@host PRIVMSG nick :\001DCC CHAT chat 2130706433 6379\001"); + client.ReadUntil("refused: bad address 2130706433"); + ircd.Write(":friend!user@host PRIVMSG nick :\001DCC SEND f 2852039166 80 1\001"); + client.ReadUntil("refused: bad address 2852039166"); + ircd.Write(":friend!user@host PRIVMSG nick :\001DCC CHAT chat 6425673729 22\001"); + client.ReadUntil("refused: bad address 6425673729"); } TEST_F(ZNCTest, ChanSaverModule) {