lokinet/llarp/router_contact.cpp
2018-06-13 12:32:34 -04:00

221 lines
4.7 KiB
C++

#include <llarp/bencode.h>
#include <llarp/router_contact.h>
#include <llarp/version.h>
#include <llarp/crypto.hpp>
#include "buffer.hpp"
#include "logger.hpp"
extern "C" {
void
llarp_rc_free(struct llarp_rc *rc)
{
if(rc->exits)
llarp_xi_list_free(rc->exits);
if(rc->addrs)
llarp_ai_list_free(rc->addrs);
rc->exits = 0;
rc->addrs = 0;
}
struct llarp_rc_decoder
{
struct llarp_rc *rc;
struct llarp_alloc *mem;
};
static bool
llarp_rc_decode_dict(struct dict_reader *r, llarp_buffer_t *key)
{
uint64_t v;
llarp_buffer_t strbuf;
llarp_rc *rc = static_cast< llarp_rc * >(r->user);
if(!key)
return true;
if(llarp_buffer_eq(*key, "a"))
{
if(rc->addrs)
{
llarp_ai_list_free(rc->addrs);
}
rc->addrs = llarp_ai_list_new();
return llarp_ai_list_bdecode(rc->addrs, r->buffer);
}
if(llarp_buffer_eq(*key, "k"))
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz != PUBKEYSIZE)
return false;
memcpy(rc->pubkey, strbuf.base, PUBKEYSIZE);
return true;
}
if(llarp_buffer_eq(*key, "p"))
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz != PUBKEYSIZE)
return false;
memcpy(rc->enckey, strbuf.base, PUBKEYSIZE);
return true;
}
if(llarp_buffer_eq(*key, "u"))
{
if(!bencode_read_integer(r->buffer, &rc->last_updated))
return false;
return true;
}
if(llarp_buffer_eq(*key, "v"))
{
if(!bencode_read_integer(r->buffer, &v))
return false;
return v == LLARP_PROTO_VERSION;
}
if(llarp_buffer_eq(*key, "x"))
{
if(rc->exits)
{
llarp_xi_list_free(rc->exits);
}
rc->exits = llarp_xi_list_new();
return llarp_xi_list_bdecode(rc->exits, r->buffer);
}
if(llarp_buffer_eq(*key, "z"))
{
if(!bencode_read_string(r->buffer, &strbuf))
return false;
if(strbuf.sz != SIGSIZE)
return false;
memcpy(rc->signature, strbuf.base, SIGSIZE);
return true;
}
return false;
}
void
llarp_rc_copy(struct llarp_rc *dst, const struct llarp_rc *src)
{
llarp_rc_free(dst);
llarp_rc_clear(dst);
memcpy(dst->pubkey, src->pubkey, PUBKEYSIZE);
memcpy(dst->enckey, src->enckey, PUBKEYSIZE);
memcpy(dst->signature, src->signature, SIGSIZE);
dst->last_updated = src->last_updated;
if(src->addrs)
{
dst->addrs = llarp_ai_list_new();
llarp_ai_list_copy(dst->addrs, src->addrs);
}
if(src->exits)
{
dst->exits = llarp_xi_list_new();
llarp_xi_list_copy(dst->exits, src->exits);
}
}
bool
llarp_rc_bdecode(struct llarp_rc *rc, llarp_buffer_t *buff)
{
dict_reader r = {buff, rc, &llarp_rc_decode_dict};
return bencode_read_dict(buff, &r);
}
bool
llarp_rc_verify_sig(struct llarp_crypto *crypto, struct llarp_rc *rc)
{
// maybe we should copy rc before modifying it
// would that make it more thread safe?
// jeff agrees
bool result = false;
llarp::Signature sig;
byte_t tmp[MAX_RC_SIZE];
auto buf = llarp::StackBuffer< decltype(tmp) >(tmp);
// copy sig
memcpy(sig, rc->signature, SIGSIZE);
// zero sig
size_t sz = 0;
while(sz < SIGSIZE)
rc->signature[sz++] = 0;
// bencode
if(llarp_rc_bencode(rc, &buf))
{
buf.sz = buf.cur - buf.base;
buf.cur = buf.base;
result = crypto->verify(rc->pubkey, buf, sig);
}
else
llarp::Warn(__FILE__, "RC encode failed");
// restore sig
memcpy(rc->signature, sig, SIGSIZE);
return result;
}
bool
llarp_rc_bencode(const struct llarp_rc *rc, llarp_buffer_t *buff)
{
/* write dict begin */
if(!bencode_start_dict(buff))
return false;
if(rc->addrs)
{
/* write ai if they exist */
if(!bencode_write_bytestring(buff, "a", 1))
return false;
if(!llarp_ai_list_bencode(rc->addrs, buff))
return false;
}
/* write signing pubkey */
if(!bencode_write_bytestring(buff, "k", 1))
return false;
if(!bencode_write_bytestring(buff, rc->pubkey, PUBKEYSIZE))
return false;
/* write encryption pubkey */
if(!bencode_write_bytestring(buff, "p", 1))
return false;
if(!bencode_write_bytestring(buff, rc->enckey, PUBKEYSIZE))
return false;
/* write last updated */
if(!bencode_write_bytestring(buff, "u", 1))
return false;
if(!bencode_write_uint64(buff, rc->last_updated))
return false;
/* write version */
if(!bencode_write_version_entry(buff))
return false;
if(rc->exits)
{
/* write ai if they exist */
if(!bencode_write_bytestring(buff, "x", 1))
return false;
if(!llarp_xi_list_bencode(rc->exits, buff))
return false;
}
/* write signature */
if(!bencode_write_bytestring(buff, "z", 1))
return false;
if(!bencode_write_bytestring(buff, rc->signature, SIGSIZE))
return false;
return bencode_end(buff);
}
}