Remove dead code

This commit is contained in:
Jeremy Lakeman 2012-10-19 14:56:20 +10:30
parent f1b0374b97
commit f93216f369
14 changed files with 0 additions and 2352 deletions

View File

@ -10,11 +10,8 @@ SERVALD_SRC_FILES = \
serval-dna/overlay_payload.c \
serval-dna/overlay_route.c \
serval-dna/overlay_mdp.c \
serval-dna/batman.c \
serval-dna/crypto.c \
serval-dna/ciphers.c \
serval-dna/cli.c \
serval-dna/client.c \
serval-dna/commandline.c \
serval-dna/conf.c \
serval-dna/dataformats.c \
@ -31,7 +28,6 @@ SERVALD_SRC_FILES = \
serval-dna/overlay_address.c \
serval-dna/performance_timing.c \
serval-dna/packetformats.c \
serval-dna/peers.c \
serval-dna/randombytes.c \
serval-dna/rhizome.c \
serval-dna/rhizome_bundle.c \
@ -42,11 +38,9 @@ SERVALD_SRC_FILES = \
serval-dna/rhizome_packetformats.c \
serval-dna/rhizome_direct.c \
serval-dna/rhizome_direct_http.c \
serval-dna/responses.c \
serval-dna/serval_packetvisualise.c \
serval-dna/server.c \
serval-dna/sha2.c \
serval-dna/simulate.c \
serval-dna/srandomdev.c \
serval-dna/str.c \
serval-dna/keyring.c \

7
Makefile.in Normal file → Executable file
View File

@ -3,10 +3,7 @@ include $(NACL_BASE)/nacl.mk
SRCS= $(NACL_SOURCES) \
audiodevices.c \
audio_reflector.c \
batman.c \
ciphers.c \
cli.c \
client.c \
codecs.c \
commandline.c \
conf.c \
@ -14,7 +11,6 @@ SRCS= $(NACL_SOURCES) \
dataformats.c \
directory_client.c \
dna_helper.c \
dna_identity.c \
encode.c \
fdqueue.c \
fifo.c \
@ -41,9 +37,7 @@ SRCS= $(NACL_SOURCES) \
overlay_route.c \
packetformats.c \
performance_timing.c \
peers.c \
randombytes.c \
responses.c \
rhizome.c \
rhizome_bundle.c \
rhizome_crypto.c \
@ -57,7 +51,6 @@ SRCS= $(NACL_SOURCES) \
server.c \
sha2.c \
sighandlers.c \
simulate.c \
sqlite-amalgamation-3070900/sqlite3.c \
srandomdev.c \
str.c \

320
batman.c
View File

@ -1,320 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
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.
*/
#include <sys/types.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <time.h>
#include "serval.h"
struct reachable_peer {
unsigned char addr_len;
unsigned char addr[32];
unsigned char tq_avg;
};
#ifndef RTF_UP
/* Keep this in sync with /usr/src/linux/include/linux/route.h */
#define RTF_UP 0x0001 /* route usable */
#define RTF_GATEWAY 0x0002 /* destination is a gateway */
#define RTF_HOST 0x0004 /* host entry (net otherwise) */
#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
#define RTF_MTU 0x0040 /* specific MTU for this route */
#ifndef RTF_MSS
#define RTF_MSS RTF_MTU /* Compatibility :-( */
#endif
#define RTF_WINDOW 0x0080 /* per route window clamping */
#define RTF_IRTT 0x0100 /* Initial round trip time */
#define RTF_REJECT 0x0200 /* Reject route */
#endif
int readRoutingTable(struct in_addr peers[],int *peer_count,int peer_max){
char devname[64];
unsigned long d, g, m;
int flgs, ref, use, metric, mtu, win, ir;
if (debug&DEBUG_PEERS) DEBUG("Reading routing table");
FILE *fp = fopen("/proc/net/route","r");
if (!fp) return -1;
if (debug&DEBUG_PEERS) DEBUG("Skipping line");
if (fscanf(fp, "%*[^\n]\n") < 0)
goto ERROR;
while(1){
int r;
if (debug&DEBUG_PEERS) DEBUG("Reading next route");
r = fscanf(fp, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n",
devname, &d, &g, &flgs, &ref, &use, &metric, &m,
&mtu, &win, &ir);
if (r != 11) {
if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
if (debug&DEBUG_PEERS) DEBUG("eof");
break;
}
ERROR:
fclose(fp);
return WHY("Unable to parse routing table");
}
if (!(flgs & RTF_UP)) { /* Skip interfaces that are down. */
if (debug&DEBUG_PEERS) DEBUGF("Skipping down interface %s",devname);
continue;
}
if (m!=0xFFFFFFFF){
/* Netmask indicates a network, so calculate broadcast address */
d=(d&m)|(0xffffffff^m);
if (debug&DEBUG_PEERS) DEBUGF("Adding broadcast address %08lx",d);
}
if (*peer_count<peer_max) peers[(*peer_count)++].s_addr=d;
if (debug&DEBUG_PEERS) DEBUGF("Found peer %08lx from routing table",d);
}
fclose(fp);
return 0;
}
int readArpTable(struct in_addr peers[],int *peer_count,int peer_max){
unsigned long d;
int q1,q2,q3,q4;
if (debug&DEBUG_PEERS) DEBUG("Reading ARP table");
FILE *fp = fopen("/proc/net/arp","r");
if (!fp) return -1;
if (debug&DEBUG_PEERS) DEBUG("Skipping line");
if (fscanf(fp, "%*[^\n]\n") < 0)
goto ERROR;
while(1){
int r;
r = fscanf(fp, "%d.%d.%d.%d%*[^\n]\n",
&q1,&q2,&q3,&q4);
if (debug&DEBUG_PEERS) DEBUGF("Reading next arp entry (r=%d, %d.%d.%d.%d)",r,q1,q2,q3,q4);
d = (q1&0xff)
+((q2&0xff)<<8)
+((q3&0xff)<<16)
+((q4&0xff)<<24);
if (r != 4) {
if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
if (debug&DEBUG_PEERS) DEBUG("eof");
break;
}
ERROR:
fclose(fp);
return WHY("Unable to parse arp table");
}
if (*peer_count<peer_max) peers[(*peer_count)++].s_addr=d;
if (debug&DEBUG_PEERS) DEBUGF("Found peer %08lx from ARP table",d);
}
fclose(fp);
return 0;
}
int readBatmanPeerFile(char *file_path,struct in_addr peers[],int *peer_count,int peer_max)
{
/* Shiny new code to read the flat file containing peer list */
FILE *f;
unsigned int offset=0;
unsigned int timestamp=0;
struct reachable_peer p;
f=fopen(file_path,"r");
if (!f) {
WHY_perror("fopen");
return WHYF("Failed to open peer list file `%s'",file_path);
}
if (fread(&offset,sizeof(offset),1,f)!=1) {
WHY_perror("fread");
fclose(f);
return WHYF("Failed to read peer list offset from `%s'",file_path);
}
offset=ntohl(offset);
if (fseek(f,offset,SEEK_SET)) {
WHY_perror("fseek");
fclose(f);
return WHYF("Failed to seek to peer list offset 0x%x in `%s'",offset,file_path);
}
if (fread(&timestamp,sizeof(timestamp),1,f)!=1) {
WHY_perror("fread");
fclose(f);
return WHYF("Failed to read peer list timestamp from `%s'",file_path);
}
timestamp=ntohl(timestamp);
if (timestamp<(time(0)-3)) {
if (debug&DEBUG_PEERS)
DEBUGF("Ignoring stale BATMAN peer list (%d seconds old)",(int)(time(0)-timestamp));
fclose(f);
return -1;
}
while(fread(&p,sizeof(p),1,f)==1) {
struct in_addr i;
if (!p.addr_len) break;
union { char c[4]; uint32_t ui32; } *u = (void*)&p.addr[0];
i.s_addr = u->ui32;
if (*peer_count<peer_max) peers[(*peer_count)++]=i;
if (debug&DEBUG_PEERS) DEBUGF("Found BATMAN peer '%s'",inet_ntoa(i));
}
if (fclose(f) == EOF)
WHY_perror("fclose");
return 0;
}
int getBatmanPeerList(char *socket_path,struct in_addr peers[],int *peer_count,int peer_max)
{
#ifdef WIN32
return -1;
#else
int sock;
struct sockaddr_un socket_address;
unsigned char buf[16384]; /* big enough for a gigabit jumbo frame or loopback godzilla-gram */
int ofs=0;
int bytes=0;
struct pollfd fds;
int notDone=1;
int res;
int tries=0;
askagain:
/* Make socket */
sock=socket(PF_UNIX,SOCK_STREAM,0);
memset(&socket_address,0,sizeof(struct sockaddr_un));
socket_address.sun_family=PF_UNIX;
if (strlen(socket_path)>256) return WHY("BATMAN socket path too long");
strcpy(socket_address.sun_path,socket_path);
/* Connect the socket */
if (connect(sock,(struct sockaddr*)&socket_address,sizeof(socket_address))<0)
return WHY("connect() to BATMAN socket failed.");
char cmd[30];
snprintf(cmd, sizeof cmd, "d:%c", 1);
cmd[sizeof cmd - 1] = '\0';
if (write(sock,cmd,30) != 30) {
close(sock);
return WHY("write() command failed to BATMAN socket.");
}
fds.fd=sock;
fds.events=POLLIN;
getmore:
while(notDone)
{
switch (poll(&fds,1,1500)) {
case 1: /* Excellent - we have a response */ break;
case 0: if (debug&DEBUG_PEERS) DEBUGF("BATMAN did not respond to peer enquiry");
close(sock);
if (tries++<=3) goto askagain;
return WHY("No response from BATMAN.");
default: /* some sort of error, e.g., lost connection */
close(sock);
return WHY("poll() of BATMAN socket failed.");
}
res=read(sock,&buf[bytes],16383-bytes); close(sock);
ofs=0;
if (res<1) {
if (bytes)
{
/* Got a partial response, then a dead line.
Should probably ask again unless we have tried too many times.
*/
if (debug&DEBUG_PEERS) DEBUGF("Trying again after cold drop");
close(sock);
bytes=0;
if (tries++<=3) goto askagain;
else return WHY("failed to read() from BATMAN socket (too many tries).");
}
return WHY("failed to read() from BATMAN socket.");
}
if (!res) return 0;
if (debug&DEBUG_PEERS) DEBUGF("BATMAN has responded with %d bytes",res);
if (debug&DEBUG_PEERS) dump("BATMAN says",&buf[bytes],res);
if (res<80 /*||buf[bytes]!='B' -- turns out we can't rely on this, either */
||buf[bytes+res-1]!=0x0a||buf[bytes+res-4]!='E')
{
/* Jolly BATMAN on Android sometimes sends us bung packets from time to
time. Sometimes it is fragmenting, other times it is just plain
odd.
If this happens, we should just ask again.
We should also try to reassemble fragments.
Sometimes we get cold-drops and resumes, too. Yay.
*/
if (buf[bytes+res-4]!='E') {
/* no end marker, so try adding record to the end. */
if (debug&DEBUG_PEERS) DEBUGF("Data has no end marker, accumulating");
bytes+=res;
goto getmore;
}
close(sock);
goto askagain;
}
bytes+=res;
while(ofs<bytes)
{
if(debug&DEBUG_PEERS) DEBUGF("New line @ %d",ofs);
/* Check for IP address of peers */
if (isdigit(buf[ofs]))
{
int i;
for(i=0;ofs+i<bytes;i++)
if (buf[i+ofs]==' ') {
buf[i+ofs]=0;
if (*peer_count<peer_max) peers[(*peer_count)++].s_addr=inet_addr((char *)&buf[ofs]);
if (debug&DEBUG_PEERS) DEBUGF("Found BATMAN peer '%s'",&buf[ofs]);
buf[ofs+i]=' ';
break;
}
}
/* Check for end of transmission */
if (buf[ofs]=='E') { notDone=0; }
/* Skip to next line */
while(buf[ofs]>=' '&&(ofs<bytes)) ofs++;
while(buf[ofs]<' '&&(ofs<bytes)) ofs++;
}
bytes=0;
}
return 0;
#endif
}

