static int list_set_udel(struct ip_set *set, void *value, const struct ip_set_ext *ext, struct ip_set_ext *mext, u32 flags) { struct list_set *map = set->data; struct set_adt_elem *d = value; struct set_elem *e; u32 i; for (i = 0; i < map->size; i++) { e = list_set_elem(set, map, i); if (e->id == IPSET_INVALID_ID) return d->before != 0 ? -IPSET_ERR_REF_EXIST : -IPSET_ERR_EXIST; else if (SET_WITH_TIMEOUT(set) && ip_set_timeout_expired(ext_timeout(e, set))) continue; else if (e->id != d->id) continue; if (d->before == 0) return list_set_del(set, i); else if (d->before > 0) { if (!id_eq(set, i + 1, d->refid)) return -IPSET_ERR_REF_EXIST; return list_set_del(set, i); } else if (i == 0 || !id_eq(set, i - 1, d->refid)) return -IPSET_ERR_REF_EXIST; else return list_set_del(set, i); } return -IPSET_ERR_EXIST; }
static int list_set_utest(struct ip_set *set, void *value, const struct ip_set_ext *ext, struct ip_set_ext *mext, u32 flags) { struct list_set *map = set->data; struct set_adt_elem *d = value; struct set_elem *e; u32 i; int ret; for (i = 0; i < map->size; i++) { e = list_set_elem(set, map, i); if (e->id == IPSET_INVALID_ID) return 0; else if (SET_WITH_TIMEOUT(set) && ip_set_timeout_expired(ext_timeout(e, set))) continue; else if (e->id != d->id) continue; if (d->before == 0) return 1; else if (d->before > 0) ret = id_eq(set, i + 1, d->refid); else ret = i > 0 && id_eq(set, i - 1, d->refid); return ret; } return 0; }
static int list_set_uadd(struct ip_set *set, void *value, const struct ip_set_ext *ext, struct ip_set_ext *mext, u32 flags) { struct list_set *map = set->data; struct set_adt_elem *d = value; struct set_elem *e; bool flag_exist = flags & IPSET_FLAG_EXIST; u32 i, ret = 0; if (SET_WITH_TIMEOUT(set)) set_cleanup_entries(set); /* Check already added element */ for (i = 0; i < map->size; i++) { e = list_set_elem(set, map, i); if (e->id == IPSET_INVALID_ID) goto insert; else if (e->id != d->id) continue; if ((d->before > 1 && !id_eq(set, i + 1, d->refid)) || (d->before < 0 && (i == 0 || !id_eq(set, i - 1, d->refid)))) /* Before/after doesn't match */ return -IPSET_ERR_REF_EXIST; if (!flag_exist) /* Can't re-add */ return -IPSET_ERR_EXIST; /* Update extensions */ ip_set_ext_destroy(set, e); if (SET_WITH_TIMEOUT(set)) ip_set_timeout_set(ext_timeout(e, set), ext->timeout); if (SET_WITH_COUNTER(set)) ip_set_init_counter(ext_counter(e, set), ext); if (SET_WITH_COMMENT(set)) ip_set_init_comment(ext_comment(e, set), ext); /* Set is already added to the list */ ip_set_put_byindex(map->net, d->id); return 0; } insert: ret = -IPSET_ERR_LIST_FULL; for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) { e = list_set_elem(set, map, i); if (e->id == IPSET_INVALID_ID) ret = d->before != 0 ? -IPSET_ERR_REF_EXIST : list_set_add(set, i, d, ext); else if (e->id != d->refid) continue; else if (d->before > 0) ret = list_set_add(set, i, d, ext); else if (i + 1 < map->size) ret = list_set_add(set, i + 1, d, ext); } return ret; }
int handle_ping_response(uint8_t* packet, uint32_t length, IP_Port source) { pingres_t* p = (pingres_t*) packet; int rc; uint64_t ping_id; if (length != sizeof(pingres_t) || id_eq(&p->client_id, self_id)) return 1; // Decrypt ping_id rc = decrypt_data((uint8_t*) &p->client_id, self_secret_key, (uint8_t*) &p->nonce, (uint8_t*) &p->ping_id, sizeof(ping_id) + ENCRYPTION_PADDING, (uint8_t*) &ping_id); if (rc != sizeof(ping_id)) return 1; // Make sure ping_id is correct if(!is_pinging(source, ping_id)) return 1; // Associate source ip with client_id addto_lists(source, (uint8_t*) &p->client_id); return 0; }
int handle_ping_request(uint8_t* packet, uint32_t length, IP_Port source) { pingreq_t* p = (pingreq_t*) packet; int rc; uint64_t ping_id; if (length != sizeof(pingreq_t) || id_eq(&p->client_id, self_id)) return 1; // Decrypt ping_id rc = decrypt_data((uint8_t*) &p->client_id, self_secret_key, (uint8_t*) &p->nonce, (uint8_t*) &p->ping_id, sizeof(ping_id) + ENCRYPTION_PADDING, (uint8_t*) &ping_id); if (rc != sizeof(ping_id)) return 1; // Send response send_ping_response(source, &p->client_id, ping_id); send_ping_request(source, &p->client_id); // Make this smarter? return 0; }
int send_ping_request(IP_Port ipp, clientid_t* client_id) { pingreq_t pk; int rc; uint64_t ping_id; if (is_pinging(ipp, 0) || id_eq(client_id, self_id)) return 1; // Generate random ping_id ping_id = add_ping(ipp); pk.magic = PACKET_PING_REQ; id_cpy(&pk.client_id, self_id); // Our pubkey random_nonce((uint8_t*) &pk.nonce); // Generate random nonce // Encrypt ping_id using recipient privkey rc = encrypt_data((uint8_t*) client_id, self_secret_key, (uint8_t*) &pk.nonce, (uint8_t*) &ping_id, sizeof(ping_id), (uint8_t*) &pk.ping_id); if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) return 1; return sendpacket(ipp, (uint8_t*) &pk, sizeof(pk)); }
static int handle_ping_response(void *_dht, IP_Port source, uint8_t *packet, uint32_t length) { DHT *dht = _dht; int rc; uint64_t ping_id; if (length != DHT_PING_SIZE) return 1; PING *ping = dht->ping; if (id_eq(packet + 1, ping->c->self_public_key)) return 1; // Decrypt ping_id rc = decrypt_data(packet + 1, ping->c->self_secret_key, packet + 1 + CLIENT_ID_SIZE, packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, sizeof(ping_id) + ENCRYPTION_PADDING, (uint8_t *) &ping_id); if (rc != sizeof(ping_id)) return 1; /* Make sure ping_id is correct. */ if (!is_pinging(ping, source, ping_id)) return 1; // Associate source ip with client_id addto_lists(dht, source, packet + 1); return 0; }
static int handle_ping_request(void *_dht, IP_Port source, uint8_t *packet, uint32_t length) { DHT *dht = _dht; int rc; uint64_t ping_id; if (length != DHT_PING_SIZE) return 1; PING *ping = dht->ping; if (id_eq(packet + 1, ping->c->self_public_key)) return 1; // Decrypt ping_id rc = decrypt_data(packet + 1, ping->c->self_secret_key, packet + 1 + CLIENT_ID_SIZE, packet + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES, sizeof(ping_id) + ENCRYPTION_PADDING, (uint8_t *) &ping_id); if (rc != sizeof(ping_id)) return 1; // Send response send_ping_response(ping, source, packet + 1, ping_id); add_toping(ping, packet + 1, source); return 0; }
int send_ping_request(PING *ping, IP_Port ipp, uint8_t *client_id) { uint8_t pk[DHT_PING_SIZE]; int rc; uint64_t ping_id; if (is_pinging(ping, ipp, 0) || id_eq(client_id, ping->c->self_public_key)) return 1; // Generate random ping_id. ping_id = add_ping(ping, ipp); pk[0] = NET_PACKET_PING_REQUEST; id_cpy(pk + 1, ping->c->self_public_key); // Our pubkey new_nonce(pk + 1 + CLIENT_ID_SIZE); // Generate new nonce // Encrypt ping_id using recipient privkey rc = encrypt_data(client_id, ping->c->self_secret_key, pk + 1 + CLIENT_ID_SIZE, (uint8_t *) &ping_id, sizeof(ping_id), pk + 1 + CLIENT_ID_SIZE + crypto_box_NONCEBYTES); if (rc != sizeof(ping_id) + ENCRYPTION_PADDING) return 1; return sendpacket(ping->c->lossless_udp->net, ipp, pk, sizeof(pk)); }
static int list_set_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { struct list_set *map = set->data; bool with_timeout = with_timeout(map->timeout); bool flag_exist = flags & IPSET_FLAG_EXIST; int before = 0; u32 timeout = map->timeout; ip_set_id_t id, refid = IPSET_INVALID_ID; const struct set_elem *elem; struct ip_set *s; u32 i; int ret = 0; if (unlikely(!tb[IPSET_ATTR_NAME] || !ip_set_optattr_netorder(tb, IPSET_ATTR_TIMEOUT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); id = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAME]), &s); if (id == IPSET_INVALID_ID) return -IPSET_ERR_NAME; /* "Loop detection" */ if (s->type->features & IPSET_TYPE_NAME) { ret = -IPSET_ERR_LOOP; goto finish; } if (tb[IPSET_ATTR_CADT_FLAGS]) { u32 f = ip_set_get_h32(tb[IPSET_ATTR_CADT_FLAGS]); before = f & IPSET_FLAG_BEFORE; } if (before && !tb[IPSET_ATTR_NAMEREF]) { ret = -IPSET_ERR_BEFORE; goto finish; } if (tb[IPSET_ATTR_NAMEREF]) { refid = ip_set_get_byname(nla_data(tb[IPSET_ATTR_NAMEREF]), &s); if (refid == IPSET_INVALID_ID) { ret = -IPSET_ERR_NAMEREF; goto finish; } if (!before) before = -1; } if (tb[IPSET_ATTR_TIMEOUT]) { if (!with_timeout) { ret = -IPSET_ERR_TIMEOUT; goto finish; } timeout = ip_set_timeout_uget(tb[IPSET_ATTR_TIMEOUT]); } if (with_timeout && adt != IPSET_TEST) cleanup_entries(map); switch (adt) { case IPSET_TEST: for (i = 0; i < map->size && !ret; i++) { elem = list_set_elem(map, i); if (elem->id == IPSET_INVALID_ID || (before != 0 && i + 1 >= map->size)) break; else if (with_timeout && list_set_expired(map, i)) continue; else if (before > 0 && elem->id == id) ret = id_eq_timeout(map, i + 1, refid); else if (before < 0 && elem->id == refid) ret = id_eq_timeout(map, i + 1, id); else if (before == 0 && elem->id == id) ret = 1; } break; case IPSET_ADD: for (i = 0; i < map->size; i++) { elem = list_set_elem(map, i); if (elem->id != id) continue; if (!(with_timeout && flag_exist)) { ret = -IPSET_ERR_EXIST; goto finish; } else { struct set_telem *e = list_set_telem(map, i); if ((before > 1 && !id_eq(map, i + 1, refid)) || (before < 0 && (i == 0 || !id_eq(map, i - 1, refid)))) { ret = -IPSET_ERR_EXIST; goto finish; } e->timeout = ip_set_timeout_set(timeout); ip_set_put_byindex(id); ret = 0; goto finish; } } ret = -IPSET_ERR_LIST_FULL; for (i = 0; i < map->size && ret == -IPSET_ERR_LIST_FULL; i++) { elem = list_set_elem(map, i); if (elem->id == IPSET_INVALID_ID) ret = before != 0 ? -IPSET_ERR_REF_EXIST : list_set_add(map, i, id, timeout); else if (elem->id != refid) continue; else if (before > 0) ret = list_set_add(map, i, id, timeout); else if (i + 1 < map->size) ret = list_set_add(map, i + 1, id, timeout); } break; case IPSET_DEL: ret = -IPSET_ERR_EXIST; for (i = 0; i < map->size && ret == -IPSET_ERR_EXIST; i++) { elem = list_set_elem(map, i); if (elem->id == IPSET_INVALID_ID) { ret = before != 0 ? -IPSET_ERR_REF_EXIST : -IPSET_ERR_EXIST; break; } else if (elem->id == id && (before == 0 || (before > 0 && id_eq(map, i + 1, refid)))) ret = list_set_del(map, i); else if (elem->id == refid && before < 0 && id_eq(map, i + 1, id)) ret = list_set_del(map, i + 1); } break; default: break; } finish: if (refid != IPSET_INVALID_ID) ip_set_put_byindex(refid); if (adt != IPSET_ADD || ret) ip_set_put_byindex(id); return ip_set_eexist(ret, flags) ? 0 : ret; }
int parse_packet(const unsigned char *buf, int buflen, struct sockaddr_in6 *from, int unicast, struct interface *interface) { unsigned char id[4]; unsigned int eid = 42; /* silence gcc */ int have_id = 0; int i = 0, rc; int recompute = 0; if(debug_level >= 3) debugf("Received %d bytes.\n", buflen); while(i < buflen) { unsigned const char *tlv = buf + i; int type, bodylen; if(buflen - i < 4) { fprintf(stderr, "Received truncated TLV.\n"); goto fail; } DO_NTOHS(type, tlv); DO_NTOHS(bodylen, tlv + 2); if(buflen - i < 4 + bodylen) { fprintf(stderr, "Received truncated TLV.\n"); goto fail; } switch(type) { case 1: { debugf(" REQ-NETWORK-STATE\n"); int i; buffer_network_state(from, NULL); for(i = 0; i < numnodes; i++) buffer_node_state(&nodes[i], 0, from, NULL); break; } case 2: { struct node *node; if(bodylen < 4) { fprintf(stderr, "Truncated REQ-NODE-STATE\n"); goto fail; } debugf(" REQ-NODE-STATE %s\n", format_32(tlv + 4)); node = find_node(tlv + 4, 0); if(node) buffer_node_state(node, 1, from, NULL); break; } case 3: { struct neighbour *neigh; if(bodylen < 8) { fprintf(stderr, "Truncated NODE-ENDPOINT.\n"); break; } if(have_id) { fprintf(stderr, "Duplicate NODE-ENDPOINT.\n"); break; } memcpy(id, tlv + 4, 4); DO_NTOHL(eid, tlv + 8); debugf(" NODE-ENDPOINT %s %u\n", format_32(id), eid); if(id_eq(id, myid)) { fprintf(stderr, "Node id collision.\n"); goto fail; } have_id = 1; if(unicast) { neigh = find_neighbour(interface, id, eid, from); if(neigh && unicast) neigh->last_contact = now; } break; } case 4: { int rc; unsigned char h[8]; struct neighbour *neigh = NULL; struct timespec t; if(have_id) neigh = find_neighbour(interface, id, eid, NULL); if(bodylen < 8) { fprintf(stderr, "Truncated NETWORK-STATE.\n"); goto fail; } rc = network_hash(h); if(rc < 0) { fprintf(stderr, "Eek!\n"); goto fail; } if(memcmp(h, tlv + 4, 8) == 0) { debugf(" NETWORK-STATE %s (consistent)\n", format_64(tlv + 4)); if(neigh) neigh->last_contact = now; trickle_reset(&interface->trickle, 1); break; } debugf(" NETWORK-STATE %s (inconsistent, %s)\n", format_64(tlv + 4), format_64(h)); /* But don't reset Trickle. */ ts_add_msec(&t, &interface->last_request_sent, HNCP_I_min); if(ts_compare(&now, &t) >= 0) { interface->last_request_sent = now; debugf("-> REQ-NETWORK-STATE\n"); buffer_tlv(1, NULL, 0, from, NULL); } break; } case 5: { struct node *node; unsigned int seqno; int msecs, mine; int datalen = bodylen - 20; if(bodylen < 20) { fprintf(stderr, "Truncated NODE-STATE.\n"); goto fail; } if(!have_id) { fprintf(stderr, "NODE-STATE with no NODE-ENDPOINT.\n"); } DO_NTOHL(seqno, tlv + 8); DO_NTOHL(msecs, tlv + 12); debugf(" NODE-STATE %s %d %d", format_32(tlv + 4), seqno, msecs); mine = id_eq(tlv + 4, myid); if(mine) debugf(" (mine)"); node = find_node(tlv + 4, 0); if(node && (seqno - node->seqno) & 0x80000000) { debugf(" (older)\n"); } else if(!node || seqno != node->seqno || memcmp(tlv + 16, node->datahash, 8) != 0) { debugf(" (newer%s, %s)\n", datalen ? ", data" : "", format_64(tlv + 16)); if(mine) { fprintf(stderr, "Duplicate node identifier -- reclaiming.\n"); node->seqno = seqno + 42; break; } if(datalen) { unsigned char *new_data; unsigned char h[8]; int rc; node_hash(h, tlv + 24, datalen); if(memcmp(h, tlv + 16, 8) != 0) { fprintf(stderr, "Corrupt hash.\n"); goto fail; } if(!node) node = find_node(tlv + 4, 1); if(!node) { fprintf(stderr, "Couldn't create node.\n"); goto fail; } new_data = realloc(node->data, datalen); if(new_data == NULL) { fprintf(stderr, "Eek!\n"); goto fail; } node->interface = interface; node->seqno = seqno; ts_add_msec(&node->orig_time, &now, msecs + 1); node->data = new_data; memcpy(node->data, tlv + 24, datalen); node->datalen = datalen; memcpy(node->datahash, tlv + 16, 8); rc = parse_node_state(node); if(rc < 0) fprintf(stderr, "Couldn't parse node state.\n"); else trickle_reset_all(); recompute = 1; } else { struct neighbour *neigh = NULL; if(have_id) neigh = find_neighbour(interface, id, eid, from); if(neigh) { debugf("-> REQ-NODE-STATE %s\n", format_32(tlv + 4)); buffer_tlv(2, tlv + 4, 4, from, NULL); } else fprintf(stderr, "No neighbour to send request to.\n"); } } else { debugf(" (consistent)\n"); } break; } default: if(debug_level >= 3) debugf(" %d: %d\n", type, bodylen); break; break; } i += 4 + bodylen; i += -i & 3; } rc = 1; goto done; fail: rc = -1; done: if(recompute) { int r; silly_walk(find_node(myid, 0)); r = prefix_assignment(1); if(r > 0) republish(0, 1); } return rc; }
int parse_node_state(struct node *node) { const unsigned char *buf = node->data; int buflen = node->datalen; int i = 0, j, rc; struct node_neighbour *nn = NULL; int numnn = 0, maxnn = 0; struct external **exts = NULL; int numexts = 0, maxexts = 0; for(j = 0; j < numneighs; j++) { if(id_eq(neighs[j].id, node->id)) neighs[j].keepalive_interval = 0; } while(i < buflen) { unsigned const char *tlv = buf + i; int type, bodylen; if(buflen - i < 4) { fprintf(stderr, "Received truncated TLV.\n"); goto fail; } DO_NTOHS(type, tlv); DO_NTOHS(bodylen, tlv + 2); if(buflen - i < 4 + bodylen) { fprintf(stderr, "Received truncated TLV.\n"); goto fail; } switch(type) { case 7: fprintf(stderr, "Received fragmented nonsense.\n"); goto fail; case 8: { if(bodylen < 12) { fprintf(stderr, "Truncated neighbour TLV.\n"); break; } if(numnn >= maxnn) { struct node_neighbour *nnn = realloc(nn, (2 * maxnn + 2) * sizeof(struct node_neighbour)); if(nnn == NULL) { fprintf(stderr, "Eek.\n"); /* Oh, well. */ break; } nn = nnn; maxnn = 2 * maxnn + 2; } memcpy(nn[numnn].neigh, tlv + 4, 4); DO_NTOHL(nn[numnn].nei, tlv + 8); DO_NTOHL(nn[numnn].lei, tlv + 12); debugf(" NEIGHBOR %s (nei=%u, lei=%u)\n", format_32(nn[numnn].neigh), nn[numnn].nei, nn[numnn].lei); numnn++; break; } case 9: { unsigned eid, interval; if(bodylen < 8) { fprintf(stderr, "Truncated KEEP-ALIVE-INTERVAL.\n"); break; } DO_NTOHL(eid, tlv + 4); DO_NTOHL(interval, tlv + 8); debugf(" KEEP-ALIVE-INTERVAL %u (eid=%u)\n", interval, eid); for(j = 0; j < numneighs; j++) { if(id_eq(neighs[j].id, node->id) && neighs[j].eid == eid) neighs[j].keepalive_interval = interval ? interval : 0xFFFFFFFF; } break; } case 32: { if(bodylen < 4) { debugf("Truncated VERSION\n"); goto fail; } debugf(" VERSION\n"); memcpy(node->capabilities, tlv + 6, 2); break; } case 33: { struct external *ext; debugf(" EXTERNAL-CONNECTION\n"); ext = parse_external(node, tlv + 4, bodylen); if(ext) { if(numexts >= maxexts) { struct external **e = realloc(exts, (2 * maxexts + 2) * sizeof(struct external *)); if(e == NULL) { fprintf(stderr, "Eek.\n"); break; } maxexts = 2 * maxexts + 2; exts = e; } exts[numexts++] = ext; } break; } case 35: { unsigned char plen; struct in6_addr addr; int prio; unsigned int eid; struct prefix_list *pl; if(bodylen < 6) { fprintf(stderr, "Truncated ASSIGNED-PREFIX.\n"); break; } DO_NTOHL(eid, tlv + 4); plen = *(tlv + 9); if(bodylen < 6 + (plen + 7) / 8) { fprintf(stderr, "Truncated ASSIGNED-PREFIX.\n"); break; } prio = tlv[8] & 0x0F; parse_pref(&addr, tlv + 10, plen); debugf(" ASSIGNED-PREFIX "); debug_prefix_raw(&addr, plen); debugf(" (%d, prio=%d)\n", eid, prio); pl = prefix_list_cons(node->assigned, &addr, plen, node->id, eid, prio); if(pl) node->assigned = pl; break; } case 36: { unsigned int eid; struct prefix_list *pl; struct in6_addr addr; if(bodylen < 20) { fprintf(stderr, "Truncated NODE-ADDRESS.\n"); break; } DO_NTOHL(eid, tlv + 4); memcpy(&addr, tlv + 8, 16); debugf(" NODE-ADDRESS "); debug_address(&addr); debugf(" %d\n",eid); pl = prefix_list_cons(node->addresses, &addr, 128, node->id, eid, 0); if(pl) node->addresses = pl; break; } default: if(debug_level >= 3) debugf(" %d: %d\n", type, bodylen); break; } i += 4 + bodylen; i += -i & 3; } rc = 1; goto done; fail: rc = -1; done: if(node->neighs) free(node->neighs); node->neighs = nn; node->numneighs = numnn; if(node->exts) { for(i = 0; i < node->numexts; i++) destroy_external(node->exts[i]); free(node->exts); } node->exts = exts; node->numexts = numexts; return rc; }