diff --git a/.gitignore b/.gitignore index 7e4f2718..e63a7fde 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ nacl/naclinc.txt nacl/nacllib.txt serval.c servald +directory_service *.so test.*.log testlog diff --git a/Android.mk b/Android.mk index f829caef..4eb91ee9 100644 --- a/Android.mk +++ b/Android.mk @@ -16,6 +16,7 @@ SERVALD_SRC_FILES = \ serval-dna/commandline.c \ serval-dna/conf.c \ serval-dna/dataformats.c \ + serval-dna/directory_client.c \ serval-dna/xprintf.c \ serval-dna/log.c \ serval-dna/net.c \ diff --git a/Makefile.in b/Makefile.in old mode 100644 new mode 100755 index 23d0e45b..835a831c --- a/Makefile.in +++ b/Makefile.in @@ -10,6 +10,7 @@ SRCS= \ commandline.c \ conf.c \ dataformats.c \ + directory_client.c \ dna_helper.c \ dna_identity.c \ encode.c \ @@ -132,6 +133,10 @@ servald: $(OBJS) @echo LINK $@ @$(CC) $(CFLAGS) -Wall -o $@ $(OBJS) $(LDFLAGS) +directory_service: $(MDPCLIENTOBJS) directory_service.o + @echo LINK $@ + @$(CC) $(CFLAGS) -Wall -o $@ $(MDPCLIENTOBJS) directory_service.o $(LDFLAGS) + # This does not build on 64 bit elf platforms as NaCL isn't built with -fPIC # DOC 20120615 libservald.so: $(OBJS) diff --git a/constants.h b/constants.h index 86c7823d..258fcac5 100644 --- a/constants.h +++ b/constants.h @@ -246,6 +246,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define MDP_PORT_VOMP 0x10000002 #define MDP_PORT_DNALOOKUP 0x10000003 #define MDP_PORT_NOREPLY 0x10000000 +#define MDP_PORT_DIRECTORY 10 #define MDP_TYPE_MASK 0xff #define MDP_FLAG_MASK 0xff00 diff --git a/directory_client.c b/directory_client.c new file mode 100644 index 00000000..651b67a2 --- /dev/null +++ b/directory_client.c @@ -0,0 +1,88 @@ + + +/* + + 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.h" +#include "overlay_address.h" + +#define MDP_DIRECTORY 999 + +struct subscriber *directory_service; + +// send a registration packet +static void directory_send(struct subscriber *directory_service, const unsigned char *sid, const char *did, const char *name){ + overlay_mdp_frame request; + + memset(&request, 0, sizeof(overlay_mdp_frame)); + + bcopy(sid, request.out.src.sid, SID_SIZE); + request.out.src.port=MDP_PORT_NOREPLY; + + bcopy(request.out.dst.sid, directory_service->sid, SID_SIZE); + request.out.dst.port=MDP_DIRECTORY; + request.out.payload_length = snprintf((char *)request.out.payload, sizeof(request.out.payload), + "%s|%s", did, name); + + overlay_mdp_dispatch(&request, 0, NULL, 0); +} + +// send a registration packet for each unlocked identity +static void directory_send_keyring(struct subscriber *directory_service){ + int cn=0, in=0, kp=0, k2; + + for (; !keyring_sanitise_position(keyring, &cn, &in, &kp); ++kp){ + keyring_identity *i = keyring->contexts[cn]->identities[in]; + + if (i->keypairs[kp]->type == KEYTYPE_CRYPTOBOX){ + const unsigned char *packedSid = i->keypairs[0]->public_key; + + for(k2=0; k2 < i->keypair_count; k2++){ + if (i->keypairs[k2]->type==KEYTYPE_DID){ + const char *unpackedDid = (const char *) i->keypairs[kp]->private_key; + const char *name = (const char *) i->keypairs[kp]->public_key; + + directory_send(directory_service, packedSid, unpackedDid, name); + // send the first DID only + break; + } + } + } + } +} + +static int load_directory_config(){ + const char *sid_hex = confValueGet("directory.service", NULL); + if (!sid_hex) + return 0; + + unsigned char sid[SID_SIZE]; + if (stowSid(sid, 0, sid_hex)==-1) + return WHYF("Invalid directory server SID %s", sid_hex); + + directory_service = find_subscriber(sid, SID_SIZE, 1); + if (!directory_service) + return WHYF("Failed to create subscriber record"); + + return load_subscriber_address(directory_service); +} + +int directory_interface_up(overlay_interface *interface){ + // reload config, now that an interface is up + load_directory_config(); + + if (directory_service && subscriber_is_reachable(directory_service) != REACHABLE_NONE){ + directory_send_keyring(directory_service); + } + return 0; +} + diff --git a/directory_service.c b/directory_service.c new file mode 100644 index 00000000..cb0cb134 --- /dev/null +++ b/directory_service.c @@ -0,0 +1,124 @@ + +#include "constants.h" +#include "mdp_client.h" +#include +#include +#include + +char last_add[256]="dummy"; + +void store(char *key, char *value){ + fprintf(stderr,"Adding; \"%s\" = \"%s\"\n", key, value); + strncpy(value, last_add, sizeof(last_add)); + last_add[255]=0; +} + +const char *retrieve(char *key){ + fprintf(stderr, "Looking for; \"%s\"\n", key); + + // dummy code, just reply with the last record we've heard + return last_add; +} + + +void add_record(){ + int ttl; + overlay_mdp_frame mdp; + + if (!overlay_mdp_recv(&mdp, &ttl)) + return; + + // make sure the payload is a NULL terminated string + mdp.in.payload[mdp.in.payload_length]=0; + + char *did=(char *)mdp.in.payload; + int i=0; + while(i0){ + if (fds[0].revents & POLLIN) + resolve_request(); + if (fds[1].revents & POLLIN) + add_record(); + + if (fds[0].revents & (POLLHUP | POLLERR)) + break; + } + fprintf(stderr,"."); + } + + fprintf(stderr, "Bye\n"); + overlay_mdp_client_done(); + return 0; +} \ No newline at end of file diff --git a/overlay_address.c b/overlay_address.c index 723a9fe8..e920ad61 100644 --- a/overlay_address.c +++ b/overlay_address.c @@ -215,6 +215,38 @@ int reachable_unicast(struct subscriber *subscriber, overlay_interface *interfac return 0; } +// load a unicast address from configuration, replace with database?? +int load_subscriber_address(struct subscriber *subscriber){ + char buff[80]; + const char *sid_hex = alloca_tohex_sid(subscriber->sid); + + snprintf(buff, sizeof(buff), "%s.interface", sid_hex); + const char *interface_name = confValueGet(buff, NULL); + if (!interface_name) + return 1; + + snprintf(buff, sizeof(buff), "%s.address", sid_hex); + const char *address = confValueGet(buff, NULL); + if (!address) + return 1; + + snprintf(buff, sizeof(buff), "%s.port", sid_hex); + int port = confValueGetInt64Range(buff, PORT_DNA, 1, 65535); + + overlay_interface *interface = overlay_interface_find_name(interface_name); + if (!interface){ + WARNF("Interface %s is not UP", interface_name); + return -1; + } + + struct in_addr addr; + if (!inet_aton(address, &addr)){ + return WHYF("%s doesn't look like an IP address", address); + } + + return reachable_unicast(subscriber, interface, addr, port); +} + // generate a new random broadcast address int overlay_broadcast_generate_address(struct broadcast *addr) { diff --git a/overlay_address.h b/overlay_address.h index c0092e6d..213c3881 100644 --- a/overlay_address.h +++ b/overlay_address.h @@ -103,6 +103,7 @@ struct subscriber *find_subscriber(const unsigned char *sid, int len, int create void enum_subscribers(struct subscriber *start, int(*callback)(struct subscriber *, void *), void *context); int subscriber_is_reachable(struct subscriber *subscriber); int reachable_unicast(struct subscriber *subscriber, overlay_interface *interface, struct in_addr addr, int port); +int load_subscriber_address(struct subscriber *subscriber); int overlay_broadcast_drop_check(struct broadcast *addr); int overlay_broadcast_generate_address(struct broadcast *addr); diff --git a/overlay_interface.c b/overlay_interface.c index 1f28cd38..3a546520 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -266,6 +266,18 @@ overlay_interface * overlay_interface_find(struct in_addr addr){ return NULL; } +overlay_interface * overlay_interface_find_name(const char *name){ + int i; + for (i=0;isend_full = 1; + + // try to register ourselves with a directory service + directory_interface_up(interface); + return 0; } diff --git a/serval.h b/serval.h index 5d703923..02533b87 100644 --- a/serval.h +++ b/serval.h @@ -863,6 +863,9 @@ int overlay_interface_register(char *name, struct in_addr addr, struct in_addr mask); overlay_interface * overlay_interface_find(struct in_addr addr); +overlay_interface * overlay_interface_find_name(const char *name); + +int directory_interface_up(overlay_interface *interface); #ifdef HAVE_VOIPTEST int app_pa_phone(int argc, const char *const *argv, struct command_line_option *o);