2012-03-16 22:30:51 +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.
|
|
|
|
*/
|
|
|
|
|
2012-03-20 15:06:52 +00:00
|
|
|
#include <sys/stat.h>
|
2012-07-18 09:46:30 +00:00
|
|
|
#include "serval.h"
|
|
|
|
#include "strbuf.h"
|
2012-08-22 00:51:38 +00:00
|
|
|
#include "overlay_buffer.h"
|
2012-08-27 00:34:59 +00:00
|
|
|
#include "overlay_address.h"
|
|
|
|
#include "overlay_packet.h"
|
2012-03-17 02:32:09 +00:00
|
|
|
|
2012-08-14 05:01:25 +00:00
|
|
|
struct profile_total mdp_stats={.name="overlay_mdp_poll"};
|
|
|
|
|
|
|
|
struct sched_ent mdp_abstract={
|
|
|
|
.function = overlay_mdp_poll,
|
|
|
|
.stats = &mdp_stats,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sched_ent mdp_named={
|
|
|
|
.function = overlay_mdp_poll,
|
|
|
|
.stats = &mdp_stats,
|
|
|
|
};
|
2012-07-02 03:49:54 +00:00
|
|
|
|
2012-08-27 00:34:59 +00:00
|
|
|
// is the SID entirely 0xFF?
|
|
|
|
static int is_broadcast(const unsigned char *sid){
|
|
|
|
int i;
|
|
|
|
for (i=0;i<SID_SIZE;i++)
|
|
|
|
if (sid[i]!=0xFF)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// is the SID entirely 0x00?
|
|
|
|
static int is_sid_any(unsigned char *sid){
|
|
|
|
int i;
|
|
|
|
for (i=0;i<SID_SIZE;i++)
|
|
|
|
if (sid[i])
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2012-03-16 22:30:51 +00:00
|
|
|
int overlay_mdp_setup_sockets()
|
|
|
|
{
|
|
|
|
struct sockaddr_un name;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
name.sun_family = AF_UNIX;
|
|
|
|
|
|
|
|
#ifndef HAVE_LINUX_IF_H
|
|
|
|
/* Abstrack name space (i.e., non-file represented) unix domain sockets are a
|
|
|
|
linux-only thing. */
|
2012-07-02 03:49:54 +00:00
|
|
|
mdp_abstract.poll.fd = -1;
|
2012-03-16 22:30:51 +00:00
|
|
|
#else
|
2012-08-14 05:01:25 +00:00
|
|
|
if (mdp_abstract.poll.fd<=0) {
|
2012-03-17 02:32:09 +00:00
|
|
|
/* Abstract name space unix sockets is a special Linux thing, which is
|
|
|
|
convenient for us because Android is Linux, but does not have a shared
|
|
|
|
writable path that is on a UFS partition, so we cannot use traditional
|
|
|
|
named unix domain sockets. So the abstract name space gives us a solution. */
|
|
|
|
name.sun_path[0]=0;
|
|
|
|
/* XXX The 100 should be replaced with the actual maximum allowed.
|
|
|
|
Apparently POSIX requires it to be at least 100, but I would still feel
|
|
|
|
more comfortable with using the appropriate constant. */
|
2012-06-21 05:15:09 +00:00
|
|
|
snprintf(&name.sun_path[1],100,
|
2012-06-22 07:16:30 +00:00
|
|
|
confValueGet("mdp.socket",DEFAULT_MDP_SOCKET_NAME));
|
2012-03-17 02:32:09 +00:00
|
|
|
len = 1+strlen(&name.sun_path[1]) + sizeof(name.sun_family);
|
|
|
|
|
2012-07-02 03:49:54 +00:00
|
|
|
mdp_abstract.poll.fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (mdp_abstract.poll.fd>-1) {
|
2012-05-17 03:43:42 +00:00
|
|
|
int reuseP=1;
|
2012-07-03 08:07:33 +00:00
|
|
|
if (setsockopt( mdp_abstract.poll.fd, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) == -1) {
|
|
|
|
WARN_perror("setsockopt(SO_REUSEADDR)");
|
|
|
|
WARN("Could not set socket reuse addresses");
|
2012-05-20 06:36:32 +00:00
|
|
|
}
|
2012-07-03 08:07:33 +00:00
|
|
|
if (bind(mdp_abstract.poll.fd, (struct sockaddr *)&name, len) == -1) {
|
|
|
|
WARN_perror("bind");
|
2012-07-02 03:49:54 +00:00
|
|
|
close(mdp_abstract.poll.fd);
|
2012-07-03 08:07:33 +00:00
|
|
|
mdp_abstract.poll.fd = -1;
|
|
|
|
WARN("bind of abstract name space socket failed (not a problem on non-linux systems)");
|
2012-03-17 02:32:09 +00:00
|
|
|
}
|
2012-04-24 05:09:58 +00:00
|
|
|
int send_buffer_size=64*1024;
|
2012-07-03 08:07:33 +00:00
|
|
|
if (setsockopt(mdp_abstract.poll.fd, SOL_SOCKET, SO_SNDBUF, &send_buffer_size, sizeof(send_buffer_size)) == -1)
|
|
|
|
WARN_perror("setsockopt(SO_SNDBUF)");
|
2012-07-02 03:49:54 +00:00
|
|
|
mdp_abstract.poll.events = POLLIN;
|
|
|
|
watch(&mdp_abstract);
|
2012-05-17 03:43:42 +00:00
|
|
|
}
|
2012-03-16 22:30:51 +00:00
|
|
|
}
|
|
|
|
#endif
|
2012-08-14 05:01:25 +00:00
|
|
|
if (mdp_named.poll.fd<=0) {
|
2012-07-03 08:07:33 +00:00
|
|
|
if (!form_serval_instance_path(&name.sun_path[0], 100, "mdp.socket"))
|
2012-03-29 03:37:07 +00:00
|
|
|
return WHY("Cannot construct name of unix domain socket.");
|
2012-03-18 23:13:11 +00:00
|
|
|
unlink(&name.sun_path[0]);
|
|
|
|
len = 0+strlen(&name.sun_path[0]) + sizeof(name.sun_family)+1;
|
2012-07-02 03:49:54 +00:00
|
|
|
mdp_named.poll.fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (mdp_named.poll.fd>-1) {
|
2012-05-17 03:43:42 +00:00
|
|
|
int reuseP=1;
|
2012-07-03 08:07:33 +00:00
|
|
|
if(setsockopt( mdp_named.poll.fd, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) == -1) {
|
|
|
|
WARN_perror("setsockopt(SO_REUSEADDR)");
|
|
|
|
WARN("Could not set socket reuse addresses");
|
|
|
|
}
|
|
|
|
if (bind(mdp_named.poll.fd, (struct sockaddr *)&name, len) == -1) {
|
|
|
|
WARN_perror("bind");
|
2012-07-02 03:49:54 +00:00
|
|
|
close(mdp_named.poll.fd);
|
2012-07-03 08:07:33 +00:00
|
|
|
mdp_named.poll.fd = -1;
|
|
|
|
WARN("Could not bind named unix domain socket");
|
2012-03-17 02:32:09 +00:00
|
|
|
}
|
2012-04-24 05:09:58 +00:00
|
|
|
int send_buffer_size=64*1024;
|
2012-07-03 08:07:33 +00:00
|
|
|
if (setsockopt(mdp_named.poll.fd, SOL_SOCKET, SO_RCVBUF, &send_buffer_size, sizeof(send_buffer_size)) == -1)
|
|
|
|
WARN_perror("setsockopt(SO_RCVBUF)");
|
2012-07-02 03:49:54 +00:00
|
|
|
mdp_named.function = overlay_mdp_poll;
|
2012-07-02 05:50:30 +00:00
|
|
|
mdp_named.stats = &mdp_stats;
|
2012-07-02 03:49:54 +00:00
|
|
|
mdp_named.poll.events = POLLIN;
|
|
|
|
watch(&mdp_named);
|
2012-03-16 22:30:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-03-20 06:41:58 +00:00
|
|
|
#define MDP_MAX_BINDINGS 100
|
|
|
|
#define MDP_MAX_SOCKET_NAME_LEN 110
|
2012-08-14 05:01:25 +00:00
|
|
|
|
|
|
|
struct mdp_binding{
|
|
|
|
int any;
|
|
|
|
sockaddr_mdp addr;
|
|
|
|
char socket_name[MDP_MAX_SOCKET_NAME_LEN];
|
|
|
|
int name_len;
|
|
|
|
time_ms_t binding_time;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mdp_binding mdp_bindings[MDP_MAX_BINDINGS];
|
2012-03-20 06:41:58 +00:00
|
|
|
int mdp_bindings_initialised=0;
|
|
|
|
|
|
|
|
int overlay_mdp_reply_error(int sock,
|
|
|
|
struct sockaddr_un *recvaddr,int recvaddrlen,
|
|
|
|
int error_number,char *message)
|
|
|
|
{
|
|
|
|
overlay_mdp_frame mdpreply;
|
|
|
|
|
|
|
|
mdpreply.packetTypeAndFlags=MDP_ERROR;
|
|
|
|
mdpreply.error.error=error_number;
|
2012-08-27 00:34:59 +00:00
|
|
|
if (error_number)
|
|
|
|
WHYF("MDP error, code #%d %s",error_number, message);
|
|
|
|
|
2012-03-20 06:41:58 +00:00
|
|
|
if (error_number==0||message)
|
|
|
|
snprintf(&mdpreply.error.message[0],128,"%s",message?message:"Success");
|
2012-08-27 00:34:59 +00:00
|
|
|
else{
|
2012-03-20 06:41:58 +00:00
|
|
|
snprintf(&mdpreply.error.message[0],128,"Error code #%d",error_number);
|
2012-08-27 00:34:59 +00:00
|
|
|
}
|
2012-03-20 06:41:58 +00:00
|
|
|
mdpreply.error.message[127]=0;
|
2012-03-27 08:55:38 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2012-05-02 17:30:34 +00:00
|
|
|
if (!recvaddr) return 0;
|
|
|
|
|
2012-03-27 08:55:38 +00:00
|
|
|
replylen=overlay_mdp_relevant_bytes(mdpreply);
|
|
|
|
if (replylen<0) return WHY("Invalid MDP frame (could not compute length)");
|
|
|
|
|
2012-03-20 06:41:58 +00:00
|
|
|
errno=0;
|
2012-03-27 08:55:38 +00:00
|
|
|
int r=sendto(sock,(char *)mdpreply,replylen,0,
|
2012-03-20 06:41:58 +00:00
|
|
|
(struct sockaddr *)recvaddr,recvaddrlen);
|
2012-04-21 22:55:48 +00:00
|
|
|
if (r<replylen) {
|
2012-05-08 05:15:26 +00:00
|
|
|
WHY_perror("sendto(d)");
|
2012-05-08 08:18:16 +00:00
|
|
|
return WHYF("sendto() failed when sending MDP reply, sock=%d, r=%d", sock, r);
|
2012-04-21 22:55:48 +00:00
|
|
|
} else
|
2012-05-20 06:36:32 +00:00
|
|
|
if (0) DEBUGF("reply of %d bytes sent",r);
|
2012-03-20 06:41:58 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int overlay_mdp_reply_ok(int sock,
|
|
|
|
struct sockaddr_un *recvaddr,int recvaddrlen,
|
|
|
|
char *message)
|
|
|
|
{
|
|
|
|
return overlay_mdp_reply_error(sock,recvaddr,recvaddrlen,0,message);
|
|
|
|
}
|
|
|
|
|
2012-04-30 20:40:47 +00:00
|
|
|
int overlay_mdp_releasebindings(struct sockaddr_un *recvaddr,int recvaddrlen)
|
|
|
|
{
|
|
|
|
/* Free up any MDP bindings held by this client. */
|
|
|
|
int i;
|
|
|
|
for(i=0;i<MDP_MAX_BINDINGS;i++)
|
2012-08-14 05:01:25 +00:00
|
|
|
if (mdp_bindings[i].name_len==recvaddrlen)
|
|
|
|
if (!memcmp(mdp_bindings[i].socket_name,recvaddr->sun_path,recvaddrlen))
|
|
|
|
mdp_bindings[i].addr.port=0;
|
2012-04-30 20:40:47 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2012-03-20 06:41:58 +00:00
|
|
|
int overlay_mdp_process_bind_request(int sock,overlay_mdp_frame *mdp,
|
|
|
|
struct sockaddr_un *recvaddr,int recvaddrlen)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
if (!mdp_bindings_initialised) {
|
|
|
|
/* Mark all slots as unused */
|
2012-08-14 05:01:25 +00:00
|
|
|
for(i=0;i<MDP_MAX_BINDINGS;i++)
|
|
|
|
mdp_bindings[i].addr.port=0;
|
2012-03-20 06:41:58 +00:00
|
|
|
mdp_bindings_initialised=1;
|
|
|
|
}
|
|
|
|
|
2012-05-25 00:25:56 +00:00
|
|
|
// DEBUG("Doesn't authenticate source address on multi-SID installations like an OpenBTS:mesh gateway)");
|
2012-03-27 08:55:38 +00:00
|
|
|
|
|
|
|
/* Make sure source address is either all zeros (listen on all), or a valid
|
|
|
|
local address */
|
2012-08-27 00:34:59 +00:00
|
|
|
if (!is_sid_any(mdp->bind.sid)){
|
|
|
|
struct subscriber *subscriber = find_subscriber(mdp->bind.sid, SID_SIZE, 0);
|
|
|
|
if (!subscriber || subscriber->reachable != REACHABLE_SELF){
|
|
|
|
WHYF("Invalid bind request for sid=%s", alloca_tohex_sid(mdp->bind.sid));
|
2012-03-27 08:55:38 +00:00
|
|
|
/* 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).");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-20 06:41:58 +00:00
|
|
|
/* See if binding already exists */
|
|
|
|
int found=-1;
|
|
|
|
int free=-1;
|
|
|
|
for(i=0;i<MDP_MAX_BINDINGS;i++) {
|
|
|
|
/* Look for duplicate bindings */
|
2012-08-14 05:01:25 +00:00
|
|
|
if (mdp_bindings[i].addr.port==mdp->bind.port_number)
|
|
|
|
if (!memcmp(mdp_bindings[i].addr.sid,mdp->bind.sid,SID_SIZE))
|
2012-03-20 06:41:58 +00:00
|
|
|
{ found=i; break; }
|
|
|
|
/* Look for free slots in case we need one */
|
2012-08-14 05:01:25 +00:00
|
|
|
if ((free==-1)&&(mdp_bindings[i].addr.port==0)) free=i;
|
2012-03-20 06:41:58 +00:00
|
|
|
}
|
2012-03-20 15:06:52 +00:00
|
|
|
|
2012-03-20 06:41:58 +00:00
|
|
|
/* Binding was found. See if it is us, if so, then all is well,
|
|
|
|
else we check flags to see if we should override the existing binding. */
|
|
|
|
if (found>-1) {
|
2012-08-14 05:01:25 +00:00
|
|
|
if (mdp_bindings[found].name_len==recvaddrlen)
|
|
|
|
if (!memcmp(mdp_bindings[found].socket_name,recvaddr->sun_path,recvaddrlen))
|
2012-03-20 06:41:58 +00:00
|
|
|
{
|
2012-05-20 06:36:32 +00:00
|
|
|
INFO("Identical binding exists");
|
|
|
|
DEBUG("Need to return binding information to client");
|
2012-03-20 06:41:58 +00:00
|
|
|
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
|
|
|
|
return an error */
|
|
|
|
if (!(mdp->packetTypeAndFlags&MDP_FORCE))
|
|
|
|
{
|
2012-07-27 08:31:04 +00:00
|
|
|
WHY("Port already in use");
|
|
|
|
return overlay_mdp_reply_error(sock,recvaddr,recvaddrlen,3, "Port already in use");
|
2012-03-20 06:41:58 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Cause existing binding to be replaced.
|
|
|
|
XXX - We should notify the existing binding holder that their binding
|
|
|
|
has been snaffled. */
|
2012-05-20 06:36:32 +00:00
|
|
|
DEBUG("Warn socket holder about port-snatch");
|
2012-03-20 06:41:58 +00:00
|
|
|
free=found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Okay, so no binding exists. Make one, and return success.
|
|
|
|
If we have too many bindings, we should return an error.
|
|
|
|
XXX - We don't find out when the socket responsible for a binding has died,
|
|
|
|
so stale bindings can hang around. We really need a solution to this, e.g.,
|
|
|
|
probing the sockets periodically (by sending an MDP NOOP frame perhaps?) and
|
|
|
|
destroying any socket that reports an error.
|
|
|
|
*/
|
|
|
|
if (free==-1) {
|
|
|
|
/* XXX Should we probe for stale bindings here and now, since this is when
|
2012-04-30 20:40:47 +00:00
|
|
|
we want the spare slots ?
|
|
|
|
|
|
|
|
Picking one at random is as good a policy as any.
|
|
|
|
Call listeners don't have a port binding, so are unaffected by this.
|
|
|
|
*/
|
|
|
|
free=random()%MDP_MAX_BINDINGS;
|
2012-08-14 05:01:25 +00:00
|
|
|
mdp_bindings[free].addr.port=0;
|
2012-03-20 06:41:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Okay, record binding and report success */
|
2012-08-14 05:01:25 +00:00
|
|
|
mdp_bindings[free].addr.port=mdp->bind.port_number;
|
|
|
|
memcpy(mdp_bindings[free].addr.sid,mdp->bind.sid,SID_SIZE);
|
|
|
|
mdp_bindings[free].name_len=recvaddrlen-2;
|
|
|
|
memcpy(mdp_bindings[free].socket_name,recvaddr->sun_path,
|
|
|
|
mdp_bindings[free].name_len);
|
|
|
|
mdp_bindings[free].binding_time=gettime_ms();
|
2012-03-20 06:41:58 +00:00
|
|
|
return overlay_mdp_reply_ok(sock,recvaddr,recvaddrlen,"Port bound");
|
|
|
|
}
|
|
|
|
|
2012-09-01 02:47:22 +00:00
|
|
|
int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp)
|
2012-03-27 08:55:38 +00:00
|
|
|
{
|
2012-06-25 23:52:51 +00:00
|
|
|
IN();
|
2012-04-14 00:03:29 +00:00
|
|
|
|
2012-09-01 02:47:22 +00:00
|
|
|
int len=f->payload->sizeLimit;
|
2012-05-10 04:37:11 +00:00
|
|
|
unsigned char *b = NULL;
|
2012-09-01 02:47:22 +00:00
|
|
|
unsigned char plain_block[len+16];
|
2012-04-14 00:03:29 +00:00
|
|
|
|
2012-04-13 22:45:29 +00:00
|
|
|
switch(f->modifiers&OF_CRYPTO_BITS) {
|
|
|
|
case 0:
|
2012-04-14 02:47:46 +00:00
|
|
|
/* get payload */
|
|
|
|
b=&f->payload->bytes[0];
|
2012-08-14 04:36:59 +00:00
|
|
|
mdp->packetTypeAndFlags|=MDP_NOCRYPT|MDP_NOSIGN;
|
|
|
|
break;
|
2012-04-13 22:45:29 +00:00
|
|
|
case OF_CRYPTO_CIPHERED:
|
2012-09-01 02:47:22 +00:00
|
|
|
RETURN(WHY("decryption not implemented"));
|
|
|
|
|
2012-04-13 22:45:29 +00:00
|
|
|
case OF_CRYPTO_SIGNED:
|
2012-04-14 17:47:36 +00:00
|
|
|
{
|
|
|
|
/* This call below will dispatch the request for the SAS if we don't
|
|
|
|
already have it. In the meantime, we just drop the frame if the SAS
|
|
|
|
is not available. */
|
2012-08-14 04:36:59 +00:00
|
|
|
unsigned char *key = keyring_find_sas_public(keyring,mdp->out.src.sid);
|
|
|
|
if (!key)
|
2012-09-01 02:47:22 +00:00
|
|
|
RETURN(WHY("SAS key not currently on record, cannot verify"));
|
2012-04-14 17:47:36 +00:00
|
|
|
|
|
|
|
/* get payload and following compacted signature */
|
|
|
|
b=&f->payload->bytes[0];
|
2012-09-01 02:47:22 +00:00
|
|
|
len=f->payload->sizeLimit-crypto_sign_edwards25519sha512batch_BYTES;
|
2012-04-14 17:47:36 +00:00
|
|
|
|
|
|
|
/* get hash */
|
|
|
|
unsigned char hash[crypto_hash_sha512_BYTES];
|
2012-09-01 02:47:22 +00:00
|
|
|
crypto_hash_sha512(hash,b,len);
|
2012-04-14 17:47:36 +00:00
|
|
|
|
|
|
|
/* reconstitute signature by putting hash between two halves of signature */
|
|
|
|
unsigned char signature[crypto_hash_sha512_BYTES
|
|
|
|
+crypto_sign_edwards25519sha512batch_BYTES];
|
2012-09-01 02:47:22 +00:00
|
|
|
bcopy(&b[len],&signature[0],32);
|
|
|
|
crypto_hash_sha512(&signature[32],b,len);
|
2012-04-15 21:34:23 +00:00
|
|
|
if (0) dump("hash for verification",hash,crypto_hash_sha512_BYTES);
|
2012-09-01 02:47:22 +00:00
|
|
|
bcopy(&b[len+32],&signature[32+crypto_hash_sha512_BYTES],32);
|
2012-04-14 17:47:36 +00:00
|
|
|
|
|
|
|
/* verify signature */
|
|
|
|
unsigned char m[crypto_hash_sha512_BYTES];
|
|
|
|
unsigned long long mlen=0;
|
|
|
|
int result
|
|
|
|
=crypto_sign_edwards25519sha512batch_open(m,&mlen,
|
|
|
|
signature,sizeof(signature),
|
|
|
|
key);
|
2012-06-25 23:52:51 +00:00
|
|
|
if (result) {
|
2012-09-01 02:47:22 +00:00
|
|
|
RETURN(WHY("Signature verification failed: incorrect signature"));
|
2012-06-25 23:55:42 +00:00
|
|
|
} else if (0) DEBUG("signature check passed");
|
2012-04-15 21:34:23 +00:00
|
|
|
}
|
2012-09-01 02:47:22 +00:00
|
|
|
mdp->packetTypeAndFlags|=MDP_NOCRYPT;
|
|
|
|
break;
|
2012-04-13 22:45:29 +00:00
|
|
|
case OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED:
|
2012-04-14 02:47:46 +00:00
|
|
|
{
|
2012-07-27 08:31:04 +00:00
|
|
|
if (0) DEBUGF("crypted MDP frame for %s", alloca_tohex_sid(mdp->out.dst.sid));
|
2012-04-14 04:50:49 +00:00
|
|
|
|
2012-06-25 23:52:51 +00:00
|
|
|
unsigned char *k=keyring_get_nm_bytes(&mdp->out.dst,&mdp->out.src);
|
2012-04-14 02:47:46 +00:00
|
|
|
unsigned char *nonce=&f->payload->bytes[0];
|
|
|
|
int nb=crypto_box_curve25519xsalsa20poly1305_NONCEBYTES;
|
2012-04-14 03:03:15 +00:00
|
|
|
int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
|
2012-09-01 02:47:22 +00:00
|
|
|
if (!k)
|
|
|
|
RETURN(WHY("I don't have the private key required to decrypt that"));
|
2012-04-14 02:47:46 +00:00
|
|
|
bzero(&plain_block[0],crypto_box_curve25519xsalsa20poly1305_ZEROBYTES-16);
|
2012-08-22 00:51:38 +00:00
|
|
|
int cipher_len=f->payload->sizeLimit-nb;
|
2012-04-14 02:47:46 +00:00
|
|
|
bcopy(&f->payload->bytes[nb],&plain_block[16],cipher_len);
|
2012-04-14 04:26:53 +00:00
|
|
|
if (0) {
|
|
|
|
dump("nm bytes",k,crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES);
|
|
|
|
dump("nonce",nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
|
|
|
|
dump("cipher block",&plain_block[16],cipher_len);
|
|
|
|
}
|
2012-04-14 02:47:46 +00:00
|
|
|
if (crypto_box_curve25519xsalsa20poly1305_open_afternm
|
2012-06-25 23:52:51 +00:00
|
|
|
(plain_block,plain_block,cipher_len+16,nonce,k)) {
|
2012-09-01 02:47:22 +00:00
|
|
|
RETURN(WHYF("crypto_box_open_afternm() failed (forged or corrupted packet of %d bytes)",cipher_len+16));
|
2012-06-25 23:52:51 +00:00
|
|
|
}
|
2012-04-14 04:26:53 +00:00
|
|
|
if (0) dump("plain block",&plain_block[zb],cipher_len-16);
|
2012-04-14 03:03:15 +00:00
|
|
|
b=&plain_block[zb];
|
2012-09-01 02:47:22 +00:00
|
|
|
len=cipher_len-16;
|
2012-04-14 02:47:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2012-04-13 22:45:29 +00:00
|
|
|
}
|
2012-09-01 02:47:22 +00:00
|
|
|
|
|
|
|
if (!b)
|
|
|
|
RETURN(WHY("Failed to decode mdp payload"));
|
|
|
|
|
|
|
|
int version=(b[0]<<8)+b[1];
|
|
|
|
if (version!=0x0101) RETURN(WHY("Saw unsupported MDP frame version"));
|
|
|
|
|
|
|
|
/* Indicate MDP message type */
|
|
|
|
mdp->packetTypeAndFlags=MDP_TX;
|
|
|
|
|
|
|
|
/* extract MDP port numbers */
|
|
|
|
mdp->in.src.port=(b[2]<<24)+(b[3]<<16)+(b[4]<<8)+b[5];
|
|
|
|
mdp->in.dst.port=(b[6]<<24)+(b[7]<<16)+(b[8]<<8)+b[9];
|
|
|
|
if (0) DEBUGF("RX mdp dst.port=%d, src.port=%d", mdp->in.dst.port, mdp->in.src.port);
|
|
|
|
|
|
|
|
mdp->in.payload_length=len-10;
|
|
|
|
bcopy(&b[10],&mdp->in.payload[0],mdp->in.payload_length);
|
|
|
|
|
|
|
|
RETURN(0);
|
2012-06-25 23:52:51 +00:00
|
|
|
}
|
|
|
|
|
2012-08-27 00:34:59 +00:00
|
|
|
int overlay_saw_mdp_containing_frame(struct overlay_frame *f, time_ms_t now)
|
2012-06-25 23:52:51 +00:00
|
|
|
{
|
|
|
|
IN();
|
|
|
|
/* Take frame source and destination and use them to populate mdp->in->{src,dst}
|
|
|
|
SIDs.
|
|
|
|
Take ports from mdp frame itself.
|
|
|
|
Take payload from mdp frame itself.
|
|
|
|
*/
|
|
|
|
overlay_mdp_frame mdp;
|
2012-08-22 00:51:38 +00:00
|
|
|
int len=f->payload->sizeLimit;
|
2012-06-25 23:52:51 +00:00
|
|
|
|
|
|
|
/* Get source and destination addresses */
|
2012-08-27 00:34:59 +00:00
|
|
|
if (f->destination)
|
|
|
|
bcopy(f->destination->sid,mdp.in.dst.sid,SID_SIZE);
|
|
|
|
else{
|
|
|
|
// pack the broadcast address into the mdp structure
|
|
|
|
memset(mdp.in.dst.sid, 0xFF, SID_SIZE - BROADCAST_LEN);
|
|
|
|
bcopy(f->broadcast_id.id, mdp.in.dst.sid + SID_SIZE - BROADCAST_LEN, BROADCAST_LEN);
|
|
|
|
}
|
|
|
|
bcopy(f->source->sid,mdp.in.src.sid,SID_SIZE);
|
2012-06-25 23:52:51 +00:00
|
|
|
|
|
|
|
if (len<10) RETURN(WHY("Invalid MDP frame"));
|
|
|
|
|
|
|
|
/* copy crypto flags from frame so that we know if we need to decrypt or verify it */
|
2012-09-01 02:47:22 +00:00
|
|
|
if (overlay_mdp_decrypt(f,&mdp))
|
|
|
|
RETURN(-1);
|
2012-04-14 00:03:29 +00:00
|
|
|
|
2012-04-13 22:45:29 +00:00
|
|
|
/* and do something with it! */
|
2012-07-02 03:49:54 +00:00
|
|
|
RETURN(overlay_saw_mdp_frame(&mdp,now));
|
2012-03-27 08:55:38 +00:00
|
|
|
}
|
|
|
|
|
2012-04-15 20:36:43 +00:00
|
|
|
int overlay_mdp_swap_src_dst(overlay_mdp_frame *mdp)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-09 02:44:32 +00:00
|
|
|
int overlay_saw_mdp_frame(overlay_mdp_frame *mdp, time_ms_t now)
|
2012-03-16 22:30:51 +00:00
|
|
|
{
|
2012-06-25 23:52:51 +00:00
|
|
|
IN();
|
2012-03-28 00:58:04 +00:00
|
|
|
int i;
|
|
|
|
int match=-1;
|
2012-03-27 10:43:40 +00:00
|
|
|
|
|
|
|
switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK) {
|
|
|
|
case MDP_TX:
|
|
|
|
/* 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
|
2012-04-14 00:03:29 +00:00
|
|
|
more prudent path.
|
|
|
|
*/
|
2012-06-22 08:00:21 +00:00
|
|
|
|
2012-06-25 05:16:55 +00:00
|
|
|
if (0)
|
|
|
|
WHYF("Received packet with listener (MDP ports: src=%s*:%d, dst=%d)",
|
2012-07-04 01:00:46 +00:00
|
|
|
alloca_tohex(mdp->out.src.sid, 7),
|
2012-06-25 05:16:55 +00:00
|
|
|
mdp->out.src.port,mdp->out.dst.port);
|
2012-06-22 08:00:21 +00:00
|
|
|
|
2012-03-28 00:58:04 +00:00
|
|
|
for(i=0;i<MDP_MAX_BINDINGS;i++)
|
|
|
|
{
|
2012-08-14 05:01:25 +00:00
|
|
|
if (!memcmp(&mdp->out.dst,&mdp_bindings[i].addr,sizeof(sockaddr_mdp)))
|
2012-03-28 00:58:04 +00:00
|
|
|
{ /* 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)
|
2012-08-14 05:01:25 +00:00
|
|
|
if (mdp->out.dst.port==mdp_bindings[i].addr.port)
|
2012-03-28 00:58:04 +00:00
|
|
|
{
|
|
|
|
int j;
|
2012-08-14 05:01:25 +00:00
|
|
|
for(j=0;j<SID_SIZE;j++) if (mdp_bindings[i].addr.sid[j]) break;
|
2012-03-28 00:58:04 +00:00
|
|
|
if (j==SID_SIZE) match=i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-14 05:01:25 +00:00
|
|
|
if (match>-1) {
|
2012-03-28 02:40:41 +00:00
|
|
|
struct sockaddr_un addr;
|
2012-06-22 08:00:21 +00:00
|
|
|
|
2012-08-14 05:01:25 +00:00
|
|
|
bcopy(mdp_bindings[match].socket_name,addr.sun_path,mdp_bindings[match].name_len);
|
2012-03-28 02:40:41 +00:00
|
|
|
addr.sun_family=AF_UNIX;
|
2012-06-21 02:51:25 +00:00
|
|
|
errno=0;
|
|
|
|
int len=overlay_mdp_relevant_bytes(mdp);
|
2012-07-02 03:49:54 +00:00
|
|
|
int r=sendto(mdp_named.poll.fd,mdp,len,0,(struct sockaddr*)&addr,sizeof(addr));
|
2012-06-21 02:51:25 +00:00
|
|
|
if (r==overlay_mdp_relevant_bytes(mdp)) {
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(0);
|
2012-06-21 02:51:25 +00:00
|
|
|
}
|
2012-06-25 23:52:51 +00:00
|
|
|
WHY("didn't send mdp packet");
|
2012-06-21 02:51:25 +00:00
|
|
|
if (errno==ENOENT) {
|
|
|
|
/* far-end of socket has died, so drop binding */
|
2012-08-14 05:01:25 +00:00
|
|
|
INFOF("Closing dead MDP client '%s'",mdp_bindings[match].socket_name);
|
|
|
|
overlay_mdp_releasebindings(&addr,mdp_bindings[match].name_len);
|
2012-06-21 02:51:25 +00:00
|
|
|
}
|
2012-05-08 05:15:26 +00:00
|
|
|
WHY_perror("sendto(e)");
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(WHY("Failed to pass received MDP frame to client"));
|
2012-03-28 00:58:04 +00:00
|
|
|
} else {
|
|
|
|
/* No socket is bound, ignore the packet ... except for magic sockets */
|
|
|
|
switch(mdp->out.dst.port) {
|
2012-04-18 22:04:12 +00:00
|
|
|
case MDP_PORT_VOMP:
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(vomp_mdp_received(mdp));
|
2012-04-14 17:47:36 +00:00
|
|
|
case MDP_PORT_KEYMAPREQUEST:
|
|
|
|
/* Either respond with the appropriate SAS, or record this one if it
|
2012-08-14 04:36:59 +00:00
|
|
|
verifies out okay. */
|
|
|
|
if (debug & DEBUG_MDPREQUESTS)
|
|
|
|
DEBUG("MDP_PORT_KEYMAPREQUEST");
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(keyring_mapping_request(keyring,mdp));
|
2012-04-25 05:54:21 +00:00
|
|
|
case MDP_PORT_DNALOOKUP: /* attempt to resolve DID to SID */
|
|
|
|
{
|
|
|
|
int cn=0,in=0,kp=0;
|
|
|
|
char did[64+1];
|
|
|
|
int pll=mdp->out.payload_length;
|
2012-05-07 06:17:20 +00:00
|
|
|
if (pll>64) pll=64;
|
2012-04-25 05:54:21 +00:00
|
|
|
/* get did from the packet */
|
2012-06-25 23:52:51 +00:00
|
|
|
if (mdp->out.payload_length<1) {
|
|
|
|
RETURN(WHY("Empty DID in DNA resolution request")); }
|
2012-04-25 05:54:21 +00:00
|
|
|
bcopy(&mdp->out.payload[0],&did[0],pll);
|
|
|
|
did[pll]=0;
|
2012-06-20 22:37:03 +00:00
|
|
|
int results=0;
|
2012-04-25 05:54:21 +00:00
|
|
|
while(keyring_find_did(keyring,&cn,&in,&kp,did))
|
|
|
|
{
|
2012-05-01 05:08:09 +00:00
|
|
|
/* 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). */
|
2012-07-20 08:47:43 +00:00
|
|
|
if (keyring->contexts[cn]->identities[in]->keypairs[kp]->private_key_len > DID_MAXSIZE)
|
2012-04-25 05:54:21 +00:00
|
|
|
/* skip excessively long DID records */
|
|
|
|
continue;
|
2012-07-20 08:47:43 +00:00
|
|
|
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_putc(b, '/');
|
|
|
|
strbuf_puts(b, unpackedDid);
|
2012-08-06 07:14:36 +00:00
|
|
|
overlay_mdp_dnalookup_reply(&mdp->out.src, packedSid, strbuf_str(b), unpackedDid, name);
|
2012-04-25 10:54:08 +00:00
|
|
|
kp++;
|
2012-06-20 22:37:03 +00:00
|
|
|
results++;
|
2012-04-25 05:54:21 +00:00
|
|
|
}
|
2012-06-20 22:37:03 +00:00
|
|
|
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.
|
|
|
|
*/
|
2012-07-20 08:47:43 +00:00
|
|
|
dna_helper_enqueue(mdp, did, mdp->out.src.sid);
|
2012-08-10 05:58:56 +00:00
|
|
|
monitor_tell_formatted(MONITOR_DNAHELPER, "LOOKUP:%s:%d:%s\n", alloca_tohex_sid(mdp->out.src.sid), mdp->out.src.port, did);
|
2012-06-20 22:37:03 +00:00
|
|
|
}
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(0);
|
2012-04-25 05:54:21 +00:00
|
|
|
}
|
|
|
|
break;
|
2012-04-14 17:47:36 +00:00
|
|
|
case MDP_PORT_ECHO: /* well known ECHO port for TCP/UDP and now MDP */
|
2012-03-28 00:58:04 +00:00
|
|
|
{
|
|
|
|
/* Echo is easy: we swap the sender and receiver addresses (and thus port
|
|
|
|
numbers) and send the frame back. */
|
2012-04-14 13:42:45 +00:00
|
|
|
|
2012-03-28 00:58:04 +00:00
|
|
|
/* Swap addresses */
|
2012-04-15 20:36:43 +00:00
|
|
|
overlay_mdp_swap_src_dst(mdp);
|
2012-04-14 04:50:49 +00:00
|
|
|
|
2012-06-25 23:52:51 +00:00
|
|
|
if (mdp->out.dst.port==MDP_PORT_ECHO) {
|
|
|
|
RETURN(WHY("echo loop averted"));
|
|
|
|
}
|
2012-03-28 02:49:53 +00:00
|
|
|
/* If the packet was sent to broadcast, then replace broadcast address
|
|
|
|
with our local address. For now just responds with first local address */
|
2012-08-27 00:34:59 +00:00
|
|
|
if (is_broadcast(mdp->out.src.sid))
|
2012-03-28 02:49:53 +00:00
|
|
|
{
|
2012-08-27 00:34:59 +00:00
|
|
|
if (my_subscriber)
|
|
|
|
bcopy(my_subscriber->sid,
|
2012-04-12 23:55:03 +00:00
|
|
|
mdp->out.src.sid,SID_SIZE);
|
2012-03-28 02:49:53 +00:00
|
|
|
else
|
|
|
|
/* No local addresses, so put all zeroes */
|
|
|
|
bzero(mdp->out.src.sid,SID_SIZE);
|
|
|
|
}
|
2012-03-28 00:58:04 +00:00
|
|
|
|
2012-04-15 21:34:23 +00:00
|
|
|
/* queue frame for delivery */
|
|
|
|
overlay_mdp_dispatch(mdp,0 /* system generated */,
|
|
|
|
NULL,0);
|
|
|
|
|
|
|
|
/* 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);
|
2012-06-25 23:52:51 +00:00
|
|
|
|
2012-03-28 00:58:04 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Unbound socket. We won't be sending ICMP style connection refused
|
|
|
|
messages, partly because they are a waste of bandwidth. */
|
2012-06-25 23:52:51 +00:00
|
|
|
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-03-28 00:58:04 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-27 10:43:40 +00:00
|
|
|
break;
|
|
|
|
default:
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(WHYF("We should only see MDP_TX frames here (MDP message type = 0x%x)",
|
|
|
|
mdp->packetTypeAndFlags));
|
2012-03-27 10:43:40 +00:00
|
|
|
}
|
|
|
|
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(0);
|
2012-03-16 22:30:51 +00:00
|
|
|
}
|
2012-03-17 02:32:09 +00:00
|
|
|
|
2012-08-06 07:14:36 +00:00
|
|
|
int overlay_mdp_dnalookup_reply(const sockaddr_mdp *dstaddr, const unsigned char *resolved_sid, const char *uri, const char *did, const char *name)
|
2012-07-20 08:47:43 +00:00
|
|
|
{
|
|
|
|
overlay_mdp_frame mdpreply;
|
|
|
|
bzero(&mdpreply, sizeof mdpreply);
|
|
|
|
mdpreply.packetTypeAndFlags = MDP_TX; // outgoing MDP message
|
2012-08-06 07:14:36 +00:00
|
|
|
memcpy(mdpreply.out.src.sid, resolved_sid, SID_SIZE);
|
|
|
|
mdpreply.out.src.port = MDP_PORT_DNALOOKUP;
|
|
|
|
bcopy(dstaddr, &mdpreply.out.dst, sizeof(sockaddr_mdp));
|
2012-07-20 08:47:43 +00:00
|
|
|
/* build reply as TOKEN|URI|DID|NAME|<NUL> */
|
|
|
|
strbuf b = strbuf_local((char *)mdpreply.out.payload, sizeof mdpreply.out.payload);
|
2012-08-06 07:14:36 +00:00
|
|
|
strbuf_tohex(b, resolved_sid, SID_SIZE);
|
2012-07-20 08:47:43 +00:00
|
|
|
strbuf_sprintf(b, "|%s|%s|%s|", uri, did, name);
|
|
|
|
if (strbuf_overrun(b))
|
|
|
|
return WHY("MDP payload overrun");
|
|
|
|
mdpreply.out.payload_length = strbuf_len(b) + 1;
|
|
|
|
/* deliver reply */
|
|
|
|
return overlay_mdp_dispatch(&mdpreply, 0 /* system generated */, NULL, 0);
|
|
|
|
}
|
|
|
|
|
2012-04-14 00:03:29 +00:00
|
|
|
int overlay_mdp_sanitytest_sourceaddr(sockaddr_mdp *src,int userGeneratedFrameP,
|
2012-03-27 09:15:39 +00:00
|
|
|
struct sockaddr_un *recvaddr,
|
|
|
|
int recvaddrlen)
|
|
|
|
{
|
2012-08-27 00:34:59 +00:00
|
|
|
if (is_broadcast(src->sid))
|
2012-03-27 09:15:39 +00:00
|
|
|
{
|
|
|
|
/* 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");
|
|
|
|
}
|
2012-08-06 07:14:36 +00:00
|
|
|
|
2012-03-27 09:15:39 +00:00
|
|
|
/* Now make sure that source address is in the list of bound addresses,
|
|
|
|
and that the recvaddr matches. */
|
|
|
|
int i;
|
2012-08-06 07:14:36 +00:00
|
|
|
for(i = 0; i < MDP_MAX_BINDINGS; ++i) {
|
2012-08-14 05:01:25 +00:00
|
|
|
if (mdp_bindings[i].addr.port && memcmp(src, &mdp_bindings[i].addr, sizeof(sockaddr_mdp)) == 0) {
|
2012-08-06 07:14:36 +00:00
|
|
|
/* Binding matches, now make sure the sockets match */
|
2012-08-14 05:01:25 +00:00
|
|
|
if ( mdp_bindings[i].name_len == recvaddrlen - sizeof(short)
|
|
|
|
&& memcmp(mdp_bindings[i].socket_name, recvaddr->sun_path, recvaddrlen - sizeof(short)) == 0
|
2012-08-06 07:14:36 +00:00
|
|
|
) {
|
|
|
|
/* Everything matches, so this unix socket and MDP address combination is valid */
|
|
|
|
return 0;
|
|
|
|
}
|
2012-03-27 09:15:39 +00:00
|
|
|
}
|
2012-08-06 07:14:36 +00:00
|
|
|
}
|
2012-03-27 09:15:39 +00:00
|
|
|
|
2012-08-27 00:34:59 +00:00
|
|
|
struct subscriber *subscriber = find_subscriber(src->sid, SID_SIZE, 1);
|
2012-04-15 20:36:43 +00:00
|
|
|
/* Check for build-in port listeners */
|
2012-08-27 00:34:59 +00:00
|
|
|
if (subscriber && subscriber->reachable == REACHABLE_SELF) {
|
2012-04-15 20:36:43 +00:00
|
|
|
switch(src->port) {
|
|
|
|
case MDP_PORT_ECHO:
|
|
|
|
/* we don't allow user/network generated packets claiming to
|
|
|
|
be from the echo port, largely to prevent echo:echo connections
|
|
|
|
and the resulting denial of service from triggering endless pongs. */
|
2012-08-06 07:14:36 +00:00
|
|
|
if (!userGeneratedFrameP)
|
|
|
|
return 0;
|
2012-04-15 20:36:43 +00:00
|
|
|
break;
|
|
|
|
/* other built-in listeners */
|
|
|
|
case MDP_PORT_KEYMAPREQUEST:
|
2012-04-18 22:04:12 +00:00
|
|
|
case MDP_PORT_VOMP:
|
2012-04-24 20:47:26 +00:00
|
|
|
case MDP_PORT_DNALOOKUP:
|
2012-04-15 20:36:43 +00:00
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
break;
|
2012-08-06 07:14:36 +00:00
|
|
|
}
|
|
|
|
}
|
2012-04-15 20:36:43 +00:00
|
|
|
|
2012-08-06 07:14:36 +00:00
|
|
|
return WHYF("No such binding: recvaddr=%p %s addr=%s port=%u (0x%x) -- possible spoofing attack",
|
|
|
|
recvaddr,
|
|
|
|
recvaddr ? alloca_toprint(-1, recvaddr->sun_path, recvaddrlen - sizeof(short)) : "",
|
2012-08-02 07:46:18 +00:00
|
|
|
alloca_tohex_sid(src->sid),
|
2012-08-06 07:14:36 +00:00
|
|
|
src->port, src->port
|
2012-08-02 07:46:18 +00:00
|
|
|
);
|
2012-03-27 09:15:39 +00:00
|
|
|
}
|
|
|
|
|
2012-03-28 00:58:04 +00:00
|
|
|
/* 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()
|
|
|
|
*/
|
2012-04-14 00:03:29 +00:00
|
|
|
int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP,
|
|
|
|
struct sockaddr_un *recvaddr,int recvaddrlen)
|
2012-03-28 00:58:04 +00:00
|
|
|
{
|
2012-06-25 23:52:51 +00:00
|
|
|
IN();
|
2012-03-28 00:58:04 +00:00
|
|
|
/* Work out if destination is broadcast or not */
|
2012-04-14 00:03:29 +00:00
|
|
|
if (overlay_mdp_sanitytest_sourceaddr(&mdp->out.src,userGeneratedFrameP,
|
2012-03-28 00:58:04 +00:00
|
|
|
recvaddr,recvaddrlen))
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(overlay_mdp_reply_error
|
2012-07-02 03:49:54 +00:00
|
|
|
(mdp_named.poll.fd,
|
2012-06-25 23:52:51 +00:00
|
|
|
(struct sockaddr_un *)recvaddr,
|
|
|
|
recvaddrlen,8,
|
|
|
|
"Source address is invalid (you must bind to a source address before"
|
|
|
|
" you can send packets"));
|
2012-03-28 00:58:04 +00:00
|
|
|
|
2012-08-27 00:34:59 +00:00
|
|
|
/* Prepare the overlay frame for dispatch */
|
|
|
|
struct overlay_frame *frame = calloc(1,sizeof(struct overlay_frame));
|
|
|
|
|
|
|
|
if (is_broadcast(mdp->out.dst.sid)){
|
|
|
|
/* 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 (!(mdp->packetTypeAndFlags&MDP_NOCRYPT))
|
|
|
|
RETURN(overlay_mdp_reply_error(mdp_named.poll.fd,
|
|
|
|
recvaddr,recvaddrlen,5,
|
|
|
|
"Broadcast packets cannot be encrypted "));
|
|
|
|
|
|
|
|
overlay_broadcast_generate_address(&frame->broadcast_id);
|
|
|
|
frame->destination = NULL;
|
|
|
|
}else{
|
|
|
|
frame->destination = find_subscriber(mdp->out.dst.sid, SID_SIZE, 1);
|
|
|
|
}
|
|
|
|
frame->ttl=64; /* normal TTL (XXX allow setting this would be a good idea) */
|
2012-03-28 00:58:04 +00:00
|
|
|
|
2012-08-27 00:34:59 +00:00
|
|
|
if (is_sid_any(mdp->out.src.sid)){
|
|
|
|
/* set source to ourselves */
|
|
|
|
frame->source = my_subscriber;
|
|
|
|
bcopy(frame->source->sid, mdp->out.src.sid, SID_SIZE);
|
|
|
|
}else{
|
|
|
|
frame->source = find_subscriber(mdp->out.src.sid, SID_SIZE, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!frame->destination || frame->destination->reachable == REACHABLE_SELF)
|
2012-03-28 00:58:04 +00:00
|
|
|
{
|
|
|
|
/* Packet is addressed such that we should process it. */
|
2012-07-30 07:52:38 +00:00
|
|
|
overlay_saw_mdp_frame(mdp,gettime_ms());
|
2012-08-27 00:34:59 +00:00
|
|
|
if (frame->destination) {
|
2012-03-28 00:58:04 +00:00
|
|
|
/* Is local, and is not broadcast, so shouldn't get sent out
|
|
|
|
on the wire. */
|
2012-08-27 00:34:59 +00:00
|
|
|
op_free(frame);
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(0);
|
2012-03-28 00:58:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-25 03:38:18 +00:00
|
|
|
/* give voice packets priority */
|
|
|
|
if (mdp->out.dst.port==MDP_PORT_VOMP) frame->type=OF_TYPE_DATA_VOICE;
|
|
|
|
else frame->type=OF_TYPE_DATA;
|
2012-03-28 00:58:04 +00:00
|
|
|
frame->prev=NULL;
|
|
|
|
frame->next=NULL;
|
2012-08-27 00:34:59 +00:00
|
|
|
frame->payload=ob_new();
|
2012-03-28 00:58:04 +00:00
|
|
|
|
2012-04-13 16:44:41 +00:00
|
|
|
int fe=0;
|
|
|
|
|
2012-08-27 00:34:59 +00:00
|
|
|
/* Work out the disposition of the frame-> For now we are only worried
|
2012-03-28 00:58:04 +00:00
|
|
|
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)) {
|
2012-04-13 16:44:41 +00:00
|
|
|
case 0: /* crypted and signed (using CryptoBox authcryption primitive) */
|
|
|
|
frame->modifiers=OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED;
|
|
|
|
/* Prepare payload */
|
2012-08-27 00:34:59 +00:00
|
|
|
ob_makespace(frame->payload,
|
|
|
|
1 // frame type (MDP)
|
|
|
|
+1 // MDP version
|
|
|
|
+4 // dst port
|
|
|
|
+4 // src port
|
|
|
|
+crypto_box_curve25519xsalsa20poly1305_NONCEBYTES
|
|
|
|
+crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
|
|
|
|
+mdp->out.payload_length);
|
2012-04-13 16:44:41 +00:00
|
|
|
{
|
|
|
|
/* write cryptobox nonce */
|
|
|
|
unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES];
|
2012-05-20 06:36:32 +00:00
|
|
|
if (urandombytes(nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES)) {
|
|
|
|
op_free(frame);
|
2012-06-25 23:52:51 +00:00
|
|
|
RETURN(WHY("urandombytes() failed to generate nonce"));
|
2012-05-20 06:36:32 +00:00
|
|
|
}
|
|
|
|
fe|= ob_append_bytes(frame->payload,nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
|
2012-04-13 16:44:41 +00:00
|
|
|
/* generate plain message with zero bytes and get ready to cipher it */
|
|
|
|
unsigned char plain[crypto_box_curve25519xsalsa20poly1305_ZEROBYTES
|
2012-04-14 02:47:46 +00:00
|
|
|
+10+mdp->out.payload_length];
|
|
|
|
/* zero bytes */
|
|
|
|
int zb=crypto_box_curve25519xsalsa20poly1305_ZEROBYTES;
|
|
|
|
bzero(&plain[0],zb);
|
|
|
|
/* MDP version 1 */
|
|
|
|
plain[zb+0]=0x01;
|
|
|
|
plain[zb+1]=0x01;
|
|
|
|
/* Ports */
|
2012-04-14 04:50:49 +00:00
|
|
|
plain[zb+2]=(mdp->out.src.port>>24)&0xff;
|
|
|
|
plain[zb+3]=(mdp->out.src.port>>16)&0xff;
|
|
|
|
plain[zb+4]=(mdp->out.src.port>>8)&0xff;
|
|
|
|
plain[zb+5]=(mdp->out.src.port>>0)&0xff;
|
|
|
|
plain[zb+6]=(mdp->out.dst.port>>24)&0xff;
|
|
|
|
plain[zb+7]=(mdp->out.dst.port>>16)&0xff;
|
|
|
|
plain[zb+8]=(mdp->out.dst.port>>8)&0xff;
|
|
|
|
plain[zb+9]=(mdp->out.dst.port>>0)&0xff;
|
2012-04-14 02:47:46 +00:00
|
|
|
/* payload */
|
|
|
|
bcopy(&mdp->out.payload,&plain[zb+10],mdp->out.payload_length);
|
|
|
|
int cipher_len=zb+10+mdp->out.payload_length;
|
2012-04-13 16:44:41 +00:00
|
|
|
|
|
|
|
/* get pre-computed PKxSK bytes (the slow part of auth-cryption that can be
|
|
|
|
retained and reused, and use that to do the encryption quickly. */
|
|
|
|
unsigned char *k=keyring_get_nm_bytes(&mdp->out.src,&mdp->out.dst);
|
2012-08-27 00:34:59 +00:00
|
|
|
if (!k) {
|
|
|
|
op_free(frame);
|
|
|
|
RETURN(WHY("could not compute Curve25519(NxM)"));
|
|
|
|
}
|
2012-04-13 16:44:41 +00:00
|
|
|
/* Get pointer to place in frame where the ciphered text needs to go */
|
2012-08-22 00:51:38 +00:00
|
|
|
int cipher_offset=frame->payload->position;
|
2012-04-14 02:47:46 +00:00
|
|
|
unsigned char *cipher_text=ob_append_space(frame->payload,cipher_len);
|
2012-08-27 00:34:59 +00:00
|
|
|
if (fe||(!cipher_text)){
|
|
|
|
op_free(frame);
|
|
|
|
RETURN(WHY("could not make space for ciphered text"));
|
|
|
|
}
|
2012-04-13 16:44:41 +00:00
|
|
|
/* Actually authcrypt the payload */
|
2012-04-14 02:47:46 +00:00
|
|
|
if (crypto_box_curve25519xsalsa20poly1305_afternm
|
2012-08-27 00:34:59 +00:00
|
|
|
(cipher_text,plain,cipher_len,nonce,k)){
|
|
|
|
op_free(frame);
|
|
|
|
RETURN(WHY("crypto_box_afternm() failed"));
|
|
|
|
}
|
2012-04-14 02:47:46 +00:00
|
|
|
/* now shuffle down 16 bytes to get rid of the temporary space that crypto_box
|
|
|
|
uses. */
|
|
|
|
bcopy(&cipher_text[16],&cipher_text[0],cipher_len-16);
|
2012-08-22 00:51:38 +00:00
|
|
|
frame->payload->position-=16;
|
2012-04-14 04:50:49 +00:00
|
|
|
if (0) {
|
2012-05-20 06:36:32 +00:00
|
|
|
DEBUG("authcrypted mdp frame");
|
2012-04-14 03:03:15 +00:00
|
|
|
dump("nm bytes",k,crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES);
|
|
|
|
dump("nonce",nonce,crypto_box_curve25519xsalsa20poly1305_NONCEBYTES);
|
2012-04-14 02:47:46 +00:00
|
|
|
dump("plain text",&plain[16],cipher_len-16);
|
2012-04-14 03:03:15 +00:00
|
|
|
dump("cipher text",cipher_text,cipher_len-16);
|
2012-08-22 00:51:38 +00:00
|
|
|
DEBUGF("frame->payload->length=%d,cipher_len-16=%d,cipher_offset=%d", frame->payload->position,cipher_len-16,cipher_offset);
|
2012-04-14 02:47:46 +00:00
|
|
|
dump("frame",&frame->payload->bytes[0],
|
2012-08-22 00:51:38 +00:00
|
|
|
frame->payload->position);
|
2012-04-14 02:47:46 +00:00
|
|
|
}
|
2012-04-13 16:44:41 +00:00
|
|
|
}
|
2012-03-28 00:58:04 +00:00
|
|
|
break;
|
|
|
|
case MDP_NOCRYPT:
|
2012-04-14 17:47:36 +00:00
|
|
|
/* Payload is sent unencrypted, but signed.
|
|
|
|
|
|
|
|
To save space we do a trick where we hash the payload, and get the
|
|
|
|
signature of that, but do not send the hash itself, since that can
|
|
|
|
be reproduced (and indeed must be for verification) at the receiver's
|
|
|
|
end.
|
|
|
|
|
|
|
|
As the signing key is implicit, and the hash is also implicit, we can
|
|
|
|
chop out part of the signature and thus save some bytes.
|
|
|
|
*/
|
2012-03-28 00:58:04 +00:00
|
|
|
frame->modifiers=OF_CRYPTO_SIGNED;
|
2012-04-14 17:47:36 +00:00
|
|
|
/* Prepare payload */
|
2012-08-27 00:34:59 +00:00
|
|
|
ob_makespace(frame->payload,
|
|
|
|
1 // frame type (MDP)
|
|
|
|
+1 // MDP version
|
|
|
|
+4 // dst port
|
|
|
|
+4 // src port
|
2012-08-22 00:51:38 +00:00
|
|
|
+crypto_sign_edwards25519sha512batch_BYTES
|
2012-08-27 00:34:59 +00:00
|
|
|
+mdp->out.payload_length);
|
2012-04-14 17:47:36 +00:00
|
|
|
{
|
2012-08-27 00:34:59 +00:00
|
|
|
unsigned char *key=keyring_find_sas_private(keyring, frame->source->sid, NULL);
|
|
|
|
if (!key) {
|
|
|
|
op_free(frame);
|
|
|
|
RETURN(WHY("could not find signing key"));
|
|
|
|
}
|
2012-04-14 17:47:36 +00:00
|
|
|
|
|
|
|
/* Build plain-text that includes header and hash it so that
|
|
|
|
we can sign that hash. */
|
|
|
|
unsigned char hash[crypto_hash_sha512_BYTES];
|
|
|
|
unsigned char plain[10+mdp->out.payload_length];
|
|
|
|
|
|
|
|
/* MDP version 1 */
|
|
|
|
plain[0]=0x01;
|
|
|
|
plain[1]=0x01;
|
|
|
|
/* Ports */
|
|
|
|
plain[2]=(mdp->out.src.port>>24)&0xff;
|
|
|
|
plain[3]=(mdp->out.src.port>>16)&0xff;
|
|
|
|
plain[4]=(mdp->out.src.port>>8)&0xff;
|
|
|
|
plain[5]=(mdp->out.src.port>>0)&0xff;
|
|
|
|
plain[6]=(mdp->out.dst.port>>24)&0xff;
|
|
|
|
plain[7]=(mdp->out.dst.port>>16)&0xff;
|
|
|
|
plain[8]=(mdp->out.dst.port>>8)&0xff;
|
|
|
|
plain[9]=(mdp->out.dst.port>>0)&0xff;
|
|
|
|
/* payload */
|
|
|
|
bcopy(&mdp->out.payload,&plain[10],mdp->out.payload_length);
|
|
|
|
/* now hash it */
|
|
|
|
crypto_hash_sha512(hash,plain,10+mdp->out.payload_length);
|
|
|
|
|
|
|
|
unsigned char signature[crypto_hash_sha512_BYTES
|
|
|
|
+crypto_sign_edwards25519sha512batch_BYTES];
|
|
|
|
unsigned long long sig_len=0;
|
|
|
|
crypto_sign_edwards25519sha512batch(signature,&sig_len,
|
|
|
|
hash,crypto_hash_sha512_BYTES,
|
|
|
|
key);
|
2012-08-27 00:34:59 +00:00
|
|
|
if (!sig_len) {
|
|
|
|
op_free(frame);
|
|
|
|
RETURN(WHY("Signing MDP frame failed"));
|
|
|
|
}
|
2012-04-14 17:47:36 +00:00
|
|
|
/* chop hash out of middle of signature since it has to be recomputed
|
|
|
|
at the far end, anyway, as described above. */
|
|
|
|
bcopy(&signature[32+64],&signature[32],32);
|
|
|
|
sig_len-=crypto_hash_sha512_BYTES;
|
|
|
|
|
|
|
|
/* ok, now chain plain-text with the signature at the end and send it */
|
|
|
|
ob_append_bytes(frame->payload,plain,10+mdp->out.payload_length);
|
|
|
|
/* chop hash out of middle of signature since it has to be recomputed
|
|
|
|
at the far end, anyway, as described above. */
|
|
|
|
ob_append_bytes(frame->payload,&signature[0],32);
|
|
|
|
ob_append_bytes(frame->payload,&signature[32+crypto_hash_sha512_BYTES],32);
|
|
|
|
}
|
2012-03-28 00:58:04 +00:00
|
|
|
break;
|
|
|
|
case MDP_NOSIGN|MDP_NOCRYPT: /* clear text and no signature */
|
|
|
|
frame->modifiers=0;
|
|
|
|
/* Copy payload body in */
|
2012-08-27 00:34:59 +00:00
|
|
|
ob_makespace(frame->payload,
|
|
|
|
1 // frame type (MDP)
|
|
|
|
+1 // MDP version
|
|
|
|
+4 // dst port
|
|
|
|
+4 // src port
|
|
|
|
+mdp->out.payload_length);
|
2012-03-28 00:58:04 +00:00
|
|
|
/* MDP version 1 */
|
|
|
|
ob_append_byte(frame->payload,0x01);
|
|
|
|
ob_append_byte(frame->payload,0x01);
|
|
|
|
/* Destination port */
|
2012-08-22 00:51:38 +00:00
|
|
|
ob_append_ui32(frame->payload,mdp->out.src.port);
|
|
|
|
ob_append_ui32(frame->payload,mdp->out.dst.port);
|
2012-03-28 00:58:04 +00:00
|
|
|
ob_append_bytes(frame->payload,mdp->out.payload,mdp->out.payload_length);
|
|
|
|
break;
|
2012-08-27 00:34:59 +00:00
|
|
|
case MDP_NOSIGN:
|
|
|
|
default:
|
|
|
|
/* ciphered, but not signed.
|
|
|
|
This means we don't use CryptoBox, but rather a more compact means
|
|
|
|
of representing the ciphered stream segment.
|
|
|
|
*/
|
|
|
|
op_free(frame);
|
|
|
|
RETURN(WHY("Not implemented"));
|
|
|
|
break;
|
2012-04-13 22:45:29 +00:00
|
|
|
}
|
2012-03-28 00:58:04 +00:00
|
|
|
|
2012-08-27 00:34:59 +00:00
|
|
|
// TODO include priority in packet header
|
|
|
|
int qn=OQ_ORDINARY;
|
|
|
|
/* Make sure voice traffic gets priority */
|
|
|
|
if ((frame->type&OF_TYPE_BITS)==OF_TYPE_DATA_VOICE) {
|
|
|
|
qn=OQ_ISOCHRONOUS_VOICE;
|
2012-05-22 04:45:19 +00:00
|
|
|
rhizome_saw_voice_traffic();
|
2012-05-06 23:01:53 +00:00
|
|
|
}
|
2012-08-27 00:34:59 +00:00
|
|
|
|
|
|
|
if (overlay_payload_enqueue(qn, frame))
|
|
|
|
op_free(frame);
|
|
|
|
RETURN(0);
|
2012-03-28 00:58:04 +00:00
|
|
|
}
|
|
|
|
|
2012-08-15 04:06:10 +00:00
|
|
|
struct search_state{
|
|
|
|
overlay_mdp_frame *mdp;
|
|
|
|
overlay_mdp_frame *mdpreply;
|
|
|
|
int first;
|
|
|
|
int max;
|
|
|
|
int index;
|
|
|
|
int count;
|
|
|
|
};
|
|
|
|
|
2012-08-27 00:34:59 +00:00
|
|
|
static int search_subscribers(struct subscriber *subscriber, void *context){
|
2012-08-15 04:06:10 +00:00
|
|
|
struct search_state *state = context;
|
2012-08-27 00:34:59 +00:00
|
|
|
|
|
|
|
if (state->mdp->addrlist.mode == MDP_ADDRLIST_MODE_SELF && subscriber->reachable != REACHABLE_SELF){
|
2012-08-15 04:06:10 +00:00
|
|
|
return 0;
|
2012-08-27 00:34:59 +00:00
|
|
|
}
|
2012-08-15 04:06:10 +00:00
|
|
|
|
2012-08-27 00:34:59 +00:00
|
|
|
if (state->mdp->addrlist.mode == MDP_ADDRLIST_MODE_ROUTABLE_PEERS &&
|
|
|
|
(subscriber->reachable != REACHABLE_DIRECT && subscriber->reachable != REACHABLE_INDIRECT)){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->mdp->addrlist.mode == MDP_ADDRLIST_MODE_ALL_PEERS &&
|
|
|
|
subscriber->reachable == REACHABLE_SELF){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state->count++ >= state->first && state->index < state->max) {
|
|
|
|
memcpy(state->mdpreply->addrlist.sids[state->index++], subscriber->sid, SID_SIZE);
|
2012-08-15 04:06:10 +00:00
|
|
|
}
|
2012-08-27 00:34:59 +00:00
|
|
|
|
2012-08-15 04:06:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-07-02 03:49:54 +00:00
|
|
|
void overlay_mdp_poll(struct sched_ent *alarm)
|
2012-03-17 02:32:09 +00:00
|
|
|
{
|
2012-08-22 05:20:14 +00:00
|
|
|
if (alarm->poll.revents & POLLIN) {
|
|
|
|
unsigned char buffer[16384];
|
|
|
|
int ttl;
|
|
|
|
unsigned char recvaddrbuffer[1024];
|
|
|
|
struct sockaddr *recvaddr=(struct sockaddr *)&recvaddrbuffer[0];
|
|
|
|
socklen_t recvaddrlen=sizeof(recvaddrbuffer);
|
|
|
|
struct sockaddr_un *recvaddr_un=NULL;
|
|
|
|
|
|
|
|
ttl=-1;
|
|
|
|
bzero((void *)recvaddrbuffer,sizeof(recvaddrbuffer));
|
2012-08-27 00:34:59 +00:00
|
|
|
|
2012-08-22 05:20:14 +00:00
|
|
|
ssize_t len = recvwithttl(alarm->poll.fd,buffer,sizeof(buffer),&ttl, recvaddr, &recvaddrlen);
|
|
|
|
recvaddr_un=(struct sockaddr_un *)recvaddr;
|
|
|
|
|
|
|
|
if (len>0) {
|
|
|
|
/* Look at overlay_mdp_frame we have received */
|
|
|
|
overlay_mdp_frame *mdp=(overlay_mdp_frame *)&buffer[0];
|
|
|
|
unsigned int mdp_type = mdp->packetTypeAndFlags & MDP_TYPE_MASK;
|
|
|
|
|
|
|
|
switch (mdp_type) {
|
|
|
|
case MDP_GOODBYE:
|
|
|
|
if (debug & DEBUG_MDPREQUESTS) DEBUG("MDP_GOODBYE");
|
|
|
|
overlay_mdp_releasebindings(recvaddr_un,recvaddrlen);
|
|
|
|
return;
|
|
|
|
case MDP_NODEINFO:
|
|
|
|
if (debug & DEBUG_MDPREQUESTS) DEBUG("MDP_NODEINFO");
|
|
|
|
overlay_route_node_info(mdp,recvaddr_un,recvaddrlen);
|
|
|
|
return;
|
|
|
|
case MDP_GETADDRS:
|
|
|
|
if (debug & DEBUG_MDPREQUESTS)
|
|
|
|
DEBUGF("MDP_GETADDRS first_sid=%u last_sid=%u frame_sid_count=%u mode=%d",
|
|
|
|
mdp->addrlist.first_sid,
|
|
|
|
mdp->addrlist.last_sid,
|
|
|
|
mdp->addrlist.frame_sid_count,
|
|
|
|
mdp->addrlist.mode
|
|
|
|
);
|
|
|
|
{
|
|
|
|
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 (max_sids>MDP_MAX_SID_REQUEST) max_sids=MDP_MAX_SID_REQUEST;
|
|
|
|
if (max_sids<0) max_sids=0;
|
2012-08-15 04:06:10 +00:00
|
|
|
|
2012-08-22 05:20:14 +00:00
|
|
|
/* Prepare reply packet */
|
|
|
|
mdpreply.packetTypeAndFlags = MDP_ADDRLIST;
|
|
|
|
mdpreply.addrlist.mode = mdp->addrlist.mode;
|
|
|
|
mdpreply.addrlist.first_sid = sid_num;
|
|
|
|
mdpreply.addrlist.last_sid = max_sid;
|
|
|
|
mdpreply.addrlist.frame_sid_count = max_sids;
|
|
|
|
|
|
|
|
/* Populate with SIDs */
|
2012-08-27 00:34:59 +00:00
|
|
|
struct search_state state={
|
|
|
|
.mdp=mdp,
|
|
|
|
.mdpreply=&mdpreply,
|
|
|
|
.first=sid_num,
|
|
|
|
.max=max_sid,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum_subscribers(NULL, search_subscribers, &state);
|
|
|
|
|
|
|
|
mdpreply.addrlist.frame_sid_count = state.index;
|
|
|
|
mdpreply.addrlist.last_sid = sid_num + state.index - 1;
|
|
|
|
mdpreply.addrlist.server_sid_count = state.count;
|
2012-08-22 05:20:14 +00:00
|
|
|
|
|
|
|
if (debug & DEBUG_MDPREQUESTS)
|
|
|
|
DEBUGF("reply MDP_ADDRLIST first_sid=%u last_sid=%u frame_sid_count=%u server_sid_count=%u",
|
|
|
|
mdpreply.addrlist.first_sid,
|
|
|
|
mdpreply.addrlist.last_sid,
|
|
|
|
mdpreply.addrlist.frame_sid_count,
|
|
|
|
mdpreply.addrlist.server_sid_count
|
|
|
|
);
|
|
|
|
|
|
|
|
/* Send back to caller */
|
|
|
|
overlay_mdp_reply(alarm->poll.fd,
|
|
|
|
(struct sockaddr_un *)recvaddr,recvaddrlen,
|
|
|
|
&mdpreply);
|
|
|
|
return;
|
2012-03-27 08:55:38 +00:00
|
|
|
}
|
2012-08-22 05:20:14 +00:00
|
|
|
break;
|
|
|
|
case MDP_TX: /* Send payload (and don't treat it as system privileged) */
|
|
|
|
if (debug & DEBUG_MDPREQUESTS) DEBUG("MDP_TX");
|
|
|
|
overlay_mdp_dispatch(mdp,1,(struct sockaddr_un*)recvaddr,recvaddrlen);
|
2012-06-22 03:55:41 +00:00
|
|
|
return;
|
2012-08-22 05:20:14 +00:00
|
|
|
break;
|
|
|
|
case MDP_BIND: /* Bind to port */
|
|
|
|
if (debug & DEBUG_MDPREQUESTS) DEBUG("MDP_BIND");
|
|
|
|
overlay_mdp_process_bind_request(alarm->poll.fd,mdp, recvaddr_un, recvaddrlen);
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Client is not allowed to send any other frame type */
|
|
|
|
WARNF("Unsupported MDP frame type: %d", mdp_type);
|
|
|
|
mdp->packetTypeAndFlags=MDP_ERROR;
|
|
|
|
mdp->error.error=2;
|
|
|
|
snprintf(mdp->error.message,128,"Illegal request type. Clients may use only MDP_TX or MDP_BIND.");
|
|
|
|
int len=4+4+strlen(mdp->error.message)+1;
|
|
|
|
errno=0;
|
|
|
|
/* We ignore the result of the following, because it is just sending an
|
|
|
|
error message back to the client. If this fails, where would we report
|
|
|
|
the error to? My point exactly. */
|
|
|
|
sendto(alarm->poll.fd,mdp,len,0,(struct sockaddr *)recvaddr,recvaddrlen);
|
2012-03-19 05:53:05 +00:00
|
|
|
}
|
2012-03-19 05:36:34 +00:00
|
|
|
}
|
|
|
|
}
|
2012-08-22 05:20:14 +00:00
|
|
|
|
|
|
|
if (alarm->poll.revents & (POLLHUP | POLLERR)) {
|
|
|
|
INFO("Error on mdp socket");
|
|
|
|
}
|
2012-06-22 03:55:41 +00:00
|
|
|
return;
|
2012-03-19 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
2012-03-27 08:55:38 +00:00
|
|
|
int overlay_mdp_relevant_bytes(overlay_mdp_frame *mdp)
|
|
|
|
{
|
|
|
|
int len=4;
|
|
|
|
switch(mdp->packetTypeAndFlags&MDP_TYPE_MASK)
|
|
|
|
{
|
2012-04-30 20:40:47 +00:00
|
|
|
case MDP_GOODBYE:
|
|
|
|
/* no arguments for saying goodbye */
|
|
|
|
break;
|
2012-04-20 05:47:38 +00:00
|
|
|
case MDP_ADDRLIST:
|
|
|
|
len=&mdp->addrlist.sids[0][0]-(unsigned char *)mdp;
|
|
|
|
len+=mdp->addrlist.frame_sid_count*SID_SIZE;
|
2012-03-27 08:55:38 +00:00
|
|
|
break;
|
2012-04-20 05:47:38 +00:00
|
|
|
case MDP_GETADDRS:
|
|
|
|
len=&mdp->addrlist.sids[0][0]-(unsigned char *)mdp;
|
2012-03-27 08:55:38 +00:00
|
|
|
break;
|
|
|
|
case MDP_TX:
|
2012-04-20 05:47:38 +00:00
|
|
|
len=&mdp->out.payload[0]-(unsigned char *)mdp;
|
|
|
|
len+=mdp->out.payload_length;
|
2012-03-27 08:55:38 +00:00
|
|
|
break;
|
2012-04-20 05:47:38 +00:00
|
|
|
case MDP_BIND:
|
|
|
|
len=&mdp->bind.sid[SID_SIZE]-(unsigned char *)mdp;
|
2012-04-21 22:55:48 +00:00
|
|
|
break;
|
2012-03-27 08:55:38 +00:00
|
|
|
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 */
|
2012-04-20 05:47:38 +00:00
|
|
|
len=&mdp->error.message[0]-(char *)mdp;
|
2012-05-18 03:25:56 +00:00
|
|
|
len+=strlen(mdp->error.message)+1;
|
2012-06-21 04:13:28 +00:00
|
|
|
if (mdp->error.error) INFOF("mdp return/error code: %d:%s",mdp->error.error,mdp->error.message);
|
2012-04-20 05:52:42 +00:00
|
|
|
break;
|
2012-04-25 21:44:01 +00:00
|
|
|
case MDP_NODEINFO:
|
2012-04-26 06:17:37 +00:00
|
|
|
/* XXX problems with calculating this due to structure padding,
|
|
|
|
so doubled required space, and now it works. */
|
|
|
|
len=sizeof(overlay_mdp_nodeinfo)*2;
|
2012-04-25 21:44:01 +00:00
|
|
|
break;
|
2012-03-27 08:55:38 +00:00
|
|
|
default:
|
|
|
|
return WHY("Illegal MDP frame type.");
|
|
|
|
}
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2012-03-19 05:36:34 +00:00
|
|
|
int mdp_client_socket=-1;
|
2012-03-28 00:58:04 +00:00
|
|
|
int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms)
|
2012-03-19 05:36:34 +00:00
|
|
|
{
|
2012-03-19 05:53:05 +00:00
|
|
|
int len=4;
|
|
|
|
|
2012-04-27 09:22:39 +00:00
|
|
|
if (mdp_client_socket==-1)
|
|
|
|
if (overlay_mdp_client_init() != 0)
|
|
|
|
return -1;
|
2012-03-20 16:30:39 +00:00
|
|
|
|
2012-03-19 05:53:05 +00:00
|
|
|
/* Minimise frame length to save work and prevent accidental disclosure of
|
|
|
|
memory contents. */
|
2012-03-27 08:55:38 +00:00
|
|
|
len=overlay_mdp_relevant_bytes(mdp);
|
|
|
|
if (len<0) return WHY("MDP frame invalid (could not compute length)");
|
2012-03-19 05:53:05 +00:00
|
|
|
|
2012-03-19 05:36:34 +00:00
|
|
|
/* Construct name of socket to send to. */
|
|
|
|
struct sockaddr_un name;
|
|
|
|
name.sun_family = AF_UNIX;
|
2012-03-29 03:37:07 +00:00
|
|
|
if (!FORM_SERVAL_INSTANCE_PATH(name.sun_path, "mdp.socket"))
|
|
|
|
return -1;
|
2012-03-19 05:36:34 +00:00
|
|
|
|
2012-07-10 07:03:39 +00:00
|
|
|
set_nonblock(mdp_client_socket);
|
2012-03-19 05:53:05 +00:00
|
|
|
int result=sendto(mdp_client_socket, mdp, len, 0,
|
2012-03-19 05:36:34 +00:00
|
|
|
(struct sockaddr *)&name, sizeof(struct sockaddr_un));
|
2012-07-10 07:03:39 +00:00
|
|
|
set_block(mdp_client_socket);
|
2012-03-19 05:36:34 +00:00
|
|
|
if (result<0) {
|
2012-03-19 05:53:05 +00:00
|
|
|
mdp->packetTypeAndFlags=MDP_ERROR;
|
|
|
|
mdp->error.error=1;
|
|
|
|
snprintf(mdp->error.message,128,"Error sending frame to MDP server.");
|
2012-05-08 08:18:16 +00:00
|
|
|
return WHY_perror("sendto(f)");
|
2012-03-19 05:36:34 +00:00
|
|
|
} else {
|
2012-03-20 16:30:39 +00:00
|
|
|
if (!(flags&MDP_AWAITREPLY)) {
|
2012-03-20 15:06:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2012-03-19 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
2012-06-26 01:47:33 +00:00
|
|
|
if (overlay_mdp_client_poll(timeout_ms)<=0){
|
2012-03-19 05:36:34 +00:00
|
|
|
/* Timeout */
|
|
|
|
mdp->packetTypeAndFlags=MDP_ERROR;
|
|
|
|
mdp->error.error=1;
|
2012-03-20 16:30:39 +00:00
|
|
|
snprintf(mdp->error.message,128,"Timeout waiting for reply to MDP packet (packet was successfully sent).");
|
2012-06-21 06:51:16 +00:00
|
|
|
return -1; /* WHY("Timeout waiting for server response"); */
|
2012-03-19 05:36:34 +00:00
|
|
|
}
|
|
|
|
|
2012-03-20 15:06:52 +00:00
|
|
|
int ttl=-1;
|
2012-03-20 17:25:13 +00:00
|
|
|
if (!overlay_mdp_recv(mdp,&ttl)) {
|
2012-03-20 15:06:52 +00:00
|
|
|
/* If all is well, examine result and return error code provided */
|
2012-03-20 16:37:29 +00:00
|
|
|
if ((mdp->packetTypeAndFlags&MDP_TYPE_MASK)==MDP_ERROR)
|
|
|
|
return mdp->error.error;
|
2012-03-20 16:30:39 +00:00
|
|
|
else
|
2012-03-27 08:55:38 +00:00
|
|
|
/* Something other than an error has been returned */
|
|
|
|
return 0;
|
2012-03-20 16:30:39 +00:00
|
|
|
} else {
|
|
|
|
/* poll() said that there was data, but there isn't.
|
|
|
|
So we will abort. */
|
|
|
|
return WHY("poll() aborted");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-22 09:16:14 +00:00
|
|
|
char overlay_mdp_client_socket_path[1024];
|
|
|
|
int overlay_mdp_client_socket_path_len=-1;
|
|
|
|
|
2012-03-20 16:30:39 +00:00
|
|
|
int overlay_mdp_client_init()
|
|
|
|
{
|
|
|
|
if (mdp_client_socket==-1) {
|
|
|
|
/* Open socket to MDP server (thus connection is always local) */
|
2012-04-30 19:46:16 +00:00
|
|
|
if (0) WHY("Use of abstract name space socket for Linux not implemented");
|
2012-03-20 15:06:52 +00:00
|
|
|
|
2012-03-20 16:30:39 +00:00
|
|
|
mdp_client_socket = socket(AF_UNIX, SOCK_DGRAM, 0);
|
|
|
|
if (mdp_client_socket < 0) {
|
2012-05-08 05:15:26 +00:00
|
|
|
WHY_perror("socket");
|
2012-03-20 16:30:39 +00:00
|
|
|
return WHY("Could not open socket to MDP server");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We must bind to a temporary file name */
|
|
|
|
struct sockaddr_un name;
|
2012-04-22 09:16:14 +00:00
|
|
|
unsigned int random_value;
|
|
|
|
if (urandombytes((unsigned char *)&random_value,sizeof(int)))
|
|
|
|
return WHY("urandombytes() failed");
|
2012-03-20 16:30:39 +00:00
|
|
|
name.sun_family = AF_UNIX;
|
2012-04-22 09:16:14 +00:00
|
|
|
if (overlay_mdp_client_socket_path_len==-1) {
|
|
|
|
char fmt[1024];
|
2012-04-30 10:35:40 +00:00
|
|
|
if (!FORM_SERVAL_INSTANCE_PATH(fmt, "mdp-client-%d-%08x.socket"))
|
2012-04-22 09:16:14 +00:00
|
|
|
return WHY("Could not form MDP client socket name");
|
2012-04-30 10:35:40 +00:00
|
|
|
snprintf(overlay_mdp_client_socket_path,1024,fmt,getpid(),random_value);
|
2012-04-30 06:04:54 +00:00
|
|
|
overlay_mdp_client_socket_path_len=strlen(overlay_mdp_client_socket_path)+1;
|
2012-05-21 06:48:09 +00:00
|
|
|
if(debug&DEBUG_IO) DEBUGF("MDP client socket name='%s'",overlay_mdp_client_socket_path);
|
2012-04-22 09:16:14 +00:00
|
|
|
}
|
2012-06-22 12:17:30 +00:00
|
|
|
if (overlay_mdp_client_socket_path_len > 104 - 1)
|
|
|
|
FATALF("MDP socket path too long (%d > %d)", overlay_mdp_client_socket_path_len, 104 - 1);
|
|
|
|
|
2012-04-22 09:16:14 +00:00
|
|
|
bcopy(overlay_mdp_client_socket_path,name.sun_path,
|
|
|
|
overlay_mdp_client_socket_path_len);
|
2012-03-29 03:37:07 +00:00
|
|
|
unlink(name.sun_path);
|
|
|
|
int len = 1 + strlen(name.sun_path) + sizeof(name.sun_family) + 1;
|
2012-03-20 16:30:39 +00:00
|
|
|
int r=bind(mdp_client_socket, (struct sockaddr *)&name, len);
|
|
|
|
if (r) {
|
2012-05-08 05:15:26 +00:00
|
|
|
WHY_perror("bind");
|
2012-05-08 08:18:16 +00:00
|
|
|
return WHY("Could not bind MDP client socket to file name");
|
2012-03-20 16:30:39 +00:00
|
|
|
}
|
2012-04-24 11:27:59 +00:00
|
|
|
|
|
|
|
int send_buffer_size=128*1024;
|
2012-07-03 08:07:33 +00:00
|
|
|
if (setsockopt(mdp_client_socket, SOL_SOCKET, SO_RCVBUF,
|
|
|
|
&send_buffer_size, sizeof(send_buffer_size)) == -1)
|
|
|
|
WARN_perror("setsockopt");
|
2012-03-20 15:06:52 +00:00
|
|
|
}
|
2012-03-20 16:30:39 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2012-03-20 15:06:52 +00:00
|
|
|
|
2012-03-20 16:30:39 +00:00
|
|
|
int overlay_mdp_client_done()
|
|
|
|
{
|
2012-04-30 21:28:07 +00:00
|
|
|
if (mdp_client_socket!=-1) {
|
|
|
|
/* Tell MDP server to release all our bindings */
|
|
|
|
overlay_mdp_frame mdp;
|
|
|
|
mdp.packetTypeAndFlags=MDP_GOODBYE;
|
|
|
|
overlay_mdp_send(&mdp,0,0);
|
|
|
|
}
|
2012-04-30 20:40:47 +00:00
|
|
|
|
2012-04-22 09:16:14 +00:00
|
|
|
if (overlay_mdp_client_socket_path_len>-1)
|
|
|
|
unlink(overlay_mdp_client_socket_path);
|
2012-03-29 03:37:07 +00:00
|
|
|
if (mdp_client_socket!=-1)
|
|
|
|
close(mdp_client_socket);
|
2012-03-20 16:30:39 +00:00
|
|
|
mdp_client_socket=-1;
|
|
|
|
return 0;
|
2012-03-17 02:32:09 +00:00
|
|
|
}
|
2012-03-20 16:57:47 +00:00
|
|
|
|
2012-08-09 02:44:32 +00:00
|
|
|
int overlay_mdp_client_poll(time_ms_t timeout_ms)
|
2012-03-20 16:57:47 +00:00
|
|
|
{
|
2012-04-22 10:45:57 +00:00
|
|
|
fd_set r;
|
2012-07-03 05:42:42 +00:00
|
|
|
int ret;
|
|
|
|
IN();
|
2012-04-22 10:45:57 +00:00
|
|
|
FD_ZERO(&r);
|
|
|
|
FD_SET(mdp_client_socket,&r);
|
2012-03-20 16:57:47 +00:00
|
|
|
if (timeout_ms<0) timeout_ms=0;
|
2012-04-22 10:45:57 +00:00
|
|
|
|
|
|
|
struct timeval tv;
|
2012-03-20 16:57:47 +00:00
|
|
|
|
2012-04-22 10:45:57 +00:00
|
|
|
if (timeout_ms>=0) {
|
|
|
|
tv.tv_sec=timeout_ms/1000;
|
|
|
|
tv.tv_usec=(timeout_ms%1000)*1000;
|
2012-07-03 05:42:42 +00:00
|
|
|
ret=select(mdp_client_socket+1,&r,NULL,&r,&tv);
|
2012-04-22 10:45:57 +00:00
|
|
|
}
|
|
|
|
else
|
2012-07-03 05:42:42 +00:00
|
|
|
ret=select(mdp_client_socket+1,&r,NULL,&r,NULL);
|
|
|
|
RETURN(ret);
|
2012-03-20 16:57:47 +00:00
|
|
|
}
|
2012-03-20 17:25:13 +00:00
|
|
|
|
|
|
|
int overlay_mdp_recv(overlay_mdp_frame *mdp,int *ttl)
|
|
|
|
{
|
|
|
|
char mdp_socket_name[101];
|
|
|
|
unsigned char recvaddrbuffer[1024];
|
|
|
|
struct sockaddr *recvaddr=(struct sockaddr *)recvaddrbuffer;
|
|
|
|
unsigned int recvaddrlen=sizeof(recvaddrbuffer);
|
|
|
|
struct sockaddr_un *recvaddr_un;
|
2012-06-27 07:24:42 +00:00
|
|
|
|
|
|
|
if (!FORM_SERVAL_INSTANCE_PATH(mdp_socket_name, "mdp.socket"))
|
|
|
|
return WHY("Could not find mdp socket");
|
2012-03-20 17:25:13 +00:00
|
|
|
mdp->packetTypeAndFlags=0;
|
2012-06-27 07:24:42 +00:00
|
|
|
|
|
|
|
/* Check if reply available */
|
2012-07-10 07:03:39 +00:00
|
|
|
set_nonblock(mdp_client_socket);
|
2012-07-03 06:06:51 +00:00
|
|
|
ssize_t len = recvwithttl(mdp_client_socket,(unsigned char *)mdp, sizeof(overlay_mdp_frame),ttl,recvaddr,&recvaddrlen);
|
2012-07-10 07:03:39 +00:00
|
|
|
set_block(mdp_client_socket);
|
2012-06-27 07:24:42 +00:00
|
|
|
|
2012-03-20 17:25:13 +00:00
|
|
|
recvaddr_un=(struct sockaddr_un *)recvaddr;
|
2012-03-29 10:15:07 +00:00
|
|
|
/* Null terminate received address so that the stat() call below can succeed */
|
|
|
|
if (recvaddrlen<1024) recvaddrbuffer[recvaddrlen]=0;
|
2012-03-20 17:25:13 +00:00
|
|
|
if (len>0) {
|
|
|
|
/* Make sure recvaddr matches who we sent it to */
|
2012-03-26 04:32:42 +00:00
|
|
|
if (strncmp(mdp_socket_name, recvaddr_un->sun_path, sizeof(recvaddr_un->sun_path))) {
|
2012-03-20 17:25:13 +00:00
|
|
|
/* Okay, reply was PROBABLY not from the server, but on OSX if the path
|
|
|
|
has a symlink in it, it is resolved in the reply path, but might not
|
|
|
|
be in the request path (mdp_socket_name), thus we need to stat() and
|
|
|
|
compare inode numbers etc */
|
|
|
|
struct stat sb1,sb2;
|
|
|
|
if (stat(mdp_socket_name,&sb1)) return WHY("stat(mdp_socket_name) failed, so could not verify that reply came from MDP server");
|
|
|
|
if (stat(recvaddr_un->sun_path,&sb2)) return WHY("stat(ra->sun_path) failed, so could not verify that reply came from MDP server");
|
|
|
|
if ((sb1.st_ino!=sb2.st_ino)||(sb1.st_dev!=sb2.st_dev))
|
|
|
|
return WHY("Reply did not come from server");
|
|
|
|
}
|
2012-05-24 08:02:54 +00:00
|
|
|
|
|
|
|
int expected_len = overlay_mdp_relevant_bytes(mdp);
|
|
|
|
|
|
|
|
if (len < expected_len){
|
2012-07-03 06:06:51 +00:00
|
|
|
return WHYF("Expected packet length of %d, received only %lld bytes", expected_len, (long long) len);
|
2012-05-24 08:02:54 +00:00
|
|
|
}
|
2012-03-20 17:25:13 +00:00
|
|
|
/* Valid packet received */
|
|
|
|
return 0;
|
|
|
|
} else
|
|
|
|
/* no packet received */
|
2012-04-25 05:54:21 +00:00
|
|
|
return -1;
|
2012-03-20 17:25:13 +00:00
|
|
|
|
|
|
|
}
|
2012-04-25 05:54:21 +00:00
|
|
|
|
|
|
|
int overlay_mdp_bind(unsigned char *localaddr,int port)
|
|
|
|
{
|
|
|
|
overlay_mdp_frame mdp;
|
2012-04-30 06:15:07 +00:00
|
|
|
mdp.packetTypeAndFlags=MDP_BIND|MDP_FORCE;
|
2012-04-25 05:54:21 +00:00
|
|
|
bcopy(localaddr,mdp.bind.sid,SID_SIZE);
|
|
|
|
mdp.bind.port_number=port;
|
|
|
|
int result=overlay_mdp_send(&mdp,MDP_AWAITREPLY,5000);
|
|
|
|
if (result) {
|
|
|
|
if (mdp.packetTypeAndFlags==MDP_ERROR)
|
2012-07-27 08:31:04 +00:00
|
|
|
WHYF("Could not bind to MDP port %d: error=%d, message='%s'",
|
2012-04-25 05:54:21 +00:00
|
|
|
port,mdp.error.error,mdp.error.message);
|
|
|
|
else
|
2012-07-27 08:31:04 +00:00
|
|
|
WHYF("Could not bind to MDP port %d (no reason given)",port);
|
2012-04-25 05:54:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2012-04-25 10:44:56 +00:00
|
|
|
|
|
|
|
int overlay_mdp_getmyaddr(int index,unsigned char *sid)
|
|
|
|
{
|
|
|
|
overlay_mdp_frame a;
|
2012-08-27 00:34:59 +00:00
|
|
|
memset(&a, 0, sizeof(a));
|
|
|
|
|
2012-04-25 10:44:56 +00:00
|
|
|
a.packetTypeAndFlags=MDP_GETADDRS;
|
2012-07-04 02:36:15 +00:00
|
|
|
a.addrlist.mode = MDP_ADDRLIST_MODE_SELF;
|
2012-04-25 10:44:56 +00:00
|
|
|
a.addrlist.first_sid=index;
|
|
|
|
a.addrlist.last_sid=0x7fffffff;
|
|
|
|
a.addrlist.frame_sid_count=MDP_MAX_SID_REQUEST;
|
|
|
|
int result=overlay_mdp_send(&a,MDP_AWAITREPLY,5000);
|
|
|
|
if (result) {
|
2012-07-27 08:31:04 +00:00
|
|
|
if (a.packetTypeAndFlags == MDP_ERROR)
|
|
|
|
DEBUGF("MDP Server error #%d: '%s'", a.error.error, a.error.message);
|
2012-04-25 10:44:56 +00:00
|
|
|
return WHY("Failed to get local address list");
|
|
|
|
}
|
|
|
|
if ((a.packetTypeAndFlags&MDP_TYPE_MASK)!=MDP_ADDRLIST)
|
|
|
|
return WHY("MDP Server returned something other than an address list");
|
2012-07-03 08:29:30 +00:00
|
|
|
if (0) DEBUGF("local addr 0 = %s",alloca_tohex_sid(a.addrlist.sids[0]));
|
2012-04-25 10:44:56 +00:00
|
|
|
bcopy(&a.addrlist.sids[0][0],sid,SID_SIZE);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|