int overlay_mdp_client_done() { if (mdp_client_socket!=-1) { /* Tell MDP server to release all our bindings */ overlay_mdp_frame mdp; mdp.packetTypeAndFlags=MDP_GOODBYE; overlay_mdp_send(&mdp,0,0); } if (overlay_mdp_client_socket_path_len>-1) unlink(overlay_mdp_client_socket_path); if (mdp_client_socket!=-1) close(mdp_client_socket); mdp_client_socket=-1; return 0; }
// send a request to servald deamon to add a port binding int overlay_mdp_bind(const sid_t *localaddr, int port) { overlay_mdp_frame mdp; mdp.packetTypeAndFlags=MDP_BIND|MDP_FORCE; bcopy(localaddr->binary, mdp.bind.sid, SID_SIZE); mdp.bind.port=port; int result=overlay_mdp_send(&mdp,MDP_AWAITREPLY,5000); if (result) { if (mdp.packetTypeAndFlags==MDP_ERROR) WHYF("Could not bind to MDP port %d: error=%d, message='%s'", port,mdp.error.error,mdp.error.message); else WHYF("Could not bind to MDP port %d (no reason given)",port); return -1; } return 0; }
// Function to check if a SID is reachable via MDP or MSP. int _rpc_sid_is_reachable (sid_t sid) { // Create a MDP socket. int mdp_sockfd; if ((mdp_sockfd = mdp_socket()) < 0) { pfatal("Could not create MDP lookup socket. Aborting."); return -1; } // Init a mdp_frame overlay_mdp_frame mdp; bzero(&mdp,sizeof(mdp)); // Set the packettype to get a routingtable. mdp.packetTypeAndFlags = MDP_ROUTING_TABLE; overlay_mdp_send(mdp_sockfd, &mdp, 0, 0); // Poll until there is nothing left. while (overlay_mdp_client_poll(mdp_sockfd, 200)) { // Create mdp_frame for incoming data. TTL is required but not needed... overlay_mdp_frame recv_frame; int ttl; if (overlay_mdp_recv(mdp_sockfd, &recv_frame, 0, &ttl)) { continue; } // Handle incoming data. int offset=0; while (offset + sizeof(struct overlay_route_record) <= recv_frame.out.payload_length) { // Make new route record struct where all needed information is stored in. struct overlay_route_record *record = &recv_frame.out.route_record; offset += sizeof(struct overlay_route_record); // If the record (aka SID) is reachable, and the record is the desired SID, return 1 and clean up. if ((record->reachable == REACHABLE_INDIRECT || record->reachable == REACHABLE_UNICAST || record->reachable == REACHABLE_BROADCAST || record->reachable == REACHABLE_SELF) && !cmp_sid_t(&record->sid, &sid)) { mdp_close(mdp_sockfd); return 1; } } } mdp_close(mdp_sockfd); return 0; }
int overlay_mdp_getmyaddr(unsigned index, sid_t *sid) { overlay_mdp_frame a; memset(&a, 0, sizeof(a)); a.packetTypeAndFlags=MDP_GETADDRS; a.addrlist.mode = MDP_ADDRLIST_MODE_SELF; a.addrlist.first_sid=index; a.addrlist.last_sid=OVERLAY_MDP_ADDRLIST_MAX_SID_COUNT; a.addrlist.frame_sid_count=MDP_MAX_SID_REQUEST; int result=overlay_mdp_send(&a,MDP_AWAITREPLY,5000); if (result) { if (a.packetTypeAndFlags == MDP_ERROR) DEBUGF("MDP Server error #%d: '%s'", a.error.error, a.error.message); return WHY("Failed to get local address list"); } if ((a.packetTypeAndFlags&MDP_TYPE_MASK)!=MDP_ADDRLIST) return WHY("MDP Server returned something other than an address list"); if (0) DEBUGF("local addr 0 = %s",alloca_tohex_sid(a.addrlist.sids[0])); bcopy(&a.addrlist.sids[0][0], sid->binary, sizeof sid->binary); return 0; }
int keyring_send_sas_request_client(const char *sid_str, const size_t sid_len, char *sas_buf, const size_t sas_buf_len){ int sent, found = 0, ret = 0, mdp_sockfd = -1; int siglen=SID_SIZE+crypto_sign_edwards25519sha512batch_BYTES; sid_t srcsid; unsigned char dstsid[SID_SIZE] = {0}; unsigned char signature[siglen]; time_ms_t now = gettime_ms(); CHECK_MEM(sas_buf); CHECK(sas_buf_len >= 2 * SAS_SIZE + 1, "Insufficient SAS buffer"); CHECK(sid_len == 2 * SID_SIZE && __fromhexstr(dstsid, sid_str, SID_SIZE) == 0, "Invalid SID"); CHECK((mdp_sockfd = overlay_mdp_client_socket()) >= 0,"Cannot create MDP socket"); CHECK(overlay_mdp_getmyaddr(mdp_sockfd, 0, &srcsid) == 0, "Could not get local address"); int client_port = 32768 + (random() & 32767); CHECK(overlay_mdp_bind(mdp_sockfd, &srcsid, client_port) == 0, "Failed to bind to client socket"); /* request mapping (send request auth-crypted). */ overlay_mdp_frame mdp; memset(&mdp,0,sizeof(mdp)); mdp.packetTypeAndFlags=MDP_TX; mdp.out.queue=OQ_MESH_MANAGEMENT; memmove(mdp.out.dst.sid.binary,dstsid,SID_SIZE); mdp.out.dst.port=MDP_PORT_KEYMAPREQUEST; mdp.out.src.port=client_port; memmove(mdp.out.src.sid.binary,srcsid.binary,SID_SIZE); mdp.out.payload_length=1; mdp.out.payload[0]=KEYTYPE_CRYPTOSIGN; sent = overlay_mdp_send(mdp_sockfd, &mdp, 0,0); if (sent) { DEBUG("Failed to send SAS resolution request: %d", sent); CHECK(mdp.packetTypeAndFlags != MDP_ERROR,"MDP Server error #%d: '%s'",mdp.error.error,mdp.error.message); } time_ms_t timeout = now + 5000; while(now<timeout) { time_ms_t timeout_ms = timeout - gettime_ms(); int result = overlay_mdp_client_poll(mdp_sockfd, timeout_ms); if (result>0) { int ttl=-1; if (overlay_mdp_recv(mdp_sockfd, &mdp, client_port, &ttl)==0) { switch(mdp.packetTypeAndFlags&MDP_TYPE_MASK) { case MDP_ERROR: ERROR("overlay_mdp_recv: %s (code %d)", mdp.error.message, mdp.error.error); break; case MDP_TX: { DEBUG("Received SAS mapping response"); found = 1; break; } break; default: DEBUG("overlay_mdp_recv: Unexpected MDP frame type 0x%x", mdp.packetTypeAndFlags); break; } if (found) break; } } now=gettime_ms(); } unsigned keytype = mdp.out.payload[0]; CHECK(keytype == KEYTYPE_CRYPTOSIGN,"Ignoring SID:SAS mapping with unsupported key type %u", keytype); CHECK(mdp.out.payload_length >= 1 + SAS_SIZE,"Truncated key mapping announcement? payload_length: %d", mdp.out.payload_length); unsigned char *sas_public=&mdp.out.payload[1]; unsigned char *compactsignature = &mdp.out.payload[1+SAS_SIZE]; /* reconstitute signed SID for verification */ memmove(&signature[0],&compactsignature[0],64); memmove(&signature[64],&mdp.out.src.sid.binary[0],SID_SIZE); CHECK(__tohex(sas_buf,sas_public,SAS_SIZE),"Failed to convert signing key"); sas_buf[2*SAS_SIZE] = '\0'; ret = 1; error: if (mdp_sockfd != -1) overlay_mdp_client_close(mdp_sockfd); return ret; }
static int keyring_send_sas_request_client(struct subscriber *subscriber){ int sent, client_port, found = 0, ret = 0; int siglen=SID_SIZE+crypto_sign_edwards25519sha512batch_BYTES; unsigned char *srcsid[SID_SIZE] = {0}, *plain = NULL; unsigned char signature[siglen]; time_ms_t now = gettime_ms(); CHECK_ERR(overlay_mdp_getmyaddr(0,(sid_t *)srcsid) == 0,"Could not get local address"); if (subscriber->sas_valid) return 1; CHECK_ERR(now >= subscriber->sas_last_request + 100,"Too soon to ask for SAS mapping again"); CHECK_ERR(my_subscriber,"couldn't request SAS (I don't know who I am)"); DEBUG("Requesting SAS mapping for SID=%s", alloca_tohex_sid(subscriber->sid)); CHECK_ERR(overlay_mdp_bind((sid_t *)my_subscriber->sid,(client_port=32768+(random()&32767))) == 0,"Failed to bind to client socket"); /* request mapping (send request auth-crypted). */ overlay_mdp_frame mdp; memset(&mdp,0,sizeof(mdp)); mdp.packetTypeAndFlags=MDP_TX; mdp.out.queue=OQ_MESH_MANAGEMENT; memmove(mdp.out.dst.sid,subscriber->sid,SID_SIZE); mdp.out.dst.port=MDP_PORT_KEYMAPREQUEST; mdp.out.src.port=client_port; memmove(mdp.out.src.sid,srcsid,SID_SIZE); mdp.out.payload_length=1; mdp.out.payload[0]=KEYTYPE_CRYPTOSIGN; sent = overlay_mdp_send(&mdp, 0,0); if (sent) { DEBUG("Failed to send SAS resolution request: %d", sent); CHECK_ERR(mdp.packetTypeAndFlags != MDP_ERROR,"MDP Server error #%d: '%s'",mdp.error.error,mdp.error.message); } time_ms_t timeout = now + 5000; while(now<timeout) { time_ms_t timeout_ms = timeout - gettime_ms(); int result = overlay_mdp_client_poll(timeout_ms); if (result>0) { int ttl=-1; if (overlay_mdp_recv(&mdp, client_port, &ttl)==0) { switch(mdp.packetTypeAndFlags&MDP_TYPE_MASK) { case MDP_ERROR: ERROR("overlay_mdp_recv: %s (code %d)", mdp.error.message, mdp.error.error); break; case MDP_TX: { DEBUG("Received SAS mapping response"); found = 1; break; } break; default: DEBUG("overlay_mdp_recv: Unexpected MDP frame type 0x%x", mdp.packetTypeAndFlags); break; } if (found) break; } } now=gettime_ms(); if (servalShutdown) break; } unsigned keytype = mdp.out.payload[0]; CHECK_ERR(keytype == KEYTYPE_CRYPTOSIGN,"Ignoring SID:SAS mapping with unsupported key type %u", keytype); CHECK_ERR(mdp.out.payload_length >= 1 + SAS_SIZE,"Truncated key mapping announcement? payload_length: %d", mdp.out.payload_length); plain = (unsigned char*)calloc(mdp.out.payload_length,sizeof(unsigned char)); unsigned long long plain_len=0; unsigned char *sas_public=&mdp.out.payload[1]; unsigned char *compactsignature = &mdp.out.payload[1+SAS_SIZE]; /* reconstitute signed SID for verification */ memmove(&signature[0],&compactsignature[0],64); memmove(&signature[64],&mdp.out.src.sid[0],SID_SIZE); int r=crypto_sign_edwards25519sha512batch_open(plain,&plain_len, signature,siglen, sas_public); CHECK_ERR(r == 0,"SID:SAS mapping verification signature does not verify"); /* These next two tests should never be able to fail, but let's just check anyway. */ CHECK_ERR(plain_len == SID_SIZE,"SID:SAS mapping signed block is wrong length"); CHECK_ERR(memcmp(plain, mdp.out.src.sid, SID_SIZE) == 0,"SID:SAS mapping signed block is for wrong SID"); memmove(subscriber->sas_public, sas_public, SAS_SIZE); subscriber->sas_valid=1; subscriber->sas_last_request=now; ret = 1; error: if (plain) free(plain); return ret; }