View File

@ -1,79 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
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.
*/
#include "serval.h"
int current_sid_set=0;
unsigned char current_sid[SID_SIZE];
int packetSetMySid(char *sid)
{
/* Set SID identity if not the first SID in the HLR */
return WHY("Not implemented");
}
int packetGetPrivateKeyForSid()
{
return WHY("Not implemented");
}
int packetClearPrivateKeys()
{
return WHY("Not implemented");
}
int packetDecipher(unsigned char *packet,int len,int cipher)
{
// Not encrypting for now
return 0;
switch(cipher) {
case 0: /* plain text */
case CRYPT_PUBLIC: /*make it public, with no other requirements == plain text */
return 0;
case CRYPT_SIGNED:
case CRYPT_PUBLIC|CRYPT_SIGNED:
/* Sign but don't encrypt, i.e., crypto_sign() */
return 0;
case CRYPT_CIPHERED:
/* encrypt, but don't sign.
Down the track we will use crypto_stream(), but we need a shared secret for the conversation.
*/
return 0;
case CRYPT_CIPHERED|CRYPT_SIGNED:
/* encrypt and sign, i.e., crypto_box() */
return 0;
default:
return WHY("Unknown packet cipher");
}
}
int packetEncipher(unsigned char *packet,int maxlen,int *len,int cryptoflags)
{
// Not encrypting for now
return 0;
if (cryptoflags)
{
return WHY("Unknown packet cipher");
}
else return 0; /* plain text */
}

348
client.c
View File

