More work on MDP.

Swapped functions of overlay_mdp_send() and overlay_mdp_dispatch()
to match normal socket operations and thus avoid programmer confusion.
This commit is contained in:
gardners 2012-03-28 11:28:04 +10:30
parent d3cd7714ac
commit 8fbbdc5087
3 changed files with 223 additions and 149 deletions

View File

@ -373,7 +373,7 @@ int app_mdp_ping(int argc,char **argv,struct command_line_option *o)
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);
int result=overlay_mdp_send(&mdp,MDP_AWAITREPLY,5000);
if (result) {
if (mdp.packetTypeAndFlags==MDP_ERROR)
{
@ -407,7 +407,7 @@ int app_mdp_ping(int argc,char **argv,struct command_line_option *o)
unsigned char srcsid[SID_SIZE];
bcopy(mdp.bind.sid,srcsid,SID_SIZE);
mdp.bind.port_number=port;
result=overlay_mdp_dispatch(&mdp,MDP_AWAITREPLY,5000);
result=overlay_mdp_send(&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",

View File

@ -276,6 +276,8 @@ int overlay_saw_mdp_containing_frame(int interface,overlay_frame *f,long long no
int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
{
int i;
int match=-1;
printf("mdp frame type=0x%x\n",mdp->packetTypeAndFlags);
switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK) {
@ -283,7 +285,77 @@ int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now)
/* Regular MDP frame addressed to us. Look for matching port binding,
and if available, push to client. Else do nothing, or if we feel nice
send back a connection refused type message? Silence is probably the
more prudent path. */
more prudent path. */
if ((!overlay_address_is_local(mdp->out.dst.sid))
&&(!overlay_address_is_broadcast(mdp->out.dst.sid)))
{
fprintf(stderr,"%s is not a local address\n",
overlay_render_sid(mdp->out.dst.sid));
return WHY("Asked to process an MDP packet that was not addressed to this node.");
}
for(i=0;i<MDP_MAX_BINDINGS;i++)
{
if (!bcmp(&mdp->out.dst,&mdp_bindings[i],sizeof(sockaddr_mdp)))
{ /* exact and specific match, so stop searching */
match=i; break; }
else {
/* No exact match, so see if the port matches, and local-side address
is the anonymous address (all zeroes), the destination address is
a local address, and the ports match. This is to find matches to
the mdp equivalent of a socket bound to 0.0.0.0:port in IPv4.
Just as with the IPv4 situation, we prioritise ports that are listening
on a specific address over those with no address bound. Thus we only
try to match these 0.0.0.0 style bindings if there is no specific
binding, and we keep looking in case there is a more specific binding.
Because there is no concept of sub-nets in the Serval overlay mesh
(since addresses are randomly allocated from the entire address
space), we don't have to worry about a more structured heirarchy where
more completely specified addresses take priority over less completely
specified addresses.
*/
if (match==-1)
if (mdp->out.dst.port==mdp_bindings[i].port)
{
int j;
for(j=0;j<SID_SIZE;j++) if (mdp_bindings[i].sid[j]) break;
if (j==SID_SIZE) match=i;
}
}
}
if (match>-1) {
/* We now know the socket, and so we can pass the MDP_TX frame to the
recipient. We do, however, translate it into an MDP_RX frame first,
so that the recipient understands the context. */
} else {
/* No socket is bound, ignore the packet ... except for magic sockets */
switch(mdp->out.dst.port) {
case 7: /* well known ECHO port for TCP/UDP and now MDP */
{
/* Echo is easy: we swap the sender and receiver addresses (and thus port
numbers) and send the frame back. */
/* Swap addresses */
sockaddr_mdp temp;
bcopy(&mdp->out.dst,&temp,sizeof(sockaddr_mdp));
bcopy(&mdp->out.src,&mdp->out.dst,sizeof(sockaddr_mdp));
bcopy(&temp,&mdp->out.src,sizeof(sockaddr_mdp));
/* queue frame for delivery */
return
overlay_saw_mdp_frame(-1 /* we don't know the originating interface */,
mdp,overlay_gettime_ms());
}
break;
default:
/* Unbound socket. We won't be sending ICMP style connection refused
messages, partly because they are a waste of bandwidth. */
return WHY("Received packet for which no listening process exists");
}
}
break;
default:
return WHY("We should only see MDP_TX frames here");
@ -334,6 +406,139 @@ int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,
return WHY("No such socket binding:unix domain socket tuple exists -- someone might be trying to spoof someone else's connection");
}
/* Construct MDP packet frame from overlay_mdp_frame structure
(need to add return address from bindings list, and copy
payload etc).
This is for use by the SERVER.
Clients should use overlay_mdp_send()
*/
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,
struct sockaddr_un *recvaddr,int recvaddrlen)
{
/* Work out if destination is broadcast or not */
int broadcast=1;
if (overlay_mdp_sanitytest_sourceaddr(&mdp->out.src,
recvaddr,recvaddrlen))
return overlay_mdp_reply_error
(mdp_named_socket,
(struct sockaddr_un *)recvaddr,
recvaddrlen,8,
"Source address is invalid (you must bind to a source address before"
" you can send packets");
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
NaCl cryptobox keys can be used for signing. */
if (broadcast) {
if ((mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN))
!=(MDP_NOCRYPT|MDP_NOSIGN))
return overlay_mdp_reply_error(mdp_named_socket,
recvaddr,recvaddrlen,5,
"Broadcast packets cannot be encrypted "
"or signed (signing will be possible in"
" a future version).");
}
/* Prepare the overlay frame for dispatch */
struct overlay_frame *frame;
frame=calloc(sizeof(overlay_frame),1);
if (!frame) return WHY("calloc() failed to allocate overlay frame");
frame->type=OF_TYPE_DATA;
frame->prev=NULL;
frame->next=NULL;
/* Work out the disposition of the frame. For now we are only worried
about the crypto matters, and not compression that may be applied
before encryption (since applying it after is useless as ciphered
text should have maximum entropy). */
switch(mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN)) {
case 0: /* crypted and signed (using CryptBox authcryption primitive) */
frame->modifiers=OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED;
op_free(frame);
return WHY("ciphered+signed MDP frames not implemented");
break;
case MDP_NOSIGN:
/* ciphered, but not signed.
This means we don't use CryptoBox, but rather a more compact means
of representing the ciphered stream segment.
*/
frame->modifiers=OF_CRYPTO_CIPHERED;
op_free(frame);
return WHY("ciphered MDP packets not implemented");
break;
case MDP_NOCRYPT:
/* clear text, but signed (need to think about how to implement this
while NaCl cannot sign using CryptoBox keys. We could use a
CryptoSign key, and allow queries as to the authenticity of said key
via authcrypted channel between the parties. */
frame->modifiers=OF_CRYPTO_SIGNED;
op_free(frame);
return WHY("signed MDP packets not implemented");
break;
case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */
frame->modifiers=0;
/* Copy payload body in */
frame->payload=ob_new(1 /* frame type (MDP) */
+1 /* MDP version */
+4 /* dst port */
+4 /* src port */
+mdp->out.payload_length);
/* MDP version 1 */
ob_append_byte(frame->payload,0x01);
ob_append_byte(frame->payload,0x01);
/* Destination port */
ob_append_int(frame->payload,mdp->out.dst.port);
/* XXX we should probably pull the source port from the bindings
On that note, when a binding is granted, we should probably
provide a token that can be used to lookup the binding and
indicate which binding the packet is for? */
ob_append_int(frame->payload,0);
ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length);
break;
}
frame->ttl=64; /* normal TTL (XXX allow setting this would be a good idea) */
/* set source to ourselves
XXX should eventually honour binding, which should allow choosing which
local identity. This will be required for openbts integration/SIP:MSIP
gateways etc. */
overlay_frame_set_me_as_source(frame);
/* Set destination address */
if (broadcast)
overlay_frame_set_broadcast_as_destination(frame);
else{
bcopy(&mdp->out.dst.sid[0],frame->destination,SID_SIZE);
frame->destination_address_status=OA_RESOLVED;
}
if (overlay_payload_enqueue(OQ_ORDINARY,frame))
{
if (frame) op_free(frame);
return WHY("Error enqueuing frame");
}
else {
WHY("queued frame");
return 0;
}
}
int overlay_mdp_poll()
{
unsigned char buffer[16384];
@ -395,134 +600,7 @@ int overlay_mdp_poll()
}
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 broadcast=1;
if (overlay_mdp_sanitytest_sourceaddr(&mdp->out.src,
(struct sockaddr_un *)recvaddr,
recvaddrlen))
return overlay_mdp_reply_error
(mdp_named_socket,
(struct sockaddr_un *)recvaddr,
recvaddrlen,8,
"Source address is invalid (you must bind to a source address before"
" you can send packets");
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
NaCl cryptobox keys can be used for signing. */
if (broadcast) {
if ((mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN))
!=(MDP_NOCRYPT|MDP_NOSIGN))
return overlay_mdp_reply_error(mdp_named_socket,
recvaddr_un,recvaddrlen,5,
"Broadcast packets cannot be encrypted "
"or signed (signing will be possible in"
" a future version).");
}
/* Prepare the overlay frame for dispatch */
struct overlay_frame *frame;
frame=calloc(sizeof(overlay_frame),1);
if (!frame) return WHY("calloc() failed to allocate overlay frame");
frame->type=OF_TYPE_DATA;
frame->prev=NULL;
frame->next=NULL;
/* Work out the disposition of the frame. For now we are only worried
about the crypto matters, and not compression that may be applied
before encryption (since applying it after is useless as ciphered
text should have maximum entropy). */
switch(mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN)) {
case 0: /* crypted and signed (using CryptBox authcryption primitive) */
frame->modifiers=OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED;
op_free(frame);
return WHY("ciphered+signed MDP frames not implemented");
break;
case MDP_NOSIGN:
/* ciphered, but not signed.
This means we don't use CryptoBox, but rather a more compact means
of representing the ciphered stream segment.
*/
frame->modifiers=OF_CRYPTO_CIPHERED;
op_free(frame);
return WHY("ciphered MDP packets not implemented");
break;
case MDP_NOCRYPT:
/* clear text, but signed (need to think about how to implement this
while NaCl cannot sign using CryptoBox keys. We could use a
CryptoSign key, and allow queries as to the authenticity of said key
via authcrypted channel between the parties. */
frame->modifiers=OF_CRYPTO_SIGNED;
op_free(frame);
return WHY("signed MDP packets not implemented");
break;
case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */
frame->modifiers=0;
/* Copy payload body in */
frame->payload=ob_new(1 /* frame type (MDP) */
+1 /* MDP version */
+4 /* dst port */
+4 /* src port */
+mdp->out.payload_length);
/* MDP version 1 */
ob_append_byte(frame->payload,0x01);
ob_append_byte(frame->payload,0x01);
/* Destination port */
ob_append_int(frame->payload,mdp->out.dst.port);
/* XXX we should probably pull the source port from the bindings
On that note, when a binding is granted, we should probably
provide a token that can be used to lookup the binding and
indicate which binding the packet is for? */
ob_append_int(frame->payload,0);
ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length);
break;
}
frame->ttl=64; /* normal TTL (XXX allow setting this would be a good idea) */
/* set source to ourselves
XXX should eventually honour binding, which should allow choosing which
local identity. This will be required for openbts integration/SIP:MSIP
gateways etc. */
overlay_frame_set_me_as_source(frame);
/* Set destination address */
if (broadcast)
overlay_frame_set_broadcast_as_destination(frame);
else{
bcopy(&mdp->out.dst.sid[0],frame->destination,SID_SIZE);
frame->destination_address_status=OA_RESOLVED;
}
if (overlay_payload_enqueue(OQ_ORDINARY,frame))
{
if (frame) op_free(frame);
return WHY("Error enqueuing frame");
}
else {
WHY("queued frame");
return 0;
}
}
return overlay_mdp_dispatch(mdp,(struct sockaddr_un*)recvaddr,recvaddrlen);
break;
case MDP_BIND: /* Bind to port */
return overlay_mdp_process_bind_request(mdp_named_socket,mdp,
@ -591,7 +669,7 @@ int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp)
}
int mdp_client_socket=-1;
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int flags,int timeout_ms)
int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms)
{
int len=4;

View File

@ -1000,20 +1000,13 @@ typedef struct sockaddr_mdp {
#define MDP_NOCRYPT 0x0200
#define MDP_NOSIGN 0x0400
#define MDP_TX 1
#define MDP_RX 2
typedef struct overlay_mdp_outgoing_frame {
sockaddr_mdp src;
sockaddr_mdp dst;
unsigned short payload_length;
unsigned char payload[1900];
} overlay_mdp_outgoing_frame;
#define MDP_RX 2
typedef struct overlay_mdp_incoming_frame {
sockaddr_mdp dst;
sockaddr_mdp src;
unsigned short payload_length;
unsigned char payload[1900];
} overlay_mdp_incoming_frame;
} overlay_mdp_data_frame;
#define MDP_BIND 3
typedef struct overlay_mdp_bind_request {
@ -1045,8 +1038,8 @@ typedef struct overlay_mdp_frame {
#define MDP_AWAITREPLY 7
unsigned int packetTypeAndFlags;
union {
overlay_mdp_outgoing_frame out;
overlay_mdp_incoming_frame in;
overlay_mdp_data_frame out;
overlay_mdp_data_frame in;
overlay_mdp_bind_request bind;
overlay_mdp_addrlist addrlist;
overlay_mdp_error error;
@ -1056,20 +1049,23 @@ 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);
/* Client-side MDP function */
extern int mdp_client_socket;
int overlay_mdp_client_init();
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_send(overlay_mdp_frame *mdp,int flags,int timeout_ms);
/* Server-side MDP functions */
int overlay_saw_mdp_frame(int interface, overlay_mdp_frame *mdp,long long now);
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 overlay_mdp_dispatch(overlay_mdp_frame *mdp,
struct sockaddr_un *recvaddr,int recvaddlen);
int ob_bcopy(overlay_buffer *b,int from, int to, int len);
int ob_setbyte(overlay_buffer *b,int ofs,unsigned char value);