mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-04-08 11:34:13 +00:00
Various fixes and work towards MDP ping working.
MDP clients can now request the set of local addresses. Framework is improved to avoid info leaks by sending more bytes in an MDP frame than are necessary, but without having to bzero almost 2KB each time.
This commit is contained in:
parent
d1bb637cba
commit
aa543e1766
@ -368,12 +368,44 @@ int app_mdp_ping(int argc,char **argv,struct command_line_option *o)
|
||||
payload (rest of packet) */
|
||||
overlay_mdp_frame mdp;
|
||||
|
||||
/* Get list of local addresses */
|
||||
mdp.packetTypeAndFlags=MDP_GETADDRS;
|
||||
mdp.addrlist.first_sid=-1;
|
||||
mdp.addrlist.last_sid=0x7fffffff;
|
||||
mdp.addrlist.frame_sid_count=MDP_MAX_SID_REQUEST;
|
||||
int result=overlay_mdp_dispatch(&mdp,MDP_AWAITREPLY,5000);
|
||||
if (result) {
|
||||
if (mdp.packetTypeAndFlags==MDP_ERROR)
|
||||
{
|
||||
fprintf(stderr,"Could not get list of local MDP addresses\n");
|
||||
fprintf(stderr," MDP Server error #%d: '%s'\n",
|
||||
mdp.error.error,mdp.error.message);
|
||||
}
|
||||
else
|
||||
fprintf(stderr,"Could not get list of local MDP addresses\n");
|
||||
return -1;
|
||||
} else {
|
||||
if (mdp.packetTypeAndFlags!=MDP_ADDRLIST)
|
||||
return WHY("MDP Server returned wrong frame type.");
|
||||
fprintf(stderr,"Server returned list of %d local addresses.\n",
|
||||
mdp.addrlist.frame_sid_count);
|
||||
int i;
|
||||
for(i=0;i<mdp.addrlist.frame_sid_count;i++)
|
||||
fprintf(stderr," %s\n",overlay_render_sid(mdp.addrlist.sids[i]));
|
||||
}
|
||||
|
||||
/* Bind to MDP socket and await confirmation */
|
||||
int port=32768+(random()&32767);
|
||||
mdp.packetTypeAndFlags=MDP_BIND;
|
||||
if (0)
|
||||
bzero(&mdp.bind.sid[0],SID_SIZE); // listen on all addressses
|
||||
else
|
||||
/* Listen on a local address.
|
||||
Must be done before setting anything else in mdp.bind, since mdp.bind
|
||||
and mdp.addrlist share storage as a union in the mdp structure. */
|
||||
bcopy(&mdp.addrlist.sids[0][0],mdp.bind.sid,SID_SIZE);
|
||||
mdp.bind.port_number=port;
|
||||
bzero(&mdp.bind.sid[0],SID_SIZE); // listen on all addressses
|
||||
int result=overlay_mdp_dispatch(&mdp,MDP_AWAITREPLY,5000);
|
||||
result=overlay_mdp_dispatch(&mdp,MDP_AWAITREPLY,5000);
|
||||
if (result) {
|
||||
if (mdp.packetTypeAndFlags==MDP_ERROR)
|
||||
fprintf(stderr,"Could not bind to MDP port %d: error=%d, message='%s'\n",
|
||||
@ -387,7 +419,8 @@ int app_mdp_ping(int argc,char **argv,struct command_line_option *o)
|
||||
unsigned int firstSeq=random();
|
||||
unsigned int sequence_number=firstSeq;
|
||||
|
||||
/* Get SID that we want to ping */
|
||||
/* Get SID that we want to ping.
|
||||
XXX - allow lookup of SID prefixes */
|
||||
int i;
|
||||
unsigned char ping_sid[SID_SIZE];
|
||||
if (strcasecmp(sid,"broadcast")) {
|
||||
|
@ -369,7 +369,7 @@ int overlay_frame_process(int interface,overlay_frame *f)
|
||||
overlay_rhizome_saw_advertisements(interface,f,now);
|
||||
break;
|
||||
case OF_TYPE_DATA:
|
||||
overlay_saw_mdp_frame(interface,f,now);
|
||||
overlay_saw_mdp_containing_frame(interface,f,now);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Unsupported f->type=0x%x\n",f->type);
|
||||
|
176
overlay_mdp.c
176
overlay_mdp.c
@ -133,9 +133,20 @@ int overlay_mdp_reply_error(int sock,
|
||||
else
|
||||
snprintf(&mdpreply.error.message[0],128,"Error code #%d",error_number);
|
||||
mdpreply.error.message[127]=0;
|
||||
int replylen=4+4+strlen(mdpreply.error.message)+1;
|
||||
|
||||
return overlay_mdp_reply(sock,recvaddr,recvaddrlen,&mdpreply);
|
||||
}
|
||||
|
||||
int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr,int recvaddrlen,
|
||||
overlay_mdp_frame *mdpreply)
|
||||
{
|
||||
int replylen;
|
||||
|
||||
replylen=overlay_mdp_relevant_bytes(mdpreply);
|
||||
if (replylen<0) return WHY("Invalid MDP frame (could not compute length)");
|
||||
|
||||
errno=0;
|
||||
int r=sendto(sock,(char *)&mdpreply,replylen,0,
|
||||
int r=sendto(sock,(char *)mdpreply,replylen,0,
|
||||
(struct sockaddr *)recvaddr,recvaddrlen);
|
||||
if (r<0) {
|
||||
perror("sendto");
|
||||
@ -163,6 +174,31 @@ int overlay_mdp_process_bind_request(int sock,overlay_mdp_frame *mdp,
|
||||
mdp_bindings_initialised=1;
|
||||
}
|
||||
|
||||
WHY("Doesn't authenticate source address on multi-SID installations like an OpenBTS:mesh gateway)");
|
||||
|
||||
/* Make sure source address is either all zeros (listen on all), or a valid
|
||||
local address */
|
||||
for(i=0;i<SID_SIZE;i++) if (mdp->bind.sid[i]) break;
|
||||
if (i<SID_SIZE) {
|
||||
/* Not all zeroes, so make sure it is a valid SID */
|
||||
int j,ok=0;
|
||||
for(j=0;j<overlay_local_identity_count;j++)
|
||||
{
|
||||
fprintf(stderr,"Comparing %s against local addr ",
|
||||
overlay_render_sid(mdp->bind.sid));
|
||||
fprintf(stderr,"%s\n",
|
||||
overlay_render_sid(overlay_local_identities[j]));
|
||||
for(i=0;i<SID_SIZE;i++)
|
||||
if (mdp->bind.sid[i]!=overlay_local_identities[j][i]) break;
|
||||
if (i==SID_SIZE) { ok=1; break; }
|
||||
}
|
||||
if (!ok) {
|
||||
/* Source address is invalid */
|
||||
return overlay_mdp_reply_error(sock,recvaddr,recvaddrlen,7,
|
||||
"Bind address is not valid (must be a local MDP address, or all zeroes).");
|
||||
}
|
||||
}
|
||||
|
||||
/* See if binding already exists */
|
||||
int found=-1;
|
||||
int free=-1;
|
||||
@ -182,6 +218,7 @@ int overlay_mdp_process_bind_request(int sock,overlay_mdp_frame *mdp,
|
||||
if (!memcmp(mdp_bindings_sockets[found],recvaddr->sun_path,recvaddrlen))
|
||||
{
|
||||
fprintf(stderr,"Identical binding exists");
|
||||
WHY("Need to return binding information to client");
|
||||
return overlay_mdp_reply_ok(sock,recvaddr,recvaddrlen,"Port bound (actually, it was already bound to you)");
|
||||
}
|
||||
/* Okay, so there is an existing binding. Either replace it (if requested) or
|
||||
@ -223,10 +260,16 @@ int overlay_mdp_process_bind_request(int sock,overlay_mdp_frame *mdp,
|
||||
memcpy(&mdp_bindings_sockets[free][0],&recvaddr->sun_path[0],
|
||||
mdp_bindings_socket_name_lengths[free]);
|
||||
fprintf(stderr,"Port bound\n");
|
||||
WHY("Need to return binding information to client");
|
||||
return overlay_mdp_reply_ok(sock,recvaddr,recvaddrlen,"Port bound");
|
||||
}
|
||||
|
||||
int overlay_saw_mdp_frame(int interface,overlay_frame *f,long long now)
|
||||
int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long now)
|
||||
{
|
||||
return WHY("Not implemented");
|
||||
}
|
||||
|
||||
int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
|
||||
{
|
||||
return WHY("Not implemented");
|
||||
}
|
||||
@ -249,18 +292,88 @@ int overlay_mdp_poll()
|
||||
recvaddr,&recvaddrlen);
|
||||
recvaddr_un=(struct sockaddr_un *)recvaddr;
|
||||
|
||||
dump("mdp frame",buffer,len);
|
||||
|
||||
if (len>0) {
|
||||
/* Look at overlay_mdp_frame we have received */
|
||||
overlay_mdp_frame *mdp=(overlay_mdp_frame *)&buffer[0];
|
||||
switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK) {
|
||||
case MDP_GETADDRS:
|
||||
{
|
||||
overlay_mdp_frame mdpreply;
|
||||
|
||||
/* Work out which SIDs to get ... */
|
||||
int sid_num=mdp->addrlist.first_sid;
|
||||
int max_sid=mdp->addrlist.last_sid;
|
||||
int max_sids=mdp->addrlist.frame_sid_count;
|
||||
/* ... and constrain list for sanity */
|
||||
if (sid_num<0) sid_num=0;
|
||||
if (sid_num>overlay_local_identity_count) max_sids=0;
|
||||
if (max_sids>MDP_MAX_SID_REQUEST) max_sids=MDP_MAX_SID_REQUEST;
|
||||
if (max_sids>(overlay_local_identity_count-sid_num))
|
||||
max_sids=overlay_local_identity_count-sid_num;
|
||||
if (max_sid>(overlay_local_identity_count-sid_num))
|
||||
max_sid=overlay_local_identity_count-sid_num;
|
||||
if (max_sids<0) max_sids=0;
|
||||
|
||||
/* Prepare reply packet */
|
||||
mdpreply.packetTypeAndFlags=MDP_ADDRLIST;
|
||||
mdpreply.addrlist.server_sid_count=overlay_local_identity_count;
|
||||
mdpreply.addrlist.first_sid=sid_num;
|
||||
mdpreply.addrlist.last_sid=max_sid;
|
||||
mdpreply.addrlist.frame_sid_count=max_sids;
|
||||
|
||||
/* Populate with SIDs */
|
||||
int i;
|
||||
for(i=0;i<max_sids;i++)
|
||||
bcopy(overlay_local_identities[sid_num+i],
|
||||
mdpreply.addrlist.sids[i],SID_SIZE);
|
||||
|
||||
/* Send back to caller */
|
||||
return overlay_mdp_reply(mdp_named_socket,
|
||||
(struct sockaddr_un *)recvaddr,recvaddrlen,
|
||||
&mdpreply);
|
||||
}
|
||||
break;
|
||||
case MDP_TX: /* Send payload */
|
||||
/* Construct MDP packet frame from overlay_mdp_frame structure
|
||||
(need to add return address from bindings list, and copy
|
||||
payload etc). */
|
||||
{
|
||||
/* Work out if destination is broadcast or not */
|
||||
int i,broadcast=1;
|
||||
for(i=0;i<SID_SIZE;i++) if (mdp->out.dst.sid[i]!=0xff) broadcast=0;
|
||||
int broadcast=1;
|
||||
|
||||
if (overlay_address_is_broadcast(mdp->out.src.sid))
|
||||
{
|
||||
/* This is rather naughty if it happens, since broadcasting a
|
||||
response can lead to all manner of nasty things.
|
||||
Picture a packet with broadcast as the source address, sent
|
||||
to, say, the MDP echo port on another node, and with a source
|
||||
port also of the echo port. Said echo will get multiplied many,
|
||||
many, many times over before the TTL finally reaches zero.
|
||||
So we just say no to any packet with a broadcast source address.
|
||||
(Of course we have other layers of protection against such
|
||||
shenanigens, such as using BPIs to smart-flood broadcasts, but
|
||||
security comes through depth.)
|
||||
*/
|
||||
return WHY("Packet had broadcast address as source address");
|
||||
}
|
||||
|
||||
if (!overlay_address_is_broadcast(mdp->out.dst.sid)) broadcast=0;
|
||||
|
||||
if (overlay_address_is_local(mdp->out.dst.sid)||broadcast)
|
||||
{
|
||||
/* Packet is addressed such that we should process it. */
|
||||
overlay_saw_mdp_frame(-1 /* not received on a network interface */,
|
||||
mdp,overlay_gettime_ms());
|
||||
|
||||
if (!broadcast) {
|
||||
/* Is local, and is not broadcast, so shouldn't get sent out
|
||||
on the wire. */
|
||||
WHY("non-broadcast packet delivered locally");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* broadcast packets cannot be encrypted, so complain if MDP_NOCRYPT
|
||||
flag is not set. Also, MDP_NOSIGN must also be applied, until
|
||||
@ -385,6 +498,45 @@ int overlay_mdp_poll()
|
||||
return -1;
|
||||
}
|
||||
|
||||
int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp)
|
||||
{
|
||||
int len=4;
|
||||
switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK)
|
||||
{
|
||||
case MDP_ADDRLIST: len=4
|
||||
+sizeof(mdp->addrlist.frame_sid_count)
|
||||
+sizeof(mdp->addrlist.first_sid)
|
||||
+sizeof(mdp->addrlist.last_sid)
|
||||
+sizeof(mdp->addrlist.server_sid_count)
|
||||
+mdp->addrlist.frame_sid_count*SID_SIZE;
|
||||
break;
|
||||
case MDP_GETADDRS: len=4
|
||||
+sizeof(mdp->addrlist.frame_sid_count)
|
||||
+sizeof(mdp->addrlist.first_sid)
|
||||
+sizeof(mdp->addrlist.last_sid)
|
||||
+sizeof(mdp->addrlist.server_sid_count);
|
||||
break;
|
||||
case MDP_TX:
|
||||
len=4+sizeof(mdp->out)
|
||||
-sizeof(mdp->out.payload)
|
||||
+mdp->out.payload_length;
|
||||
break;
|
||||
case MDP_RX:
|
||||
len=4+sizeof(mdp->in)
|
||||
-sizeof(mdp->in.payload)
|
||||
+mdp->in.payload_length; break;
|
||||
case MDP_BIND: len=4+sizeof(mdp->bind); break;
|
||||
case MDP_ERROR:
|
||||
/* This formulation is used so that we don't copy any bytes after the
|
||||
end of the string, to avoid information leaks */
|
||||
len=4+4+strlen(mdp->error.message)+1; break;
|
||||
default:
|
||||
fprintf(stderr,"mdp frame type=0x%x\n",mdp->packetTypeAndFlags);
|
||||
return WHY("Illegal MDP frame type.");
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
int mdp_client_socket=-1;
|
||||
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int flags,int timeout_ms)
|
||||
{
|
||||
@ -394,15 +546,8 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int flags,int timeout_ms)
|
||||
|
||||
/* Minimise frame length to save work and prevent accidental disclosure of
|
||||
memory contents. */
|
||||
switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK)
|
||||
{
|
||||
case MDP_TX: len=4+sizeof(mdp->out)+mdp->out.payload_length; break;
|
||||
case MDP_RX: len=4+sizeof(mdp->in)+mdp->out.payload_length; break;
|
||||
case MDP_BIND: len=4+4; break;
|
||||
case MDP_ERROR: len=4+4+strlen(mdp->error.message)+1; break;
|
||||
default:
|
||||
return WHY("Illegal MDP frame type.");
|
||||
}
|
||||
len=overlay_mdp_relevant_bytes(mdp);
|
||||
if (len<0) return WHY("MDP frame invalid (could not compute length)");
|
||||
|
||||
/* Construct name of socket to send to. */
|
||||
char mdp_socket_name[101];
|
||||
@ -450,7 +595,8 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int flags,int timeout_ms)
|
||||
if ((mdp->packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR)
|
||||
return mdp->error.error;
|
||||
else
|
||||
return WHY("MDP server replied with something unexpected");
|
||||
/* Something other than an error has been returned */
|
||||
return 0;
|
||||
} else {
|
||||
/* poll() said that there was data, but there isn't.
|
||||
So we will abort. */
|
||||
|
25
serval.h
25
serval.h
@ -901,7 +901,7 @@ int overlay_rhizome_saw_advertisements(int i,overlay_frame *f, long long now);
|
||||
int overlay_route_please_advertise(overlay_node *n);
|
||||
int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
|
||||
int rhizome_server_poll();
|
||||
int overlay_saw_mdp_frame(int interface,overlay_frame *f,long long now);
|
||||
int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long now);
|
||||
|
||||
#include "nacl.h"
|
||||
|
||||
@ -1001,6 +1001,7 @@ typedef struct sockaddr_mdp {
|
||||
#define MDP_NOSIGN 0x0400
|
||||
#define MDP_TX 1
|
||||
typedef struct overlay_mdp_outgoing_frame {
|
||||
sockaddr_mdp src;
|
||||
sockaddr_mdp dst;
|
||||
unsigned short payload_length;
|
||||
unsigned char payload[1900];
|
||||
@ -1026,13 +1027,28 @@ typedef struct overlay_mdp_error {
|
||||
char message[128];
|
||||
} overlay_mdp_error;
|
||||
|
||||
#define MDP_GETADDRS 5
|
||||
#define MDP_ADDRLIST 6
|
||||
typedef struct overlay_mdp_addrlist {
|
||||
unsigned int server_sid_count;
|
||||
unsigned int first_sid;
|
||||
unsigned int last_sid;
|
||||
unsigned char frame_sid_count; /* how many of the following 59 slots are
|
||||
populated */
|
||||
/* 59*32 < 1900, so up to 59 SIDs in a single reply.
|
||||
Multiple replies can be used to respond with more. */
|
||||
#define MDP_MAX_SID_REQUEST 59
|
||||
unsigned char sids[MDP_MAX_SID_REQUEST][SID_SIZE];
|
||||
} overlay_mdp_addrlist;
|
||||
|
||||
typedef struct overlay_mdp_frame {
|
||||
#define MDP_AWAITREPLY 5
|
||||
#define MDP_AWAITREPLY 7
|
||||
unsigned int packetTypeAndFlags;
|
||||
union {
|
||||
overlay_mdp_outgoing_frame out;
|
||||
overlay_mdp_incoming_frame in;
|
||||
overlay_mdp_bind_request bind;
|
||||
overlay_mdp_addrlist addrlist;
|
||||
overlay_mdp_error error;
|
||||
/* 2048 is too large (causes EMSGSIZE errors on OSX, but probably fine on
|
||||
Linux) */
|
||||
@ -1041,6 +1057,7 @@ typedef struct overlay_mdp_frame {
|
||||
} overlay_mdp_frame;
|
||||
|
||||
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int flags,int timeout_ms);
|
||||
int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now);
|
||||
|
||||
|
||||
int setVerbosity(char *optarg);
|
||||
@ -1049,6 +1066,10 @@ int overlay_mdp_client_done();
|
||||
int overlay_mdp_client_poll(long long timeout_ms);
|
||||
int overlay_mdp_recv(overlay_mdp_frame *mdp,int *ttl);
|
||||
extern int mdp_client_socket;
|
||||
int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr,int recvaddrlen,
|
||||
overlay_mdp_frame *mdpreply);
|
||||
int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp);
|
||||
|
||||
|
||||
int ob_bcopy(overlay_buffer *b,int from, int to, int len);
|
||||
int ob_setbyte(overlay_buffer *b,int ofs,unsigned char value);
|
||||
|
Loading…
x
Reference in New Issue
Block a user