@ -1,348 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
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.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "serval.h"
int sock = -1;
char *outputtemplate = NULL;
static int dnatimeout = 3000; /* default 3000 ms request timeout */
int packetSendFollowup(struct in_addr destination,
unsigned char *packet,int packet_len)
{
struct sockaddr_in peer_addr;
int r;
bzero(&peer_addr, sizeof(peer_addr));
peer_addr.sin_family=AF_INET;
peer_addr.sin_port = htons( PORT_DNA );
peer_addr.sin_addr.s_addr=destination.s_addr;
if (!serverMode) {
sock=socket(PF_INET,SOCK_DGRAM,0);
if (sock == -1) {
WHY_perror("socket");
FATAL("Could not create UDP socket");
}
r=1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &r, sizeof(r));
}
r=sendto(sock,packet,packet_len,0,(struct sockaddr *)&peer_addr,sizeof(peer_addr));
if (r<packet_len) {
if (debug&DEBUG_PACKETTX) DEBUGF("Could not send to %s (r=%d, packet_len=%d)",inet_ntoa(destination),r,packet_len);
perror("sendto(a)");
} else {
if (debug&DEBUG_PACKETTX) DEBUGF("Sent request to client %s",inet_ntoa(destination));
}
return 0;
}
int packetSendRequest(int method,unsigned char *packet,int packet_len,int batchP,
unsigned char *transaction_id,struct sockaddr *recvaddr,
struct response_set *responses)
{
int i;
int cumulative_timeout=0; /* ms */
int this_timeout=125; /* ms */
int peer_low,peer_high;
int timeout_remaining;
struct timeval time_in,now;
/* Prepare ephemeral UDP socket (hence no binding)
If in server mode, then we already have a socket available to us and appropriately bound */
if (!serverMode) {
sock=socket(PF_INET,SOCK_DGRAM,0);
if (sock == -1) {
WHY_perror("socket");
FATAL("Could not create UDP socket");
}
i=1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i));
}
/* Deal with special case */
if (method==REQ_REPLY)
{
int r;
if (overlayMode)
r=overlay_sendto((struct sockaddr_in *)recvaddr,packet,packet_len);
else
r=sendto(sock,packet,packet_len,0,recvaddr,sizeof(struct sockaddr_in));
if (r<packet_len) {
if (debug&DEBUG_PACKETTX) DEBUGF("Could not send to client %s (packet=%p,len=%d,sock=%d)",
inet_ntoa(client_addr),packet,packet_len,sock);
perror("sendto(b)");
} else {
if (debug&DEBUG_PACKETTX) DEBUGF("Sent request to client %s",inet_ntoa(client_addr));
}
return 0;
}
if (!peer_count) getPeerList();
gettimeofday(&time_in,NULL);
/* REQ_SERIAL & REQ_PARALLEL work in fundamentally different ways,
but it turns out the retry/timeout code is the dominant part.
So we do a bit of fiddling around to make one loop that can handle both */
if (method==REQ_SERIAL) {
peer_low=0; peer_high=peer_count-1;
/* If there are too many peers to allow sending to each three times, then we should
adjust our incremental timeout accordingly, so far as is practicable */
if (this_timeout*peer_count*3>dnatimeout)
{
this_timeout=dnatimeout/(3*peer_count);
if (this_timeout<10) this_timeout=10; /* 10ms minimum sending interval */
}
} else
{ peer_low=-1; peer_high=-1;}
while(cumulative_timeout<=dnatimeout)
{
/* If not in serial mode, then send request to everyone immediately.
Make sure we only ask once in parallel mode, since it will always ask everyone */
if (method==REQ_PARALLEL) sendToPeers(packet,packet_len,method,0,responses);
else if (method!=REQ_SERIAL)
for(i=0;i<peer_count;i++) sendToPeers(packet,packet_len,method,i,responses);
/* If in serial mode, send request to peers in turn until one responds positively,
otherwise just deal with the reply fetching loop to listen to as many or few reply. */
for(i=peer_low;i<=peer_high;i++) {
struct response *rr;
if (i>-1) sendToPeers(packet,packet_len,REQ_SERIAL,i,responses);
/* Placing the timeout calculation here means that the total timeout is shared among
all peers in a serial request, but round-robining after each time-step.
We adjust this_timeout if there are many peers to allow 3 sends to each peer where possible.
*/
cumulative_timeout+=this_timeout;
timeout_remaining=this_timeout;
while(1)
{
/* Wait for response */
int r=getReplyPackets(method,i,batchP,responses,transaction_id,recvaddr,timeout_remaining);
if (r && (debug & DEBUG_DNARESPONSES)) DEBUG("returned on timeout");
switch(method)
{
case REQ_PARALLEL:
/* XXX We could stop once all peers have replied.
(need to update the test script if we do that, so that it tests with multiple
peers and so tests that we wait if not all peers have responded) */
break;
case REQ_FIRSTREPLY:
if (debug&DEBUG_DNARESPONSES) DEBUGF("Returning with first reply (REQ_FIRSTREPLY)");
if (!r) return 0;
break;
case REQ_SERIAL:
if (!r) {
/* Stop if we have an affirmative response.
XXX - doesn't allow for out of order replies. */
if (debug&DEBUG_DNARESPONSES) dumpResponses(responses);
rr=responses->last_response;
while (rr)
{
if (rr->checked) break;
if (debug&DEBUG_DNARESPONSES)
DEBUGF("Got a response code 0x%02x, checking if that is what we need",rr->code);
switch (rr->code)
{
case ACTION_OKAY: case ACTION_DATA:
/* bingo */
if (!batchP) return 0;
break;
}
rr->checked=1;
rr=rr->prev;
}
/* not what we are after, so clear response and try with next peer */
clearResponses(responses);
}
break;
}
/* Wait for the previous timeout to really expire,
(this is for the case where all peers have replied) */
{
int elapsed_usecs=0;
int cumulative_usecs=cumulative_timeout*1000;
int remaining_usecs;
gettimeofday(&now,NULL);
elapsed_usecs=(now.tv_sec-time_in.tv_sec)*1000000;
elapsed_usecs+=(now.tv_usec-time_in.tv_usec);
remaining_usecs=cumulative_usecs-elapsed_usecs;
if (remaining_usecs<=0) break;
else timeout_remaining=remaining_usecs/1000;
}
}
}
cumulative_timeout+=this_timeout;
}
if ((debug&DEBUG_DNARESPONSES) && cumulative_timeout>=dnatimeout)
DEBUGF("Request timed out after retries (timeout=%d, elapsed=%d)",
dnatimeout,cumulative_timeout);
return 0;
}
/* Some data types can end in @ if they require the address of the sender to be appended for correct local interpretation */
int fixResponses(struct response_set *responses)
{
struct response *rr;
if (debug&DEBUG_DNARESPONSES) DEBUG("Fixing response set");
if (!responses) return -1;
rr=responses->responses;
while(rr)
{
if (debug&DEBUG_DNARESPONSES)
DEBUGF(" len=%d, rr->code=%02x, rr->var_id=%02x",
rr->value_bytes,rr->code,rr->var_id);
if (rr->value_bytes>0&&rr->code==ACTION_DATA&&rr->var_id==VAR_LOCATIONS)
{
if (debug&DEBUG_DNARESPONSES)
DEBUGF(" response='%s'",rr->response);
if (rr->response[rr->value_bytes-1]=='@')
{
/* Append response with IP address of sender */
char *addr=inet_ntoa(rr->sender);
int alen=strlen(addr);
char *new = malloc(rr->value_bytes+alen+1);
if (debug&DEBUG_DNARESPONSES)
DEBUGF("Fixing LOCATIONS response '%s' received from '%s (0x%08x)'",
rr->response,addr,(unsigned int)rr->sender.s_addr);
if (!new) return -1;
bcopy(rr->response,new,rr->value_bytes);
bcopy(addr,&new[rr->value_bytes],alen+1);
free(rr->response); rr->response=NULL;
rr->response=(unsigned char *)new;
rr->value_len+=alen;
rr->value_bytes+=alen;
new[rr->value_len]=0; /* Make sure it is null terminated */
if (debug&DEBUG_DNARESPONSES) DEBUGF("Response string now '%s'",rr->response);
}
}
rr=rr->next;
}
return 0;
}
int getReplyPackets(int method,int peer,int batchP,struct response_set *responses,
unsigned char *transaction_id,struct sockaddr *recvaddr,int timeout)
{
/* set timeout alarm */
/* get packets until timeout, or until we get a packet from the specified peer
if method==REQ_SERIAL. If REQ_SERIAL we also reject packets from other
senders as they must be spoofs.
*/
struct timeval t;
int timeout_secs;
int timeout_usecs;
int to=timeout;
if (debug&DEBUG_DNARESPONSES) DEBUGF("getReplyPackets(policy=%d)",method);
/* Work out when the timeout will expire */
gettimeofday(&t,NULL);
timeout_secs=t.tv_sec; timeout_usecs=t.tv_usec;
if (to>1000) { timeout_secs+=(to/1000); to=to%1000; }
timeout_usecs+=to*1000; if (timeout_usecs>1000000) { timeout_secs++; timeout_usecs-=1000000; }
while(1) {
unsigned char buffer[16384];
struct sockaddr sender;
socklen_t recvaddrlen = sizeof(struct sockaddr);
struct pollfd fds;
if (recvaddr) bzero((void *)recvaddr,sizeof(struct sockaddr));
fds.fd=sock; fds.events=POLLIN; fds.revents=0;
while (poll(&fds,1,10 /* wait for 10ms at a time */)==0)
{
gettimeofday(&t,NULL);
if (t.tv_sec>timeout_secs) return 1;
if (t.tv_sec==timeout_secs&&t.tv_usec>=timeout_usecs) return 1;
}
/* Use this temporary socket address structure if one was not supplied */
struct sockaddr reply_recvaddr;
int ttl=-1;
if (!recvaddr) recvaddr=&reply_recvaddr;
ssize_t len = recvwithttl(sock,buffer,sizeof(buffer),&ttl,recvaddr,&recvaddrlen);
if (len == -1)
return WHY("Unable to receive packet.");
if (recvaddr) {
client_port=((struct sockaddr_in *)recvaddr)->sin_port;
client_addr=((struct sockaddr_in *)recvaddr)->sin_addr;
if (debug&DEBUG_DNARESPONSES) DEBUGF("Received reply from %s (len=%lld)", inet_ntoa(client_addr), (long long) len);
if (debug&DEBUG_DNARESPONSES) dump("recvaddr", (unsigned char *)&sender, recvaddrlen);
if (debug&DEBUG_DNARESPONSES) dump("packet", (unsigned char *)buffer, len);
}
if (dropPacketP(len)) {
if (debug&DEBUG_DNARESPONSES) DEBUGF("Simulation mode: Dropped packet due to simulated link parameters");
continue;
}
if (!packetOk(NULL,buffer,len,transaction_id,ttl,recvaddr,recvaddrlen,0)) {
/* Packet passes tests - extract responses and append them to the end of the response list */
if (extractResponses(client_addr,buffer,len,responses))
return WHY("Problem extracting response fields from reply packets");
if (method==REQ_SERIAL||method==REQ_FIRSTREPLY) {
if (!batchP) return 0;
/* In batch mode we need ACTION_DONE to mark end of transmission.
While it gets sent last, out-of-order delivery means we can't rely on
such a nice arrangement. */
{
/* XXX inefficient for long lists.
XXX can be made better by working backwards from end using double-linked list and
remembering the previous length of the list */
struct response *r=responses->responses;
while(r)
{
if (r->code==ACTION_DONE) return 0;
r=r->next;
}
}
}
else {
if (debug&DEBUG_DNARESPONSES) DEBUGF("Waiting for more packets, since called with policy %d",method);
}
} else {
if (debug&(DEBUG_PACKETRX|DEBUG_DNARESPONSES)) DEBUG("Ignoring invalid packet");
}
}
}

View File

