/* $ModDep: m_spanningtree/timesynctimer.h m_spanningtree/resolvers.h m_spanningtree/main.h m_spanningtree/utils.h m_spanningtree/treeserver.h m_spanningtree/link.h m_spanningtree/treesocket.h m_hash.h */
+
/** Because most of the I/O gubbins are encapsulated within
* InspSocket, we just call the superclass constructor for
* most of the action, and append a few of our own values
* socket, and set a timer waiting for handshake before we send CAPAB etc.
*/
if (Hook)
- {
InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
- Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(Utils->LinkBlocks[0]), this->Utils));
- }
- else
- {
- /* Otherwise, theres no lower layer transport in plain TCP/IP,
- * so just send the capabilities right now.
- */
- this->SendCapabilities();
- }
+
+ Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(Utils->LinkBlocks[0]), this->Utils, 1));
}
ServerState TreeSocket::GetLinkState()
std::string TreeSocket::MakePass(const std::string &password, const std::string &challenge)
{
+ /* This is a simple (maybe a bit hacky?) HMAC algorithm, thanks to jilles for
+ * suggesting the use of HMAC to secure the password against various attacks.
+ *
+ * Note: If m_sha256.so is not loaded, we MUST fall back to plaintext with no
+ * HMAC challenge/response.
+ */
Module* sha256 = Instance->FindModule("m_sha256.so");
- if (sha256 && !challenge.empty())
+ if (Utils->ChallengeResponse && sha256 && !challenge.empty())
{
- /* sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) ) */
+ /* XXX: This is how HMAC is supposed to be done:
+ *
+ * sha256( (pass xor 0x5c) + sha256((pass xor 0x36) + m) )
+ *
+ * Note that we are encoding the hex hash, not the binary
+ * output of the hash which is slightly different to standard.
+ *
+ * Don't ask me why its always 0x5c and 0x36... it just is.
+ */
std::string hmac1, hmac2;
for (size_t n = 0; n < password.length(); n++)
std::string hmac = hmac1 + hmac2 + challenge;
hmac = HashSumRequest(Utils->Creator, sha256, hmac).Send();
- return hmac;
+ return "HMAC-SHA256:"+ hmac;
}
else if (!challenge.empty() && !sha256)
Instance->Log(DEFAULT,"Not authenticating to server using SHA256/HMAC because we don't have m_sha256 loaded!");
InspSocketHookRequest(this, (Module*)Utils->Creator, Hook).Send();
this->Instance->SNO->WriteToSnoMask('l',"Connection to \2"+myhost+"\2["+(x->HiddenFromStats ? "<hidden>" : this->GetIP())+"] using transport \2"+x->Hook+"\2");
}
- else
- this->SendCapabilities();
+ this->OutboundPass = x->SendPass;
/* found who we're supposed to be connecting to, send the neccessary gubbins. */
- Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(*x), this->Utils));
+ Instance->Timers->AddTimer(new HandshakeTimer(Instance, this, &(*x), this->Utils, 2));
return true;
}
}
std::string TreeSocket::RandString(unsigned int length)
{
+ char* randombuf = new char[length+1];
std::string out;
+ int fd = open("/dev/urandom", O_RDONLY, 0);
+
+ if (fd >= 0)
+ {
+ read(fd, randombuf, length);
+ close(fd);
+ }
+ else
+ {
+ for (unsigned int i = 0; i < length; i++)
+ randombuf[i] = rand();
+ }
+
for (unsigned int i = 0; i < length; i++)
- out += static_cast<char>((rand() % 26) + 65);
+ out += static_cast<char>((randombuf[i] & 0x7F) | 0x21);
+
+ delete[] randombuf;
return out;
}
#ifdef SUPPORT_IP6LINKS
ip6support = 1;
#endif
- this->SetOurChallenge(RandString(20));
- this->WriteLine("CAPAB CAPABILITIES :NICKMAX="+ConvToStr(NICKMAX)+" HALFOP="+ConvToStr(this->Instance->Config->AllowHalfop)+" CHANMAX="+ConvToStr(CHANMAX)+" MAXMODES="+ConvToStr(MAXMODES)+" IDENTMAX="+ConvToStr(IDENTMAX)+" MAXQUIT="+ConvToStr(MAXQUIT)+" MAXTOPIC="+ConvToStr(MAXTOPIC)+" MAXKICK="+ConvToStr(MAXKICK)+" MAXGECOS="+ConvToStr(MAXGECOS)+" MAXAWAY="+ConvToStr(MAXAWAY)+" IP6NATIVE="+ConvToStr(ip6)+" IP6SUPPORT="+ConvToStr(ip6support)+" PROTOCOL="+ConvToStr(ProtocolVersion)+" CHALLENGE="+this->GetOurChallenge());
+ std::string extra;
+ /* Do we have sha256 available? If so, we send a challenge */
+ if (Utils->ChallengeResponse && (Instance->FindModule("m_sha256.so")))
+ {
+ this->SetOurChallenge(RandString(20));
+ extra = " CHALLENGE=" + this->GetOurChallenge();
+ }
+
+ this->WriteLine("CAPAB CAPABILITIES :NICKMAX="+ConvToStr(NICKMAX)+" HALFOP="+ConvToStr(this->Instance->Config->AllowHalfop)+" CHANMAX="+ConvToStr(CHANMAX)+" MAXMODES="+ConvToStr(MAXMODES)+" IDENTMAX="+ConvToStr(IDENTMAX)+" MAXQUIT="+ConvToStr(MAXQUIT)+" MAXTOPIC="+ConvToStr(MAXTOPIC)+" MAXKICK="+ConvToStr(MAXKICK)+" MAXGECOS="+ConvToStr(MAXGECOS)+" MAXAWAY="+ConvToStr(MAXAWAY)+" IP6NATIVE="+ConvToStr(ip6)+" IP6SUPPORT="+ConvToStr(ip6support)+" PROTOCOL="+ConvToStr(ProtocolVersion)+extra);
this->WriteLine("CAPAB END");
}
/* Challenge response, store their challenge for our password */
std::map<std::string,std::string>::iterator n = this->CapKeys.find("CHALLENGE");
- if (n != this->CapKeys.end())
+ if (Utils->ChallengeResponse && (n != this->CapKeys.end()) && (Instance->FindModule("m_sha256.so")))
{
/* Challenge-response is on now */
this->SetTheirChallenge(n->second);
+ if (!this->GetOurChallenge().empty() && (this->LinkState == CONNECTING))
+ {
+ this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+this->MakePass(OutboundPass, this->GetTheirChallenge())+" 0 :"+this->Instance->Config->ServerDesc);
+ }
+ }
+ else
+ {
+ /* They didnt specify a challenge or we don't have m_sha256.so, we use plaintext */
+ if (this->LinkState == CONNECTING)
+ this->WriteLine(std::string("SERVER ")+this->Instance->Config->ServerName+" "+OutboundPass+" 0 :"+this->Instance->Config->ServerDesc);
}
if (reason.length())
*/
void TreeSocket::DoBurst(TreeServer* s)
{
+ std::string name = s->GetName();
std::string burst = "BURST "+ConvToStr(Instance->Time(true));
std::string endburst = "ENDBURST";
- // Because by the end of the netburst, it could be gone!
- std::string name = s->GetName();
- this->Instance->SNO->WriteToSnoMask('l',"Bursting to \2"+name+"\2.");
+ this->Instance->SNO->WriteToSnoMask('l',"Bursting to \2%s\2 (Authentication: %s).", name.c_str(), this->GetTheirChallenge().empty() ? "plaintext password" : "SHA256-HMAC challenge-response");
this->WriteLine(burst);
/* send our version string */
this->WriteLine(std::string(":")+this->Instance->Config->ServerName+" VERSION :"+this->Instance->GetVersionString());