From 5faa1d1d6021dbf8963c5396e3c8a78e491dd08c Mon Sep 17 00:00:00 2001 From: psychon Date: Tue, 31 Mar 2009 08:24:34 +0000 Subject: [PATCH] DCC only allows file transfers of up to 4 GiB big files Make CDCCSock use uint32_t to generate the "unsigned, 4 byte integer in network byte order" which is used to acknowledge the received data. Also make OpenFile() abort for files bigger than 4 GiB, because we would run into integer overflows later on. These transfers might work with some remote client, but ZNC is (no longer?) one of them. ;) Thanks to KiNgMaR for the original patch and some help with the uint32_t stuff. git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@1461 726aef4b-f618-498e-8847-2d620e286838 --- DCCSock.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/DCCSock.cpp b/DCCSock.cpp index 55e945ed..a40a4609 100644 --- a/DCCSock.cpp +++ b/DCCSock.cpp @@ -28,12 +28,16 @@ void CDCCSock::ReadData(const char* data, int len) { Close(); } + // DCC specs says the receiving end sends the number of bytes it + // received so far as a 4 byte integer in network byte order, so we need + // uint32_t to do the job portably. This also means that the maximum + // file that we can transfer is 4 GiB big (see OpenFile()). if (m_bSend) { m_sSendBuf.append(data, len); while (m_sSendBuf.size() >= 4) { - unsigned int iRemoteSoFar; - memcpy(&iRemoteSoFar, m_sSendBuf.data(), 4); + uint32_t iRemoteSoFar; + memcpy(&iRemoteSoFar, m_sSendBuf.data(), sizeof(iRemoteSoFar)); iRemoteSoFar = ntohl(iRemoteSoFar); if ((iRemoteSoFar + 65536) >= m_uBytesSoFar) { @@ -45,8 +49,8 @@ void CDCCSock::ReadData(const char* data, int len) { } else { m_pFile->Write(data, len); m_uBytesSoFar += len; - unsigned long uSoFar = htonl(m_uBytesSoFar); - Write((char*) &uSoFar, sizeof(unsigned long)); + uint32_t uSoFar = htonl(m_uBytesSoFar); + Write((char*) &uSoFar, sizeof(uSoFar)); if (m_uBytesSoFar >= m_uFileSize) { Close(); @@ -172,7 +176,17 @@ CFile* CDCCSock::OpenFile(bool bWrite) { return NULL; } - m_uFileSize = m_pFile->GetSize(); + // The DCC specs only allow file transfers with files smaller + // than 4GiB (see ReadData()). + off_t uFileSize = m_pFile->GetSize(); + if (uFileSize > 0xffffffff) { + delete m_pFile; + m_pFile = NULL; + m_pUser->PutModule(m_sModuleName, "DCC -> [" + m_sRemoteNick + "] - File too large (>4 GiB) [" + m_sLocalFile + "]"); + return NULL; + } + + m_uFileSize = (unsigned long) uFileSize; } m_sFileName = m_pFile->GetShortName();