Initial work on proper gateway support with direct tie-in to Asterisk.

This commit is contained in:
gardners 2011-05-16 16:58:25 +09:30
parent def9a60fe5
commit d20da9616e
6 changed files with 201 additions and 33 deletions

View File

@ -1,5 +1,5 @@
OBJS= dna.o server.o client.o peers.o ciphers.o responses.o packetformats.o dataformats.o \
hlrdata.o srandomdev.o simulate.o batman.o overlay.o export.o
hlrdata.o srandomdev.o simulate.o batman.o overlay.o export.o gateway.o
HDRS= Makefile mphlr.h
LDFLAGS=
DEFS= -DPACKAGE_NAME=\"\" -DPACKAGE_TARNAME=\"\" -DPACKAGE_VERSION=\"\" -DPACKAGE_STRING=\"\" -DPACKAGE_BUGREPORT=\"\" -DPACKAGE_URL=\"\" -DHAVE_LIBC=1 -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STDIO_H=1 -DHAVE_ERRNO_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRINGS_H=1 -DHAVE_UNISTD_H=1 -DHAVE_STRING_H=1 -DHAVE_ARPA_INET_H=1 -DHAVE_SYS_SOCKET_H=1 -DHAVE_SYS_MMAN_H=1 -DHAVE_SYS_TIME_H=1 -DHAVE_POLL_H=1 -DHAVE_NETDB_H=1

View File

@ -1,5 +1,5 @@
OBJS= dna.o server.o client.o peers.o ciphers.o responses.o packetformats.o dataformats.o \
hlrdata.o srandomdev.o simulate.o batman.o overlay.o export.o
hlrdata.o srandomdev.o simulate.o batman.o overlay.o export.o gateway.o
HDRS= Makefile mphlr.h
LDFLAGS= @LDFLAGS@
DEFS= @DEFS@

2
dna.c
View File

@ -321,7 +321,7 @@ int main(int argc,char **argv)
if (instance<-1||instance>255) usage("Illegal variable instance ID.");
break;
case 'f':
if (clientMode||(!serverMode)) usage("Only servers use backing files");
if (clientMode) usage("Only servers use backing files");
hlr_file=strdup(optarg);
break;
case 'p': /* additional peers to query */

145
gateway.c Normal file
View File

