Replaced use of HLR with keyring for phone number lookups and

other functions.  Not yet tested.
This commit is contained in:
gardners 2012-04-13 09:25:03 +09:30
parent 7b8d78533d
commit 5ac83f9ca1
13 changed files with 445 additions and 614 deletions

View File

@ -32,20 +32,6 @@ int packetSetMySid(char *sid)
int packetGetPrivateKeyForSid()
{
/* Add all local SIDs to our cache */
int ofs=0;
while(findHlr(hlr,&ofs,NULL,NULL)) {
// XXX If the SIDs match, then this is it */
if (!current_sid_set) {
/* we are using the first sid in the HLR */
} else {
/* Compare current SID with SID of this HLR record */
/* XXX get PIN field which contains the private key or ciphered private key.
Use code from ACTION_GET case in server.c as a guide */
}
if (nextHlr(hlr,&ofs)) break;
}
return setReason("Not implemented");
}

View File

@ -19,6 +19,17 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
/* Now that we are using the keyring, we only support a small subset of variables.
(VAR_NAME is not properly supported yet)
*/
struct mphlr_variable vars[]={
{VAR_NAME, "name", "Published name of this subscriber"},
{VAR_DIDS,"dids","Numbers claimed by this subscriber"},
{VAR_LOCATIONS,"locations","Network address of telephone end point"},
{0x00,NULL,NULL}
};
int packetSendFollowup(struct in_addr destination,
unsigned char *packet,int packet_len)
{

View File

@ -245,19 +245,9 @@ int app_server_start(int argc,char **argv,struct command_line_option *o)
*/
rhizome_datastore_path = serval_instancepath();
rhizome_opendb();
char *hlr_file;
if (asprintf(&hlr_file, "%s/%s", serval_instancepath(), "hlr.dat") == -1) {
fprintf(stderr,"ERROR: asprintf() failed\n");
return -1;
}
hlr_size=atof(confValueGet("hlr_size","1"))*1048576;
if (hlr_size<0) {
fprintf(stderr,"HLR Size must be >0MB\n");
return -1;
}
overlayMode=1;
return server(hlr_file,hlr_size,foregroundP);
return server(NULL,foregroundP);
}
int app_server_stop(int argc,char **argv,struct command_line_option *o)

109
dna.c
View File

