diff --git a/commandline.c b/commandline.c index 6c36ada9..2ec6bac2 100644 --- a/commandline.c +++ b/commandline.c @@ -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;itype=0x%x\n",f->type); diff --git a/overlay_mdp.c b/overlay_mdp.c index 87d24410..764941f1 100644 --- a/overlay_mdp.c +++ b/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;ibind.sid[i]) break; + if (ibind.sid)); + fprintf(stderr,"%s\n", + overlay_render_sid(overlay_local_identities[j])); + for(i=0;ibind.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;iout.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. */ diff --git a/serval.h b/serval.h index 21612065..aca775d7 100644 --- a/serval.h +++ b/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);