#include namespace llarp { namespace iwp { LinkLayer::LinkLayer(Crypto* c, const SecretKey& enckey, GetRCFunc getrc, LinkMessageHandler h, SessionEstablishedHandler est, SessionRenegotiateHandler reneg, SignBufferFunc sign, TimeoutHandler t, SessionClosedHandler closed) : ILinkLayer(enckey, getrc, h, sign, est, reneg, t, closed), crypto(c) { m_FlowCookie.Randomize(); } LinkLayer::~LinkLayer() { } void LinkLayer::Pump() { ILinkLayer::Pump(); } const char* LinkLayer::Name() const { return "iwp"; } bool LinkLayer::KeyGen(SecretKey& k) { k.Zero(); crypto->encryption_keygen(k); return !k.IsZero(); } uint16_t LinkLayer::Rank() const { return 2; } bool LinkLayer::Start(Logic* l) { if(!ILinkLayer::Start(l)) return false; /// TODO: change me to true when done return false; } void LinkLayer::RecvFrom(const Addr& from, const void* pkt, size_t sz) { m_OuterMsg.Clear(); llarp_buffer_t sigbuf(pkt, sz); llarp_buffer_t decodebuf(pkt, sz); if(!m_OuterMsg.Decode(&decodebuf)) { LogError("failed to decode outer message"); return; } NetID ourNetID; switch(m_OuterMsg.command) { case eOCMD_ObtainFlowID: sigbuf.sz -= m_OuterMsg.Zsig.size(); if(!crypto->verify(m_OuterMsg.pubkey, sigbuf, m_OuterMsg.Zsig)) { LogError("failed to verify signature on '", (char)m_OuterMsg.command, "' message from ", from); return; } if(!ShouldSendFlowID(from)) { SendReject(from, "no flo 4u :^)"); return; } if(m_OuterMsg.netid == ourNetID) { if(GenFlowIDFor(m_OuterMsg.pubkey, from, m_OuterMsg.flow)) SendFlowID(from, m_OuterMsg.flow); else SendReject(from, "genflow fail"); } else SendReject(from, "bad netid"); } } std::shared_ptr< ILinkSession > LinkLayer::NewOutboundSession(const RouterContact& rc, const AddressInfo& ai) { (void)rc; (void)ai; // TODO: implement me return {}; } void LinkLayer::SendFlowID(const Addr& to, const FlowID_t& flow) { // TODO: implement me (void)to; (void)flow; } bool LinkLayer::VerifyFlowID(const PubKey& pk, const Addr& from, const FlowID_t& flow) const { FlowID_t expected; if(!GenFlowIDFor(pk, from, expected)) return false; return expected == flow; } bool LinkLayer::GenFlowIDFor(const PubKey& pk, const Addr& from, FlowID_t& flow) const { std::array< byte_t, 128 > tmp = {{0}}; if(inet_ntop(AF_INET6, from.addr6(), (char*)tmp.data(), tmp.size()) == nullptr) return false; std::copy_n(pk.begin(), pk.size(), tmp.begin() + 64); std::copy_n(m_FlowCookie.begin(), m_FlowCookie.size(), tmp.begin() + 64 + pk.size()); llarp_buffer_t buf(tmp); ShortHash h; if(!crypto->shorthash(h, buf)) return false; std::copy_n(h.begin(), flow.size(), flow.begin()); return true; } bool LinkLayer::ShouldSendFlowID(const Addr& to) const { (void)to; // TODO: implement me return false; } void LinkLayer::SendReject(const Addr& to, const char* msg) { if(strlen(msg) > 14) { throw std::logic_error("reject message too big"); } std::array< byte_t, 120 > pkt; auto now = Now(); PubKey pk = GetOurRC().pubkey; OuterMessage m; m.CreateReject(msg, now, pk); llarp_buffer_t encodebuf(pkt); if(!m.Encode(&encodebuf)) { LogError("failed to encode reject message to ", to); return; } llarp_buffer_t signbuf(pkt.data(), pkt.size() - m.Zsig.size()); if(!Sign(m.Zsig, signbuf)) { LogError("failed to sign reject messsage to ", to); return; } std::copy_n(m.Zsig.begin(), m.Zsig.size(), pkt.begin() + (pkt.size() - m.Zsig.size())); llarp_buffer_t pktbuf(pkt); SendTo_LL(to, pktbuf); } } // namespace iwp } // namespace llarp