@ -40,45 +40,6 @@ int returnMultiVars=0;
int hexdigit[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
struct mphlr_variable vars[]={
/* Variables that can have only a single value */
{VAR_EOR,"eor","Marks end of record"},
{VAR_CREATETIME,"createtime","Time HLR record was created"},
{VAR_CREATOR,"creator","Device that created this HLR record"},
{VAR_REVISION,"revision","Revision number of this HLR record"},
{VAR_REVISOR,"revisor","Device that revised this HLR record"},
{VAR_PIN,"pin","Secret PIN for this HLR record"},
/* GSM encoded audio, so a 16KB MPHLR maximum size shouldn't
pose a problem. 8KB = ~4.5 seconds, which is a long time
to say your name in, leaving 8KB for other variables. */
{VAR_VOICESIG,"voicesig","Voice signature of this subscriber"},
{VAR_HLRMASTER,"hlrmaster","Location where the master copy of this HLR record is maintained."},
{VAR_NAME, "name", "Published name of this subscriber"},
/* Variables that can take multiple values */
{VAR_DIDS,"dids","Numbers claimed by this subscriber"},
{VAR_LOCATIONS,"locations","Locations where this subscriber wishes to receive calls"},
{VAR_IEMIS,"iemis","GSM IEMIs claimed by this subscriber"},
{VAR_TEMIS,"temis","GSM TEMIs claimed by this subscriber"},
/* Each entry here has a flag byte (unread, ...) */
{VAR_CALLS_IN,"callsin","Calls received by this subscriber"},
{VAR_CALLS_MISSED,"callsmissed","Calls missed by this subscriber"},
{VAR_CALLS_OUT,"callsout","Calls made by this subscriber"},
{VAR_SMESSAGES,"smessages","SMS received by this subscriber"},
{VAR_DID2SUBSCRIBER,"did2subscriber","Preferred subscribers for commonly called DIDs"},
{VAR_HLRBACKUPS,"hlrbackups","Locations where backups of this HLR record are maintained."},
{VAR_NOTE,"note","Free-form notes on this HLR record"},
{0x00,NULL,NULL}
};
int sock=-1;
#ifndef HAVE_BZERO
@ -160,7 +121,7 @@ int parseAssignment(unsigned char *text,int *var_id,unsigned char *value,int *va
Values are length limited to 65535 bytes.
*/
int i,v;
int i;
int max_len=*value_len;
int vlen=0;
int tlen=strlen((char *)text);
@ -170,11 +131,13 @@ int parseAssignment(unsigned char *text,int *var_id,unsigned char *value,int *va
}
/* Identify which variable */
*var_id=-1;
for(i=0;i<tlen;i++) if (text[i]=='=') break;
for(v=0;vars[v].name;v++) if (!strncasecmp(vars[v].name,(char *)text,i)) break;
/* Go through known keyring variables */
if (!strcasecmp((char *)text,"did")) *var_id=KEYTYPE_DID;
if (!vars[v].name) return setReason("Illegal variable name in assignment");
*var_id=vars[v].id;
if (*var_id==-1) return setReason("Illegal variable name in assignment");
i++;
switch(text[i])
@ -222,9 +185,7 @@ int usage(char *complaint)
{
fprintf(stderr,"dna: %s\n",complaint);
fprintf(stderr,"usage:\n");
fprintf(stderr," dna [-v <flags>] -S <hlr size in MB> [-f HLR backing file] [-I import.txt] [-N interface,...] [-G gateway specification] [-r rhizome path]\n");
fprintf(stderr,"or\n");
fprintf(stderr," dna [-v <flags>] -f <HLR backing file> -E <hlr export file>\n");
fprintf(stderr," dna [-v <flags>] -S [-f keyring file] [-N interface,...] [-G gateway specification] [-r rhizome path]\n");
fprintf(stderr,"or\n");
fprintf(stderr," dna -r <rhizome path> -M <manifest name>\n");
fprintf(stderr,"or\n");
@ -238,12 +199,10 @@ int usage(char *complaint)
fprintf(stderr,"or\n");
fprintf(stderr," dna [-v <flags>] [-t timeout] -d did -C\n");
fprintf(stderr,"or\n");
fprintf(stderr," dna [-v <flags>] -f <hlr.dat> -E <export.txt>\n");
fprintf(stderr," dna [-v <flags>] -f <keyring file> -E <export.txt>\n");
fprintf(stderr,"\n");
fprintf(stderr," -v - Set verbosity.\n");
fprintf(stderr," -E - Export specified HLR database into specified flat text file.\n");
fprintf(stderr," -I - Import a previously exported HLR database into this one.\n");
fprintf(stderr," -A - Ask for address of subscriber.\n");
fprintf(stderr," -b - Specify BATMAN socket to obtain peer list (flaky).\n");
fprintf(stderr," -l - Specify BATMAN socket to obtain peer list (better, but requires Serval patched BATMAN).\n");
@ -251,8 +210,8 @@ int usage(char *complaint)
fprintf(stderr," -m - Return multiple variable values instead of only first response.\n");
fprintf(stderr," -M - Create and import a new bundle from the specified manifest.\n");
fprintf(stderr," -n - Do not detach from foreground in server mode.\n");
fprintf(stderr," -S - Run in server mode with an HLR of the specified size.\n");
fprintf(stderr," -f - Use the specified file as a permanent store for HLR data.\n");
fprintf(stderr," -S - Run in server mode.\n");
fprintf(stderr," -f - Location of keyring file.\n");
fprintf(stderr," -d - Search by Direct Inward Dial (DID) number.\n");
fprintf(stderr," -s - Search by Subscriber ID (SID) number.\n");
fprintf(stderr," -p - Specify additional DNA nodes to query.\n");
@ -550,7 +509,7 @@ int main(int argc,char **argv)
char *pin=NULL;
char *did=NULL;
char *sid=NULL;
char *hlr_file=NULL;
char *keyring_file=NULL;
int instance=-1;
int foregroundMode=0;
@ -599,20 +558,22 @@ int main(int argc,char **argv)
" Type '%s help' to learn about the new command line structure.\n",
argv[0]);
while((c=getopt(argc,argv,"Ab:B:E:G:I:S:f:d:i:l:L:mnp:P:r:s:t:v:R:W:U:D:CO:M:N:")) != -1 )
while((c=getopt(argc,argv,"Ab:B:E:G:I:Sf:d:i:l:L:mnp:P:r:s:t:v:R:W:U:D:CO:M:N:")) != -1 )
{
switch(c)
{
case 'S': serverMode=1; break;
case 'r': /* Enable rhizome */
if (rhizome_datastore_path) return WHY("-r specified more than once");
rhizome_datastore_path=optarg;
rhizome_opendb();
/* Also set hlr file to be in the Rhizome directory, to save the need to specify it
/* Also set keyring file to be in the Rhizome directory, to save the need to specify it
separately. */
char temp[1024];
if (snprintf(temp, sizeof(temp), "%s/hlr.dat", optarg) >= sizeof(temp))
if (snprintf(temp, sizeof(temp), "%s/serval.keyring", optarg)
>= sizeof(temp))
exit(WHY("Rhizome directory name too long."));
hlr_file = strdup(temp);
keyring_file = strdup(temp);
break;
case 'M': /* Distribute specified manifest and file pair using Rhizome. */
/* This option assumes that the manifest is locally produced, and will
@ -638,19 +599,6 @@ int main(int argc,char **argv)
gatewayspec=strdup(optarg);
if(prepareGateway(gatewayspec)) return usage("Invalid gateway specification");
break;
case 'E': /* Export HLR into plain text file that can be imported later */
if (!hlr_file) usage("You must specify an HLR file to export from, i.e., dna -f hlr.dat -E hlr.txt");
return exportHlr((unsigned char*)hlr_file,optarg);
break;
case 'I': /* Import HLR data from a plain text file into current HLR */
if (importFile) usage("-I multiply specified.");
importFile=optarg;
if (!hlr_file||!serverMode) usage("-I requires -S and -f.");
if (openHlrFile(hlr_file,hlr_size))
exit(setReason("Failed to open HLR database"));
importHlr(importFile);
return 0;
break;
case 'n': /* don't detach from foreground in server mode */
foregroundMode=1; break;
case 'b': /* talk peers on a BATMAN mesh */
@ -666,18 +614,13 @@ int main(int argc,char **argv)
simulatedBER=atof(optarg);
fprintf(stderr,"WARNING: Bit error injection enabled -- this will cause packet loss and is intended only for testing.\n");
break;
case 'S':
if (atof(optarg)<0.1||atof(optarg)>16384) usage("HLR must be 0.1MB - 16384MB in size.");
hlr_size=(int)(atof(optarg)*1048576.0);
serverMode=1;
break;
case 'i':
instance=atoi(optarg);
if (instance<-1||instance>255) usage("Illegal variable instance ID.");
break;
case 'f':
if (clientMode) usage("Only servers use backing files");
hlr_file=strdup(optarg);
if (clientMode) usage("Only servers use keyring files");
keyring_file=strdup(optarg);
break;
case 'p': /* additional peers to query */
if (additionalPeer(optarg)) exit(-3);
@ -730,12 +673,8 @@ int main(int argc,char **argv)
return writeItem(did?did:sid,var_id,instance,value,0,value_len,SET_REPLACE,-1,NULL);
}
break;
case 'C': /* create a new HLR entry */
{
if (optind<argc) usage("Extraneous options after HLR creation request");
if ((!did)||(sid)) usage("Specify exactly one DID and no SID to create a new HLR entry");
return requestNewHLR(did,pin,sid,-1,NULL);
}
case 'C': /* create a new keyring entry */
return WHY("Entries in new keyring format must be used with new command line framework.");
break;
case 'O': /* output to templated files */
if (outputtemplate) usage("You can only specify -O once");
@ -749,10 +688,10 @@ int main(int argc,char **argv)
if (optind<argc) usage("Extraneous options at end of command");
if (hlr_file&&clientMode) usage("Only servers use backing files");
if (keyring_file&&clientMode) usage("Only servers use backing files");
if (serverMode&&clientMode) usage("You asked me to be both server and client. That's silly.");
if (serverMode) return server(hlr_file,hlr_size,foregroundMode);
if (!clientMode) usage("Mesh Potato Home Location Register (HLR) Tool.");
if (serverMode) return server(keyring_file,foregroundMode);
if (!clientMode) usage("Serval server and client utility.");
#if defined WIN32
WSACleanup();

View File

@ -756,19 +756,20 @@ int keyring_enter_pin(keyring_file *k,char *pin)
The crypto_box and crypto_sign key pairs are automatically created, and the PKR
is packed and written to a hithero unallocated slot which is then marked full.
*/
int keyring_create_identity(keyring_file *k,keyring_context *c,char *pin)
keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c,char *pin)
{
/* Check obvious abort conditions early */
if (!k) return WHY("keyring is NULL");
if (!k->bam) return WHY("keyring lacks BAM (not to be confused with KAPOW)");
if (!c) return WHY("keyring context is NULL");
if (c->identity_count>=KEYRING_MAX_IDENTITIES) return WHY("keyring context has too many identities");
if (!k) { WHY("keyring is NULL"); return NULL; }
if (!k->bam) { WHY("keyring lacks BAM (not to be confused with KAPOW)"); return NULL; }
if (!c) { WHY("keyring context is NULL"); return NULL; }
if (c->identity_count>=KEYRING_MAX_IDENTITIES)
{ WHY("keyring context has too many identities"); return NULL; }
int exit_code=1;
if (!pin) pin="";
keyring_identity *id=calloc(sizeof(keyring_identity),1);
if (!id) { WHY("calloc() failed"); return NULL; }
/* Store pin */
id->PKRPin=strdup(pin);
if (!id->PKRPin) {
@ -885,11 +886,11 @@ int keyring_create_identity(keyring_file *k,keyring_context *c,char *pin)
else
#endif
/* Everything went fine */
return 0;
return id;
kci_safeexit:
if (id) keyring_free_identity(id);
return exit_code;
return NULL;
}
int keyring_commit(keyring_file *k)
@ -1026,6 +1027,25 @@ int keyring_find_did(keyring_file *k,int *cn,int *in,int *kp,char *did)
return 0;
}
int keyring_next_identity(keyring_file *k,int *cn,int *in,int *kp)
{
if (!k) return 0;
while ((*cn)<k->context_count) {
while (((*cn)<k->context_count)&&((*in)>=k->contexts[*cn]->identity_count)) {
(*cn)++; (*in)=0;
}
if ((*cn)>=k->context_count) return 0;
for((*kp)=0;*kp<k->contexts[*cn]->identities[*in]->keypair_count;(*kp)++)
if (k->contexts[*cn]->identities[*in]->keypairs[*kp]->type==KEYTYPE_CRYPTOBOX)
return 1;
(*in)++;
}
return 0;
}
int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid)
{
if (!k) return 0;
@ -1095,3 +1115,28 @@ keyring_file *keyring_open_with_pins(char *pinlist)
return k;
}
/* If no identities, create an initial identity with a phone number.
This identity will not be pin protected (initially). */
int keyring_seed(keyring_file *k)
{
if (!k) return WHY("keyring is null");
/* nothing to do if there is already an identity */
if (k->contexts[0]->identity_count) return 0;
int i;
char did[65];
/* Securely generate random telephone number */
urandombytes((unsigned char *)did,10);
/* Make DID start with 2 through 9, as 1 is special in many number spaces. */
did[0]='2'+did[0]%8;
/* Then add 10 more digits, which is what we do in the mobile phone software */
for(i=1;i<11;i++) did[i]='0'+did[i]%10; did[11]=0;
keyring_identity *id=keyring_create_identity(k,k->contexts[0],"");
if (!id) return WHY("Could not create new identity");
if (keyring_set_did(id,did)) return WHY("Could not set DID of new identity");
if (keyring_commit(k)) return WHY("Could not commit new identity to keyring file");
return 0;
}

View File

@ -74,12 +74,24 @@ int overlayMode=0;
overlay_txqueue overlay_tx[OQ_MAX];
keyring_file *keyring=NULL;
int overlayServerMode()
{
/* In overlay mode we need to listen to all of our sockets, and also to
send periodic traffic. This means we need to */
fprintf(stderr,"Running in overlay mode.\n");
/* Get keyring available for use.
Required for MDP, and very soon as a complete replacement for the
HLR for DNA lookups, even in non-overlay mode. */
keyring=keyring_open_with_pins("");
if (!keyring) {
return WHY("Could not open serval keyring file.");
}
/* put initial identity in if we don't have any visible */
keyring_seed(keyring);
/* Set default congestion levels for queues */
int i;
for(i=0;i<OQ_MAX;i++) {
@ -103,20 +115,6 @@ int overlayServerMode()
/* Create structures to use 1MB of RAM for testing */
overlay_route_init(1);
/* Add all local SIDs to our cache */
int ofs=0;
while(findHlr(hlr,&ofs,NULL,NULL)) {
int i;
if (debug&DEBUG_OVERLAYINTERFACES) {
fprintf(stderr,"Adding ");
for(i=0;i<SID_SIZE;i++) fprintf(stderr,"%02x",hlr[ofs+4+i]);
fprintf(stderr," to list of local addresses.\n");
}
overlay_add_local_identity(&hlr[ofs+4]);
overlay_abbreviate_cache_address(&hlr[ofs+4]);
if (nextHlr(hlr,&ofs)) break;
}
/* Get rhizome server started BEFORE populating fd list so that
the server's listen socket is in the list for poll() */
if (rhizome_datastore_path) rhizome_server_poll();

View File

@ -462,25 +462,25 @@ int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *of
if (memcmp(in,&cache->sids[index].b[0],prefix_bytes))
{
/* No, it isn't in the cache, but it might be a local address. */
int i,j;
for(i=0;i<overlay_local_identity_count;i++)
{
for(j=0;j<prefix_bytes;j++)
if (overlay_local_identities[i][j]!=in[j]) break;
if (j>=prefix_bytes) {
if (debug&DEBUG_OVERLAYABBREVIATIONS)
WHY("Found reference to local address.");
bcopy(&overlay_local_identities[i][0],&out[(*ofs)],SID_SIZE);
(*ofs)+=SID_SIZE;
return OA_RESOLVED;
}
else {
if (debug&DEBUG_OVERLAYABBREVIATIONS)
fprintf(stderr,"not identity #%d (%02x != %02x)\n",
i,in[j],overlay_local_identities[i][j]);
}
}
int cn=0,id=0,kp=0;
for(cn=0;cn<keyring->context_count;cn++)
for(id=0;id<keyring->contexts[cn]->identity_count;id++)
for(kp=0;kp<keyring->contexts[cn]->identities[id]->keypair_count;kp++)
if (keyring->contexts[cn]->identities[id]->keypairs[kp]->type
==KEYTYPE_CRYPTOBOX)
{
if (!bcmp(in,keyring->contexts[cn]->identities[id]
->keypairs[kp]->public_key,prefix_bytes))
{
if (debug&DEBUG_OVERLAYABBREVIATIONS)
WHY("Found reference to local address.");
bcopy(&keyring->contexts[cn]->identities[id]
->keypairs[kp]->public_key[0],&out[(*ofs)],SID_SIZE);
(*ofs)+=SID_SIZE;
return OA_RESOLVED;
}
}
if (debug&DEBUG_OVERLAYABBREVIATIONS)
WHY("Encountered unresolvable address -- are we asking for explanation?");
return OA_PLEASEEXPLAIN;
@ -490,7 +490,7 @@ int overlay_abbreviate_cache_lookup(unsigned char *in,unsigned char *out,int *of
colliding prefixes and ask the sender to resolve them for us, or better yet dynamically
size the prefix length based on whether any given short prefix has collided */
if (debug&DEBUG_OVERLAYABBREVIATIONS) {
if (debug&DEBUG_OVERLAYABBREVIATIONS) {
/* It is here, so let's return it */
fprintf(stderr,"I think I looked up the following: ");
for(i=0;i<SID_SIZE;i++) fprintf(stderr,"%02x",cache->sids[index].b[i]);

View File

@ -181,17 +181,8 @@ int overlay_mdp_process_bind_request(int sock,overlay_mdp_frame *mdp,
for(i=0;i<SID_SIZE;i++) if (mdp->bind.sid[i]) break;
if (i<SID_SIZE) {
/* Not all zeroes, so make sure it is a valid SID */
int j,ok=0;
for(j=0;j<overlay_local_identity_count;j++)
{
fprintf(stderr,"Comparing %s against local addr ",
overlay_render_sid(mdp->bind.sid));
fprintf(stderr,"%s\n",
overlay_render_sid(overlay_local_identities[j]));
for(i=0;i<SID_SIZE;i++)
if (mdp->bind.sid[i]!=overlay_local_identities[j][i]) break;
if (i==SID_SIZE) { ok=1; break; }
}
int ok=0;
if (overlay_address_is_local(mdp->bind.sid)) ok=1;
if (!ok) {
/* Source address is invalid */
return overlay_mdp_reply_error(sock,recvaddr,recvaddrlen,7,
@ -355,8 +346,12 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
with our local address. For now just responds with first local address */
if (overlay_address_is_broadcast(mdp->out.src.sid))
{
if (overlay_local_identity_count)
bcopy(&overlay_local_identities[0][0],mdp->out.src.sid,SID_SIZE);
if (keyring->contexts[0]->identity_count&&
keyring->contexts[0]->identities[0]->keypair_count&&
keyring->contexts[0]->identities[0]->keypairs[0]->type
==KEYTYPE_CRYPTOBOX)
bcopy(keyring->contexts[0]->identities[0]->keypairs[0]->public_key,
mdp->out.src.sid,SID_SIZE);
else
/* No local addresses, so put all zeroes */
bzero(mdp->out.src.sid,SID_SIZE);
@ -592,26 +587,35 @@ int overlay_mdp_poll()
int max_sids=mdp->addrlist.frame_sid_count;
/* ... and constrain list for sanity */
if (sid_num<0) sid_num=0;
if (sid_num>overlay_local_identity_count) max_sids=0;
if (max_sids>MDP_MAX_SID_REQUEST) max_sids=MDP_MAX_SID_REQUEST;
if (max_sids>(overlay_local_identity_count-sid_num))
max_sids=overlay_local_identity_count-sid_num;
if (max_sid>(overlay_local_identity_count-sid_num))
max_sid=overlay_local_identity_count-sid_num;
if (max_sids<0) max_sids=0;
/* Prepare reply packet */
mdpreply.packetTypeAndFlags=MDP_ADDRLIST;
mdpreply.addrlist.server_sid_count=overlay_local_identity_count;
{
int cn=0,in=0,kp=0;
int count=0;
while(keyring_next_identity(keyring,&cn,&in,&kp)) {
in++; count++;
}
mdpreply.addrlist.server_sid_count=count;
}
mdpreply.addrlist.first_sid=sid_num;
mdpreply.addrlist.last_sid=max_sid;
mdpreply.addrlist.frame_sid_count=max_sids;
/* Populate with SIDs */
int i;
for(i=0;i<max_sids;i++)
bcopy(overlay_local_identities[sid_num+i],
mdpreply.addrlist.sids[i],SID_SIZE);
int cn=0,in=0,kp=0;
int i=0;
int count=0;
while(keyring_next_identity(keyring,&cn,&in,&kp)) {
if (count>=sid_num&&(i<max_sids))
bcopy(keyring->contexts[cn]->identities[in]->keypairs[kp]->public_key,
mdpreply.addrlist.sids[i++],SID_SIZE);
in++; kp=0;
count++;
if (i>=max_sids) break;
}
/* Send back to caller */
return overlay_mdp_reply(mdp_named_socket,

View File

@ -278,11 +278,20 @@ int overlay_frame_set_broadcast_as_destination(overlay_frame *f)
unsigned char *overlay_get_my_sid()
{
/* Make sure we can find our SID */
int zero=0;
if (!findHlr(hlr,&zero,NULL,NULL)) { WHY("Could not find first entry in HLR"); return NULL; }
return &hlr[zero+4];
int kp;
if (!keyring)
{ WHY("keyring is null"); return NULL; }
if (!keyring->context_count)
{ WHY("No context zero in keyring"); return NULL; }
if (!keyring->contexts[0]->identity_count)
{ WHY("No identity in keyring context zero"); return NULL; }
for(kp=0;kp<keyring->contexts[0]->identities[0]->keypair_count;kp++)
if (keyring->contexts[0]->identities[0]->keypairs[kp]->type==KEYTYPE_CRYPTOBOX)
return keyring->contexts[0]->identities[0]->keypairs[kp]->public_key;
WHY("Could not find first entry in HLR"); return NULL;
}
int overlay_frame_set_me_as_source(overlay_frame *f)

View File

@ -1046,39 +1046,12 @@ int overlay_route_record_link(long long now,unsigned char *to,unsigned char *via
return 0;
}
int overlay_local_identity_count=0;
unsigned char *overlay_local_identities[OVERLAY_MAX_LOCAL_IDENTITIES];
int overlay_address_is_local(unsigned char *s)
{ int ii,i;
for (ii=0;ii<overlay_local_identity_count;ii++) {
for(i=0;i<SID_SIZE;i++)
if (s[i]!=overlay_local_identities[ii][i])
{ if (debug&DEBUG_OVERLAYROUTING) fprintf(stderr,"address is not local address #%d, since byte %d = %02x != %02x\n",
ii,i,s[i],overlay_local_identities[ii][i]);
break; }
if (i==SID_SIZE) { return 1; }
}
return 0;
}
{
int cn=0,in=0,kp=0;
int found=keyring_find_sid(keyring,&cn,&in,&kp,s);
int overlay_add_local_identity(unsigned char *s)
{
int i;
if (overlay_local_identity_count>=OVERLAY_MAX_LOCAL_IDENTITIES)
return WHY("Too many local identities. Increase OVERLAY_MAX_LOCAL_IDENTITIES.");
overlay_local_identities[overlay_local_identity_count]=malloc(SID_SIZE);
if (!overlay_local_identities[overlay_local_identity_count])
return WHY("malloc() failed while recording local identity.");
for(i=0;i<SID_SIZE;i++) {
overlay_local_identities[overlay_local_identity_count][i]=s[i];
}
overlay_local_identity_count++;
return 0;
return found;
}
int overlay_route_dump()
@ -1087,13 +1060,18 @@ int overlay_route_dump()
long long now=overlay_gettime_ms();
fprintf(stderr,"\nOverlay Local Identities\n------------------------\n");
for(n=0;n<overlay_local_identity_count;n++)
{
int i;
for(i=0;i<SID_SIZE;i++)
fprintf(stderr,"%02x",overlay_local_identities[n][i]);
fprintf(stderr,"\n");
}
int cn,in,kp;
for(cn=0;cn<keyring->context_count;cn++)
for(in=0;in<keyring->contexts[cn]->identity_count;in++)
for(kp=0;kp<keyring->contexts[cn]->identities[in]->keypair_count;kp++)
if (keyring->contexts[cn]->identities[in]->keypairs[kp]->type
==KEYTYPE_CRYPTOBOX)
{
for(i=0;i<SID_SIZE;i++)
fprintf(stderr,"%02x",keyring->contexts[cn]->identities[in]
->keypairs[kp]->public_key[i]);
fprintf(stderr,"\n");
}
fprintf(stderr,"\nOverlay Neighbour Table\n------------------------\n");
for(n=0;n<overlay_neighbour_count;n++)

View File

@ -206,6 +206,28 @@ int packetSetSid(unsigned char *packet,int packet_maxlen,int *packet_len,char *s
return stowSid(packet,ofs,sid);
}
int packetSetSidFromId(unsigned char *packet,int packet_maxlen,int *packet_len,
keyring_identity *id)
{
if (!id) return WHY("id is null");
unsigned char *sid=NULL;
int i;
for(i=0;i<id->keypair_count;i++)
if (id->keypairs[i]->type==KEYTYPE_CRYPTOBOX)
{ sid=id->keypairs[i]->public_key; break; }
if (!sid) return WHY("Could not find SID in identity");
/* find and copy SID from identity */
int ofs=OFS_SIDDIDFIELD;
packet[ofs++]=0x01; /* SID */
bcopy(sid,&packet[ofs],SID_SIZE);
return 0;
}
int packetFinalise(unsigned char *packet,int packet_maxlen,int recvttl,
int *packet_len,int cryptoflags)
{
@ -512,7 +534,8 @@ int extractResponses(struct in_addr sender,unsigned char *buffer,int len,struct
return 0;
}
int packageVariableSegment(unsigned char *data,int *dlen,struct hlrentry_handle *h,
int packageVariableSegment(unsigned char *data,int *dlen,
struct response *h,
int offset,int buffer_size)
{
int bytes;
@ -546,7 +569,7 @@ int packageVariableSegment(unsigned char *data,int *dlen,struct hlrentry_handle
if (debug&DEBUG_PACKETFORMATS) fprintf(stderr,"Packaging %d bytes\n",bytes);
/* Package the variable value itself (or part thereof) */
bcopy(&h->value[offset],&data[*dlen],bytes);
bcopy(&h->response[offset],&data[*dlen],bytes);
(*dlen)+=bytes;
if (debug&DEBUG_PACKETFORMATS) dump("Variable segment octets",&data[dlen_in],(*dlen)-dlen_in);

200
serval.h
View File

@ -163,8 +163,91 @@ extern char *instrumentation_file;
extern char *batman_socket;
extern char *batman_peerfile;
/* HLR records can be upto 4GB, so 4x8bits are needed to encode the size */
#define HLR_RECORD_LEN_SIZE 4
typedef struct keypair {
int type;
unsigned char *private_key;
int private_key_len;
unsigned char *public_key;
int public_key_len;
} keypair;
/* Contains just the list of private:public key pairs and types,
the pin used to extract them, and the slot in the keyring file
(so that it can be replaced/rewritten as required). */
#define PKR_MAX_KEYPAIRS 64
#define PKR_SALT_BYTES 32
#define PKR_MAC_BYTES 64
typedef struct keyring_identity {
char *PKRPin;
unsigned int slot;
int keypair_count;
keypair *keypairs[PKR_MAX_KEYPAIRS];
} keyring_identity;
/* 64K identities, can easily be increased should the need arise,
but keep it low-ish for now so that the 64K pointers don't eat too
much ram on a small device. Should probably think about having
small and large device settings for some of these things */
#define KEYRING_MAX_IDENTITIES 65536
typedef struct keyring_context {
char *KeyRingPin;
unsigned char *KeyRingSalt;
int KeyRingSaltLen;
int identity_count;
keyring_identity *identities[KEYRING_MAX_IDENTITIES];
} keyring_context;
#define KEYRING_PAGE_SIZE 4096LL
#define KEYRING_BAM_BYTES 2048LL
#define KEYRING_BAM_BITS (KEYRING_BAM_BYTES<<3)
#define KEYRING_SLAB_SIZE (KEYRING_PAGE_SIZE*KEYRING_BAM_BITS)
typedef struct keyring_bam {
off_t file_offset;
unsigned char bitmap[KEYRING_BAM_BYTES];
struct keyring_bam *next;
} keyring_bam;
#define KEYRING_MAX_CONTEXTS 256
typedef struct keyring_file {
int context_count;
keyring_bam *bam;
keyring_context *contexts[KEYRING_MAX_CONTEXTS];
FILE *file;
off_t file_size;
} keyring_file;
void keyring_free(keyring_file *k);
void keyring_free_context(keyring_context *c);
void keyring_free_identity(keyring_identity *id);
void keyring_free_keypair(keypair *kp);
int keyring_identity_mac(keyring_context *c,keyring_identity *id,
unsigned char *pkrsalt,unsigned char *mac);
#define KEYTYPE_CRYPTOBOX 0x01
#define KEYTYPE_CRYPTOSIGN 0x02
#define KEYTYPE_RHIZOME 0x03
/* DIDs aren't really keys, but the keyring is a real handy place to keep them,
and keep them private if people so desire */
#define KEYTYPE_DID 0x04
/* handle to keyring file for use in running instance */
extern keyring_file *keyring;
/* Public calls to keyring management */
keyring_file *keyring_open(char *file);
keyring_file *keyring_open_with_pins(char *pinlist);
int keyring_enter_pin(keyring_file *k,char *pin);
int keyring_enter_pins(keyring_file *k,char *pinlist);
int keyring_set_did(keyring_identity *id,char *did);
int keyring_next_identity(keyring_file *k,int *cn,int *in,int *kp);
int keyring_find_did(keyring_file *k,int *cn,int *in,int *kp,char *did);
int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid);
int keyring_commit(keyring_file *k);
keyring_identity *keyring_create_identity(keyring_file *k,keyring_context *c,
char *pin);
int keyring_seed(keyring_file *k);
/* Packet format:
@ -240,19 +323,6 @@ struct response_set {
unsigned char *reply_bitmask;
};
struct hlrentry_handle {
int record_length;
unsigned char *hlr;
int hlr_offset;
int var_id;
int var_instance;
unsigned char *value;
int value_len;
int entry_offset;
};
/* Array of variables that can be placed in an MPHLR */
#define VAR_EOR 0x00
#define VAR_CREATETIME 0x01
@ -313,13 +383,14 @@ int stowSid(unsigned char *packet,int ofs,char *sid);
int stowDid(unsigned char *packet,int *ofs,char *did);
int isFieldZeroP(unsigned char *packet,int start,int count);
void srandomdev();
int respondSimple(char *sid,int action,unsigned char *action_text,int action_len,
int respondSimple(keyring_identity *id,
int action,unsigned char *action_text,int action_len,
unsigned char *transaction_id,int recvttl,
struct sockaddr *recvaddr,int cryptoFlags);
int requestItem(char *did,char *sid,char *item,int instance,unsigned char *buffer,int buffer_length,int *len,
unsigned char *transaction_id);
int requestNewHLR(char *did,char *pin,char *sid,int recvttl,struct sockaddr *recvaddr);
int server(char *backing_file,int size,int foregroundMode);
int server(char *backing_file,int foregroundMode);
int isTransactionInCache(unsigned char *transaction_id);
void insertTransactionInCache(unsigned char *transaction_id);
@ -333,7 +404,10 @@ int process_packet(unsigned char *packet,int len,
int recvttl,struct sockaddr *sender,int sender_len);
int packetMakeHeader(unsigned char *packet,int packet_maxlen,int *packet_len,unsigned char *transaction_id,int cryptoflags);
int packetSetDid(unsigned char *packet,int packet_maxlen,int *packet_len,char *did);
int packetSetSid(unsigned char *packet,int packet_maxlen,int *packet_len,char *sid);
// Deprecated
// int packetSetSid(unsigned char *packet,int packet_maxlen,int *packet_len,char *sid);
int packetSetSidFromId(unsigned char *packet,int packet_maxlen,int *packet_len,
keyring_identity *id);
int packetFinalise(unsigned char *packet,int packet_maxlen,int recvttl,
int *packet_len,int cryptoflags);
int packetAddHLRCreateRequest(unsigned char *packet,int packet_maxlen,int *packet_len);
@ -346,16 +420,8 @@ int sendToPeers(unsigned char *packet,int packet_len,int method,int peerId,struc
int getReplyPackets(int method,int peer,int batchP,struct response_set *responses,
unsigned char *transaction_id,struct sockaddr *recvaddr,int timeout);
int clearResponse(struct response **response);
int nextHlr(unsigned char *hlr,int *ofs);
int seedHlr();
int findHlr(unsigned char *hlr,int *ofs,char *sid,char *did);
int createHlr(char *did,char *sid);
struct hlrentry_handle *openhlrentry(unsigned char *hlr,int hofs);
struct hlrentry_handle *hlrentrygetent(struct hlrentry_handle *h);
int hlrStowValue(unsigned char *hlr,int hofs,int hlr_offset,
int varid,int varinstance,unsigned char *value,int len);
int hlrMakeSpace(unsigned char *hlr,int hofs,int hlr_offset,int bytes);
int packageVariableSegment(unsigned char *data,int *dlen,struct hlrentry_handle *h,
int packageVariableSegment(unsigned char *data,int *dlen,
struct response *h,
int offset,int buffer_size);
int packetDecipher(unsigned char *packet,int len,int cipher);
int safeZeroField(unsigned char *packet,int start,int count);
@ -1088,81 +1154,3 @@ void *_serval_debug_malloc(unsigned int bytes,char *file,const char *func,int li
void *_serval_debug_calloc(unsigned int bytes,unsigned int count,char *file,const char *func,int line);
void _serval_debug_free(void *p,char *file,const char *func,int line);
#endif
typedef struct keypair {
int type;
unsigned char *private_key;
int private_key_len;
unsigned char *public_key;
int public_key_len;
} keypair;
/* Contains just the list of private:public key pairs and types,
the pin used to extract them, and the slot in the keyring file
(so that it can be replaced/rewritten as required). */
#define PKR_MAX_KEYPAIRS 64
#define PKR_SALT_BYTES 32
#define PKR_MAC_BYTES 64
typedef struct keyring_identity {
char *PKRPin;
unsigned int slot;
int keypair_count;
keypair *keypairs[PKR_MAX_KEYPAIRS];
} keyring_identity;
/* 64K identities, can easily be increased should the need arise,
but keep it low-ish for now so that the 64K pointers don't eat too
much ram on a small device. Should probably think about having
small and large device settings for some of these things */
#define KEYRING_MAX_IDENTITIES 65536
typedef struct keyring_context {
char *KeyRingPin;
unsigned char *KeyRingSalt;
int KeyRingSaltLen;
int identity_count;
keyring_identity *identities[KEYRING_MAX_IDENTITIES];
} keyring_context;
#define KEYRING_PAGE_SIZE 4096LL
#define KEYRING_BAM_BYTES 2048LL
#define KEYRING_BAM_BITS (KEYRING_BAM_BYTES<<3)
#define KEYRING_SLAB_SIZE (KEYRING_PAGE_SIZE*KEYRING_BAM_BITS)
typedef struct keyring_bam {
off_t file_offset;
unsigned char bitmap[KEYRING_BAM_BYTES];
struct keyring_bam *next;
} keyring_bam;
#define KEYRING_MAX_CONTEXTS 256
typedef struct keyring_file {
int context_count;
keyring_bam *bam;
keyring_context *contexts[KEYRING_MAX_CONTEXTS];
FILE *file;
off_t file_size;
} keyring_file;
void keyring_free(keyring_file *k);
void keyring_free_context(keyring_context *c);
void keyring_free_identity(keyring_identity *id);
void keyring_free_keypair(keypair *kp);
int keyring_identity_mac(keyring_context *c,keyring_identity *id,
unsigned char *pkrsalt,unsigned char *mac);
#define KEYTYPE_CRYPTOBOX 0x01
#define KEYTYPE_CRYPTOSIGN 0x02
#define KEYTYPE_RHIZOME 0x03
/* DIDs aren't really keys, but the keyring is a real handy place to keep them,
and keep them private if people so desire */
#define KEYTYPE_DID 0x04
/* Public calls to keyring management */
keyring_file *keyring_open(char *file);
keyring_file *keyring_open_with_pins(char *pinlist);
int keyring_enter_pin(keyring_file *k,char *pin);
int keyring_enter_pins(keyring_file *k,char *pinlist);
int keyring_set_did(keyring_identity *id,char *did);
int keyring_find_did(keyring_file *k,int *cn,int *in,int *kp,char *did);
int keyring_find_sid(keyring_file *k,int *cn,int *in,int *kp,unsigned char *sid);
int keyring_commit(keyring_file *k);
int keyring_create_identity(keyring_file *k,keyring_context *c,char *pin);

436
server.c
View File

@ -31,7 +31,7 @@ FILE *i_f=NULL;
struct in_addr client_addr;
int client_port;
int getBackingStore(char *s,int size);
int getKeyring(char *s);
int createServerSocket();
int simpleServerMode();
@ -96,10 +96,10 @@ int recvwithttl(int sock,unsigned char *buffer,int bufferlen,int *ttl,
}
int server(char *backing_file,int size,int foregroundMode)
int server(char *backing_file,int foregroundMode)
{
/* Get backing store for HLR */
getBackingStore(backing_file,size);
getKeyring(backing_file);
if (overlayMode)
{
@ -142,55 +142,22 @@ int server(char *backing_file,int size,int foregroundMode)
return 0;
}
int getBackingStore(char *backing_file,int size)
int getKeyring(char *backing_file)
{
if (!backing_file)
{
/* transitory storage of HLR data, so just malloc() the memory */
hlr=calloc(size,1);
if (!hlr) exit(setReason("Failed to calloc() HLR database."));
if (debug&DEBUG_HLR) fprintf(stderr,"Allocated %d byte temporary HLR store\n",size);
{
exit(WHY("Keyring requires a backing file"));
}
else
{
unsigned char zero[8192];
FILE *f=fopen(backing_file,"r+");
if (!f) f=fopen(backing_file,"w+");
if (!f) exit(setReason("Could not open backing file."));
bzero(&zero[0],8192);
fseek(f,0,SEEK_END);
errno=0;
while(ftell(f)<size)
{
int r;
fseek(f,0,SEEK_END);
if ((r=fwrite(zero,8192,1,f))!=1)
{
perror("fwrite");
exit(setReason("Could not enlarge backing file to requested size (short write)"));
}
fseek(f,0,SEEK_END);
}
if (errno) perror("fseek");
if (fwrite("",1,1,f)!=1)
{
fprintf(stderr,"Failed to set backing file size.\n");
perror("fwrite");
}
hlr=(unsigned char *)mmap(NULL,size,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_NORESERVE,fileno(f),0);
if (hlr==MAP_FAILED) {
perror("mmap");
exit(setReason("Memory mapping of HLR backing file failed."));
if (keyring) {
exit(WHY("Keyring being opened twice"));
keyring=keyring_open(backing_file);
}
if (debug&DEBUG_HLR) fprintf(stderr,"Allocated %d byte HLR store backed by file `%s'\n",
size,backing_file);
}
hlr_size=size;
keyring_seed(keyring);
seedHlr();
return 0;
return 0;
}
int processRequest(unsigned char *packet,int len,
@ -198,7 +165,7 @@ int processRequest(unsigned char *packet,int len,
unsigned char *transaction_id,int recvttl, char *did,char *sid)
{
/* Find HLR entry by DID or SID, unless creating */
int ofs,rofs=0;
int ofs;
int records_searched=0;
int prev_pofs=0;
@ -217,26 +184,22 @@ int processRequest(unsigned char *packet,int len,
you can't choose a SID. */
if (debug&DEBUG_HLR) fprintf(stderr,"Creating a new HLR record. did='%s', sid='%s'\n",did,sid);
if (!did[0]) return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id,recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED);
if (sid[0]) return respondSimple(sid,ACTION_DECLINED,NULL,0,transaction_id,recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED);
if (sid[0])
return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id,
recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED);
if (debug&DEBUG_HLR) fprintf(stderr,"Verified that create request supplies DID but not SID\n");
{
/* Look for an existing HLR with the requested DID. If there is one, respond with its
SID. This handles duplicates of the same message. If there is none, then make a new
HLR with random SID and initial DID. */
int ofs = 0;
int response = ACTION_DECLINED;
if (findHlr(hlr, &ofs, sid, did)) {
hlrSid(hlr, ofs, sid);
if (debug&DEBUG_HLR) fprintf(stderr,"HLR found with did='%s' at ofs=%x: sid='%s'\n", did, ofs, sid);
response = ACTION_OKAY;
}
else if (createHlr(did, sid) == 0) {
if (debug&DEBUG_HLR) fprintf(stderr,"HLR created with did='%s': sid='%s'\n", did, sid);
response = ACTION_OKAY;
}
return respondSimple(sid, response, NULL, 0, transaction_id, recvttl, sender, CRYPT_CIPHERED|CRYPT_SIGNED);
}
/* Creating an identity is nice and easy now with the new keyring */
keyring_identity *id=keyring_create_identity(keyring,keyring->contexts[0],
"");
if (id) keyring_set_did(id,did);
if (id==NULL||keyring_commit(keyring))
return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id,recvttl,
sender,CRYPT_CIPHERED|CRYPT_SIGNED);
else
return respondSimple(id,ACTION_OKAY,NULL,0,transaction_id,recvttl,
sender,CRYPT_CIPHERED|CRYPT_SIGNED);
pofs+=1;
pofs+=1+SID_SIZE;
}
@ -269,137 +232,13 @@ int processRequest(unsigned char *packet,int len,
}
}
break;
case ACTION_DIGITALTELEGRAM:
if (debug&DEBUG_DNAREQUESTS) fprintf(stderr,"In ACTION_DIGITALTELEGRAM\n");
{
// Unpack SMS message.
char emitterPhoneNumber[256];
char message[256];
pofs++;
/* char messageType = packet[pofs]; */
pofs++;
char emitterPhoneNumberLen = packet[pofs];
pofs++;
char messageLen = packet[pofs];
pofs++;
strncpy(emitterPhoneNumber, (const char*)packet+pofs, emitterPhoneNumberLen);
emitterPhoneNumber[(unsigned int)emitterPhoneNumberLen]=0;
pofs+=emitterPhoneNumberLen;
strncpy(message, (const char*)packet+pofs, messageLen);
message[(unsigned int)messageLen]=0;
pofs+=messageLen;
// Check if I'm the recipient
ofs=0;
if (findHlr(hlr, &ofs, sid, did)) {
// Check transaction cache to see if message has already been delivered. If not,
// then deliver it now.
if (!isTransactionInCache(transaction_id)) {
// Deliver SMS to android.
char amCommand[576]; // 64 char + 2*256(max) char = 576
sprintf(amCommand, "am broadcast -a org.servalproject.DT -e number \"%s\" -e content \"%s\"", emitterPhoneNumber, message);
if (debug&DEBUG_DNAREQUESTS) fprintf(stderr,"Delivering DT message via intent: %s\n",amCommand);
runCommand(amCommand);
// Record in cache to prevent re-delivering the same message if a duplicate is received.
insertTransactionInCache(transaction_id);
}
char sid[SID_STRLEN+1];
respondSimple(hlrSid(hlr, ofs, sid), ACTION_OKAY, NULL, 0, transaction_id, recvttl, sender, CRYPT_CIPHERED|CRYPT_SIGNED);
}
}
break;
case ACTION_SET:
ofs=0;
if (debug&DEBUG_DNAREQUESTS) fprintf(stderr,"Looking for hlr entries with sid='%s' / did='%s'\n",sid,did);
if ((!sid)||(!sid[0])) {
setReason("You can only set variables by SID");
return respondSimple(NULL,ACTION_ERROR,
(unsigned char *)"SET requires authentication by SID",
0,transaction_id,recvttl,
sender,CRYPT_CIPHERED|CRYPT_SIGNED);
}
while(findHlr(hlr,&ofs,sid,did))
{
int itemId,instance,start_offset,bytes,flags;
unsigned char value[9000],oldvalue[65536];
int oldr,oldl;
if (debug&DEBUG_HLR) fprintf(stderr,"findHlr found a match for writing at 0x%x\n",ofs);
if (debug&DEBUG_HLR) hlrDump(hlr,ofs);
/* XXX consider taking action on this HLR
(check PIN first depending on the action requested) */
setReason("You can only set keyring variables locally");
return respondSimple(NULL,ACTION_ERROR,
(unsigned char *)"Would be insecure",
0,transaction_id,recvttl,
sender,CRYPT_CIPHERED|CRYPT_SIGNED);
/* XXX Doesn't verify PIN authentication */
/* Get write request */
pofs++; rofs=pofs;
if (extractRequest(packet,&pofs,len,
&itemId,&instance,value,
&start_offset,&bytes,&flags))
{
setReason("Could not extract ACTION_SET request");
return
respondSimple(NULL,ACTION_ERROR,
(unsigned char *)"Mal-formed SET request",
0,transaction_id,recvttl,
sender,CRYPT_CIPHERED|CRYPT_SIGNED);
}
/* Get the stored value */
oldl=65536;
oldr=hlrGetVariable(hlr,ofs,itemId,instance,oldvalue,&oldl);
if (oldr) {
if (flags==SET_NOREPLACE) {
oldl=0;
} else {
setReason("Tried to SET_NOCREATE/SET_REPLACE a non-existing value");
return
respondSimple(NULL,ACTION_ERROR,
(unsigned char *)"Cannot SET NOCREATE/REPLACE a value that does not exist",
0,transaction_id,recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED);
}
} else {
if (flags==SET_NOREPLACE) {
setReason("Tried to SET_NOREPLACE an existing value");
if (debug&DEBUG_DNAREQUESTS) dump("Existing value (in SET_NOREPLACE flagged request)",oldvalue,oldl);
return
respondSimple(NULL,ACTION_ERROR,
(unsigned char *)"Cannot SET NOREPLACE; a value exists",
0,transaction_id,recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED);
}
}
/* Replace the changed portion of the stored value */
if ((start_offset+bytes)>oldl) {
bzero(&oldvalue[oldl],start_offset+bytes-oldl);
oldl=start_offset+bytes;
}
bcopy(&value[0],&oldvalue[start_offset],bytes);
/* Write new value back */
if (hlrSetVariable(hlr,ofs,itemId,instance,oldvalue,oldl))
{
setReason("Failed to write variable");
return
respondSimple(NULL,ACTION_ERROR,
(unsigned char *)"Failed to SET variable",
0,transaction_id,recvttl,
sender,CRYPT_CIPHERED|CRYPT_SIGNED);
}
if (debug&DEBUG_HLR) { fprintf(stderr,"HLR after writing:\n"); hlrDump(hlr,ofs); }
/* Reply that we wrote the fragment */
respondSimple(sid,ACTION_WROTE,&packet[rofs],6,
transaction_id,recvttl,
sender,CRYPT_CIPHERED|CRYPT_SIGNED);
/* Advance to next record and keep searching */
if (nextHlr(hlr,&ofs)) break;
}
break;
case ACTION_GET:
{
@ -416,112 +255,132 @@ int processRequest(unsigned char *packet,int len,
if (var_id&0x80) instance=packet[++pofs];
pofs++;
int offset=(packet[pofs]<<8)+packet[pofs+1]; pofs+=2;
char *hlr_sid=NULL;
char hlr_sid_s[SID_STRLEN+1];
keyring_identity *responding_id=NULL;
pofs+=2;
if (debug&DEBUG_DNAREQUESTS) fprintf(stderr,"Processing ACTION_GET (var_id=%02x, instance=%02x, pofs=0x%x, len=%d)\n",var_id,instance,pofs,len);
ofs=0;
if (debug&DEBUG_HLR) fprintf(stderr,"Looking for hlr entries with sid='%s' / did='%s'\n",(sid&&sid[0])?sid:"null",did?did:"null");
if (debug&DEBUG_HLR) fprintf(stderr,"Looking for identities with sid='%s' / did='%s'\n",(sid&&sid[0])?sid:"null",did?did:"null");
/* Keyring only has DIDs in it for now.
Location is implied, so we allow that */
switch(var_id) {
case VAR_DIDS:
case VAR_LOCATIONS:
break;
default:
return respondSimple(NULL,ACTION_ERROR,
(unsigned char *)"Unsupported variable",
0,transaction_id,recvttl,
sender,CRYPT_CIPHERED|CRYPT_SIGNED);
while(1)
{
struct hlrentry_handle *h;
}
// if an empty did was passed in, get results from all hlr records
if (*sid || *did){
if (!findHlr(hlr,&ofs,sid,did)) break;
if (debug&DEBUG_HLR) fprintf(stderr,"findHlr found a match @ 0x%x\n",ofs);
{
int cn=0,in=0,kp=0;
int found=0;
int count=0;
while(cn<keyring->context_count) {
found=0;
if (sid) {
unsigned char packedSid[SID_SIZE];
stowSid(packedSid,0,sid);
found=keyring_find_sid(keyring,&cn,&in,&kp,packedSid);
} else {
found=keyring_find_did(keyring,&cn,&in,&kp,did);
}
if (debug&DEBUG_HLR) hlrDump(hlr,ofs);
/* XXX consider taking action on this HLR
(check PIN first depending on the action requested) */
/* Form a reply packet containing the requested data */
if (instance==0xff) instance=-1;
/* Step through HLR to find any matching instances of the requested variable */
h=openhlrentry(hlr,ofs);
if (debug&DEBUG_HLR) fprintf(stderr,"openhlrentry(hlr,%d) returned %p\n",ofs,h);
while(h)
{
/* Is this the variable? */
if (debug&DEBUG_HLR) fprintf(stderr," considering var_id=%02x, instance=%02x\n",
h->var_id,h->var_instance);
if (h->var_id==var_id)
{
if (h->var_instance==instance||instance==-1)
{
if (debug&DEBUG_HLR) fprintf(stderr,"Sending matching variable value instance (instance #%d), value offset %d.\n",
h->var_instance,offset);
// only send each value when the *next* record is found, that way we can easily stamp the last response with DONE
if (sendDone>0)
respondSimple(hlr_sid,ACTION_DATA,data,dlen,
transaction_id,recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED);
struct response r;
dlen=0;
if (packageVariableSegment(data,&dlen,h,offset,MAX_DATA_BYTES+16))
return setReason("packageVariableSegment() failed.");
hlr_sid = hlrSid(hlr, ofs, hlr_sid_s);
sendDone++;
}
else
if (debug&DEBUG_HLR) fprintf(stderr,"Ignoring variable instance %d (not %d)\n",
h->var_instance,instance);
}
else
if (debug&DEBUG_HLR) fprintf(stderr,"Ignoring variable ID %d (not %d)\n",
h->var_id,var_id);
h=hlrentrygetent(h);
if (found&&(instance==-1||instance==count)) {
/* We have a matching identity/DID, now see what variable
they want.
VAR_DIDS and VAR_LOCATIONS are the only ones we support
with the new keyring file format for now. */
r.var_id=var_id;
r.var_instance=instance;
switch(var_id) {
case VAR_DIDS:
r.response=keyring->contexts[cn]->identities[in]
->keypairs[kp]->private_key;
r.value_len=strlen((char *)r.response);
break;
case VAR_LOCATIONS:
r.response=(unsigned char *)"4000@";
r.value_len=strlen((char *)r.response);
break;
}
/* Advance to next record and keep searching */
if (nextHlr(hlr,&ofs)) break;
}
if (sendDone)
{
data[dlen++]=ACTION_DONE;
data[dlen++]=sendDone&0xff;
respondSimple(hlr_sid,ACTION_DATA,data,dlen,transaction_id,
recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED);
}
if (gatewayspec&&(var_id==VAR_LOCATIONS)&&did&&strlen(did))
{
/* We are a gateway, so offer connection via the gateway as well */
unsigned char data[MAX_DATA_BYTES+16];
int dlen=0;
struct hlrentry_handle fake;
unsigned char uri[1024];
/* We use asterisk to provide the gateway service,
so we need to create a temporary extension in extensions.conf,
ask asterisk to re-read extensions.conf, and then make sure it has
a functional SIP gateway.
*/
if (!asteriskObtainGateway(sid,did,(char *)uri))
{
fake.value_len=strlen((char *)uri);
fake.var_id=var_id;
fake.value=uri;
if (packageVariableSegment(data,&dlen,&fake,offset,MAX_DATA_BYTES+16))
return setReason("packageVariableSegment() of gateway URI failed.");
char sid[SID_STRLEN+1];
respondSimple(hlrSid(hlr, 0, sid),ACTION_DATA,data,dlen,
transaction_id,recvttl,sender,
CRYPT_CIPHERED|CRYPT_SIGNED);
}
else
{
/* For multiple packet responses, we want to tag only the
last one with DONE, so we queue up the most recently generated
packet, and only dispatch it when we are about to produce
another. Then at the end of the loop, if we have a packet
waiting we simply mark that with with DONE, and everything
falls into place. */
if (sendDone>0)
/* Send previous packet */
respondSimple(responding_id,ACTION_DATA,data,dlen,
transaction_id,recvttl,sender,
CRYPT_CIPHERED|CRYPT_SIGNED);
/* Prepare new packet */
dlen=0;
if (packageVariableSegment(data,&dlen,&r,offset,
MAX_DATA_BYTES+16))
return setReason("packageVariableSegment() failed.");
responding_id = keyring->contexts[cn]->identities[in];
/* Remember that we need to send this new packet */
sendDone++;
count++;
if (sid) in++; else kp++;
}
}
}
/* Now, see if we have a final queued packet which needs marking with
DONE and then sending. */
if (sendDone)
{
data[dlen++]=ACTION_DONE;
data[dlen++]=sendDone&0xff;
respondSimple(responding_id,ACTION_DATA,data,dlen,transaction_id,
recvttl,sender,CRYPT_CIPHERED|CRYPT_SIGNED);
}
if (gatewayspec&&(var_id==VAR_LOCATIONS)&&did&&strlen(did))
{
/* We are a gateway, so offer connection via the gateway as well */
unsigned char data[MAX_DATA_BYTES+16];
int dlen=0;
struct response fake;
unsigned char uri[1024];
/* We use asterisk to provide the gateway service,
so we need to create a temporary extension in extensions.conf,
ask asterisk to re-read extensions.conf, and then make sure it has
a functional SIP gateway.
*/
if (!asteriskObtainGateway(sid,did,(char *)uri))
{
fake.value_len=strlen((char *)uri);
fake.var_id=var_id;
fake.response=uri;
if (packageVariableSegment(data,&dlen,&fake,offset,MAX_DATA_BYTES+16))
return setReason("packageVariableSegment() of gateway URI failed.");
WHY("Gateway claims to be 1st identity, when it should probably have its own identity");
respondSimple(keyring->contexts[0]->identities[0],
ACTION_DATA,data,dlen,
transaction_id,recvttl,sender,
CRYPT_CIPHERED|CRYPT_SIGNED);
}
else
{
/* Should we indicate the gateway is not available? */
}
}
@ -542,7 +401,8 @@ int processRequest(unsigned char *packet,int len,
return 0;
}
int respondSimple(char *sid,int action,unsigned char *action_text,int action_len,
int respondSimple(keyring_identity *id,
int action,unsigned char *action_text,int action_len,
unsigned char *transaction_id,int recvttl,
struct sockaddr *recvaddr,int cryptoFlags)
{
@ -570,8 +430,8 @@ int respondSimple(char *sid,int action,unsigned char *action_text,int action_len
/* Prepare the request packet */
if (packetMakeHeader(packet,8000,packet_len,transaction_id,cryptoFlags))
return WHY("packetMakeHeader() failed.");
if (sid&&sid[0])
{ if (packetSetSid(packet,8000,packet_len,sid))
if (id)
{ if (packetSetSidFromId(packet,8000,packet_len,id))
return setReason("invalid SID in reply"); }
else
{ if (packetSetDid(packet,8000,packet_len,""))