Esempio n. 1
0
// open must be e3x_channel_receive or e3x_channel_send next yet
e3x_channel_t e3x_channel_new(lob_t open)
{
  uint32_t id;
  char *type;
  e3x_channel_t c;

  if(!open) return LOG("open packet required");
  id = (uint32_t)lob_get_int(open,"c");
  if(!id) return LOG("invalid channel id");
  type = lob_get(open,"type");
  if(!type) return LOG("missing channel type");

  c = malloc(sizeof (struct e3x_channel_struct));
  memset(c,0,sizeof (struct e3x_channel_struct));
  c->state = OPENING;
  c->id = id;
  sprintf(c->c,"%u",id);
  c->open = lob_copy(open);
  c->type = lob_get(open,"type");
  c->capacity = 1024*1024; // 1MB total default

  // generate a unique id in hex
  _uids++;
  util_hex((uint8_t*)&_uids,4,c->uid);

  // reliability
  if(lob_get(open,"seq"))
  {
    c->seq = 1;
  }

  LOG("new %s channel %s %d %s",c->seq?"reliable":"unreliable",c->uid,id,type);
  return c;
}
Esempio n. 2
0
File: link.c Progetto: fd/telehash-c
// process a decrypted channel packet
link_t link_receive(link_t link, lob_t inner, pipe_t pipe)
{
  chan_t chan;

  if(!link || !inner) return LOG("bad args");

  // see if existing channel and send there
  if((chan = xht_get(link->index, lob_get(inner,"c"))))
  {
    if(channel3_receive(chan->c3, inner)) return LOG("channel receive error, dropping %s",lob_json(inner));
    link_pipe(link,pipe); // we trust the pipe at this point
    if(chan->handle) chan->handle(link, chan->c3, chan->arg);
    // check if there's any packets to be sent back
    return link_flush(link, chan->c3, NULL);
  }

  // if it's an open, validate and fire event
  if(!lob_get(inner,"type")) return LOG("invalid channel open, no type %s",lob_json(inner));
  if(!exchange3_cid(link->x, inner)) return LOG("invalid channel open id %s",lob_json(inner));
  link_pipe(link,pipe); // we trust the pipe at this point
  inner = mesh_open(link->mesh,link,inner);
  if(inner)
  {
   LOG("unhandled channel open %s",lob_json(inner));
   lob_free(inner);
   return NULL;
  }
  
  return link;
}
Esempio n. 3
0
int main(int argc, char **argv)
{
  fail_unless(e3x_init(NULL) == 0);
  lob_t id = e3x_generate();
  fail_unless(id);

  e3x_self_t self = e3x_self_new(id,NULL);
  fail_unless(self);
  
  int i, count = 0;
  for(i = 0; i < CS_MAX; i++)
  {
    if(!self->locals[i]) continue;
    LOG("self testing CS %d",i);
    count++;
    fail_unless(self->locals[i]);
    fail_unless(self->keys[i]);
    fail_unless(self->keys[i]->body_len);
    fail_unless(lob_get(self->keys[i],"key"));
    fail_unless(lob_get(self->keys[i],"hash"));
    fail_unless(strlen(lob_get(self->keys[i],"hash")) == 52);
  }

  fail_unless(count);
  e3x_self_free(self);
  lob_free(id);

  return 0;
}
Esempio n. 4
0
File: tcp4.c Progetto: fd/telehash-c
pipe_t tcp4_path(link_t link, lob_t path)
{
  net_tcp4_t net;
  char *ip;
  int port;

  // just sanity check the path first
  if(!link || !path) return NULL;
  if(!(net = xht_get(link->mesh->index, MUID))) return NULL;
  if(util_cmp("tcp4",lob_get(path,"type"))) return NULL;
  if(!(ip = lob_get(path,"ip"))) return LOG("missing ip");
  if((port = lob_get_int(path,"port")) <= 0) return LOG("missing port");
  return tcp4_pipe(net, ip, port);
}
Esempio n. 5
0
// process an incoming handshake
link_t link_receive_handshake(link_t link, lob_t inner, pipe_t pipe)
{
  link_t ready;
  uint32_t out, err;
  seen_t seen;
  uint8_t csid = 0;
  char *hexid;
  lob_t attached, outer = lob_linked(inner);

  if(!link || !inner || !outer) return LOG("bad args");
  hexid = lob_get(inner, "csid");
  if(!lob_get(link->mesh->keys, hexid)) return LOG("unsupported csid %s",hexid);
  util_unhex(hexid, 2, &csid);
  attached = lob_parse(inner->body, inner->body_len);
  if(!link->key && link_key(link->mesh, attached, csid) != link) return LOG("invalid/mismatch link handshake");
  if((err = e3x_exchange_verify(link->x,outer))) return LOG("handshake verification fail: %d",err);

  out = e3x_exchange_out(link->x,0);
  ready = link_up(link);

  // if bad at, always send current handshake
  if(e3x_exchange_in(link->x, lob_get_uint(inner,"at")) < out)
  {
    LOG("old/bad at: %s (%d,%d,%d)",lob_json(inner),lob_get_int(inner,"at"),e3x_exchange_in(link->x,0),e3x_exchange_out(link->x,0));
    // just reset pipe seen and call link_sync to resend handshake
    for(seen = link->pipes;pipe && seen;seen = seen->next) if(seen->pipe == pipe) seen->at = 0;
    lob_free(link_sync(link));
    return NULL;
  }

  // trust/add this pipe
  if(pipe) link_pipe(link,pipe);

  // try to sync ephemeral key
  if(!e3x_exchange_sync(link->x,outer)) return LOG("sync failed");
  
  // we may need to re-sync
  if(out != e3x_exchange_out(link->x,0)) lob_free(link_sync(link));
  
  // notify of ready state change
  if(!ready && link_up(link))
  {
    LOG("link ready");
    mesh_link(link->mesh, link);
  }
  
  return link;
}
Esempio n. 6
0
// add a custom outgoing handshake packet to all links
mesh_t mesh_handshake(mesh_t mesh, lob_t handshake)
{
  if(!mesh) return NULL;
  if(handshake && !lob_get(handshake,"type")) return LOG("handshake missing a type: %s",lob_json(handshake));
  mesh->handshakes = lob_link(handshake, mesh->handshakes);
  return mesh;
}
Esempio n. 7
0
link_t mesh_add(mesh_t mesh, lob_t json, pipe_t pipe)
{
  link_t link;
  lob_t keys, paths;
  uint8_t csid;

  if(!mesh || !json) return LOG("bad args");
  LOG("mesh add %s",lob_json(json));
  link = link_get(mesh, hashname_vchar(lob_get(json,"hashname")));
  keys = lob_get_json(json,"keys");
  paths = lob_get_array(json,"paths");
  if(!link) link = link_keys(mesh, keys);
  if(!link) LOG("no hashname");
  
  LOG("loading keys/paths");
  if(keys && (csid = hashname_id(mesh->keys,keys))) link_load(link, csid, keys);

  // handle any pipe/paths
  if(pipe) link_pipe(link, pipe);
  lob_t path;
  for(path=paths;path;path = lob_next(path)) link_path(link,path);
  
  lob_free(keys);
  lob_freeall(paths);

  return link;
}
Esempio n. 8
0
// this will set the default inactivity timeout using this event timer and our uid
uint32_t e3x_channel_timeout(e3x_channel_t c, e3x_event_t ev, uint32_t timeout)
{
  if(!c) return 0;

  // un-set any
  if(ev != c->ev)
  {
    // cancel and clearn any previous timer state
    c->timeout = 0;
    if(c->ev) e3x_event_set(c->ev,NULL,c->uid,0);
    c->ev = NULL;
    lob_free(c->timer);
    c->timer = NULL;
  }
  
  // no event manager, no timeouts
  if(!ev) return 0;
  
  // no timeout, just return how much time is left
  if(!timeout) return _time_left(c);

  // add/update new timeout
  c->tsince = util_sys_seconds(); // start timer now
  c->timeout = timeout;
  c->ev = ev;
  c->timer = lob_new();
  lob_set_uint(c->timer,"c",c->id);
  lob_set(c->timer, "id", c->uid);
  lob_set(c->timer, "err", "timeout");
  e3x_event_set(c->ev, c->timer, lob_get(c->timer, "id"), timeout*1000); // ms in the future
  return _time_left(c);
}
Esempio n. 9
0
File: link.c Progetto: fd/telehash-c
// create/track a new channel for this open
channel3_t link_channel(link_t link, lob_t open)
{
  chan_t chan;
  channel3_t c3;
  if(!link || !open) return LOG("bad args");

  // add an outgoing cid if none set
  if(!lob_get_int(open,"c")) lob_set_int(open,"c",exchange3_cid(link->x, NULL));
  c3 = channel3_new(open);
  if(!c3) return LOG("invalid open %s",lob_json(open));
  LOG("new outgoing channel open: %s",lob_get(open,"type"));

  // add this channel to the link's channel index
  if(!(chan = malloc(sizeof (struct chan_struct))))
  {
    channel3_free(c3);
    return LOG("OOM");
  }
  memset(chan,0,sizeof (struct chan_struct));
  chan->c3 = c3;
  xht_set(link->channels, channel3_uid(c3), chan);
  xht_set(link->index, channel3_c(c3), chan);

  return c3;
}
Esempio n. 10
0
// process an incoming handshake
link_t link_receive_handshake(link_t link, lob_t inner)
{
  uint32_t out, at, err;
  uint8_t csid = 0;
  lob_t outer = lob_linked(inner);

  if(!link || !inner || !outer) return LOG("bad args");

  // inner/link must be validated by caller already, we just load if missing
  if(!link->key)
  {
    util_unhex(lob_get(inner, "csid"), 2, &csid);
    if(!link_load(link, csid, inner))
    {
      lob_free(inner);
      return LOG("load key failed for %s %u %s",hashname_short(link->id),csid,util_hex(inner->body,inner->body_len,NULL));
    }
  }

  if((err = e3x_exchange_verify(link->x,outer)))
  {
    lob_free(inner);
    return LOG("handshake verification fail: %d",err);
  }

  out = e3x_exchange_out(link->x,0);
  at = lob_get_uint(inner,"at");
  link_t ready = link_up(link);

  // if bad at, always send current handshake
  if(e3x_exchange_in(link->x, at) < out)
  {
    LOG("old handshake: %s (%d,%d,%d)",lob_json(inner),at,out);
    link_sync(link);
    lob_free(inner);
    return link;
  }

  // try to sync ephemeral key
  if(!e3x_exchange_sync(link->x,outer))
  {
    lob_free(inner);
    return LOG("sync failed");
  }

  // we may need to re-sync
  if(out != e3x_exchange_out(link->x,0)) link_sync(link);

  // notify of ready state change
  if(!ready && link_up(link))
  {
    LOG("link ready");
    mesh_link(link->mesh, link);
  }

  link->handshake = lob_free(link->handshake);
  link->handshake = inner;
  return link;
}
Esempio n. 11
0
int main(int argc, char **argv)
{
  lob_t opts = lob_new();
  fail_unless(e3x_init(opts) == 0);
  fail_unless(!lob_get(opts,"err"));
  fail_unless(!e3x_err());
  lob_free(opts);
  return 0;
}
Esempio n. 12
0
uint8_t e3x_cipher_init(lob_t options)
{
  e3x_cipher_default = NULL;
  memset(e3x_cipher_sets, 0, CS_MAX * sizeof(e3x_cipher_t));
  
  e3x_cipher_sets[CS_1a] = cs1a_init(options);
  if(e3x_cipher_sets[CS_1a]) e3x_cipher_default = e3x_cipher_sets[CS_1a];
  if(lob_get(options, "err")) return 1;

  e3x_cipher_sets[CS_2a] = cs2a_init(options);
  if(e3x_cipher_sets[CS_2a]) e3x_cipher_default = e3x_cipher_sets[CS_2a];
  if(lob_get(options, "err")) return 1;

  e3x_cipher_sets[CS_3a] = cs3a_init(options);
  if(e3x_cipher_sets[CS_3a]) e3x_cipher_default = e3x_cipher_sets[CS_3a];
  if(lob_get(options, "err")) return 1;

  return 0;
}
Esempio n. 13
0
uint8_t cipher3_init(lob_t options)
{
  cipher3_default = NULL;
  memset(cipher3_sets, 0, CS_MAX * sizeof(cipher3_t));
  
  cipher3_sets[CS_1a] = cs1a_init(options);
  if(cipher3_sets[CS_1a]) cipher3_default = cipher3_sets[CS_1a];
  if(lob_get(options, "err")) return 1;

  cipher3_sets[CS_2a] = cs2a_init(options);
  if(cipher3_sets[CS_2a]) cipher3_default = cipher3_sets[CS_2a];
  if(lob_get(options, "err")) return 1;

  cipher3_sets[CS_3a] = cs3a_init(options);
  if(cipher3_sets[CS_3a]) cipher3_default = cipher3_sets[CS_3a];
  if(lob_get(options, "err")) return 1;

  return 0;
}
Esempio n. 14
0
// query the cache of handshakes for a matching one with a specific type
lob_t mesh_handshakes(mesh_t mesh, lob_t handshake, char *type)
{
  lob_t matched;
  char *id;
  
  if(!mesh || !type || !(id = lob_get(handshake,"id"))) return LOG("bad args");
  
  for(matched = mesh->cached;matched;matched = lob_match(matched->next,"id",id))
  {
    if(lob_get_cmp(matched,"type",type) == 0) return matched;
  }
  
  return NULL;
}
Esempio n. 15
0
uint8_t e3x_exchange_validate(e3x_exchange_t x, lob_t args, lob_t sig, uint8_t *data, size_t len)
{
  remote_t remote = NULL;
  e3x_cipher_t cs = NULL;
  char *alg = lob_get(args,"alg");
  if(!data || !len || !alg) return 1;
  cs = e3x_cipher_set(0,alg);
  if(!cs || !cs->remote_validate)
  {
    LOG("no validate support for %s",alg);
    return 1;
  }
  if(x && x->cs == cs) remote = x->remote;
  return cs->remote_validate(remote,args,sig,data,len);
}
Esempio n. 16
0
// create/track a new channel for this open
chan_t link_chan(link_t link, lob_t open)
{
  chan_t c;
  if(!link || !open) return LOG("bad args");

  // add an outgoing cid if none set
  if(!lob_get_int(open,"c")) lob_set_uint(open,"c",e3x_exchange_cid(link->x, NULL));
  c = chan_new(open);
  if(!c) return LOG("invalid open %s",lob_json(open));
  LOG("new outgoing channel %d open: %s",chan_id(c), lob_get(open,"type"));

  c->link = link;
  c->next = link->chans;
  link->chans = c;

  return c;
}
Esempio n. 17
0
uint8_t hashname_id(lob_t a, lob_t b)
{
  uint8_t id, best;
  uint32_t i;
  char *key;

  if(!a || !b) return 0;

  best = 0;
  for(i=0;(key = lob_get_index(a,i));i+=2)
  {
    if(strlen(key) != 2) continue;
    if(!lob_get(b,key)) continue;
    id = 0;
    util_unhex(key,2,&id);
    if(id > best) best = id;
  }
  
  return best;
}
Esempio n. 18
0
// process a decrypted channel packet
link_t link_receive(link_t link, lob_t inner)
{
  chan_t c;

  if(!link || !inner) return LOG("bad args");

  LOG("<-- %d",lob_get_int(inner,"c"));
  // see if existing channel and send there
  if((c = link_chan_get(link, lob_get_int(inner,"c"))))
  {
    LOG("found chan");
    // consume inner
    chan_receive(c, inner);
    // process any changes
    link->chans = link_process_chan(link->chans, 0);
    return link;
  }

  // if it's an open, validate and fire event
  if(!lob_get(inner,"type"))
  {
    LOG("invalid channel open, no type %s",lob_json(inner));
    lob_free(inner);
    return NULL;
  }
  if(!e3x_exchange_cid(link->x, inner))
  {
    LOG("invalid channel open id %s",lob_json(inner));
    lob_free(inner);
    return NULL;
  }
  inner = mesh_open(link->mesh,link,inner);
  if(inner)
  {
    LOG("unhandled channel open %s",lob_json(inner));
    lob_free(inner);
    return NULL;
  }

  return link;
}
Esempio n. 19
0
// get paths from host and query
lob_t util_uri_paths(lob_t uri)
{
  uint32_t i;
  uint16_t port;
  uint8_t *buf;
  size_t len;
  char *key, *value;
  lob_t paths, query = lob_linked(uri);
  if(!query) return NULL;
  paths = NULL;
  
  // gen paths from host/port
  if((port = lob_get_uint(uri,"port")))
  {
    key = lob_get(uri,"host");
    paths = lob_chain(paths);
    lob_set(paths,"type","upd4");
    lob_set(paths,"ip",key);
    lob_set_uint(paths,"port",port);
    paths = lob_chain(paths);
    lob_set(paths,"type","tcp4");
    lob_set(paths,"ip",key);
    lob_set_uint(paths,"port",port);
  }

  // loop through all keyval pairs to find paths
  buf = NULL;
  for(i=0;(key = lob_get_index(query,i));i+=2)
  {
    value = lob_get_index(query,i+1);
    if(util_cmp(key,"paths") != 0 || !value) continue;
    len = base32_decode_floor(strlen(value));
    buf = util_reallocf(buf,len);
    if(!buf) continue;
    if(base32_decode(value,strlen(value),buf,len) < len) continue;
    paths = lob_link(lob_parse(buf,len), paths);
  }
  free(buf);
  
  return paths;
}
Esempio n. 20
0
int main(int argc, char **argv)
{
	lob_t id;
	mesh_t mesh;
  lob_t opts = lob_new();
  fail_unless(e3x_init(opts) == 0);
  fail_unless(!e3x_err());

  // need cs1a support to continue testing
  e3x_cipher_t cs = e3x_cipher_set(0x1a,NULL);
  if(!cs) return 0;

  cs = e3x_cipher_set(0,"1a");
  fail_unless(cs);
  fail_unless(cs->id == CS_1a);
  
  uint8_t buf[32];
  fail_unless(e3x_rand(buf,32));

  char hex[65];
  util_hex(e3x_hash((uint8_t*)"foo",3,buf),32,hex);
  fail_unless(strcmp(hex,"2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae") == 0);

  id = util_fjson("/Users/chrigel/.id.json");
  if(!id) return -1;

  lob_t secrets = lob_get_json(id,"secrets");
  fail_unless(secrets);
  fail_unless(lob_get(secrets,"1a"));
  lob_t keys = lob_get_json(id,"keys");
  fail_unless(keys);
  fail_unless(lob_get(keys,"1a"));
  LOG("generated key %s secret %s",lob_get(keys,"1a"),lob_get(secrets,"1a"));

  local_t localA = cs->local_new(keys,secrets);
  fail_unless(localA);

  remote_t remoteA = cs->remote_new(lob_get_base32(keys,"1a"), NULL);
  fail_unless(remoteA);

  // create another to start testing real packets
  lob_t secretsB = e3x_generate();
  fail_unless(lob_linked(secretsB));
  printf("XX %s\n",lob_json(lob_linked(secretsB)));
  local_t localB = cs->local_new(lob_linked(secretsB),secretsB);
  fail_unless(localB);
  remote_t remoteB = cs->remote_new(lob_get_base32(lob_linked(secretsB),"1a"), NULL);
  fail_unless(remoteB);

  // generate a message
  lob_t messageAB = lob_new();
  lob_set_int(messageAB,"a",42);
  lob_t outerAB = cs->remote_encrypt(remoteB,localA,messageAB);
  fail_unless(outerAB);
  fail_unless(lob_len(outerAB) == 42);

  // decrypt and verify it
  lob_t innerAB = cs->local_decrypt(localB,outerAB);
  fail_unless(innerAB);
  fail_unless(lob_get_int(innerAB,"a") == 42);
  fail_unless(cs->remote_verify(remoteA,localB,outerAB) == 0);

  ephemeral_t ephemBA = cs->ephemeral_new(remoteA,outerAB);
  fail_unless(ephemBA);
  
  lob_t channelBA = lob_new();
  lob_set(channelBA,"type","foo");
  lob_t couterBA = cs->ephemeral_encrypt(ephemBA,channelBA);
  fail_unless(couterBA);
  fail_unless(lob_len(couterBA) == 42);

  lob_t outerBA = cs->remote_encrypt(remoteA,localB,messageAB);
  fail_unless(outerBA);
  ephemeral_t ephemAB = cs->ephemeral_new(remoteB,outerBA);
  fail_unless(ephemAB);

  lob_t cinnerAB = cs->ephemeral_decrypt(ephemAB,couterBA);
  fail_unless(cinnerAB);
  fail_unless(util_cmp(lob_get(cinnerAB,"type"),"foo") == 0);

  return 0;
}
Esempio n. 21
0
int main(int argc, char **argv)
{
  lob_t packet;
  packet = lob_new();
  fail_unless(packet);
  lob_free(packet);

  uint8_t buf[1024];
  char *hex = "001d7b2274797065223a2274657374222c22666f6f223a5b22626172225d7d616e792062696e61727921";
  uint8_t len = strlen(hex)/2;
  util_unhex(hex,strlen(hex),buf);
  packet = lob_parse(buf,len);
  fail_unless(packet);
  fail_unless(lob_len(packet));
  fail_unless(packet->head_len == 29);
  fail_unless(packet->body_len == 11);
  fail_unless(util_cmp(lob_get(packet,"type"),"test") == 0);
  fail_unless(util_cmp(lob_get(packet,"foo"),"[\"bar\"]") == 0);
  
  lob_free(packet);
  packet = lob_new();
  lob_set_base32(packet,"32",buf,len);
  fail_unless(lob_get(packet,"32"));
  fail_unless(strlen(lob_get(packet,"32")) == (base32_encode_length(len)-1));
  lob_t bin = lob_get_base32(packet,"32");
  fail_unless(bin);
  fail_unless(bin->body_len == len);

  lob_set(packet,"key","value");
  fail_unless(lob_keys(packet) == 2);

  // test sorting
  lob_set(packet,"zz","value");
  lob_set(packet,"a","value");
  lob_set(packet,"z","value");
  lob_sort(packet);
  fail_unless(util_cmp(lob_get_index(packet,0),"32") == 0);
  fail_unless(util_cmp(lob_get_index(packet,2),"a") == 0);
  fail_unless(util_cmp(lob_get_index(packet,4),"key") == 0);
  fail_unless(util_cmp(lob_get_index(packet,6),"z") == 0);
  fail_unless(util_cmp(lob_get_index(packet,8),"zz") == 0);
  lob_free(packet);
  
  // minimal comparison test
  lob_t a = lob_new();
  lob_set(a,"foo","bar");
  lob_t b = lob_new();
  lob_set(b,"foo","bar");
  fail_unless(lob_cmp(a,b) == 0);
  lob_set(b,"bar","foo");
  fail_unless(lob_cmp(a,b) != 0);

  // lots of basic list testing
  lob_t list = lob_new();
  lob_t item = lob_new();
  fail_unless(lob_push(list,item));
  fail_unless(lob_pop(list) == item);
  list = item->next;
  fail_unless((list = lob_unshift(list,item)));
  fail_unless(lob_shift(list) == item);
  list = item->next;
  fail_unless(lob_push(list,item));
  fail_unless(list->next == item);
  lob_t insert = lob_new();
  fail_unless(lob_insert(list,list,insert));
  fail_unless(list->next == insert);
  fail_unless(insert->next == item);
  fail_unless(lob_splice(list,insert));
  fail_unless(list->next == item);

  lob_t array = lob_array(list);
  fail_unless(array);
  fail_unless(util_cmp(lob_json(array),"[,]") == 0);

  fail_unless(lob_freeall(list) == NULL);

  // simple index testing
  lob_t index = lob_new();
  lob_t c1 = lob_new();
  lob_set(c1,"id","c1");
  lob_push(index,c1);
  lob_t c2 = lob_new();
  lob_set(c2,"id","c2");
  lob_push(index,c2);
  fail_unless(lob_match(index,"id","c1") == c1);
  fail_unless(lob_match(index,"id","c2") == c2);
  
  float f = 42.42;
  lob_t ft = lob_new();
  lob_head(ft,(uint8_t*)"{\"foo\":42.42}",13);
  fail_unless(lob_get_float(ft,"foo") == f);
  lob_set_float(ft,"bar2",f,2);
  fail_unless(lob_get_float(ft,"bar2") == f);
  lob_set_float(ft,"bar1",f,1);
  fail_unless(lob_get_cmp(ft,"bar1","42.4") == 0);
  lob_set_float(ft,"bar0",f,0);
  fail_unless(lob_get_int(ft,"bar0") == 42);
  LOG("floats %s",lob_json(ft));

  return 0;
}
Esempio n. 22
0
// process any unencrypted handshake packet
link_t mesh_receive_handshake(mesh_t mesh, lob_t handshake, pipe_t pipe)
{
  uint32_t now;
  hashname_t from;
  link_t link;

  if(!mesh || !handshake) return LOG("bad args");
  if(!lob_get(handshake,"id"))
  {
    LOG("bad handshake, no id: %s",lob_json(handshake));
    lob_free(handshake);
    return NULL;
  }
  now = util_sys_seconds();
  
  // normalize handshake
  handshake->id = now; // save when we cached it
  if(!lob_get(handshake,"type")) lob_set(handshake,"type","link"); // default to link type
  if(!lob_get_uint(handshake,"at")) lob_set_uint(handshake,"at",now); // require an at
  LOG("handshake at %d id %s",now,lob_get(handshake,"id"));
  
  // validate/extend link handshakes immediately
  if(util_cmp(lob_get(handshake,"type"),"link") == 0)
  {
    // get the csid
    uint8_t csid = 0;
    lob_t outer;
    if((outer = lob_linked(handshake)))
    {
      csid = outer->head[0];
    }else if(lob_get(handshake,"csid")){
      util_unhex(lob_get(handshake,"csid"),2,&csid);
    }
    if(!csid)
    {
      LOG("bad link handshake, no csid: %s",lob_json(handshake));
      lob_free(handshake);
      return NULL;
    }
    char hexid[3] = {0};
    util_hex(&csid, 1, hexid);
      
    // get attached hashname
    lob_t tmp = lob_parse(handshake->body, handshake->body_len);
    from = hashname_vkey(tmp, csid);
    if(!from)
    {
      LOG("bad link handshake, no hashname: %s",lob_json(handshake));
      lob_free(tmp);
      lob_free(handshake);
      return NULL;
    }
    lob_set(handshake,"csid",hexid);
    lob_set(handshake,"hashname",hashname_char(from));
    lob_set_raw(handshake,hexid,2,"true",4); // intermediate format
    lob_body(handshake, tmp->body, tmp->body_len); // re-attach as raw key
    lob_free(tmp);

    // short-cut, if it's a key from an existing link, pass it on
    // TODO: using mesh_linked here is a stack issue during loopback peer test!
    if((link = mesh_linkid(mesh,from))) return link_receive_handshake(link, handshake, pipe);
    LOG("no link found for handshake from %s",hashname_char(from));

    // extend the key json to make it compatible w/ normal patterns
    tmp = lob_new();
    lob_set_base32(tmp,hexid,handshake->body,handshake->body_len);
    lob_set_raw(handshake,"keys",0,(char*)tmp->head,tmp->head_len);
    lob_free(tmp);
    // add the path if one
    if(pipe && pipe->path)
    {
      char *paths = malloc(pipe->path->head_len+3);
      sprintf(paths,"[%.*s]",(int)pipe->path->head_len,(char*)pipe->path->head);
      lob_set_raw(handshake,"paths",0,paths,pipe->path->head_len+2);
      free(paths);
    }
  }

  // always add to the front of the cached list if needed in the future
  mesh->cached = lob_unshift(mesh->cached, handshake);

  // tell anyone listening about the newly discovered handshake
  mesh_discover(mesh, handshake, pipe);
  
  return NULL;
}
Esempio n. 23
0
// this is a very simple single-pass telehash uri parser, no magic
lob_t util_uri_parse(char *encoded)
{
  size_t klen, vlen;
  char *at, *val;
  lob_t uri;
  
  if(!encoded) return LOG("bad args");
  uri = lob_new();
  lob_set(uri,"orig",encoded);

  // check for protocol:// prefix first
  if(!(at = strstr(encoded,"://")))
  {
    lob_set(uri, "protocol", "link");
  }else{
    lob_set_len(uri, "protocol", 0, encoded, (size_t)(at - encoded));
    encoded = at+3;
  }
  
  // check for user@ prefix next
  if((at = strchr(encoded,'@')))
  {
    lob_set_len(uri, "auth", 0, encoded, (size_t)(at - encoded));
    encoded = at+1;
  }
  
  // ensure there's at least a host
  if(!strlen(encoded) || !isalnum((int)encoded[0]))
  {
    lob_free(uri);
    return LOG("invalid host: '%s'",encoded);
  }

  // copy in host and parse hostname/port
  if((at = strchr(encoded,'/')) || (at = strchr(encoded,'?')) || (at = strchr(encoded,'#')))
  {
    lob_set_len(uri, "host", 0, encoded, (size_t)(at - encoded));
  }else{
    lob_set_len(uri, "host", 0, encoded, strlen(encoded));
  }

  // hostname+port
  val = lob_get(uri, "host");
  if(val && (at = strchr(val,':')))
  {
    lob_set_len(uri, "hostname", 0, val, (size_t)(at - val));
    lob_set_uint(uri, "port", (uint16_t)strtoul(at+1,NULL,10));
  }else{
    lob_set(uri, "hostname", val);
  }

  // optional path
  if((at = strchr(encoded,'/')))
  {
    encoded = at;
    if((at = strchr(encoded+1,'?')) || (at = strchr(encoded+1,'#')))
    {
      lob_set_len(uri, "path", 0, encoded, (size_t)(at - encoded));
    }else{
      lob_set_len(uri, "path", 0, encoded, strlen(encoded));
    }
  }

  // optional hash at the end
  if((at = strchr(encoded,'#')))
  {
    lob_set_len(uri, "hash", 0, at+1, strlen(at+1));
  }

  // optional query string
  if((at = strchr(encoded,'?')))
  {
    uri->chain = lob_new();
    encoded = at+1;
    if((at = strchr(encoded,'#')))
    {
      klen = (size_t)(at - encoded);
    }else{
      klen = strlen(encoded);
    }
    while(klen)
    {
      // skip any separator
      if(*encoded == '&')
      {
        encoded++;
        klen--;
      }
      // require the equals
      if(!(val = strchr(encoded,'='))) break;
      val++;
      if((at = strchr(val,'&')))
      {
        vlen = (size_t)(at - val);
      }else{
        vlen = strlen(val);
      }
      lob_set_len(uri->chain, encoded, (size_t)(val-encoded)-1, val, vlen);
      // skip past whole block
      klen -= (size_t)((val+vlen) - encoded);
      encoded = val + vlen;
    }
  }

  return uri;
}
Esempio n. 24
0
// serialize out from lob format to "uri" key and return it
char *util_uri_format(lob_t uri)
{
  char *part, *key, *value;
  uint32_t i, prev = 0;
  lob_t buf, query;
  if(!uri) return NULL;
  
  // use a lob body as the buffer to build it up
  buf = lob_new();
  
  part = lob_get(uri, "protocol");
  if(part)
  {
    lob_append_str(buf, part);
  }else{
    lob_append_str(buf, "link");
  }
  lob_append_str(buf, "://");

  part = lob_get(uri, "hostname");
  if(part)
  {
    lob_append_str(buf, part);
    part = lob_get(uri, "port");
    if(part)
    {
      lob_append_str(buf, ":");
      lob_append_str(buf, part);
    }
  }else{
    part = lob_get(uri, "host");
    if(part) lob_append_str(buf, part);
  }
  
  part = lob_get(uri, "path");
  if(part)
  {
    lob_append_str(buf, part);
  }else{
    lob_append_str(buf, "/");
  }
  
  // append on any query string
  
  for(query = lob_linked(uri); query; query = lob_linked(query))
  {
    for(i=0;(key = lob_get_index(query,i));i+=2)
    {
      value = lob_get_index(query,i+1);
      if(!strlen(key) || !value) continue; // paranoid
      lob_append_str(buf,(prev++)?"&":"?");
      lob_append_str(buf,key);
      lob_append_str(buf,"=");
      lob_append_str(buf,value);
    }
  }

  if((part = lob_get(uri, "hash")))
  {
    lob_append_str(buf, "#");
    lob_append_str(buf, part);
  }

  lob_set_len(uri,"uri",3,(char*)buf->body,buf->body_len);
  lob_free(buf);

  return lob_get(uri,"uri");
}
Esempio n. 25
0
// processes incoming packet, it will take ownership of p
link_t mesh_receive(mesh_t mesh, lob_t outer, pipe_t pipe)
{
  lob_t inner;
  link_t link;
  char token[17];
  hashname_t id;

  if(!mesh || !outer || !pipe) return LOG("bad args");
  
  LOG("mesh receiving %s to %s via pipe %s",outer->head_len?"handshake":"channel",hashname_short(mesh->id),pipe->id);

  // process handshakes
  if(outer->head_len == 1)
  {
    inner = e3x_self_decrypt(mesh->self, outer);
    if(!inner)
    {
      LOG("%02x handshake failed %s",outer->head[0],e3x_err());
      lob_free(outer);
      return NULL;
    }
    
    // couple the two together, inner->outer
    lob_link(inner,outer);

    // set the unique id string based on some of the first 16 (routing token) bytes in the body
    base32_encode(outer->body,10,token,17);
    lob_set(inner,"id",token);

    // process the handshake
    return mesh_receive_handshake(mesh, inner, pipe);
  }

  // handle channel packets
  if(outer->head_len == 0)
  {
    if(outer->body_len < 16)
    {
      LOG("packet too small %d",outer->body_len);
      lob_free(outer);
      return NULL;
    }
    
    route_t route;
    for(route = mesh->routes;route;route = route->next) if(memcmp(route->token,outer->body,8) == 0) break;
    link = route ? route->link : NULL;
    if(!link)
    {
      LOG("dropping, no link for token %s",util_hex(outer->body,16,NULL));
      lob_free(outer);
      return NULL;
    }
    
    // forward packet
    if(!route->flag)
    {
      LOG("forwarding route token %s via %s len %d",util_hex(route->token,8,NULL),hashname_short(link->id),lob_len(outer));
      return link_send(link, outer);
    }
    
    inner = e3x_exchange_receive(link->x, outer);
    lob_free(outer);
    if(!inner) return LOG("channel decryption fail for link %s %s",hashname_short(link->id),e3x_err());
    
    LOG("channel packet %d bytes from %s",lob_len(inner),hashname_short(link->id));
    return link_receive(link,inner,pipe);
    
  }

  // transform incoming bare link json format into handshake for discovery
  if((inner = lob_get_json(outer,"keys")))
  {
    if((id = hashname_vkeys(inner)))
    {
      lob_set(outer,"hashname",hashname_char(id));
      lob_set_int(outer,"at",0);
      lob_set(outer,"type","link");
      LOG("bare incoming link json being discovered %s",lob_json(outer));
    }
    lob_free(inner);
  }
  
  // run everything else through discovery, usually plain handshakes
  mesh_discover(mesh, outer, pipe);
  link = mesh_linked(mesh, lob_get(outer,"hashname"), 0);
  lob_free(outer);

  return link;
}