@ -1,176 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
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.
*/
/*
This module is responsible for managing the known list of DID:SID:name mappings,
and any signatures that vouch for those mappings. Similarly, we wish to be able
to advertise our mapping and any signatures that vouch for us.
We have the choice of using the rhizome database, some other persistent storage
or an in-memory structure. It would be nice to have a fall-back for when we don't
have the means to run sqlite. A small in-memory cache will likely be used,
regardless. This initial implementation assumes that we have sqlite and the rhizome
database instance available.
So what data do we actually need to tell whether we have verified an identity or not?
We need a DID:SID[:name] tuple.
We also need the scope for us to mark a given tuple as verified by ourselves, e.g.,
using a Diffie-Hellman type exchange between handsets.
Finally, we want the ability to store any signatures that vouch for the identity of
a given party.
*/
#include "serval.h"
#include "rhizome.h"
/*
Look up the verification data for the first matching DID, NAME and/or SID.
(SIDs really should be unique of course).
If more than one constraint are provided, then the search results are constrained
by all provided values.
Subsequent results can be found by calling dnacache_lookup_next();
The operation of this call is greatly simplified by the single-threaded operation
of DNA, meaning that we don't have to be reentrant, so we can retain a database
cursor and generally make life simple.
So what kind of results do we need to actually return?
I guess the initial need is for a simple VERIFIED/NOTVERIFIED result, and
perhaps make the list of certifying identities available. Again the
single-threaded nature of DNA makes this much simpler than a reentrant version
would need to be.
Database schema is:
"CREATE TABLE IF NOT EXISTS VERIFICATIONS(sid text not null, did text, name text,starttime integer, endtime integer,signature blob);"
*/
/* Cache of verifications.
This really doesn't need to be too large. */
#define DNA_IDENTITY_CACHE_SIZE 16
int dna_identity_cache_initialisedP=0;
dna_identity_status dna_identity_cache[DNA_IDENTITY_CACHE_SIZE];
int dnacache_lookup_next_slot_to_examine=0;
char *dnacache_lookup_did=NULL;
char *dnacache_lookup_name=NULL;
char *dnacache_lookup_sid=NULL;
int dnacache_lookup_complete=1;
int dnacache_lookup_sidfound=0;
dna_identity_status *dnacache_lookup(char *did,char *name,char *sid)
{
/* Mark all slots as unused initially */
if (!dna_identity_cache_initialisedP) {
int i;
for(i=0;i<DNA_IDENTITY_CACHE_SIZE;i++)
dna_identity_cache[i].initialisedP=0;
dna_identity_cache_initialisedP=1;
}
/* Now prepare the query or see if the identity is already in the cache.
The cache can be used without database query if SID is specified, since
that guarantees that only one entry exists.
Also, if DID/NAME is specified without SID, and the cache entry indicates
that there are no duplicates for the specified value in the database, then
the database query can be eshewed, provided that the entry for the SID
(whether positive or negative) has been pulled into the cache.
Otherwise, the database must be queried.
Negative results are also cached so that database queries can be avoided for
repeated queries to identies that we do not know about.
*/
/* Here we just prepare the lookup, and then we do the real work in
dnacache_lookup_next(), which does the heavy lifting */
dnacache_lookup_next_slot_to_examine=0;
dnacache_lookup_did=did;
dnacache_lookup_name=name;
dnacache_lookup_sid=sid;
dnacache_lookup_complete=0;
dnacache_lookup_sidfound=0;
return dnacache_lookup_next();
}
dna_identity_status *dnacache_lookup_next()
{
if (dnacache_lookup_complete) return NULL;
/* Look in slots for matches */
while (dnacache_lookup_next_slot_to_examine<DNA_IDENTITY_CACHE_SIZE)
{
dna_identity_status *slot=
&dna_identity_cache[dnacache_lookup_next_slot_to_examine++];
/* Perform the various tests that reject this slot if it doesn't match */
if (!slot->initialisedP) continue;
if (dnacache_lookup_sid&&(strcasecmp(dnacache_lookup_sid,slot->sid)))
continue;
else dnacache_lookup_sidfound=1;
if (dnacache_lookup_did&&(strcasecmp(dnacache_lookup_did,slot->did)))
continue;
if (dnacache_lookup_name&&(strcasecmp(dnacache_lookup_name,slot->name)))
continue;
if (dnacache_lookup_sid&&dnacache_lookup_sidfound)
/* SIDs are unique, a SID was specified, and a matching record was found,
therefore no database query is required. */
dnacache_lookup_complete=1;
if (slot->uniqueDidAndName&&dnacache_lookup_did&&dnacache_lookup_name)
/* If the entry is known to be the only such DID/name combination,
then we need look no further */
dnacache_lookup_complete=1;
/* Well, we passed all the slots, so it must be us */
return slot;
}
WHY("Do database lookup");
return NULL;
}
/*
Record/update the verification status of a DID/SID combination.
If signature is not null, then add this signature to the list of verifications
for the specified DID/SID/NAME combination. NAME may be omitted.
If revokeVerificationP is non-zero, then all existing verifications for the
specified identity will be revoked.
*/
int dnacache_update_verification(char *did,char *sid,char *name,
char *signature,int revokeVerificationP)
{
return WHY("Not implemented");
}
/* Sign a verification record ourselves for the specified identity, by creating
and storing signature and adding record to the cache. */
int dnacache_vouch_for_identity(char *did,char *sid,char *name)
{
return WHY("Not implemented");
}

View File

@ -1,30 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
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.
*/
#include <dlfcn.h>
#include <stdio.h>
int main(int argc,char **argv)
{
void *h = dlopen("/data/data/org.servalproject/lib/libdnalib.so",RTLD_LAZY);
int (*dnamain)(int,char **) = dlsym(h,"main");
if (!dnamain) return fprintf(stderr,"Could not load libdnalib.so\n");
return (*dnamain)(argc,argv);
}

1
main.c
View File

@ -29,7 +29,6 @@ int main(int argc, char **argv)
signal(SIGPIPE,sigPipeHandler);
signal(SIGIO,sigIoHandler);
memabuseInit();
srandomdev();
server_save_argv(argc, (const char*const*)argv);
int status = parseCommandLine(argv[0], argc - 1, (const char*const*)&argv[1]);

View File

