mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-01-29 15:43:56 +00:00
Remove dead code
This commit is contained in:
parent
f1b0374b97
commit
f93216f369
@ -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
7
Makefile.in
Normal file → Executable 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
320
batman.c
@ -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(×tamp,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
|
||||
}
|
79
ciphers.c
79
ciphers.c
@ -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
348
client.c
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
176
dna_identity.c
176
dna_identity.c
@ -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");
|
||||
}
|
||||
|
30
dnawrap.c
30
dnawrap.c
@ -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
1
main.c
@ -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]);
|
||||
|
457
packetformats.c
457
packetformats.c
@ -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
231
peers.c
@ -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;
|
||||
|
||||
}
|
128
responses.c
128
responses.c
@ -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
121
serval.h
@ -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
406
server.c
@ -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
|
||||
|
42
simulate.c
42
simulate.c
@ -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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user