2012-11-30 01:18:00 +00:00
/*
Copyright ( C ) 2010 - 2012 Paul Gardner - Stephen , Serval Project .
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/stat.h>
# include "serval.h"
2012-12-11 05:29:46 +00:00
# include "conf.h"
2012-11-30 01:18:00 +00:00
# include "str.h"
# include "strbuf.h"
# include "overlay_buffer.h"
# include "overlay_address.h"
# include "overlay_packet.h"
# include "mdp_client.h"
2012-11-30 04:17:27 +00:00
# include "rhizome.h"
2012-11-30 01:18:00 +00:00
# include "crypto.h"
2012-11-30 10:38:06 +00:00
# include "log.h"
2012-11-30 01:18:00 +00:00
2012-11-30 03:47:05 +00:00
int overlay_mdp_service_rhizomerequest ( overlay_mdp_frame * mdp )
{
IN ( ) ;
2012-12-01 00:22:08 +00:00
2012-11-30 11:20:17 +00:00
uint64_t fileOffset =
read_uint64 ( & mdp - > out . payload [ RHIZOME_MANIFEST_ID_BYTES + 8 ] ) ;
uint32_t bitmap =
read_uint32 ( & mdp - > out . payload [ RHIZOME_MANIFEST_ID_BYTES + 8 + 8 ] ) ;
uint16_t blockLength =
read_uint16 ( & mdp - > out . payload [ RHIZOME_MANIFEST_ID_BYTES + 8 + 8 + 4 ] ) ;
2012-12-01 00:22:08 +00:00
if ( blockLength > 1024 ) RETURN ( - 1 ) ;
2012-12-04 06:08:18 +00:00
struct subscriber * source = find_subscriber ( mdp - > out . src . sid , SID_SIZE , 0 ) ;
2012-12-01 00:22:08 +00:00
if ( 0 ) {
DEBUGF ( " Someone sent me a rhizome request via MDP " ) ;
DEBUGF ( " requestor sid = %s " , alloca_tohex_sid ( mdp - > out . src . sid ) ) ;
DEBUGF ( " bundle ID = %s " , alloca_tohex_bid ( & mdp - > out . payload [ 0 ] ) ) ;
DEBUGF ( " manifest version = 0x%llx " ,
read_uint64 ( & mdp - > out . payload [ RHIZOME_MANIFEST_ID_BYTES ] ) ) ;
DEBUGF ( " file offset = 0x%llx " , fileOffset ) ;
DEBUGF ( " bitmap = 0x%08x " , bitmap ) ;
DEBUGF ( " block length = %d " , blockLength ) ;
}
2012-11-30 11:20:17 +00:00
/* Find manifest that corresponds to BID and version.
If we don ' t have this combination , then do nothing .
If we do have the combination , then find the associated file ,
and open the blob so that we can send some of it .
TODO : If we have a newer version of the manifest , and the manifest is a
journal , then the newer version is okay to use to service this request .
*/
long long row_id = - 1 ;
2012-12-04 06:17:45 +00:00
if ( sqlite_exec_int64 ( & row_id , " SELECT rowid FROM FILEBLOBS WHERE id IN (SELECT filehash FROM MANIFESTS WHERE manifests.version=%lld AND manifests.id='%s'); " ,
2012-11-30 11:20:17 +00:00
read_uint64 ( & mdp - > out . payload [ RHIZOME_MANIFEST_ID_BYTES ] ) ,
alloca_tohex_bid ( & mdp - > out . payload [ 0 ] ) ) < 1 )
{
DEBUGF ( " Couldn't find stored file. " ) ;
RETURN ( - 1 ) ;
}
2012-12-01 00:22:08 +00:00
2012-11-30 11:20:17 +00:00
sqlite3_blob * blob = NULL ;
2012-12-04 06:17:45 +00:00
int ret = sqlite3_blob_open ( rhizome_db , " main " , " fileblobs " , " data " ,
2012-11-30 11:20:17 +00:00
row_id , 0 /* read only */ , & blob ) ;
if ( ret ! = SQLITE_OK )
{
DEBUGF ( " Failed to open blob: %s " , sqlite3_errmsg ( rhizome_db ) ) ;
RETURN ( - 1 ) ;
}
2012-12-01 00:22:08 +00:00
int blob_bytes = sqlite3_blob_bytes ( blob ) ;
2012-11-30 11:20:17 +00:00
if ( blob_bytes < fileOffset ) {
sqlite3_blob_close ( blob ) ; blob = NULL ;
RETURN ( - 1 ) ;
}
overlay_mdp_frame reply ;
bzero ( & reply , sizeof ( reply ) ) ;
// Reply is broadcast, so we cannot authcrypt, and signing is too time consuming
// for low devices. The result is that an attacker can prevent rhizome transfers
// if they want to by injecting fake blocks. The alternative is to not broadcast
// back replies, and then we can authcrypt.
2012-12-03 01:20:35 +00:00
// multiple receivers starting at different times, we really need merkle-tree hashing.
// so multiple receivers is not realistic for now. So use non-broadcast unicode
// for now would seem the safest. But that would stop us from allowing multiple
// receivers in the special case where additional nodes begin listening in from the
// beginning.
reply . packetTypeAndFlags = MDP_TX | MDP_NOCRYPT | MDP_NOSIGN ;
2012-11-30 11:20:17 +00:00
reply . out . ttl = 1 ;
bcopy ( my_subscriber - > sid , reply . out . src . sid , SID_SIZE ) ;
reply . out . src . port = MDP_PORT_RHIZOME_RESPONSE ;
2013-01-29 02:12:34 +00:00
int send_broadcast = 1 ;
if ( source ) {
if ( ! ( source - > reachable & REACHABLE_DIRECT ) )
send_broadcast = 0 ;
if ( source - > reachable & REACHABLE_UNICAST & & source - > interface & & source - > interface - > prefer_unicast )
send_broadcast = 0 ;
}
if ( send_broadcast ) {
2012-12-04 06:08:18 +00:00
// send replies to broadcast so that others can hear blocks and record them
// (not that preemptive listening is implemented yet).
memset ( reply . out . dst . sid , 0xff , SID_SIZE ) ;
2013-01-29 02:12:34 +00:00
} else {
// if we get a request from a peer that we can only talk to via unicast, send data via unicast too.
bcopy ( mdp - > out . src . sid , reply . out . dst . sid , SID_SIZE ) ;
2012-12-04 06:08:18 +00:00
}
2013-01-29 02:12:34 +00:00
2012-11-30 11:20:17 +00:00
reply . out . dst . port = MDP_PORT_RHIZOME_RESPONSE ;
2013-01-28 02:35:24 +00:00
reply . out . queue = OQ_OPPORTUNISTIC ;
2012-11-30 11:20:17 +00:00
reply . out . payload [ 0 ] = ' B ' ; // reply contains blocks
// include 16 bytes of BID prefix for identification
2012-11-30 11:22:44 +00:00
bcopy ( & mdp - > out . payload [ 0 ] , & reply . out . payload [ 1 ] , 16 ) ;
2012-11-30 11:20:17 +00:00
// and version of manifest
bcopy ( & mdp - > out . payload [ RHIZOME_MANIFEST_ID_BYTES ] ,
2012-11-30 11:22:44 +00:00
& reply . out . payload [ 1 + 16 ] , 8 ) ;
2012-11-30 11:20:17 +00:00
int i ;
for ( i = 0 ; i < 32 ; i + + )
if ( ! ( bitmap & ( 1 < < ( 31 - i ) ) ) )
{
// calculate and set offset of block
uint64_t blockOffset = fileOffset + i * blockLength ;
2012-11-30 11:22:44 +00:00
write_uint64 ( & reply . out . payload [ 1 + 16 + 8 ] , blockOffset ) ;
2012-11-30 11:20:17 +00:00
// work out how many bytes to read
int blockBytes = blob_bytes - blockOffset ;
if ( blockBytes > blockLength ) blockBytes = blockLength ;
// read data for block
if ( blob_bytes > = blockOffset ) {
2013-01-28 02:35:24 +00:00
if ( overlay_queue_remaining ( reply . out . queue ) < 10 )
break ;
2012-11-30 11:22:44 +00:00
sqlite3_blob_read ( blob , & reply . out . payload [ 1 + 16 + 8 + 8 ] ,
2012-11-30 12:15:27 +00:00
blockBytes , blockOffset ) ;
2012-11-30 11:22:44 +00:00
reply . out . payload_length = 1 + 16 + 8 + 8 + blockBytes ;
2012-11-30 12:12:28 +00:00
// Mark terminal block if required
if ( blockOffset + blockBytes = = blob_bytes ) reply . out . payload [ 0 ] = ' T ' ;
2012-11-30 11:32:10 +00:00
// send packet
2013-01-28 02:35:24 +00:00
if ( overlay_mdp_dispatch ( & reply , 0 /* system generated */ , NULL , 0 ) )
break ;
2012-11-30 11:32:10 +00:00
} else break ;
2012-11-30 11:20:17 +00:00
}
sqlite3_blob_close ( blob ) ; blob = NULL ;
2012-11-30 03:47:05 +00:00
RETURN ( - 1 ) ;
}
int overlay_mdp_service_rhizomeresponse ( overlay_mdp_frame * mdp )
{
IN ( ) ;
2012-11-30 11:32:10 +00:00
if ( ! mdp - > out . payload_length ) RETURN ( - 1 ) ;
int type = mdp - > out . payload [ 0 ] ;
switch ( type ) {
case ' B ' : /* data block */
2012-11-30 12:12:28 +00:00
case ' T ' : /* terminal data block */
2012-11-30 11:32:10 +00:00
{
if ( mdp - > out . payload_length < ( 1 + 16 + 8 + 8 + 1 ) ) RETURN ( - 1 ) ;
2012-11-30 11:56:31 +00:00
unsigned char * bidprefix = & mdp - > out . payload [ 1 ] ;
2012-11-30 11:32:10 +00:00
uint64_t version = read_uint64 ( & mdp - > out . payload [ 1 + 16 ] ) ;
uint64_t offset = read_uint64 ( & mdp - > out . payload [ 1 + 16 + 8 ] ) ;
2012-11-30 11:56:31 +00:00
int count = mdp - > out . payload_length - ( 1 + 16 + 8 + 8 ) ;
unsigned char * bytes = & mdp - > out . payload [ 1 + 16 + 8 + 8 ] ;
2012-11-30 21:07:22 +00:00
if ( 0 )
DEBUGF ( " Received %d bytes @ 0x%llx for %s* version 0x%llx " ,
count , offset , alloca_tohex ( bidprefix , 16 ) , version ) ;
2012-11-30 11:56:31 +00:00
/* Now see if there is a slot that matches. If so, then
see if the bytes are in the window , and write them .
If there is not matching slot , then consider setting
a slot to capture this files as it is being requested
by someone else .
*/
2012-11-30 12:12:28 +00:00
rhizome_received_content ( bidprefix , version , offset , count , bytes , type ) ;
2012-11-30 11:56:31 +00:00
2012-11-30 11:32:10 +00:00
RETURN ( - 1 ) ;
}
break ;
}
2012-11-30 03:47:05 +00:00
RETURN ( - 1 ) ;
}
2012-11-30 01:18:00 +00:00
int overlay_mdp_service_dnalookup ( overlay_mdp_frame * mdp )
{
IN ( ) ;
int cn = 0 , in = 0 , kp = 0 ;
char did [ 64 + 1 ] ;
int pll = mdp - > out . payload_length ;
if ( pll > 64 ) pll = 64 ;
/* get did from the packet */
if ( mdp - > out . payload_length < 1 ) {
RETURN ( WHY ( " Empty DID in DNA resolution request " ) ) ; }
bcopy ( & mdp - > out . payload [ 0 ] , & did [ 0 ] , pll ) ;
did [ pll ] = 0 ;
2012-12-11 05:29:46 +00:00
if ( config . debug . mdprequests )
2012-11-30 01:18:00 +00:00
DEBUG ( " MDP_PORT_DNALOOKUP " ) ;
int results = 0 ;
while ( keyring_find_did ( keyring , & cn , & in , & kp , did ) )
{
/* package DID and Name into reply (we include the DID because
it could be a wild - card DID search , but the SID is implied
in the source address of our reply ) . */
if ( keyring - > contexts [ cn ] - > identities [ in ] - > keypairs [ kp ] - > private_key_len > DID_MAXSIZE )
/* skip excessively long DID records */
continue ;
const unsigned char * packedSid = keyring - > contexts [ cn ] - > identities [ in ] - > keypairs [ 0 ] - > public_key ;
const char * unpackedDid = ( const char * ) keyring - > contexts [ cn ] - > identities [ in ] - > keypairs [ kp ] - > private_key ;
const char * name = ( const char * ) keyring - > contexts [ cn ] - > identities [ in ] - > keypairs [ kp ] - > public_key ;
// URI is sid://SIDHEX/DID
strbuf b = strbuf_alloca ( SID_STRLEN + DID_MAXSIZE + 10 ) ;
strbuf_puts ( b , " sid:// " ) ;
strbuf_tohex ( b , packedSid , SID_SIZE ) ;
strbuf_puts ( b , " /local/ " ) ;
strbuf_puts ( b , unpackedDid ) ;
overlay_mdp_dnalookup_reply ( & mdp - > out . src , packedSid , strbuf_str ( b ) , unpackedDid , name ) ;
kp + + ;
results + + ;
}
if ( ! results ) {
/* No local results, so see if servald has been configured to use
a DNA - helper that can provide additional mappings . This provides
a generalised interface for resolving telephone numbers into URIs .
The first use will be for resolving DIDs to SIP addresses for
OpenBTS boxes run by the OTI / Commotion project .
The helper is run asynchronously , and the replies will be delivered
when results become available , so this function will return
immediately , so as not to cause blockages and delays in servald .
*/
dna_helper_enqueue ( mdp , did , mdp - > out . src . sid ) ;
monitor_tell_formatted ( MONITOR_DNAHELPER , " LOOKUP:%s:%d:%s \n " ,
alloca_tohex_sid ( mdp - > out . src . sid ) , mdp - > out . src . port ,
did ) ;
}
RETURN ( 0 ) ;
}
int overlay_mdp_service_echo ( overlay_mdp_frame * mdp )
{
/* Echo is easy: we swap the sender and receiver addresses (and thus port
numbers ) and send the frame back . */
IN ( ) ;
/* Swap addresses */
overlay_mdp_swap_src_dst ( mdp ) ;
mdp - > out . ttl = 0 ;
/* Prevent echo:echo connections and the resulting denial of service from triggering endless pongs. */
if ( mdp - > out . dst . port = = MDP_PORT_ECHO ) {
RETURN ( WHY ( " echo loop averted " ) ) ;
}
/* If the packet was sent to broadcast, then replace broadcast address
with our local address . For now just responds with first local address */
if ( is_sid_broadcast ( mdp - > out . src . sid ) )
{
if ( my_subscriber )
bcopy ( my_subscriber - > sid ,
mdp - > out . src . sid , SID_SIZE ) ;
else
/* No local addresses, so put all zeroes */
bzero ( mdp - > out . src . sid , SID_SIZE ) ;
}
/* Always send PONGs auth-crypted so that the receipient knows
that they are genuine , and so that we avoid the extra cost
of signing ( which is slower than auth - crypting ) */
int preserved = mdp - > packetTypeAndFlags ;
mdp - > packetTypeAndFlags & = ~ ( MDP_NOCRYPT | MDP_NOSIGN ) ;
/* queue frame for delivery */
overlay_mdp_dispatch ( mdp , 0 /* system generated */ ,
NULL , 0 ) ;
mdp - > packetTypeAndFlags = preserved ;
/* and switch addresses back around in case the caller was planning on
using MDP structure again ( this happens if there is a loop - back reply
and the frame needs sending on , as happens with broadcasts . MDP ping
is a simple application where this occurs ) . */
overlay_mdp_swap_src_dst ( mdp ) ;
RETURN ( 0 ) ;
}
2013-02-12 00:04:04 +00:00
static int overlay_mdp_service_manifest_response ( overlay_mdp_frame * mdp ) {
int offset = 0 ;
char id_hex [ RHIZOME_MANIFEST_ID_STRLEN ] ;
rhizome_manifest * m = rhizome_new_manifest ( ) ;
if ( ! m )
return WHY ( " Unable to allocate manifest " ) ;
while ( offset < mdp - > out . payload_length ) {
unsigned char * bar = & mdp - > out . payload [ offset ] ;
tohex ( id_hex , & bar [ RHIZOME_BAR_PREFIX_OFFSET ] , RHIZOME_BAR_PREFIX_BYTES ) ;
strcat ( id_hex , " % " ) ;
if ( ! rhizome_retrieve_manifest ( id_hex , m ) ) {
rhizome_advertise_manifest ( m ) ;
}
offset + = RHIZOME_BAR_BYTES ;
}
rhizome_manifest_free ( m ) ;
return 0 ;
}
2012-11-30 01:18:00 +00:00
int overlay_mdp_try_interal_services ( overlay_mdp_frame * mdp )
{
IN ( ) ;
switch ( mdp - > out . dst . port ) {
2012-11-30 03:47:05 +00:00
case MDP_PORT_VOMP : RETURN ( vomp_mdp_received ( mdp ) ) ;
case MDP_PORT_KEYMAPREQUEST : RETURN ( keyring_mapping_request ( keyring , mdp ) ) ;
case MDP_PORT_DNALOOKUP : RETURN ( overlay_mdp_service_dnalookup ( mdp ) ) ;
case MDP_PORT_ECHO : RETURN ( overlay_mdp_service_echo ( mdp ) ) ;
2012-12-04 04:17:57 +00:00
case MDP_PORT_PROBE : RETURN ( overlay_mdp_service_probe ( mdp ) ) ;
2012-12-07 05:34:40 +00:00
case MDP_PORT_STUNREQ : RETURN ( overlay_mdp_service_stun_req ( mdp ) ) ;
case MDP_PORT_STUN : RETURN ( overlay_mdp_service_stun ( mdp ) ) ;
2012-11-30 04:17:27 +00:00
case MDP_PORT_RHIZOME_REQUEST :
if ( is_rhizome_mdp_server_running ( ) ) {
RETURN ( overlay_mdp_service_rhizomerequest ( mdp ) ) ;
} else break ;
2012-12-04 05:40:17 +00:00
case MDP_PORT_RHIZOME_RESPONSE : RETURN ( overlay_mdp_service_rhizomeresponse ( mdp ) ) ;
2013-02-12 00:04:04 +00:00
case MDP_PORT_RHIZOME_MANIFEST_REQUEST : RETURN ( overlay_mdp_service_manifest_response ( mdp ) ) ;
2012-11-30 01:18:00 +00:00
}
2012-11-30 04:17:27 +00:00
/* Unbound socket. We won't be sending ICMP style connection refused
messages , partly because they are a waste of bandwidth . */
RETURN ( WHYF ( " Received packet for which no listening process exists (MDP ports: src=%d, dst=%d " ,
mdp - > out . src . port , mdp - > out . dst . port ) ) ;
2012-11-30 01:18:00 +00:00
}