@ -19,58 +19,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "serval.h"
int process_packet(unsigned char *packet, size_t len,
int recvttl,struct sockaddr *sender, size_t sender_len)
{
//int authenticatedP=0;
char did[128];
char sid[128];
unsigned char *transaction_id=&packet[OFS_TRANSIDFIELD];
did[0]=0; sid[0]=0;
/* Get DID or SID */
if (packetGetID(packet,len,did,sid) == -1)
return WHY("Could not parse DID or SID");
/* Check for PIN */
if (!isFieldZeroP(packet,OFS_PINFIELD,16))
{
/* Authentication has been attempted.
If it is incorrect, then we need to return with ACTION_DECLINED
*/
if (debug&DEBUG_SECURITY) DEBUG("A PIN has been supplied");
/* Can only authenticate by SID, not DID (since DIDs are ambiguous) */
if (packet[OFS_SIDDIDFIELD]!=1) return WHY("You can only authenticate against a SID");
/* XXX check authentication */
return WHY("Authentication not yet supported");
}
else
{
/* No attempt at authentication was made */
//authenticatedP=0;
if (debug&DEBUG_SECURITY) DEBUG("No PIN was supplied");
}
if (serverMode) return processRequest(packet,len,sender,sender_len,transaction_id,
recvttl,did,sid);
return 0;
}
int packetOk(struct overlay_interface *interface, unsigned char *packet, size_t len,
unsigned char *transaction_id,int ttl,
struct sockaddr *recvaddr, size_t recvaddrlen,int parseP)
{
if (len<HEADERFIELDS_LEN) return WHY("Packet is too short");
if (packet[0]==0x41&&packet[1]==0x10)
{
return packetOkDNA(packet,len,transaction_id,ttl,recvaddr,recvaddrlen,parseP);
}
if (packet[0]==0x4F&&packet[1]==0x10)
{
if (interface!=NULL)
@ -86,414 +40,3 @@ int packetOk(struct overlay_interface *interface, unsigned char *packet, size_t
return WHY("Packet type not recognised.");
}
int packetOkDNA(unsigned char *packet,int len,unsigned char *transaction_id,
int recvttl,
struct sockaddr *recvaddr, size_t recvaddrlen, int parseP)
{
/* Make sure that the packet is meant for us, and is not mal-formed */
int version;
int cipher;
int length;
int payloadRotation;
version=(packet[2]<<8)|packet[3];
length=(packet[4]<<8)|packet[5];
cipher=(packet[6]<<8)|packet[7];
if (version!=1) return WHY("Unknown packet format version");
if (cipher!=0) return WHY("Unknown packet cipher");
if (length!=len) return WHY("Packet length incorrect");
if (cipher)
if (packetDecipher(packet,len,cipher))
return WHY("Could not decipher packet");
/* Make sure the transaction ID matches */
if (transaction_id)
{
int i;
for(i=0;i<TRANSID_SIZE;i++)
if (packet[OFS_TRANSIDFIELD+i]!=transaction_id[i])
return WHY("transaction ID mismatch");
}
/* Unrotate the payload */
payloadRotation=packet[OFS_ROTATIONFIELD];
{
unsigned char temp[256];
bcopy(&packet[len-payloadRotation],&temp[0],payloadRotation);
bcopy(&packet[HEADERFIELDS_LEN],&packet[HEADERFIELDS_LEN+payloadRotation],
len-(HEADERFIELDS_LEN)-payloadRotation);
bcopy(&temp[0],&packet[HEADERFIELDS_LEN],payloadRotation);
}
if (debug&DEBUG_PACKETFORMATS) {
DEBUG("Packet passes sanity checks and is ready for decoding");
dump("unrotated packet",packet,len);
}
if (parseP) return process_packet(packet,len,recvttl,recvaddr,recvaddrlen); else return 0;
}
int packetMakeHeader(unsigned char *packet,int packet_maxlen,int *packet_len,
unsigned char *transaction_id,int cryptoflags)
{
int i;
CHECK_PACKET_LEN(OFS_PAYLOAD);
/* 0x4110 magic value */
packet[0]=0x41;
packet[1]=0x10;
/* encoding version */
packet[2]=0x00;
packet[3]=0x01;
/* Payload length (to be filled in later) */
packet[4]=0x00;
packet[5]=0x00;
/* Payload cipher (0x0000 = plain text) */
packet[6]=0x00;
packet[7]=0x00;
/* Add 64bit transaction id */
if (transaction_id)
/* Use supplied transaction ID */
for(i=0;i<TRANSID_SIZE;i++) packet[OFS_TRANSIDFIELD+i]=transaction_id[i];
else
/* No transaction ID supplied, so create random transaction ID */
for(i=0;i<TRANSID_SIZE;i++) packet[OFS_TRANSIDFIELD+i]=random()&0xff;
/* payload rotation (not yet applied) */
packet[OFS_ROTATIONFIELD]=0x00;
*packet_len=HEADERFIELDS_LEN;
/* Clear did/subscriber ID, salt and hashed pin fields.
However, we cannot zero them, because that would provide significant knowable plain-text
for a known plain text attack.
Thus, instead we fill it with random date, but make the modulo sum of each field == 0x00
to indicate that no PIN has been provided. */
safeZeroField(packet,*packet_len,SIDDIDFIELD_LEN); *packet_len+=SIDDIDFIELD_LEN;
safeZeroField(packet,*packet_len,16); *packet_len+=16;
safeZeroField(packet,*packet_len,16); *packet_len+=16;
return 0;
}
int packetSetDid(unsigned char *packet,int packet_maxlen,int *packet_len,char *did)
{
/* Set the subject field to the supplied DID.
DIDs get encoded 4bits per digit (0-9,#,*,+,SPARE1,ESCAPE,END)
*/
int ofs=OFS_SIDDIDFIELD; /* where the DID/subscriber ID gets written */
/* Put DID (ie not SID) marker into packet */
packet[ofs++]=0x00;
return stowDid(packet,&ofs,did);
}
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)
{
/* Add any padding bytes and EOT to packet */
int paddingBytes=rand()&0xf;
int payloadRotation;
if (paddingBytes)
{
CHECK_PACKET_LEN(2+paddingBytes);
packet[(*packet_len)++]=ACTION_PAD;
packet[(*packet_len)++]=paddingBytes;
while(paddingBytes--) packet[(*packet_len)++]=random()&0xff;
}
/* tell requester what the ttl was when we received the packet */
if (recvttl>-1) {
CHECK_PACKET_LEN(2);
packet[(*packet_len)++]=ACTION_RECVTTL;
packet[(*packet_len)++]=recvttl;
}
/* mark end of packet */
CHECK_PACKET_LEN(1);
packet[(*packet_len)++]=ACTION_EOT;
/* Set payload length */
packet[4]=((*packet_len)>>8)&0xff;
packet[5]=((*packet_len)&0xff);
/* Work out by how much to rotate the packet payload.
The purpose of the rotation is to make it more difficult to
conduct a known-plaintext attack against any ciphers that we
may later support.
*/
payloadRotation=(*packet_len)-HEADERFIELDS_LEN;
if (payloadRotation>0xff) payloadRotation=0xff;
payloadRotation=random()%payloadRotation;
if (debug&DEBUG_SECURITY) {
DEBUGF("Known Plaintext counter-measure: rotating packet payload by 0x%02x bytes",
payloadRotation);
dump("unrotated packet",packet,*packet_len);
}
/* Now rotate the payload */
{
unsigned char temp[256];
/*Copy first part of payload to a temporary buffer */
bcopy(&packet[HEADERFIELDS_LEN],&temp[0],payloadRotation);
/* Copy the main part of the payload left by the rotation factor */
bcopy(&packet[HEADERFIELDS_LEN+payloadRotation],&packet[HEADERFIELDS_LEN],
(*packet_len)-(HEADERFIELDS_LEN)-payloadRotation);
/* Copy the temporary buffer to the end of the packet to complete the rotation */
bcopy(&temp[0],&packet[(*packet_len)-payloadRotation],payloadRotation);
}
packet[OFS_ROTATIONFIELD]=payloadRotation;
if (debug&DEBUG_SECURITY) dump("rotated packet",packet,*packet_len);
if (cryptoflags) return packetEncipher(packet,packet_maxlen,packet_len,cryptoflags);
return 0;
}
int extractRequest(unsigned char *packet,int *packet_ofs,int packet_len,
int *itemId,int *instance,unsigned char *value,
int *start_offset,int *bytes,int *flags)
{
if (*packet_ofs<0||(*packet_ofs)+6>=packet_len)
return WHY("mal-formed request packet (packet too short/bad offset)");
*itemId=packet[(*packet_ofs)++];
if ((*itemId)&0x80) *instance=packet[(*packet_ofs)++]; else *instance=0;
if (*instance==0xff) *instance=-1;
*start_offset=packet[(*packet_ofs)++]<<8;
*start_offset|=packet[(*packet_ofs)++];
*bytes=packet[(*packet_ofs)++]<<8;
*bytes|=packet[(*packet_ofs)++];
*flags=packet[(*packet_ofs)++];
if (debug&DEBUG_PACKETFORMATS) DEBUGF("Write flags = 0x%02x",*flags);
if (*packet_ofs<0||(*packet_ofs)+(*bytes)>=packet_len)
{
if (debug&DEBUG_PACKETFORMATS) DEBUGF("Packet offset is %d, length is %d, and asked for %d bytes",*packet_ofs,packet_len,*bytes);
return WHY("mal-formed request packet (too short for claimed data)");
}
bcopy(&packet[*packet_ofs],value,*bytes);
(*packet_ofs)+=*bytes;
return 0;
}
int extractResponses(struct in_addr sender,unsigned char *buffer,int len,struct response_set *responses)
{
int ofs=OFS_PAYLOAD;
struct response *first_response=NULL;
while(ofs<len)
{
/* XXX should allocate responses from a temporary and bounded slab of memory */
struct response *r=calloc(sizeof(struct response),1);
if (!r) exit(WHY("calloc() failed."));
r->code=buffer[ofs];
r->sender=sender;
/* XXX doesn't make sure it is SID instead of DID */
bcopy(&buffer[HEADERFIELDS_LEN+1],r->sid,SID_SIZE);
switch(buffer[ofs])
{
case ACTION_EOT:
if (debug&DEBUG_DNARESPONSES) DEBUGF("Reached response packet EOT");
case ACTION_DECLINED: case ACTION_OKAY:
case ACTION_CREATEHLR:
r->response_len=0; break;
case ACTION_GET:
/* Followed by variable # to fetch.
XXX If variable number >=0x80 then get instance information */
r->response_len=1; break;
case ACTION_ERROR:
r->response_len=buffer[++ofs];
break;
case ACTION_DATA:
/* Extract variable value */
unpackageVariableSegment(&buffer[ofs+1],len-ofs,WITHDATA,r);
break;
case ACTION_DONE:
r->value_offset=buffer[ofs+1];
r->response_len=1;
break;
case ACTION_PAD:
/* Skip padding bytes */
r->response_len=1+buffer[ofs+1];
break;
case ACTION_WROTE:
/* Extract info about the variable segment that was written.
This uses the same format as the request to write it, but without the data */
unpackageVariableSegment(&buffer[ofs+1],len-ofs,WITHOUTDATA,r);
r->response=NULL;
break;
case ACTION_RECVTTL:
r->recvttl=buffer[ofs+1];
r->response_len=1;
/* Attach TTL to other responses from this packet */
{
struct response *rr=first_response;
while(rr) {
rr->recvttl=r->recvttl;
rr=rr->next;
}
}
break;
case ACTION_SET:
case ACTION_DEL:
case ACTION_XFER:
default:
free(r);
if (debug&(DEBUG_DNARESPONSES|DEBUG_PACKETFORMATS)) DEBUGF("Encountered unimplemented response code 0x%02x @ 0x%x",buffer[ofs],ofs);
fixResponses(responses);
return WHY("Encountered unimplemented response type");
}
ofs++;
if (r->response_len) {
/* extract bytes of response */
unsigned char *rr;
if (r->response) rr=r->response; else rr=&buffer[ofs];
r->response=malloc(r->response_len+1);
if (!r->response) exit(WHY("malloc() failed."));
bcopy(&rr[0],r->response,r->response_len);
r->response[r->response_len]=0;
ofs+=r->response_len;
}
/* Work out peer ID */
r->sender=sender;
for(r->peer_id=0;r->peer_id<peer_count;r->peer_id++)
{
if (sender.s_addr==peers[r->peer_id].s_addr) break;
}
if (r->peer_id>peer_count) r->peer_id=-1;
/* Link new response into chain */
if (debug&DEBUG_DNARESPONSES) DEBUGF("Linking response into response set");
r->prev=responses->last_response;
if (responses->last_response)
responses->last_response->next=r;
else
responses->responses=r;
responses->last_response=r;
responses->response_count++;
if (!first_response) first_response=r;
responseFromPeer(responses,r->peer_id);
if (debug&DEBUG_DNARESPONSES) dumpResponses(responses);
}
fixResponses(responses);
return 0;
}
int packageVariableSegment(unsigned char *data,int *dlen,
struct response *h,
int offset,int buffer_size)
{
int bytes;
int dlen_in=*dlen;
if ((buffer_size-(*dlen))<8) return WHY("Insufficient buffer space for packageVariableSegment()");
/* Figure out how many bytes we need to package */
bytes=buffer_size-(*dlen)-8;
if ((h->value_len-offset)<bytes) bytes=h->value_len-offset;
if (bytes<0) bytes=0;
if (debug&DEBUG_PACKETFORMATS) DEBUGF("Packaging %d bytes of variable",bytes);
/* Describe variable */
/* Variable id and instance # (if required) */
data[(*dlen)++]=h->var_id;
if (h->var_id&0x80) data[(*dlen)++]=h->var_instance;
/* Variable length */
data[(*dlen)++]=h->value_len>>8;
data[(*dlen)++]=h->value_len&0xff;
/* Start offset in this segment */
data[(*dlen)++]=(offset>>8)&0xff;
data[(*dlen)++]=offset&0xff;
/* Number of bytes in this segment */
data[(*dlen)++]=(bytes>>8)&0xff;
data[(*dlen)++]=bytes&0xff;
if (debug&DEBUG_PACKETFORMATS) DEBUGF("Packaging %d bytes",bytes);
/* Package the variable value itself (or part thereof) */
bcopy(&h->response[offset],&data[*dlen],bytes);
(*dlen)+=bytes;
if (debug&DEBUG_PACKETFORMATS) dump("Variable segment octets",&data[dlen_in],(*dlen)-dlen_in);
return 0;
}
int unpackageVariableSegment(unsigned char *data,int dlen,int flags,struct response *r)
{
r->response_len=0;
if (dlen<7) return WHY("unpackageVariableSegment() fed insufficient data");
r->var_id=data[r->response_len++];
if (r->var_id&0x80) r->var_instance=data[r->response_len++]; else r->var_instance=0;
if (r->var_instance==0xff) r->var_instance=-1;
r->value_len=data[r->response_len++]<<8;
r->value_len|=data[r->response_len++];
r->value_offset=data[r->response_len++]<<8;
r->value_offset|=data[r->response_len++];
r->value_bytes=data[r->response_len++]<<8;
r->value_bytes|=data[r->response_len++];
r->response=&data[r->response_len];
r->response_len+=r->value_bytes;
if (flags!=WITHOUTDATA)
if (r->response_len>dlen)
return WHY("unpackageVariableSegment() fed insufficient or corrupt data");
return 0;
}

231
peers.c
View File

@ -1,231 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
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.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "serval.h"
char *batman_socket=NULL;
char *batman_peerfile=NULL;
int peer_count=0;
struct in_addr peers[MAX_PEERS];
struct in_addr nominated_peers[256];
int nom_peer_count=0;
int additionalPeer(char *peer)
{
struct in_addr pa;
if (nom_peer_count>255) return WHY("Too many peers. You can only nominate 255 peers in this version.");
pa.s_addr=inet_addr(peer);
if (pa.s_addr==INADDR_NONE) return WHY("Invalid peer address specified.");
nominated_peers[nom_peer_count++]=pa;
return 0;
}
int getBroadcastAddresses(struct in_addr peers[],int *peer_count,int peer_max){
/* The Android ndk doesn't have ifaddrs.h, so we have to use the netlink interface.
However, netlink is only available on Linux, so for BSD systems, e.g., Mac, we
need to use the ifaddrs method.
Also, ifaddrs will work on non-linux systems which is considered critical.
*/
#ifdef HAVE_LINUX_NETLINK_H
// Ask for the address information.
struct {
struct nlmsghdr netlinkHeader;
struct ifaddrmsg msg;
}addrRequest;
char buff[16384];
int netsock;
size_t bytesRead;
struct nlmsghdr *hdr;
if (debug&DEBUG_PEERS) DEBUG("Reading broadcast addresses (linux style)");
netsock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
memset(&addrRequest, 0, sizeof(addrRequest));
addrRequest.netlinkHeader.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
addrRequest.netlinkHeader.nlmsg_type = RTM_GETADDR;
addrRequest.netlinkHeader.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(addrRequest)));
addrRequest.msg.ifa_family = AF_INET;
addrRequest.msg.ifa_index = 0; // All interfaces.
while (send(netsock, &addrRequest, addrRequest.netlinkHeader.nlmsg_len, 0)==EINTR);
while(1){
while((bytesRead = recv(netsock, buff, sizeof(buff), 0))==EINTR);
if (bytesRead<=0) break;
for (hdr = (struct nlmsghdr*)buff;
NLMSG_OK(hdr, (size_t)bytesRead);
hdr = NLMSG_NEXT(hdr, bytesRead)) {
switch (hdr->nlmsg_type) {
case NLMSG_DONE:
return 0;
case NLMSG_ERROR:
return -1;
case RTM_NEWADDR:
{
struct ifaddrmsg* address = (struct ifaddrmsg*)(NLMSG_DATA(hdr));
struct rtattr* rta = IFA_RTA(address);
size_t ifaPayloadLength = IFA_PAYLOAD(hdr);
while (RTA_OK(rta, ifaPayloadLength)) {
if (rta->rta_type == IFA_BROADCAST && address->ifa_family == AF_INET) {
struct in_addr *addr=(struct in_addr *)RTA_DATA(rta);
peers[(*peer_count)++].s_addr=addr->s_addr;
}
rta = RTA_NEXT(rta, ifaPayloadLength);
}
}
break;
}
}
}
#else
#ifdef HAVE_IFADDRS_H
struct ifaddrs *ifaddr,*ifa;
int family;
if (debug&DEBUG_PEERS) DEBUG("Reading broadcast addresses (posix style)");
if (getifaddrs(&ifaddr) == -1) {
return WHY_perror("getifaddr");
}
for (ifa=ifaddr;ifa!=NULL;ifa=ifa->ifa_next) {
family=ifa->ifa_addr->sa_family;
switch(family) {
case AF_INET:
/* Add our local address and computed broadcast address to the list of peers.
XXX - ifa->ifa_broadaddr should give us the broadcast address, but doesn't seem to
on mac osx. So we have resorted computing the normal (ceiling) broadcast address.
*/
peers[(*peer_count)++].s_addr=((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
{
unsigned int local=(((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr);
unsigned int netmask=(((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr.s_addr);
peers[(*peer_count)++].s_addr=local|~netmask;
}
break;
}
}
#else
if (debug&DEBUG_PEERS) DEBUG("Don't know how to read broadcast addresses :(");
#endif
#endif
return 0;
}
int getPeerList()
{
/* Generate the list of known peers.
If using BATMAN layer 3, this needs to be the list of exact IP addresses of the peers,
as we cannot reliably broadcast.
Once BATMAN Advanced is available, we will be able to do that.
In the mean time, we need to query BATMANd to find the known list of peers. This is not
quite as easy as we might wish.
*/
int i;
peer_count=0;
/* Add user specified peers */
for(i=0;i<nom_peer_count;i++) peers[peer_count++]=nominated_peers[i];
/* Add ourselves as a peer */
peers[peer_count++].s_addr=inet_addr("127.0.0.1");
/* Add broadcast address of every running interface */
getBroadcastAddresses(peers,&peer_count,MAX_PEERS);
/* XXX Query BATMANd for other peers */
if (batman_peerfile)
readBatmanPeerFile(batman_peerfile,peers,&peer_count,MAX_PEERS);
else if (batman_socket)
getBatmanPeerList(batman_socket,peers,&peer_count,MAX_PEERS);
else
readRoutingTable(peers,&peer_count,MAX_PEERS);
/* Read ARP table for good measure as a defence against transient loss of broadcast reception,
e.g., when screens go off on phones. */
readArpTable(peers,&peer_count,MAX_PEERS);
return 0;
}
int sendToPeers(unsigned char *packet,int packet_len,int method,int peerId,struct response_set *r)
{
/* The normal version of BATMAN works at layer 3, so we cannot simply use an ethernet broadcast
to get the message out. BATMAN Advanced might solve this, though.
So, in the mean time, we need to explicitly send the request to each peer.
We don't want to bother the peers who have already responded.
*/
int i;
int maxPeer=peer_count-1;
int n=0;
int ret;
struct sockaddr_in peer_addr;
bzero(&peer_addr, sizeof(peer_addr));
peer_addr.sin_family=AF_INET;
peer_addr.sin_port = htons(PORT_DNA);
if (method==REQ_PARALLEL) i=0; else { i=peerId; maxPeer=i; }
for(;i<=maxPeer;i++)
if (!responseFromPeerP(r,i))
{
peer_addr.sin_addr=peers[i];
if (debug&(DEBUG_PACKETTX|DEBUG_PEERS)) DEBUGF("Sending packet to peer #%d",i);
ret=sendto(sock,packet,packet_len,0,(struct sockaddr *)&peer_addr,sizeof(peer_addr));
if (ret<packet_len)
{
/* XXX something bad happened */
if (debug&(DEBUG_PACKETTX|DEBUG_PEERS)) DEBUGF("Could not send to peer %s",inet_ntoa(peer_addr.sin_addr));
}
else
{
if (debug&(DEBUG_PACKETTX|DEBUG_PEERS)) DEBUGF("Sent request to peer %s",inet_ntoa(peer_addr.sin_addr));
n++;
/* If sending to only one peer, return now */
if (method==i) break;
}
}
else
if (debug&DEBUG_PEERS) DEBUGF("Peer %s has already replied, so not sending again",
inet_ntoa(peer_addr.sin_addr));
if (debug&DEBUG_PEERS) DEBUGF("Sent request to %d peers",n);
return 0;
}

View File

@ -1,128 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
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.
*/
#include "serval.h"
int dumpResponses(struct response_set *responses)
{
struct response *r;
if (!responses) {
DEBUG("Response set is NULL");
return 0;
}
DEBUGF("Response set claims to contain %d entries.", responses->response_count);
r = responses->responses;
while(r) {
DEBUGF(" response code 0x%02x", r->code);
if (r->next && r->next->prev != r)
DEBUG(" !! response chain is broken");
r = r->next;
}
return 0;
}
int clearResponse(struct response **response)
{
while(*response)
{
struct response *r=*response;
*response=(*response)->next;
if (r->response) free(r->response);
r->response=NULL;
free(r);
}
return 0;
}
int eraseLastResponse(struct response_set *responses)
{
if (!responses) return -1;
if (responses->last_response)
{
struct response *newtail;
if (responses->last_response->prev) responses->last_response->prev->next=NULL;
newtail=responses->last_response->prev;
if (responses->responses==responses->last_response) responses->responses=NULL;
clearResponse(&responses->last_response);
responses->last_response=newtail;
responses->response_count--;
}
return 0;
}
int responseFromPeer(struct response_set *responses,int peerId)
{
int byte;
int bit;
if (peerId<0||peerId>=peer_count) return -1;
if (!responses) return -1;
if (!responses->reply_bitmask)
{
responses->reply_bitmask=calloc(1,(peer_count>>3)+(peer_count&7)?1:0);
if (!responses->reply_bitmask) return -1;
}
byte=peerId>>3;
bit=peerId&7;
responses->reply_bitmask[byte]|=1<<bit;
return 0;
}
int responseFromPeerP(struct response_set *responses,int peerId)
{
int byte;
int bit;
if (!responses) return 0;
if (!responses->reply_bitmask) return 0;
if (peerId<0||peerId>=peer_count) return 0;
byte=peerId>>3;
bit=peerId&7;
return responses->reply_bitmask[byte]&(1<<bit);
}
int clearResponses(struct response_set *responses)
{
struct response *r;
if (!responses) return -1;
r=responses->responses;
while(r)
{
struct response *rr=r;
r=r->next;
free(rr);
}
if (responses->reply_bitmask) free(responses->reply_bitmask);
responses->reply_bitmask=NULL;
responses->last_response=NULL;
responses->responses=NULL;
responses->response_count=0;
return 0;
}

121
serval.h
View File

@ -452,13 +452,7 @@ int strn_is_did(const char *did, size_t *lenp);
int str_is_uri(const char *uri);
int stowSid(unsigned char *packet, int ofs, const char *sid);
int stowDid(unsigned char *packet,int *ofs,char *did);
int isFieldZeroP(unsigned char *packet,int start,int count);
void srandomdev();
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);
time_ms_t gettime_ms();
time_ms_t sleep_ms(time_ms_t milliseconds);
int server_pid();
@ -474,87 +468,11 @@ void insertTransactionInCache(unsigned char *transaction_id);
int packetOk(struct overlay_interface *interface,unsigned char *packet, size_t len,
unsigned char *transaction_id, int recvttl,
struct sockaddr *recvaddr, size_t recvaddrlen,int parseP);
int process_packet(unsigned char *packet, size_t len, int recvttl,struct sockaddr *sender, size_t 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 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 packetGetID(unsigned char *packet,int len,char *did,char *sid);
int getPeerList();
struct response {
int code;
unsigned char sid[SID_SIZE];
struct in_addr sender;
int recvttl;
unsigned char *response;
int response_len;
int var_id;
int var_instance;
int value_len;
int value_offset;
int value_bytes;
struct response *next,*prev;
/* who sent it? */
unsigned short peer_id;
/* have we checked it to see if it allows us to stop requesting? */
unsigned char checked;
};
struct response_set {
struct response *responses;
struct response *last_response;
int response_count;
/* Bit mask of peers who have replied */
unsigned char *reply_bitmask;
};
int clearResponse(struct response **response);
int clearResponses(struct response_set *responses);
int fixResponses(struct response_set *responses);
int dumpResponses(struct response_set *responses);
int eraseLastResponse(struct response_set *responses);
int responseFromPeerP(struct response_set *responses,int peerId);
int responseFromPeer(struct response_set *responses,int peerId);
int extractResponses(struct in_addr sender,unsigned char *buffer,int len,struct response_set *responses);
int sendToPeers(unsigned char *packet,int packet_len,int method,int peerId,struct response_set *responses);
int getReplyPackets(int method,int peer,int batchP,struct response_set *responses,
unsigned char *transaction_id,struct sockaddr *recvaddr,int timeout);
int packageVariableSegment(unsigned char *data, int *dlen, struct response *h, int offset, int buffer_size);
int unpackageVariableSegment(unsigned char *data, int dlen, int flags, struct response *r);
int packetDecipher(unsigned char *packet,int len,int cipher);
int safeZeroField(unsigned char *packet,int start,int count);
int extractSid(const unsigned char *packet,int *ofs, char *sid);
int extractDid(unsigned char *packet,int *ofs,char *did);
int processRequest(unsigned char *packet,int len,struct sockaddr *sender,int sender_len,
unsigned char *transaction_id,int recvttl,char *did,char *sid);
int extractRequest(unsigned char *packet,int *packet_ofs,int packet_len,
int *itemId,int *instance,unsigned char *value,
int *start_offset,int *max_offset,int *flags);
int dropPacketP(size_t packet_len);
int additionalPeer(char *peer);
int readRoutingTable(struct in_addr peers[],int *peer_count,int peer_max);
int readBatmanPeerFile(char *file_path,struct in_addr peers[],int *peer_count,int peer_max);
int getBatmanPeerList(char *socket_path,struct in_addr peers[],int *peer_count,int peer_max);
int asteriskObtainGateway(char *requestor_sid,char *did,char *uri_out);
int packetOkDNA(unsigned char *packet,int len,unsigned char *transaction_id,
int recvttl,struct sockaddr *recvaddr, size_t recvaddrlen,int parseP);
int overlay_forward_payload(struct overlay_frame *f);
int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, size_t len,
unsigned char *transaction_id,int recvttl,
struct sockaddr *recvaddr, size_t recvaddrlen,int parseP);
int prepareGateway(char *gatewayspec);
int packetSendRequest(int method,unsigned char *packet,int packet_len,int batchP,
unsigned char *transaction_id,struct sockaddr *recvaddr,
struct response_set *responses);
int readArpTable(struct in_addr peers[],int *peer_count,int peer_max);
int overlay_frame_process(struct overlay_interface *interface, struct overlay_frame *f);
int overlay_frame_resolve_addresses(struct overlay_frame *f);
@ -564,7 +482,6 @@ int overlay_frame_resolve_addresses(struct overlay_frame *f);
#define alloca_tohex_sas(sas) alloca_tohex((sas), SAS_SIZE)
time_ms_t overlay_time_until_next_tick();
int overlay_rx_messages();
int overlay_add_selfannouncement();
int overlay_frame_append_payload(overlay_interface *interface, struct overlay_frame *p, struct subscriber *next_hop, struct overlay_buffer *b);
@ -613,9 +530,7 @@ typedef struct overlay_node {
int overlay_route_saw_selfannounce_ack(struct overlay_frame *f, time_ms_t now);
int overlay_route_saw_selfannounce(struct overlay_frame *f, time_ms_t now);
overlay_node *overlay_route_find_node(const unsigned char *sid,int prefixLen,int createP);
unsigned int overlay_route_hash_sid(const unsigned char *sid);
int packetEncipher(unsigned char *packet,int maxlen,int *len,int cryptoflags);
int overlayServerMode();
int overlay_payload_enqueue(struct overlay_frame *p);
int overlay_route_record_link( time_ms_t now,unsigned char *to,
@ -637,44 +552,8 @@ int serval_packetvisualise(XPRINTF xpf, const char *message, const unsigned char
int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
int rhizome_opendb();
typedef struct dna_identity_status {
char sid[SID_STRLEN];
char did[64+1];
char name[255+1];
int initialisedP;
time_t startofvalidity;
time_t endofvalidity;
int verifier_count;
/* Dynamically allocate these so that we don't waste a memory
(well, if we are talking about running on a feature phone, 4KB per entry
(16*256 bytes) is best avoided if we can.) */
unsigned char *verifiers[MAX_SIGNATURES];
int verificationStatus;
/* Set if we know that there are no duplicates of this DID/name
combination, as it allows us to avoid a database lookup. */
int uniqueDidAndName;
} dna_identity_status;
int parseCommandLine(const char *argv0, int argc, const char *const *argv);
dna_identity_status *dnacache_lookup(char *did,char *name,char *sid);
dna_identity_status *dnacache_lookup_next();
int dnacache_update_verification(char *did,char *sid,char *name,
char *signature,int revokeVerificationP);
int dnacache_vouch_for_identity(char *did,char *sid,char *name);
#undef DEBUG_MEM_ABUSE
#ifdef DEBUG_MEM_ABUSE
int memabuseInit();
int _memabuseCheck(const char *func,const char *file,const int line);
#define memabuseCheck() _memabuseCheck(__FUNCTION__,__FILE__,__LINE__)
#else
#define memabuseInit() /* */
#define memabuseCheck() /* */
#endif
int form_serval_instance_path(char * buf, size_t bufsiz, const char *path);
int create_serval_instance_dir();

406
server.c
View File

@ -41,16 +41,9 @@ int servalShutdown = 0;
static int server_getpid = 0;
char *instrumentation_file=NULL;
FILE *i_f=NULL;
struct in_addr client_addr;
int client_port;
void signal_handler(int signal);
void crash_handler(int signal);
int getKeyring(char *s);
int createServerSocket();
/** Return the PID of the currently running server process, return 0 if there is none.
*/
@ -126,15 +119,6 @@ int server(char *backing_file)
sigaction(SIGINT, &sig, NULL);
sigaction(SIGQUIT, &sig, NULL);
if (!overlayMode)
{
/* Create a simple socket for listening on if we are not in overlay mesh mode. */
createServerSocket();
/* Get backing store for keyring (overlay sets it up itself) */
getKeyring(backing_file);
}
/* Record PID to advertise that the server is now running */
char filename[1024];
if (!FORM_SERVAL_INSTANCE_PATH(filename, PIDFILE_NAME))
@ -379,8 +363,6 @@ void crash_handler(int signal)
dump_stack();
BACKTRACE;
if (serverRespawnOnCrash) {
if (sock>-1)
close(sock);
int i;
for(i=0;i<overlay_interface_count;i++)
if (overlay_interfaces[i].alarm.poll.fd>-1)
@ -424,391 +406,3 @@ int getKeyring(char *backing_file)
return 0;
}
int processRequest(unsigned char *packet,int len,
struct sockaddr *sender,int sender_len,
unsigned char *transaction_id,int recvttl, char *did,char *sid)
{
/* Find HLR entry by DID or SID, unless creating */
int prev_pofs=0;
int pofs=OFS_PAYLOAD;
while (pofs < len) {
if (debug & DEBUG_DNARESPONSES)
DEBUGF("len=%d, pofs=%d, pofs_prev=%d",len,pofs,prev_pofs);
/* Avoid infinite loops */
if (pofs<=prev_pofs) break;
prev_pofs=pofs;
if (debug & DEBUG_DNARESPONSES)
DEBUGF("action code 0x%02x @ packet offset 0x%x", packet[pofs], pofs);
switch (packet[pofs]) {
case ACTION_CREATEHLR: {
/* Creating an HLR requires an initial DID number and definitely no SID -
you can't choose a SID. */
if (debug & DEBUG_DNARESPONSES)
DEBUGF("Creating a new HLR record. did='%s', sid='%s'",did,sid);
if (!did[0] || sid[0])
return respondSimple(NULL, ACTION_DECLINED, NULL, 0, transaction_id, recvttl, sender, CRYPT_CIPHERED|CRYPT_SIGNED);
if (debug & DEBUG_DNARESPONSES)
DEBUG("Verified that create request supplies DID but not SID");
/* 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, "Mr. Smith");
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;
}
break;
case ACTION_PAD: /* Skip padding */
pofs++;
pofs+=1+packet[pofs];
break;
case ACTION_EOT: /* EOT */
pofs=len;
break;
case ACTION_STATS: {
/* short16 variable id,
int32 value */
pofs++;
short field=packet[pofs+1]+(packet[pofs]<<8);
int value=packet[pofs+5]+(packet[pofs+4]<<8)+(packet[pofs+3]<<16)+(packet[pofs+2]<<24);
pofs+=6;
if (instrumentation_file)
{
if (!i_f) { if (strcmp(instrumentation_file,"-")) i_f=fopen(instrumentation_file,"a"); else i_f=stdout; }
if (i_f) fprintf(i_f,"%ld:%02x%02x%02x%02x:%d:%d\n",(long)time(0),sender->sa_data[0],sender->sa_data[1],sender->sa_data[2],sender->sa_data[3],field,value);
if (i_f) fflush(i_f);
}
}
break;
case ACTION_SET:
WHY("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);
break;
case ACTION_GET: {
/* Limit transfer size to MAX_DATA_BYTES, plus an allowance for variable packing. */
unsigned char data[MAX_DATA_BYTES+16];
int dlen=0;
int sendDone=0;
if (debug&DEBUG_DNARESPONSES)
dump("Request bytes", &packet[pofs], 8);
pofs++;
int var_id=packet[pofs];
int instance=-1;
if (var_id&0x80) instance=packet[++pofs];
if (instance==0xff) instance=-1;
pofs++;
int offset=(packet[pofs]<<8)+packet[pofs+1]; pofs+=2;
keyring_identity *responding_id=NULL;
pofs+=2;
if (debug&DEBUG_DNARESPONSES) {
DEBUGF("Processing ACTION_GET (var_id=%02x, instance=%02x, pofs=0x%x, len=%d)",var_id,instance,pofs,len);
DEBUGF("Looking for identities with sid=%s did='%s'", (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);
}
{
int cn=0,in=0,kp=0;
int found=0;
int count=0;
while(cn<keyring->context_count) {
found=0;
if (sid&&sid[0]) {
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);
}
struct response r;
unsigned char packedDid[64];
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:
/* We need to pack the DID before sending off */
r.value_len=0;
stowDid(packedDid,&r.value_len,
(char *)keyring->contexts[cn]->identities[in]
->keypairs[kp]->private_key);
r.response=packedDid;
break;
case VAR_LOCATIONS:
r.response=(unsigned char *)"4000@";
r.value_len=strlen((char *)r.response);
break;
}
/* 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 WHY("packageVariableSegment() failed.");
responding_id = keyring->contexts[cn]->identities[in];
/* Remember that we need to send this new packet */
sendDone++;
count++;
}
/* look for next record.
Here the placing of DONE at the end of the response stream
becomes challenging, as we may be responding as multiple
identities. This means we have to DONE after each identity. */
int lastin=in,lastcn=cn;
kp++;
keyring_sanitise_position(keyring,&cn,&in,&kp);
if (lastin!=in||lastcn!=cn) {
/* moved off last identity, so send waiting packet if there is
one. */
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);
}
sendDone=0;
}
}
}
/* 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 WHY("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? */
}
}
}
break;
default:
if (debug & DEBUG_PACKETFORMATS) {
DEBUGF("Asked to perform unsipported action at Packet offset = 0x%x", pofs);
dump("Packet", packet, len);
}
return WHY("unsupported action");
}
}
return 0;
}
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)
{
unsigned char packet[8000];
int pl=0;
int *packet_len=&pl;
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 WHY("Crypto-flags not set.");
/* 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. */
if (action==ACTION_ERROR) {
action_len=strlen((char *)action_text);
/* Make sure the error text isn't too long.
IF it is, trim it, as we still need to communicate the error */
if (action_len>255) action_len=255;
}
/* Prepare the request packet */
if (packetMakeHeader(packet,8000,packet_len,transaction_id,cryptoFlags))
return WHY("packetMakeHeader() failed.");
if (id)
{ if (packetSetSidFromId(packet,8000,packet_len,id))
return WHY("invalid SID in reply"); }
else
{ if (packetSetDid(packet,8000,packet_len,""))
return WHY("Could not set empty DID in reply"); }
CHECK_PACKET_LEN(1+1+action_len);
packet[(*packet_len)++]=action;
if (action==ACTION_ERROR) packet[(*packet_len)++]=action_len;
for(i=0;i<action_len;i++) packet[(*packet_len)++]=action_text[i];
if (debug&DEBUG_DNARESPONSES) dump("Simple response octets",action_text,action_len);
if (packetFinalise(packet,8000,recvttl,packet_len,cryptoFlags))
return WHY("packetFinalise() failed.");
if (debug&DEBUG_DNARESPONSES) DEBUGF("Sending response of %d bytes",*packet_len);
if (packetSendRequest(REQ_REPLY,packet,*packet_len,NONBATCH,transaction_id,recvaddr,NULL))
return WHY("packetSendRequest() failed.");
return 0;
}
int createServerSocket()
{
struct sockaddr_in bind_addr;
sock=socket(PF_INET,SOCK_DGRAM,0);
if (sock<0) {
WHY_perror("socket");
WHY("Could not create UDP socket.");
exit(-3);
}
/* Automatically close socket on calls to exec().
This makes life easier when we restart with an exec after receiving
a bad signal. */
fcntl(sock, F_SETFL,
fcntl(sock, F_GETFL, NULL)|
#ifdef FD_CLOEXEC
FD_CLOEXEC
#else
O_CLOEXEC
#endif
);
int i=1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &i, sizeof(i));
errno=0;
if(setsockopt(sock, IPPROTO_IP, IP_RECVTTL, &i,sizeof(i))<0)
WHY_perror("setsockopt(IP_RECVTTL)");
bind_addr.sin_family = AF_INET;
bind_addr.sin_port = htons( PORT_DNA );
bind_addr.sin_addr.s_addr = htonl( INADDR_ANY );
if(bind(sock,(struct sockaddr *)&bind_addr,sizeof(bind_addr))) {
WHY_perror("bind");
WHYF("MP HLR server could not bind to UDP port %d", PORT_DNA);
exit(-3);
}
return 0;
}
#ifdef DEBUG_MEM_ABUSE
unsigned char groundzero[65536];
int memabuseInitP=0;
int memabuseInit()
{
if (memabuseInitP) {
WARN("memabuseInit() called more than once");
return memabuseCheck();
}
unsigned char *zero=(unsigned char *)0;
int i;
for(i=0;i<65536;i++) {
groundzero[i]=zero[i];
//printf("%04x\n",i);
}
memabuseInitP=1;
return 0;
}
int _memabuseCheck(const char *func,const char *file,const int line)
{
unsigned char *zero=(unsigned char *)0;
int firstAddr=-1;
int lastAddr=-1;
int i;
for(i=0;i<65536;i++) if (groundzero[i]!=zero[i]) {
lastAddr=i;
if (firstAddr==-1) firstAddr=i;
}
if (lastAddr>0) {
WARN("Memory corruption in first 64KB of RAM detected");
DEBUGF(" Changed bytes exist in range 0x%04x - 0x%04x",firstAddr,lastAddr);
dump("Changed memory content",&zero[firstAddr],lastAddr-firstAddr+1);
dump("Initial memory content",&groundzero[firstAddr],lastAddr-firstAddr+1);
sleep(1);
} else {
DEBUGF("All's well at %s() %s:%d",func,file,line);
}
return 0;
}
#endif

View File

@ -1,42 +0,0 @@
/*
Serval Distributed Numbering Architecture (DNA)
Copyright (C) 2010 Paul Gardner-Stephen
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.
*/
#include "serval.h"
double simulatedBER=0;
/*
We use this function to simulate a lossy link so that we can easily bench-test the
retransmission protocols.
*/
int dropPacketP(size_t packet_len)
{
size_t i;
int b;
long berThreshold=0x7fffffff*simulatedBER;
if (!simulatedBER) return 0;
for(i=0;i<packet_len;i++)
for(b=0;b<8;b++)
if (random()<=berThreshold) return 1;
return 0;
}