@ -0,0 +1,145 @@
#include "mphlr.h"
char *asterisk_extensions_conf="/data/data/org.servalproject/var/extensions_dna.conf";
char *asterisk_reload_command="/data/data/org.servalproject/sbin/asterisk -r extensions reload";
char *asterisk_outbound_sip=NULL;
typedef struct dna_gateway_extension {
char did[64];
char requestor_sid[SID_SIZE+1];
char uri[256-64-SID_SIZE-1-sizeof(int)-(sizeof(time_t)*2)];
int uriprefixlen;
time_t created; /* 0 == free */
time_t expires; /* 0 == free */
} dna_gateway_extension;
#define MAX_CURRENT_EXTENSIONS 1024
dna_gateway_extension extensions[MAX_CURRENT_EXTENSIONS];
int gatewayReadSettings(char *file)
{
char line[1024];
FILE *f=fopen(file,"r");
if (!f) return -1;
/* Location of extensions.conf file to write
(really it would be a file you #include from extensions.conf) */
line[0]=0; fgets(line,1024,f);
asterisk_extensions_conf=strdup(line);
/* The command required to get Asterisk to re-read the above file */
line[0]=0; fgets(line,1024,f);
asterisk_reload_command=strdup(line);
/* SIP Registration details for Asterisk outbound gateway
(my intention is to write them into sip.conf) */
line[0]=0; fgets(line,1024,f);
asterisk_outbound_sip=strdup(line);
/* XXX Need more here I suspect */
fclose(f);
return 0;
}
int asteriskCreateExtension(char *requestor_sid,char *did,char *uri_out)
{
/* XXX There are denial of service attacks that we have to consider here.
Primarily, naughty persons could flood the gateway with false solicitations filling the
current extension table and slowing asterisk down with lots of reloads.
Our mitigation strategy is to use a random replacement scheme, except where the same SID
has an entry in the table already, in which case we should replace that one.
Replacement entails a search, which should be done using a tree structure for speed.
Since right now we just want to get the functionality working, we will just do random replacement
no matter what.
*/
/* XXX We should add authentication checks and number validity checks here, e.g., if a gateway only wants to
allow access for a certain group of users, and/or to only a certain range of numbers */
/* XXX The "secret" extension is only secret if we encrypt the reply packet! */
int index=random()%MAX_CURRENT_EXTENSIONS;
bcopy(requestor_sid,extensions[index].requestor_sid,SID_SIZE);
strcpy(did,extensions[index].did);
extensions[index].created=time(0);
extensions[index].expires=time(0)+3600;
snprintf(extensions[index].uri,sizeof(extensions[index].uri),"4101*%08x%08x%08x@%s",
(unsigned int)random(),(unsigned int)random(),(unsigned int)random(),gatewayuri);
extensions[index].uriprefixlen=strlen(extensions[index].uri)-strlen(gatewayuri)-1;
if (extensions[index].uriprefixlen<0) {
/* Whoops - something wrong with the extension/uri, so kill the record and fail. */
extensions[index].expires=1;
return -1;
}
if (debug) fprintf(stderr,"Created extension '%s' to dial %s\n",extensions[index].uri,did);
return 0;
}
int asteriskWriteExtensions()
{
int i;
time_t now=time(0);
FILE *out;
out=fopen(asterisk_extensions_conf,"w");
if (!out) return -1;
for(i=0;i<MAX_CURRENT_EXTENSIONS;i++)
{
if (extensions[i].expires)
{
if (extensions[i].expires<now)
{
/* Clear expired gateway extensions */
bzero(&extensions[i],sizeof(dna_gateway_extension));
}
else
{
extensions[i].uri[extensions[i].uriprefixlen]=0;
fprintf(out,
"exten => _%s., 1, Dial(SIP/sdnagatewayout/%s)\n"
"exten => _%s., 2, Hangup()\n",
extensions[i].uri,
extensions[i].did,
extensions[i].uri);
extensions[i].uri[extensions[i].uriprefixlen]='@';
}
}
}
fclose(out);
return 0;
}
int asteriskReloadExtensions()
{
if (system(asterisk_reload_command))
return -1;
else
return 0;
}
int asteriskGatewayUpP()
{
/* XXX STUB */
return 0;
}
int asteriskObtainGateway(char *requestor_sid,char *did,char *uri_out)
{
/* 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 (asteriskCreateExtension(requestor_sid,did,uri_out)) return -1;
if (asteriskWriteExtensions()) return -1;
if (asteriskReloadExtensions()) return -1;
if (asteriskGatewayUpP()) return 0; else return -1;
}

View File

@ -271,7 +271,7 @@ 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,
unsigned char *transaction_id);
unsigned char *transaction_id,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);
@ -344,3 +344,7 @@ int fixResponses(struct response_set *responses);
int importHlr(char *textfile);
int exportHlr(unsigned char *hlr,char *text);
int openHlrFile(char *backing_file,int size);
#define CRYPT_CIPHERED 1
#define CRYPT_SIGNED 2
#define CRYPT_PUBLIC 4

View File

@ -153,17 +153,17 @@ int processRequest(unsigned char *packet,int len,
/* Creating an HLR requires an initial DID number and definately no SID -
you can't choose a SID. */
if (debug>1) 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);
if (sid[0]) return respondSimple(sid,ACTION_DECLINED,NULL,0,transaction_id);
if (!did[0]) return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
if (sid[0]) return respondSimple(sid,ACTION_DECLINED,NULL,0,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
if (debug>1) fprintf(stderr,"Verified that create request supplies DID but not SID\n");
{
char sid[128];
/* make HLR with new random SID and initial DID */
if (!createHlr(did,sid))
return respondSimple(sid,ACTION_OKAY,NULL,0,transaction_id);
return respondSimple(sid,ACTION_OKAY,NULL,0,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
else
return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id);
return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
}
pofs+=1;
pofs+=1+SID_SIZE;
@ -197,7 +197,7 @@ int processRequest(unsigned char *packet,int len,
break;
case ACTION_SENDSMS: /* Send an SMS to the specified SID. */
/* You cannot use a DID */
if (did[0]) return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id);
if (did[0]) return respondSimple(NULL,ACTION_DECLINED,NULL,0,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
/* XXX Thomas to complete and make sure it works:
1. Unpack SMS message.
@ -214,7 +214,7 @@ int processRequest(unsigned char *packet,int len,
if (oldr) {
/* Already exists, so no need to deliver it again */
respondSimple(sid,ACTION_SMSRECEIVED,NULL,0,transaction_id);
respondSimple(sid,ACTION_SMSRECEIVED,NULL,0,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
}
else
{
@ -223,13 +223,14 @@ int processRequest(unsigned char *packet,int len,
{
setReason("Failed to write variable");
return
respondSimple(NULL,ACTION_ERROR,(unsigned char *)"No space for message",0,transaction_id);
respondSimple(NULL,ACTION_ERROR,(unsigned char *)"No space for message",0,transaction_id,
CRYPT_CIPHERED|CRYPT_SIGNED);
}
if (debug>2) { fprintf(stderr,"HLR after writing:\n"); hlrDump(hlr,ofs); }
/* Reply that we wrote the fragment */
respondSimple(sid,ACTION_WROTE,&packet[rofs],6,
transaction_id);
transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
}
}
break;
@ -239,7 +240,8 @@ int processRequest(unsigned char *packet,int len,
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);
return respondSimple(NULL,ACTION_ERROR,(unsigned char *)"SET requires authentication by SID",0,transaction_id,
CRYPT_CIPHERED|CRYPT_SIGNED);
}
while(findHlr(hlr,&ofs,sid,did))
@ -265,7 +267,8 @@ int processRequest(unsigned char *packet,int len,
{
setReason("Could not extract ACTION_SET request");
return
respondSimple(NULL,ACTION_ERROR,(unsigned char *)"Mal-formed SET request",0,transaction_id);
respondSimple(NULL,ACTION_ERROR,(unsigned char *)"Mal-formed SET request",0,transaction_id,
CRYPT_CIPHERED|CRYPT_SIGNED);
}
/* Get the stored value */
@ -279,7 +282,7 @@ int processRequest(unsigned char *packet,int len,
return
respondSimple(NULL,ACTION_ERROR,
(unsigned char *)"Cannot SET NOCREATE/REPLACE a value that does not exist",
0,transaction_id);
0,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
}
} else {
if (flags==SET_NOREPLACE) {
@ -288,7 +291,7 @@ int processRequest(unsigned char *packet,int len,
return
respondSimple(NULL,ACTION_ERROR,
(unsigned char *)"Cannot SET NOREPLACE; a value exists",
0,transaction_id);
0,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
}
}
/* Replace the changed portion of the stored value */
@ -303,13 +306,14 @@ int processRequest(unsigned char *packet,int len,
{
setReason("Failed to write variable");
return
respondSimple(NULL,ACTION_ERROR,(unsigned char *)"Failed to SET variable",0,transaction_id);
respondSimple(NULL,ACTION_ERROR,(unsigned char *)"Failed to SET variable",0,transaction_id,
CRYPT_CIPHERED|CRYPT_SIGNED);
}
if (debug>2) { fprintf(stderr,"HLR after writing:\n"); hlrDump(hlr,ofs); }
/* Reply that we wrote the fragment */
respondSimple(sid,ACTION_WROTE,&packet[rofs],6,
transaction_id);
transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
/* Advance to next record and keep searching */
if (nextHlr(hlr,&ofs)) break;
}
@ -367,7 +371,7 @@ int processRequest(unsigned char *packet,int len,
// 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);
respondSimple(hlr_sid,ACTION_DATA,data,dlen,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
dlen=0;
@ -394,7 +398,7 @@ int processRequest(unsigned char *packet,int len,
{
data[dlen++]=ACTION_DONE;
data[dlen++]=sendDone&0xff;
respondSimple(hlr_sid,ACTION_DATA,data,dlen,transaction_id);
respondSimple(hlr_sid,ACTION_DATA,data,dlen,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
}
if (gatewayuri&&(var_id==VAR_LOCATIONS)&&did&&strlen(did))
{
@ -403,18 +407,28 @@ int processRequest(unsigned char *packet,int len,
int dlen=0;
struct hlrentry_handle fake;
unsigned char uri[1024];
/* Turn gateway into full URI including extension */
snprintf((char *)uri,1024,"4101*%s@%s",did,gatewayuri);
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.");
respondSimple(hlrSid(hlr,0),ACTION_DATA,data,dlen,transaction_id);
/* 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,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.");
respondSimple(hlrSid(hlr,0),ACTION_DATA,data,dlen,transaction_id,CRYPT_CIPHERED|CRYPT_SIGNED);
}
else
{
/* Should we indicate the gateway is not available? */
}
}
}
@ -434,7 +448,7 @@ int processRequest(unsigned char *packet,int len,
}
int respondSimple(char *sid,int action,unsigned char *action_text,int action_len,
unsigned char *transaction_id)
unsigned char *transaction_id,int cryptoFlags)
{
unsigned char packet[8000];
int pl=0;
@ -442,6 +456,11 @@ int respondSimple(char *sid,int action,unsigned char *action_text,int action_len
int packet_maxlen=8000;
int i;
/* XXX Complain about invalid crypto flags.
XXX We don't do anything with the crypto flags right now
XXX Other packet sending routines need this as well. */
if (!cryptoFlags) return -1;
/* ACTION_ERROR is associated with an error message.
For syntactic simplicity, we do not require the respondSimple() call to provide
the length of the error message. */