mirror of
https://github.com/servalproject/serval-dna.git
synced 2024-12-29 17:38:59 +00:00
160 lines
5.1 KiB
C
160 lines
5.1 KiB
C
/*
|
|
Serval DNA directory service client
|
|
Copyright (C) 2013 Serval Project Inc.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; either version 2
|
|
of the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
|
|
/*
|
|
|
|
Serval Directory Service client
|
|
|
|
When servald starts, load the SID, IP (or domain name) & port of a directory server.
|
|
When an interface comes up with a route to this server, and periodically thereafter,
|
|
send our SID name and number to the configured server.
|
|
|
|
When we perform a lookup, send an additional copy of the request to the directory server.
|
|
|
|
*/
|
|
|
|
#include "serval_types.h"
|
|
#include "cli.h"
|
|
#include "str.h"
|
|
#include "overlay_address.h"
|
|
#include "overlay_packet.h"
|
|
#include "overlay_buffer.h"
|
|
#include "conf.h"
|
|
#include "overlay_interface.h"
|
|
#include "keyring.h"
|
|
#include "serval.h" // for overlay_send_frame()
|
|
#include "route_link.h"
|
|
#include "server.h"
|
|
#include "feature.h"
|
|
|
|
DEFINE_FEATURE(directory_client);
|
|
|
|
__thread struct subscriber *directory_service;
|
|
|
|
static void directory_update(struct sched_ent *alarm);
|
|
|
|
static struct profile_total directory_timing={
|
|
.name="directory_update",
|
|
};
|
|
|
|
struct sched_ent directory_alarm={
|
|
.function=directory_update,
|
|
.stats=&directory_timing,
|
|
};
|
|
#define DIRECTORY_UPDATE_INTERVAL 120000
|
|
|
|
// send a registration packet
|
|
static void directory_send(struct subscriber *directory_service, struct subscriber *source, const char *did, const char *name)
|
|
{
|
|
// Used by tests
|
|
INFOF("Sending directory registration for %s*, %s, %s to %s*",
|
|
alloca_tohex_sid_t_trunc(source->sid, 14), did, name, alloca_tohex_sid_t_trunc(directory_service->sid, 14));
|
|
|
|
struct internal_mdp_header header;
|
|
bzero(&header, sizeof header);
|
|
|
|
header.source = source;
|
|
header.source_port = MDP_PORT_NOREPLY;
|
|
header.destination = directory_service;
|
|
header.destination_port = MDP_PORT_DIRECTORY;
|
|
header.qos = OQ_ORDINARY;
|
|
char buff[256];
|
|
struct overlay_buffer *payload = ob_static((unsigned char*)buff, sizeof buff);
|
|
ob_limitsize(payload, snprintf(buff, sizeof buff, "%s|%s", did, name));
|
|
overlay_send_frame(&header, payload);
|
|
ob_free(payload);
|
|
}
|
|
|
|
// send a registration packet for each unlocked identity
|
|
static void directory_send_keyring(struct subscriber *directory_service){
|
|
assert(keyring != NULL);
|
|
keyring_iterator it;
|
|
keyring_iterator_start(keyring, &it);
|
|
while(keyring_next_keytype(&it, KEYTYPE_DID)){
|
|
if (it.identity->subscriber && it.identity->subscriber->reachable == REACHABLE_SELF){
|
|
const char *unpackedDid = (const char *) it.keypair->private_key;
|
|
const char *name = (const char *) it.keypair->public_key;
|
|
directory_send(directory_service, it.identity->subscriber, unpackedDid, name);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void directory_update(struct sched_ent *alarm){
|
|
if (directory_service){
|
|
if (directory_service->reachable & REACHABLE){
|
|
directory_send_keyring(directory_service);
|
|
|
|
unschedule(alarm);
|
|
alarm->alarm = gettime_ms() + DIRECTORY_UPDATE_INTERVAL;
|
|
alarm->deadline = alarm->alarm + 10000;
|
|
schedule(alarm);
|
|
}else{
|
|
// always attempt to reload the address, may depend on DNS resolution
|
|
struct network_destination *destination = load_subscriber_address(directory_service);
|
|
if (destination){
|
|
overlay_send_probe(directory_service, destination, OQ_MESH_MANAGEMENT);
|
|
release_destination_ref(destination);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void directory_service_init(){
|
|
if (is_sid_t_any(config.directory.service)) {
|
|
directory_service = NULL;
|
|
}else{
|
|
directory_service = find_subscriber(config.directory.service.binary, SID_SIZE, 1);
|
|
if (!directory_service){
|
|
WHYF("Failed to create subscriber record");
|
|
}else{
|
|
// used by tests
|
|
INFOF("ADD DIRECTORY SERVICE %s", alloca_tohex_sid_t(directory_service->sid));
|
|
}
|
|
}
|
|
unschedule(&directory_alarm);
|
|
directory_update(&directory_alarm);
|
|
}
|
|
DEFINE_TRIGGER(conf_change, directory_service_init);
|
|
|
|
// called when we discover a route to the directory service SID
|
|
int directory_registration(){
|
|
// give the route & SAS keys a moment to propagate
|
|
unschedule(&directory_alarm);
|
|
directory_alarm.alarm = gettime_ms() + 200;
|
|
directory_alarm.deadline = directory_alarm.alarm + 10000;
|
|
schedule(&directory_alarm);
|
|
return 0;
|
|
}
|
|
|
|
static void interface_change(struct overlay_interface *UNUSED(interface), unsigned count){
|
|
unschedule(&directory_alarm);
|
|
if (count)
|
|
directory_update(&directory_alarm);
|
|
}
|
|
|
|
DEFINE_TRIGGER(iupdown, interface_change);
|
|
|
|
static void directory_link_changed(struct subscriber *subscriber, int UNUSED(prior_reachable)){
|
|
if (subscriber==directory_service)
|
|
directory_registration();
|
|
}
|
|
|
|
DEFINE_TRIGGER(link_change, directory_link_changed);
|