Detect combined identities & transmit them more efficiently

This commit is contained in:
Jeremy Lakeman 2016-07-25 15:50:43 +09:30
parent 82ad628c50
commit d028818c0b
4 changed files with 114 additions and 48 deletions

View File

@ -291,12 +291,28 @@ static void add_subscriber(keyring_identity *id)
{
id->subscriber = find_subscriber(id->box_pk->binary, SID_SIZE, 1);
if (id->subscriber) {
// TODO flag for unroutable identities...?
if (id->subscriber->reachable == REACHABLE_NONE){
id->subscriber->reachable = REACHABLE_SELF;
if (!my_subscriber)
my_subscriber = id->subscriber;
}
id->subscriber->identity = id;
if (id->sign_pk){
// copy our signing key, so we can pass it to peers
bcopy(id->sign_pk, id->subscriber->sas_public, sizeof id->subscriber->sas_public);
id->subscriber->sas_valid = 1;
keypair *kp = id->keypairs;
while(kp){
if (kp->type == KEYTYPE_CRYPTOCOMBINED){
id->subscriber->sas_combined = 1;
break;
}
kp = kp->next;
}
}
}
}
@ -1698,6 +1714,12 @@ static int keyring_store_sas(struct internal_mdp_header *header, struct overlay_
if (crypto_sign_verify_detached(compactsignature, header->source->sid.binary, SID_SIZE, sas_public))
return WHY("SID:SAS mapping verification signature does not verify");
// test if the sas key can be used to derive the sid
sid_t sid;
if (crypto_sign_ed25519_pk_to_curve25519(sid.binary, sas_public)==0
&& memcmp(&sid, &header->source->sid, sizeof sid) == 0)
header->source->sas_combined=1;
/* now store it */
bcopy(sas_public, header->source->sas_public, SAS_SIZE);
header->source->sas_valid=1;

View File

@ -46,6 +46,7 @@ static struct broadcast bpilist[MAX_BPIS];
#define OA_CODE_PREVIOUS 0xfe
#define OA_CODE_P2P_YOU 0xfd
#define OA_CODE_P2P_ME 0xfc
#define OA_CODE_SIGNKEY 0xfb // full sign key of an identity, from which a SID can be derived
// each node has 16 slots based on the next 4 bits of a subscriber id
// each slot either points to another tree node or a struct subscriber.
@ -274,19 +275,21 @@ void overlay_address_append(struct decode_context *context, struct overlay_buffe
else if (context && subscriber==context->previous)
ob_append_byte(b, OA_CODE_PREVIOUS);
else {
int len=SID_SIZE;
if (subscriber->send_full){
// TODO work out when we can use OA_CODE_SIGNKEY
ob_append_byte(b, SID_SIZE);
ob_append_bytes(b, subscriber->sid.binary, SID_SIZE);
subscriber->send_full=0;
}else{
len=(subscriber->abbreviate_len+2)/2;
int len=(subscriber->abbreviate_len+2)/2;
if (context && (context->flags & DECODE_FLAG_ENCODING_HEADER))
len++;
if (len>SID_SIZE)
len=SID_SIZE;
}
ob_append_byte(b, len);
ob_append_bytes(b, subscriber->sid.binary, len);
}
}
if (context)
context->previous = subscriber;
}
@ -311,24 +314,31 @@ static int add_explain_response(struct subscriber *subscriber, void *context)
ob_limitsize(response->please_explain->payload, 1024);
}
// if one of our identities is unknown,
// if our primary routing identities is unknown,
// the header of this packet must include our full sid.
if (subscriber->reachable==REACHABLE_SELF){
if (subscriber==my_subscriber){
DEBUGF(subscriber, "Explaining SELF sid=%s", alloca_tohex_sid_t(subscriber->sid));
response->please_explain->source_full=1;
return 0;
}
subscriber->send_full=1;
}
struct overlay_buffer *b = response->please_explain->payload;
// add the whole subscriber id to the payload, stop if we run out of space
DEBUGF(subscriber, "Explaining sid=%s", alloca_tohex_sid_t(subscriber->sid));
ob_checkpoint(response->please_explain->payload);
ob_append_byte(response->please_explain->payload, SID_SIZE);
ob_append_bytes(response->please_explain->payload, subscriber->sid.binary, SID_SIZE);
if (ob_overrun(response->please_explain->payload)) {
ob_rewind(response->please_explain->payload);
ob_checkpoint(b);
if (subscriber->sas_combined && response->sender && response->sender->sas_combined){
// TODO better condition for when we should send this?
ob_append_byte(b, OA_CODE_SIGNKEY);
ob_append_bytes(b, subscriber->sas_public, crypto_sign_PUBLICKEYBYTES);
}else{
ob_append_byte(b, SID_SIZE);
ob_append_bytes(b, subscriber->sid.binary, SID_SIZE);
}
if (ob_overrun(b)) {
ob_rewind(b);
return 1;
}
// let the routing engine know that we had to explain this sid, we probably need to re-send routing info
@ -342,7 +352,7 @@ static int find_subscr_buffer(struct decode_context *context, struct overlay_buf
if (len<=0 || len>SID_SIZE)
return WHYF("Invalid abbreviation length %d", len);
unsigned char *id = ob_get_bytes_ptr(b, len);
uint8_t *id = ob_get_bytes_ptr(b, len);
if (!id)
return WHY("Not enough space in buffer to parse address");
@ -387,6 +397,29 @@ int overlay_broadcast_parse(struct overlay_buffer *b, struct broadcast *broadcas
return ob_get_bytes(b, broadcast->id, BROADCAST_LEN);
}
static int decode_sid_from_signkey(struct overlay_buffer *b, struct subscriber **subscriber)
{
const uint8_t *id = ob_get_bytes_ptr(b, crypto_sign_PUBLICKEYBYTES);
if (!id)
return WHY("Not enough space in buffer to parse address");
sid_t sid;
if (crypto_sign_ed25519_pk_to_curve25519(sid.binary, id))
return WHY("Failed to convert sign key to sid");
struct subscriber *s = find_subscriber(sid.binary, SID_SIZE, 1);
if (s && !s->sas_combined){
bcopy(id, s->sas_public, crypto_sign_PUBLICKEYBYTES);
s->sas_valid=1;
s->sas_combined=1;
DEBUGF(subscriber, "Stored combined SID:SAS mapping, SID=%s SAS=%s",
alloca_tohex_sid_t(s->sid),
alloca_tohex_sas(s->sas_public)
);
}
if (subscriber)
*subscriber=s;
return 0;
}
// returns 0 = success, -1 = fatal parsing error, 1 = unable to identify address
int overlay_address_parse(struct decode_context *context, struct overlay_buffer *b, struct subscriber **subscriber)
{
@ -445,6 +478,9 @@ int overlay_address_parse(struct decode_context *context, struct overlay_buffer
*subscriber=context->previous;
}
return 0;
case OA_CODE_SIGNKEY:
return decode_sid_from_signkey(b, subscriber);
}
return find_subscr_buffer(context, b, len, subscriber);
@ -507,31 +543,36 @@ int process_explain(struct overlay_frame *frame)
while(ob_remaining(b)>0){
int len = ob_get(b);
if (len==OA_CODE_P2P_YOU){
switch (len){
case OA_CODE_P2P_YOU:
add_explain_response(my_subscriber, &context);
continue;
}
if (len<=0 || len>SID_SIZE)
return WHY("Badly formatted explain message");
unsigned char *sid = ob_get_bytes_ptr(b, len);
if (!sid)
return WHY("Ran past end of buffer");
if (len==SID_SIZE){
break;
case OA_CODE_SIGNKEY:
decode_sid_from_signkey(b, NULL);
break;
case SID_SIZE:
{
// This message is also used to inform people of previously unknown subscribers
// make sure we know this one
DEBUGF(subscriber, "Storing explain response for %s", alloca_tohex(sid, len));
find_subscriber(sid,len,1);
}else{
uint8_t *sid = ob_get_bytes_ptr(b, SID_SIZE);
if (!sid)
return WHY("Ran past end of buffer");
DEBUGF(subscriber, "Storing explain response for %s", alloca_tohex(sid, SID_SIZE));
find_subscriber(sid, SID_SIZE, 1);
break;
}
default:
{
if (len<=0 || len>SID_SIZE)
return WHY("Badly formatted explain message");
uint8_t *sid = ob_get_bytes_ptr(b, len);
// reply to the sender with all subscribers that match this abbreviation
DEBUGF(subscriber, "Sending explain responses for %s", alloca_tohex(sid, len));
prefix_matches(sid, len, add_explain_response, &context);
}
}
}
if (context.please_explain)
send_please_explain(&context, frame->destination, frame->source);
DEBUG(subscriber, "No explain responses?");
return 0;
}

View File

@ -56,9 +56,6 @@ struct subscriber{
// minimum abbreviation length, in 4bit nibbles.
int abbreviate_len;
// should we send the full address once?
int send_full;
int max_packet_version;
// link state routing information
@ -85,9 +82,13 @@ struct subscriber{
time_ms_t last_explained;
// public signing key details for remote peers
unsigned char sas_public[SAS_SIZE];
uint8_t sas_public[SAS_SIZE];
time_ms_t sas_last_request;
unsigned char sas_valid;
uint8_t sas_valid:1;
uint8_t sas_combined:1;
// should we send the full address once?
uint8_t send_full:1;
// private keys for local identities
struct keyring_identity *identity;

View File

@ -1327,6 +1327,8 @@ static int link_receive(struct internal_mdp_header *header, struct overlay_buffe
struct decode_context context;
bzero(&context, sizeof(context));
context.interface = header->receive_interface;
context.sender = header->source;
time_ms_t now = gettime_ms();
char changed = 0;