mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-21 01:42:18 +00:00
Initial work on proper gateway support with direct tie-in to Asterisk.
This commit is contained in:
parent
def9a60fe5
commit
d20da9616e
2
Makefile
2
Makefile
@ -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
|
||||
|
@ -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
2
dna.c
@ -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
145
gateway.c
Normal 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;
|
||||
|
||||
}
|
6
mphlr.h
6
mphlr.h
@ -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
|
||||
|
77
server.c
77
server.c
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user