diff --git a/commandline.c b/commandline.c index cf5c146e..8a9c7d62 100644 --- a/commandline.c +++ b/commandline.c @@ -931,9 +931,6 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context) int64_t interval_ms = 1000; str_to_uint64_interval_ms(opt_interval, &interval_ms, NULL); - overlay_mdp_frame mdp; - bzero(&mdp, sizeof(overlay_mdp_frame)); - /* First sequence number in the echo frames */ unsigned int firstSeq=random(); unsigned int sequence_number=firstSeq; @@ -941,22 +938,23 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context) int broadcast = is_sid_t_broadcast(ping_sid); /* Bind to MDP socket and await confirmation */ - if ((mdp_sockfd = overlay_mdp_client_socket()) < 0) + if ((mdp_sockfd = mdp_socket()) < 0) return WHY("Cannot create MDP socket"); - sid_t srcsid; - mdp_port_t port=32768+(random()&32767); - if (overlay_mdp_getmyaddr(mdp_sockfd, 0, &srcsid)) { - overlay_mdp_client_close(mdp_sockfd); - return WHY("Could not get local address"); - } - if (overlay_mdp_bind(mdp_sockfd, &srcsid, port)) { - overlay_mdp_client_close(mdp_sockfd); - return WHY("Could not bind to MDP socket"); - } + struct mdp_header mdp_header; + bzero(&mdp_header, sizeof(mdp_header)); + + mdp_header.local.sid = BIND_PRIMARY; + mdp_header.remote.sid = ping_sid; + mdp_header.remote.port = MDP_PORT_ECHO; + mdp_header.qos = OQ_MESH_MANAGEMENT; + mdp_header.ttl = PAYLOAD_TTL_DEFAULT; + mdp_header.flags = MDP_FLAG_BIND; + if (broadcast) + mdp_header.flags |= MDP_FLAG_NO_CRYPT; /* TODO Eventually we should try to resolve SID to phone number and vice versa */ - cli_printf(context, "MDP PING %s (%s): 12 data bytes", alloca_tohex_sid_t(ping_sid), alloca_tohex_sid_t(ping_sid)); + cli_printf(context, "MDP PING %s: 12 data bytes", alloca_tohex_sid_t(ping_sid)); cli_delim(context, "\n"); cli_flush(context); @@ -968,81 +966,91 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context) if (broadcast) WARN("broadcast ping packets will not be encrypted"); + for (; icount==0 || tx_count0) { - int ttl=-1; - if (overlay_mdp_recv(mdp_sockfd, &mdp, port, &ttl)==0) { - switch(mdp.packetTypeAndFlags&MDP_TYPE_MASK) { - case MDP_ERROR: - WHYF("mdpping: overlay_mdp_recv: %s (code %d)", mdp.error.message, mdp.error.error); - break; - case MDP_TX: - { - int *rxseq=(int *)&mdp.in.payload; - time_ms_t txtime = read_uint64(&mdp.in.payload[4]); - int hop_count = 64 - mdp.in.ttl; - time_ms_t delay = gettime_ms() - txtime; - cli_printf(context, "%s: seq=%d time=%"PRId64"ms hops=%d %s%s", - alloca_tohex_sid_t(mdp.in.src.sid), - (*rxseq)-firstSeq+1, - (int64_t)delay, - hop_count, - mdp.packetTypeAndFlags&MDP_NOCRYPT?"":" ENCRYPTED", - mdp.packetTypeAndFlags&MDP_NOSIGN?"":" SIGNED"); - cli_delim(context, "\n"); - cli_flush(context); - // TODO Put duplicate pong detection here so that stats work properly. - rx_count++; - ret=0; - rx_ms+=delay; - if (rx_mintime>delay||rx_mintime==-1) rx_mintime=delay; - if (delay>rx_maxtime) rx_maxtime=delay; - rx_times[rx_count%1024]=delay; - } - break; - default: - WHYF("mdpping: overlay_mdp_recv: Unexpected MDP frame type 0x%x", mdp.packetTypeAndFlags); - break; - } - } + + if (mdp_poll(mdp_sockfd, poll_timeout_ms)<=0) + continue; + + struct mdp_header mdp_recv_header; + uint8_t recv_payload[12]; + ssize_t len = mdp_recv(mdp_sockfd, &mdp_recv_header, recv_payload, sizeof(recv_payload)); + + if (len<0){ + WHY_perror("mdp_recv"); + break; } + + if (mdp_recv_header.flags & MDP_FLAG_ERROR){ + WHY("Serval daemon reported an error, please check the log for more information"); + break; + } + + if (mdp_recv_header.flags & MDP_FLAG_BIND){ + // received port binding confirmation + mdp_header.local = mdp_recv_header.local; + mdp_header.flags &= ~MDP_FLAG_BIND; + DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(mdp_header.local.sid), mdp_header.local.port); + continue; + } + + if (lendelay||rx_mintime==-1) rx_mintime=delay; + if (delay>rx_maxtime) rx_maxtime=delay; + rx_times[rx_count%1024]=delay; } } - overlay_mdp_client_close(mdp_sockfd); + mdp_close(mdp_sockfd); { float rx_stddev=0; @@ -2264,7 +2272,7 @@ static int handle_pins(const struct cli_parsed *parsed, struct cli_context *cont WHYF("Timeout while waiting for response"); break; } - if (rev_header.flags & MDP_FLAG_OK){ + if (rev_header.flags & MDP_FLAG_CLOSE){ ret=0; break; } @@ -2334,7 +2342,7 @@ int app_id_list(const struct cli_parsed *parsed, struct cli_context *context) // TODO receive and decode other details about this identity } - if (rev_header.flags & MDP_FLAG_OK){ + if (rev_header.flags & MDP_FLAG_CLOSE){ ret=0; break; } diff --git a/directory_client.c b/directory_client.c index 5f16e565..1f542464 100644 --- a/directory_client.c +++ b/directory_client.c @@ -52,7 +52,7 @@ static void directory_send(struct subscriber *directory_service, const sid_t *si // Used by tests INFOF("Sending directory registration for %s*, %s, %s to %s*", alloca_tohex_sid_t_trunc(*sidp, 14), did, name, alloca_tohex_sid_t_trunc(directory_service->sid, 14)); - overlay_mdp_dispatch(&request, 0, NULL, 0); + overlay_mdp_dispatch(&request, NULL); } // send a registration packet for each unlocked identity diff --git a/headerfiles.mk b/headerfiles.mk index b9169ec2..422874d3 100644 --- a/headerfiles.mk +++ b/headerfiles.mk @@ -6,6 +6,7 @@ HDRS= fifo.h \ rhizome.h \ serval.h \ keyring.h \ + socket.h \ cli.h \ str.h \ rotbuf.h \ diff --git a/keyring.c b/keyring.c index ca558a95..9d0df5c6 100644 --- a/keyring.c +++ b/keyring.c @@ -1764,7 +1764,7 @@ static int keyring_respond_sas(keyring_file *k, overlay_mdp_frame *req) alloca_tohex_sid_t(req->out.src.sid), req->out.src.port, alloca_tohex_sid_t(req->out.dst.sid), req->out.dst.port ); - return overlay_mdp_dispatch(req,0,NULL,0); + return overlay_mdp_dispatch(req, NULL); } // someone else is claiming to be me on this network @@ -1790,7 +1790,7 @@ int keyring_send_unlock(struct subscriber *subscriber) if (crypto_sign_message(subscriber, mdp.out.payload, sizeof(mdp.out.payload), &len)) return -1; mdp.out.payload_length=len; - return overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL, 0); + return overlay_mdp_dispatch(&mdp, NULL); } static int keyring_send_challenge(struct subscriber *source, struct subscriber *dest) @@ -1815,7 +1815,7 @@ static int keyring_send_challenge(struct subscriber *source, struct subscriber * bcopy(source->identity->challenge, &mdp.out.payload[1], sizeof(source->identity->challenge)); mdp.out.payload_length+=sizeof(source->identity->challenge); - return overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL, 0); + return overlay_mdp_dispatch(&mdp, NULL); } static int keyring_respond_challenge(struct subscriber *subscriber, overlay_mdp_frame *req) @@ -1839,7 +1839,7 @@ static int keyring_respond_challenge(struct subscriber *subscriber, overlay_mdp_ if (crypto_sign_message(subscriber, mdp.out.payload, sizeof(mdp.out.payload), &len)) return -1; mdp.out.payload_length=len; - return overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL, 0); + return overlay_mdp_dispatch(&mdp, NULL); } static int keyring_process_challenge(keyring_file *k, struct subscriber *subscriber, overlay_mdp_frame *req) @@ -1925,7 +1925,7 @@ int keyring_send_sas_request(struct subscriber *subscriber){ mdp.out.payload_length=1; mdp.out.payload[0]=KEYTYPE_CRYPTOSIGN; - if (overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL, 0)) + if (overlay_mdp_dispatch(&mdp, NULL)) return WHY("Failed to send SAS resolution request"); if (config.debug.keyring) DEBUGF("Dispatched SAS resolution request"); diff --git a/mdp_client.c b/mdp_client.c index f3694b9a..3db4ca9f 100644 --- a/mdp_client.c +++ b/mdp_client.c @@ -27,6 +27,7 @@ #include "overlay_address.h" #include "overlay_packet.h" #include "mdp_client.h" +#include "socket.h" int mdp_socket(void) { @@ -34,49 +35,70 @@ int mdp_socket(void) return overlay_mdp_client_socket(); } -int mdp_close(int socket) +static void mdp_unlink(int mdp_sock) { - // use the same process for closing sockets, though this will need to change once bind is implemented - return overlay_mdp_client_close(socket); + // get the socket name and unlink it from the filesystem if not abstract + struct socket_address addr; + addr.addrlen = sizeof addr.store; + if (getsockname(mdp_sock, &addr.addr, &addr.addrlen)) + WHYF_perror("getsockname(%d)", mdp_sock); + else if (addr.addr.sa_family==AF_UNIX + && addr.addrlen > sizeof addr.addr_un.sun_family + && addr.addrlen <= sizeof addr.addr_un && addr.addr_un.sun_path[0] != '\0') { + if (unlink(addr.addr_un.sun_path) == -1) + WARNF_perror("unlink(%s)", alloca_str_toprint(addr.addr_un.sun_path)); + } + close(mdp_sock); } -int mdp_send(int socket, const struct mdp_header *header, const unsigned char *payload, ssize_t len) +int mdp_close(int socket) { - struct sockaddr_un addr; - socklen_t addrlen; - if (make_local_sockaddr(&addr, &addrlen, "mdp.2.socket") == -1) + // tell the daemon to drop all bindings + struct mdp_header header={ + .flags = MDP_FLAG_CLOSE, + .local.port = 0, + }; + + mdp_send(socket, &header, NULL, 0); + + // remove socket + mdp_unlink(socket); + return 0; +} + +int mdp_send(int socket, const struct mdp_header *header, const uint8_t *payload, size_t len) +{ + struct socket_address addr; + if (make_local_sockaddr(&addr, "mdp.2.socket") == -1) return -1; - struct iovec iov[]={ - { - .iov_base = (void *)header, - .iov_len = sizeof(struct mdp_header) - }, - { - .iov_base = (void *)payload, - .iov_len = len + struct fragmented_data data={ + .fragment_count=2, + .iov={ + { + .iov_base = (void*)header, + .iov_len = sizeof(struct mdp_header) + }, + { + .iov_base = (void*)payload, + .iov_len = len + } } }; - struct msghdr hdr={ - .msg_name=&addr, - .msg_namelen=addrlen, - .msg_iov=iov, - .msg_iovlen=2, - }; - return sendmsg(socket, &hdr, 0); + return send_message(socket, &addr, &data); } -ssize_t mdp_recv(int socket, struct mdp_header *header, unsigned char *payload, ssize_t max_len) +ssize_t mdp_recv(int socket, struct mdp_header *header, uint8_t *payload, ssize_t max_len) { /* Construct name of socket to receive from. */ - struct sockaddr_un mdp_addr; - socklen_t mdp_addrlen; - if (make_local_sockaddr(&mdp_addr, &mdp_addrlen, "mdp.2.socket") == -1) - return -1; + errno=0; + struct socket_address mdp_addr; + if (make_local_sockaddr(&mdp_addr, "mdp.2.socket") == -1) + return WHY("Failed to build socket address"); - struct sockaddr_un addr; + struct socket_address addr; struct iovec iov[]={ { .iov_base = (void *)header, @@ -89,25 +111,26 @@ ssize_t mdp_recv(int socket, struct mdp_header *header, unsigned char *payload, }; struct msghdr hdr={ - .msg_name=&addr, - .msg_namelen=sizeof(struct sockaddr_un), + .msg_name=&addr.addr, + .msg_namelen=sizeof(addr.store), .msg_iov=iov, .msg_iovlen=2, }; ssize_t len = recvmsg(socket, &hdr, 0); if (lenpacketTypeAndFlags=MDP_ERROR; mdp->error.error=1; snprintf(mdp->error.message,128,"Error sending frame to MDP server."); @@ -181,16 +203,15 @@ int overlay_mdp_client_socket(void) { /* Create local per-client socket to MDP server (connection is always local) */ int mdp_sockfd; - struct sockaddr_un addr; - socklen_t addrlen; + struct socket_address addr; uint32_t random_value; if (urandombytes((unsigned char *)&random_value, sizeof random_value) == -1) return WHY("urandombytes() failed"); - if (make_local_sockaddr(&addr, &addrlen, "mdp.client.%u.%08lx.socket", getpid(), (unsigned long)random_value) == -1) + if (make_local_sockaddr(&addr, "mdp.client.%u.%08lx.socket", getpid(), (unsigned long)random_value) == -1) return -1; if ((mdp_sockfd = esocket(AF_UNIX, SOCK_DGRAM, 0)) == -1) return -1; - if (socket_bind(mdp_sockfd, (struct sockaddr *)&addr, addrlen) == -1) { + if (socket_bind(mdp_sockfd, &addr.addr, addr.addrlen) == -1) { close(mdp_sockfd); return -1; } @@ -204,16 +225,8 @@ int overlay_mdp_client_close(int mdp_sockfd) overlay_mdp_frame mdp; mdp.packetTypeAndFlags = MDP_GOODBYE; overlay_mdp_send(mdp_sockfd, &mdp, 0, 0); - // get the socket name and unlink it from the filesystem if not abstract - struct sockaddr_un addr; - socklen_t addrlen = sizeof addr; - if (getsockname(mdp_sockfd, (struct sockaddr *)&addr, &addrlen)) - WHYF_perror("getsockname(%d)", mdp_sockfd); - else if (addrlen > sizeof addr.sun_family && addrlen <= sizeof addr && addr.sun_path[0] != '\0') { - if (unlink(addr.sun_path) == -1) - WARNF_perror("unlink(%s)", alloca_str_toprint(addr.sun_path)); - } - close(mdp_sockfd); + + mdp_unlink(mdp_sockfd); return 0; } @@ -236,36 +249,35 @@ int overlay_mdp_client_poll(int mdp_sockfd, time_ms_t timeout_ms) int overlay_mdp_recv(int mdp_sockfd, overlay_mdp_frame *mdp, mdp_port_t port, int *ttl) { /* Construct name of socket to receive from. */ - struct sockaddr_un mdp_addr; - socklen_t mdp_addrlen; - if (make_local_sockaddr(&mdp_addr, &mdp_addrlen, "mdp.socket") == -1) + struct socket_address mdp_addr; + if (make_local_sockaddr(&mdp_addr, "mdp.socket") == -1) return -1; /* Check if reply available */ - struct sockaddr_un recvaddr; - socklen_t recvaddrlen = sizeof recvaddr; + struct socket_address recvaddr; + recvaddr.addrlen = sizeof recvaddr.store; ssize_t len; mdp->packetTypeAndFlags = 0; set_nonblock(mdp_sockfd); - len = recvwithttl(mdp_sockfd, (unsigned char *)mdp, sizeof(overlay_mdp_frame), ttl, (struct sockaddr *)&recvaddr, &recvaddrlen); + len = recvwithttl(mdp_sockfd, (unsigned char *)mdp, sizeof(overlay_mdp_frame), ttl, &recvaddr.addr, &recvaddr.addrlen); set_block(mdp_sockfd); if (len <= 0) return -1; // no packet received // If the received address overflowed the buffer, then it cannot have come from the server, whose // address must always fit within a struct sockaddr_un. - if (recvaddrlen > sizeof recvaddr) + if (recvaddr.addrlen > sizeof recvaddr.store) return WHY("reply did not come from server: address overrun"); // Compare the address of the sender with the address of our server, to ensure they are the same. // If the comparison fails, then try using realpath(3) on the sender address and compare again. - if ( cmp_sockaddr((struct sockaddr *)&recvaddr, recvaddrlen, (struct sockaddr *)&mdp_addr, mdp_addrlen) != 0 - && ( recvaddr.sun_family != AF_UNIX - || real_sockaddr(&recvaddr, recvaddrlen, &recvaddr, &recvaddrlen) <= 0 - || cmp_sockaddr((struct sockaddr *)&recvaddr, recvaddrlen, (struct sockaddr *)&mdp_addr, mdp_addrlen) != 0 + if ( cmp_sockaddr(&recvaddr, &mdp_addr) != 0 + && ( recvaddr.addr_un.sun_family != AF_UNIX + || real_sockaddr(&recvaddr, &recvaddr) <= 0 + || cmp_sockaddr(&recvaddr, &mdp_addr) != 0 ) ) - return WHYF("reply did not come from server: %s", alloca_sockaddr(&recvaddr, recvaddrlen)); + return WHYF("reply did not come from server: %s", alloca_socket_address(&recvaddr)); // silently drop incoming packets for the wrong port number if (port>0 && port != mdp->in.dst.port){ diff --git a/mdp_client.h b/mdp_client.h index 608e8c3a..47fbd33c 100644 --- a/mdp_client.h +++ b/mdp_client.h @@ -31,8 +31,9 @@ struct mdp_sockaddr { #define MDP_FLAG_NO_CRYPT (1<<0) #define MDP_FLAG_NO_SIGN (1<<1) -#define MDP_FLAG_BIND_ALL (1<<2) -#define MDP_FLAG_OK (1<<3) +#define MDP_FLAG_BIND (1<<2) + +#define MDP_FLAG_CLOSE (1<<3) #define MDP_FLAG_ERROR (1<<4) struct mdp_header { @@ -43,6 +44,9 @@ struct mdp_header { uint8_t ttl; }; +#define BIND_PRIMARY SID_ANY +#define BIND_ALL SID_BROADCAST + #define TYPE_SID 1 #define TYPE_PIN 2 #define ACTION_LOCK 1 @@ -50,6 +54,7 @@ struct mdp_header { /* Port numbers for commands sent to the local daemon*/ +#define MDP_LISTEN 0 /* lock and unlock identities from the local keyring * Requests start with an mdp_identity_request structure followed by a list of pins or SIDs */ @@ -82,13 +87,15 @@ struct overlay_mdp_scan{ struct in_addr addr; }; -/* V2 interface */ +/* low level V2 mdp interface */ int mdp_socket(void); int mdp_close(int socket); -int mdp_send(int socket, const struct mdp_header *header, const unsigned char *payload, ssize_t len); -ssize_t mdp_recv(int socket, struct mdp_header *header, unsigned char *payload, ssize_t max_len); +int mdp_send(int socket, const struct mdp_header *header, const uint8_t *payload, size_t len); +ssize_t mdp_recv(int socket, struct mdp_header *header, uint8_t *payload, ssize_t max_len); int mdp_poll(int socket, time_ms_t timeout_ms); + + /* Client-side MDP function */ int overlay_mdp_client_socket(void); int overlay_mdp_client_close(int mdp_sockfd); diff --git a/monitor-client.c b/monitor-client.c index a404a2f1..35ef276e 100644 --- a/monitor-client.c +++ b/monitor-client.c @@ -36,15 +36,15 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #endif #include #include +#include #include "constants.h" #include "conf.h" #include "log.h" #include "str.h" #include "strbuf_helpers.h" - +#include "socket.h" #include "monitor-client.h" -#include #define STATE_INIT 0 #define STATE_DATA 1 @@ -72,12 +72,11 @@ int monitor_client_open(struct monitor_state **res) int fd; if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) return WHYF_perror("socket(AF_UNIX, SOCK_STREAM, 0)"); - struct sockaddr_un addr; - socklen_t addrlen; - if (make_local_sockaddr(&addr, &addrlen, "monitor.socket") == -1) + struct socket_address addr; + if (make_local_sockaddr(&addr, "monitor.socket") == -1) return -1; - INFOF("Attempting to connect to %s", alloca_sockaddr(&addr, addrlen)); - if (socket_connect(fd, (struct sockaddr*)&addr, addrlen) == -1) { + INFOF("Attempting to connect to %s", alloca_socket_address(&addr)); + if (socket_connect(fd, &addr.addr, addr.addrlen) == -1) { close(fd); return -1; } diff --git a/monitor.c b/monitor.c index a1d9611c..20a710e8 100644 --- a/monitor.c +++ b/monitor.c @@ -32,6 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "strbuf_helpers.h" #include "overlay_address.h" #include "monitor-client.h" +#include "socket.h" #ifdef HAVE_UCRED_H #include @@ -80,11 +81,10 @@ int monitor_setup_sockets() int sock = -1; if ((sock = esocket(AF_UNIX, SOCK_STREAM, 0)) == -1) goto error; - struct sockaddr_un addr; - socklen_t addrlen; - if (make_local_sockaddr(&addr, &addrlen, "monitor.socket") == -1) + struct socket_address addr; + if (make_local_sockaddr(&addr, "monitor.socket") == -1) goto error; - if (socket_bind(sock, (struct sockaddr*)&addr, addrlen) == -1) + if (socket_bind(sock, &addr.addr, addr.addrlen) == -1) goto error; if (socket_listen(sock, MAX_MONITOR_SOCKETS) == -1) goto error; @@ -97,7 +97,7 @@ int monitor_setup_sockets() named_socket.poll.fd=sock; named_socket.poll.events=POLLIN; watch(&named_socket); - INFOF("Monitor socket: fd=%d %s", sock, alloca_sockaddr(&addr, addrlen)); + INFOF("Monitor socket: fd=%d %s", sock, alloca_socket_address(&addr)); return 0; error: diff --git a/overlay_link.c b/overlay_link.c index 220d605a..781b456c 100644 --- a/overlay_link.c +++ b/overlay_link.c @@ -313,7 +313,7 @@ int overlay_mdp_service_stun_req(overlay_mdp_frame *mdp) if (reply.out.payload_length){ if (config.debug.overlayrouting) DEBUGF("Sending reply"); - overlay_mdp_dispatch(&reply,0 /* system generated */, NULL,0); + overlay_mdp_dispatch(&reply, NULL); } ob_free(replypayload); ob_free(payload); @@ -387,7 +387,7 @@ int overlay_send_stun_request(struct subscriber *server, struct subscriber *requ mdp.out.payload_length=ob_position(payload); if (config.debug.overlayrouting) DEBUGF("Sending STUN request to %s", alloca_tohex_sid_t(server->sid)); - overlay_mdp_dispatch(&mdp, 0 /* system generated */, NULL,0); + overlay_mdp_dispatch(&mdp, NULL); } ob_free(payload); return 0; diff --git a/overlay_mdp.c b/overlay_mdp.c index a1391220..03008593 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -30,9 +30,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mdp_client.h" #include "crypto.h" #include "keyring.h" +#include "socket.h" static void overlay_mdp_poll(struct sched_ent *alarm); static void mdp_poll2(struct sched_ent *alarm); +static int overlay_mdp_releasebindings(struct socket_address *client); static struct profile_total mdp_stats = { .name="overlay_mdp_poll" }; static struct sched_ent mdp_sock = { @@ -49,6 +51,8 @@ static struct sched_ent mdp_sock2 = { }; static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame *mdp, time_ms_t now); +static int mdp_send2(struct socket_address *client, struct mdp_header *header, + const uint8_t *payload, size_t payload_len); /* Delete all UNIX socket files in instance directory. */ static void overlay_mdp_clean_socket_files() @@ -77,23 +81,22 @@ static void overlay_mdp_clean_socket_files() static int mdp_bind_socket(const char *name) { - struct sockaddr_un addr; - socklen_t addrlen; + struct socket_address addr; int sock; - if (make_local_sockaddr(&addr, &addrlen, "%s", name) == -1) + if (make_local_sockaddr(&addr, "%s", name) == -1) return -1; - if ((sock = esocket(AF_UNIX, SOCK_DGRAM, 0)) == -1) + if ((sock = esocket(addr.addr.sa_family, SOCK_DGRAM, 0)) == -1) return -1; if (socket_set_reuseaddr(sock, 1) == -1) WARN("Could not set socket to reuse addresses"); - if (socket_bind(sock, (struct sockaddr *)&addr, addrlen) == -1) { + if (socket_bind(sock, &addr.addr, addr.addrlen) == -1) { close(sock); return -1; } socket_set_rcvbufsize(sock, 64 * 1024); - INFOF("Socket %s: fd=%d %s", name, sock, alloca_sockaddr(&addr, addrlen)); + INFOF("Socket %s: fd=%d %s", name, sock, alloca_socket_address(&addr)); return sock; } @@ -122,17 +125,48 @@ int overlay_mdp_setup_sockets() struct mdp_binding{ struct subscriber *subscriber; mdp_port_t port; - char socket_name[MDP_MAX_SOCKET_NAME_LEN]; - int name_len; + int version; + struct socket_address client; time_ms_t binding_time; }; struct mdp_binding mdp_bindings[MDP_MAX_BINDINGS]; int mdp_bindings_initialised=0; +mdp_port_t next_port_binding=256; -int overlay_mdp_reply_error(int sock, - struct sockaddr_un *recvaddr, socklen_t recvaddrlen, - int error_number,char *message) +static int compare_client(struct socket_address *one, struct socket_address *two) +{ + if (one->addrlen==two->addrlen + && memcmp(&one->addr, &two->addr, two->addrlen)==0) + return 1; + return 0; +} + +static int overlay_mdp_reply(int sock, struct socket_address *client, + overlay_mdp_frame *mdpreply) +{ + if (!client) return WHY("No reply address"); + + ssize_t replylen = overlay_mdp_relevant_bytes(mdpreply); + if (replylen<0) return WHY("Invalid MDP frame (could not compute length)"); + + ssize_t r=sendto(sock,(char *)mdpreply,replylen,0, &client->addr, client->addrlen); + if (r == -1){ + WHYF_perror("sendto(fd=%d,len=%zu,addr=%s)", sock, (size_t)replylen, alloca_socket_address(client)); + if (errno == ENOENT){ + /* far-end of socket has died, so drop binding */ + INFOF("Closing dead MDP client '%s'", alloca_socket_address(client)); + overlay_mdp_releasebindings(client); + } + return -1; + } + if (r != replylen) + return WHYF("sendto() sent %zu bytes of MDP reply (%zu) to %s", (size_t)r, (size_t)replylen, alloca_socket_address(client)); + return 0; +} + +static int overlay_mdp_reply_error(int sock, struct socket_address *client, + int error_number, char *message) { overlay_mdp_frame mdpreply; @@ -148,49 +182,29 @@ int overlay_mdp_reply_error(int sock, } mdpreply.error.message[127]=0; - return overlay_mdp_reply(sock,recvaddr,recvaddrlen,&mdpreply); + return overlay_mdp_reply(sock, client, &mdpreply); } -int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr, socklen_t recvaddrlen, - overlay_mdp_frame *mdpreply) -{ - if (!recvaddr) - return WHY("No reply address"); - ssize_t replylen = overlay_mdp_relevant_bytes(mdpreply); - if (replylen == -1) - return WHY("Invalid MDP frame (could not compute length)"); - ssize_t r = sendto(sock, (char *)mdpreply, (size_t)replylen, 0, (struct sockaddr *)recvaddr, recvaddrlen); - if (r == -1) { - WHYF_perror("sendto(fd=%d,len=%zu,addr=%s)", sock, (size_t)replylen, alloca_sockaddr((struct sockaddr *)recvaddr, recvaddrlen)); - return WHYF("sendto() failed when sending MDP reply"); - } - if ((size_t)r != (size_t)replylen) - return WHYF("sendto() sent %zu bytes of MDP reply (%zu) to socket=%d", (size_t)r, (size_t)replylen, sock); - return 0; -} - -int overlay_mdp_reply_ok(int sock, - struct sockaddr_un *recvaddr, socklen_t recvaddrlen, +static int overlay_mdp_reply_ok(int sock, struct socket_address *client, char *message) { - return overlay_mdp_reply_error(sock,recvaddr,recvaddrlen,0,message); + return overlay_mdp_reply_error(sock, client, 0, message); } -int overlay_mdp_releasebindings(struct sockaddr_un *recvaddr, socklen_t recvaddrlen) +static int overlay_mdp_releasebindings(struct socket_address *client) { /* Free up any MDP bindings held by this client. */ int i; for(i=0;isun_path,recvaddrlen)) - mdp_bindings[i].port=0; + if (compare_client(&mdp_bindings[i].client, client)) + mdp_bindings[i].port=0; return 0; } -int overlay_mdp_process_bind_request(int sock, struct subscriber *subscriber, mdp_port_t port, - int flags, struct sockaddr_un *recvaddr, socklen_t recvaddrlen) +static int overlay_mdp_process_bind_request(int sock, struct subscriber *subscriber, mdp_port_t port, + int flags, struct socket_address *client) { if (config.debug.mdprequests) DEBUGF("Bind request %s:%"PRImdp_port_t, subscriber ? alloca_tohex_sid_t(subscriber->sid) : "NULL", port); @@ -213,8 +227,7 @@ int overlay_mdp_process_bind_request(int sock, struct subscriber *subscriber, md for(i=0;isun_path,recvaddrlen)) { + if (compare_client(&mdp_bindings[i].client, client)) { // this client already owns this port binding? INFO("Identical binding exists"); return 0; @@ -250,9 +263,9 @@ int overlay_mdp_process_bind_request(int sock, struct subscriber *subscriber, md /* Okay, record binding and report success */ mdp_bindings[free].port=port; mdp_bindings[free].subscriber=subscriber; - - mdp_bindings[free].name_len = recvaddrlen - sizeof recvaddr->sun_family; - memcpy(mdp_bindings[free].socket_name, recvaddr->sun_path, mdp_bindings[free].name_len); + mdp_bindings[free].version=0; + mdp_bindings[free].client.addrlen = client->addrlen; + memcpy(&mdp_bindings[free].client.addr, &client->addr, client->addrlen); mdp_bindings[free].binding_time=gettime_ms(); return 0; } @@ -280,7 +293,6 @@ int overlay_mdp_decrypt(struct overlay_frame *f, overlay_mdp_frame *mdp) /* Indicate MDP message type */ mdp->packetTypeAndFlags=MDP_TX; - switch(f->modifiers&(OF_CRYPTO_CIPHERED|OF_CRYPTO_SIGNED)) { case 0: /* nothing to do, b already points to the plain text */ @@ -401,76 +413,82 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame int i; int match=-1; - 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 - more prudent path. - */ + /* 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. + */ - if (config.debug.mdprequests) - DEBUGF("Received packet with listener (MDP ports: src=%s*:%"PRImdp_port_t", dst=%"PRImdp_port_t")", - alloca_tohex_sid_t_trunc(mdp->out.src.sid, 14), - mdp->out.src.port, mdp->out.dst.port); + if (config.debug.mdprequests) + DEBUGF("Received packet with listener (MDP ports: src=%s*:%"PRImdp_port_t", dst=%"PRImdp_port_t")", + alloca_tohex_sid_t_trunc(mdp->out.src.sid, 14), + mdp->out.src.port, mdp->out.dst.port); - // TODO pass in dest subscriber as an argument, we should know it by now - struct subscriber *destination = NULL; - if (frame) - destination = frame->destination; - else if (!is_sid_t_broadcast(mdp->out.dst.sid)){ - destination = find_subscriber(mdp->out.dst.sid.binary, SID_SIZE, 1); - } - - for(i=0;iout.dst.port) - continue; - - if ((!destination) || mdp_bindings[i].subscriber == destination){ - /* exact match, so stop searching */ - match=i; - break; - }else if (!mdp_bindings[i].subscriber){ - /* If we find an "ANY" binding, remember it. But we will prefer an exact match if we find one */ - match=i; - } + // TODO pass in dest subscriber as an argument, we should know it by now + struct subscriber *destination = NULL; + if (frame) + destination = frame->destination; + else if (!is_sid_t_broadcast(mdp->out.dst.sid)){ + destination = find_subscriber(mdp->out.dst.sid.binary, SID_SIZE, 1); + } + + for(i=0;iout.dst.port) + continue; + + if ((!destination) || mdp_bindings[i].subscriber == destination){ + /* exact match, so stop searching */ + match=i; + break; + }else if (!mdp_bindings[i].subscriber){ + /* If we find an "ANY" binding, remember it. But we will prefer an exact match if we find one */ + match=i; } - - if (match>-1) { - struct sockaddr_un addr; - addr.sun_family = AF_UNIX; - bcopy(mdp_bindings[match].socket_name, addr.sun_path, mdp_bindings[match].name_len); - ssize_t len = overlay_mdp_relevant_bytes(mdp); - if (len == -1) - RETURN(WHY("unsupported MDP packet type")); - socklen_t addrlen = sizeof addr.sun_family + mdp_bindings[match].name_len; - if (config.debug.mdprequests) - DEBUGF("Resolved bound socket on port %"PRImdp_port_t", addr=%s", - mdp_bindings[match].port, alloca_sockaddr(&addr, addrlen)); - ssize_t r = sendto(mdp_sock.poll.fd, mdp, (size_t)len, 0, (struct sockaddr*)&addr, addrlen); - if ((size_t)r != (size_t)len) { - if (r == -1) { - WHYF_perror("sendto(fd=%d,len=%zu,addr=%s)", mdp_sock.poll.fd, (size_t)len, alloca_sockaddr(&addr, addrlen)); - if (errno == ENOENT) { - /* far-end of socket has died, so drop binding */ - INFOF("Closing dead MDP client '%s'",mdp_bindings[match].socket_name); - overlay_mdp_releasebindings(&addr,mdp_bindings[match].name_len); + } + + if (match>-1) { + switch(mdp_bindings[match].version){ + case 0: + { + ssize_t len = overlay_mdp_relevant_bytes(mdp); + if (len < 0) + RETURN(WHY("unsupported MDP packet type")); + struct socket_address *client = &mdp_bindings[match].client; + ssize_t r = sendto(mdp_sock.poll.fd,mdp,len,0, &client->addr, client->addrlen); + if (r == -1){ + WHYF_perror("sendto(fd=%d,len=%zu,addr=%s)", mdp_sock.poll.fd, (size_t)len, alloca_socket_address(client)); + if (errno == ENOENT){ + /* far-end of socket has died, so drop binding */ + INFOF("Closing dead MDP client '%s'", alloca_socket_address(client)); + overlay_mdp_releasebindings(client); + } + RETURN(-1); } - } else - WHYF("sendto() sent %zu bytes of MDP frame (%zu) to client, socket=%d", (size_t)r, (size_t)len, mdp_sock.poll.fd); - RETURN(WHY("Failed to pass received MDP frame to client")); - } - } else { - if (config.debug.mdprequests) - DEBUGF("No socket bound to port %"PRImdp_port_t", try internal service", mdp->out.dst.port); - /* No socket is bound, ignore the packet ... except for magic sockets */ - RETURN(overlay_mdp_try_interal_services(frame, mdp)); + if (r != len) + RETURN(WHYF("sendto() sent %zu bytes of MDP reply (%zu) to %s", (size_t)r, (size_t)len, alloca_socket_address(client))); + RETURN(0); + } + case 1: + { + struct mdp_header header; + header.local.sid=mdp->out.dst.sid; + header.local.port=mdp->out.dst.port; + header.remote.sid=mdp->out.src.sid; + header.remote.port=mdp->out.src.port; + header.qos=mdp->out.queue; + header.ttl=mdp->out.ttl; + header.flags=0; + if (mdp->packetTypeAndFlags & MDP_NOCRYPT) + header.flags|=MDP_FLAG_NO_CRYPT; + if (mdp->packetTypeAndFlags & MDP_NOSIGN) + header.flags|=MDP_FLAG_NO_SIGN; + RETURN(mdp_send2(&mdp_bindings[match].client, &header, mdp->out.payload, mdp->out.payload_length)); + } } - break; - default: - RETURN(WHYF("We should only see MDP_TX frames here (MDP message type = 0x%x)", - mdp->packetTypeAndFlags)); + } else { + /* No socket is bound, ignore the packet ... except for magic sockets */ + RETURN(overlay_mdp_try_internal_services(frame, mdp)); } RETURN(0); @@ -501,14 +519,14 @@ int overlay_mdp_dnalookup_reply(const sockaddr_mdp *dstaddr, const sid_t *resolv 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); + return overlay_mdp_dispatch(&mdpreply, NULL); } -int overlay_mdp_check_binding(struct subscriber *subscriber, mdp_port_t port, int userGeneratedFrameP, - struct sockaddr_un *recvaddr, socklen_t recvaddrlen) +static int overlay_mdp_check_binding(struct subscriber *subscriber, mdp_port_t port, + struct socket_address *client) { /* System generated frames can send anything they want */ - if (!userGeneratedFrameP) + if (!client) return 0; /* Check if the address is in the list of bound addresses, @@ -520,18 +538,14 @@ int overlay_mdp_check_binding(struct subscriber *subscriber, mdp_port_t port, in continue; if ((!mdp_bindings[i].subscriber) || mdp_bindings[i].subscriber == subscriber) { /* Binding matches, now make sure the sockets match */ - if ( mdp_bindings[i].name_len == recvaddrlen - sizeof(sa_family_t) - && memcmp(mdp_bindings[i].socket_name, recvaddr->sun_path, recvaddrlen - sizeof(sa_family_t)) == 0 - ) { + if (compare_client(&mdp_bindings[i].client, client)) { /* Everything matches, so this unix socket and MDP address combination is valid */ return 0; } } } - return WHYF("No such binding: recvaddr=%p %s addr=%s port=%"PRImdp_port_t" -- possible spoofing attack", - recvaddr, - recvaddr ? alloca_toprint(-1, recvaddr->sun_path, recvaddrlen - sizeof(sa_family_t)) : "", + return WHYF("No matching binding: addr=%s port=%"PRImdp_port_t" -- possible spoofing attack", alloca_tohex_sid_t(subscriber->sid), port ); @@ -627,18 +641,75 @@ static struct overlay_buffer * encrypt_payload( } // encrypt or sign the plaintext, then queue the frame for transmission. -int overlay_send_frame(struct overlay_frame *frame, struct overlay_buffer *plaintext){ +static int overlay_send_frame( + struct subscriber *source, mdp_port_t src_port, + struct subscriber *destination, mdp_port_t dst_port, + const uint8_t *payload, size_t payload_len, + uint8_t ttl, uint8_t qos, uint8_t modifiers) +{ + if (destination && destination->reachable == REACHABLE_SELF) + return 0; - if (!frame->source) - frame->source = my_subscriber; + if (ttl == 0) + ttl = PAYLOAD_TTL_DEFAULT; + else if (ttl > PAYLOAD_TTL_MAX) + return WHYF("Invalid TTL"); + + if (qos == 0) + qos = OQ_ORDINARY; + if (!source) + return WHYF("No source specified"); + + /* Prepare the overlay frame for dispatch */ + struct overlay_frame *frame = emalloc_zero(sizeof(struct overlay_frame)); + if (!frame) + return -1; + + frame->source = source; + frame->destination = destination; + frame->ttl = ttl; + frame->queue = qos; + frame->type = OF_TYPE_DATA; + frame->modifiers = modifiers; + + // copy the plain text message into a new buffer, with the wire encoded port numbers + struct overlay_buffer *plaintext=ob_new(); + if (!plaintext){ + op_free(frame); + return -1; + } + + overlay_mdp_encode_ports(plaintext, dst_port, src_port); + if (payload && payload_len){ + ob_append_bytes(plaintext, payload, payload_len); + } + + if (ob_overrun(plaintext)) { + if (config.debug.mdprequests) + DEBUGF("Frame overrun: position=%d allocSize=%d sizeLimit=%d", + plaintext->position, plaintext->allocSize, plaintext->sizeLimit); + op_free(frame); + ob_free(plaintext); + return -1; + } + if (config.debug.mdprequests) { + DEBUGF("Send frame %u bytes", ob_position(plaintext)); + dump("Frame plaintext", ob_ptr(plaintext), ob_position(plaintext)); + } + /* 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(frame->modifiers) { - default: + switch(modifiers) { case OF_CRYPTO_SIGNED|OF_CRYPTO_CIPHERED: + if (!frame->destination){ + ob_free(plaintext); + op_free(frame); + return WHY("Cannot encrypt to broadcast destinations"); + } + /* crypted and signed (using CryptoBox authcryption primitive) */ frame->payload = encrypt_payload(frame->source, frame->destination, ob_ptr(plaintext), ob_position(plaintext)); if (!frame->payload){ @@ -671,6 +742,11 @@ int overlay_send_frame(struct overlay_frame *frame, struct overlay_buffer *plain /* clear text and no signature */ frame->payload = plaintext; break; + + default: + ob_free(plaintext); + op_free(frame); + return WHY("Invalid encrypt / sign combination"); } if (!frame->destination && frame->ttl>1) @@ -690,19 +766,17 @@ int overlay_send_frame(struct overlay_frame *frame, struct overlay_buffer *plain This is for use by the SERVER. Clients should use overlay_mdp_send() */ -int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, - struct sockaddr_un *recvaddr, socklen_t recvaddrlen) +int overlay_mdp_dispatch(overlay_mdp_frame *mdp, struct socket_address *client) { IN(); unsigned __d = 0; if (config.debug.mdprequests) { __d = fd_depth(); - DEBUGF("[%u] src=%s*:%"PRImdp_port_t", dst=%s*:%"PRImdp_port_t", userGen=%d, recv=%s", + DEBUGF("[%u] src=%s*:%"PRImdp_port_t", dst=%s*:%"PRImdp_port_t", recv=%s", __d, alloca_tohex_sid_t_trunc(mdp->out.src.sid, 14), mdp->out.src.port, alloca_tohex_sid_t_trunc(mdp->out.dst.sid, 14), mdp->out.dst.port, - userGeneratedFrameP, - recvaddr ? alloca_sockaddr(recvaddr, recvaddrlen) : "NULL" + client ? alloca_socket_address(client) : "NULL" ); } @@ -731,11 +805,10 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, } } - if (overlay_mdp_check_binding(source, mdp->out.src.port, userGeneratedFrameP, recvaddr, recvaddrlen)){ + if (overlay_mdp_check_binding(source, mdp->out.src.port, client)){ RETURN(overlay_mdp_reply_error (mdp_sock.poll.fd, - (struct sockaddr_un *)recvaddr, - recvaddrlen,8, + client,8, "Source address is invalid (you must bind to a source address before" " you can send packets")); } @@ -749,25 +822,20 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, NaCl cryptobox keys can be used for signing. */ if (!(mdp->packetTypeAndFlags&MDP_NOCRYPT)) RETURN(overlay_mdp_reply_error(mdp_sock.poll.fd, - recvaddr,recvaddrlen,5, + client,5, "Broadcast packets cannot be encrypted ")); }else{ destination = find_subscriber(mdp->out.dst.sid.binary, SID_SIZE, 1); // should we reply with an error if the destination is not currently routable? } - if (mdp->out.ttl == 0) - mdp->out.ttl = PAYLOAD_TTL_DEFAULT; - else if (mdp->out.ttl > PAYLOAD_TTL_MAX) { - RETURN(overlay_mdp_reply_error(mdp_sock.poll.fd, recvaddr,recvaddrlen,9, "TTL out of range")); + if (mdp->out.ttl > PAYLOAD_TTL_MAX) { + RETURN(overlay_mdp_reply_error(mdp_sock.poll.fd, client, 9, "TTL out of range")); } - if (mdp->out.queue == 0) - mdp->out.queue = OQ_ORDINARY; - if (config.debug.mdprequests) DEBUGF("[%u] destination->sid=%s", __d, destination ? alloca_tohex_sid_t(destination->sid) : "NULL"); - if (!destination || destination->reachable == REACHABLE_SELF) { + if (!destination || destination->reachable == REACHABLE_SELF){ /* Packet is addressed to us / broadcast, we should process it first. */ overlay_saw_mdp_frame(NULL,mdp,gettime_ms()); if (destination) { @@ -777,7 +845,7 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, RETURN(0); } } - + int modifiers=0; switch(mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN)) { @@ -803,43 +871,12 @@ int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, RETURN(WHY("Not implemented")); }; - // copy the plain text message into a new buffer, with the wire encoded port numbers - struct overlay_buffer *plaintext=ob_new(); - if (plaintext == NULL) - RETURN(-1); - - overlay_mdp_encode_ports(plaintext, mdp->out.dst.port, mdp->out.src.port); - if (mdp->out.payload_length) - ob_append_bytes(plaintext, mdp->out.payload, mdp->out.payload_length); - if (ob_overrun(plaintext)) { - if (config.debug.mdprequests) - DEBUGF("[%u] Frame overrun: position=%d allocSize=%d sizeLimit=%d", __d, - plaintext->position, plaintext->allocSize, plaintext->sizeLimit); - ob_free(plaintext); - RETURN(-1); - } - if (config.debug.mdprequests) { - DEBUGF("[%u] Send frame %u bytes", __d, ob_position(plaintext)); - dump("Frame plaintext", ob_ptr(plaintext), ob_position(plaintext)); - } - - /* Prepare the overlay frame for dispatch */ - struct overlay_frame *frame = emalloc_zero(sizeof(struct overlay_frame)); - if (!frame){ - ob_free(plaintext); - RETURN(-1); - } - - frame->source = source; - frame->destination = destination; - frame->ttl = mdp->out.ttl; - frame->queue = mdp->out.queue; - frame->type=OF_TYPE_DATA; - frame->prev=NULL; - frame->next=NULL; - frame->modifiers=modifiers; - - RETURN(overlay_send_frame(frame, plaintext)); + RETURN(overlay_send_frame( + source, mdp->out.src.port, + destination, mdp->out.dst.port, + mdp->out.payload, mdp->out.payload_length, + mdp->out.ttl, mdp->out.queue, modifiers + )); OUT(); } @@ -893,8 +930,7 @@ int overlay_mdp_address_list(overlay_mdp_addrlist *request, overlay_mdp_addrlist } struct routing_state{ - struct sockaddr_un *recvaddr_un; - socklen_t recvaddrlen; + struct socket_address *client; int fd; }; @@ -918,7 +954,7 @@ static int routing_table(struct subscriber *subscriber, void *context) strcpy(r->interface_name, subscriber->destination->interface->name); else r->interface_name[0]=0; - overlay_mdp_reply(mdp_sock.poll.fd, state->recvaddr_un, state->recvaddrlen, &reply); + overlay_mdp_reply(mdp_sock.poll.fd, state->client, &reply); return 0; } @@ -966,12 +1002,7 @@ static void overlay_mdp_scan(struct sched_ent *alarm) } } -struct mdp_client{ - struct sockaddr_un *addr; - socklen_t addrlen; -}; - -static int mdp_reply2(const struct mdp_client *client, const struct mdp_header *header, +static int mdp_reply2(const struct socket_address *client, const struct mdp_header *header, int flags, const unsigned char *payload, int payload_len) { struct mdp_header response_header; @@ -990,22 +1021,22 @@ static int mdp_reply2(const struct mdp_client *client, const struct mdp_header * }; struct msghdr hdr={ - .msg_name=client->addr, + .msg_name=(void *)&client->addr, .msg_namelen=client->addrlen, .msg_iov=iov, .msg_iovlen=2, }; if (config.debug.mdprequests) - DEBUGF("Replying to %s with code %d", alloca_sockaddr(client->addr, client->addrlen), flags); + DEBUGF("Replying to %s with flags %d", alloca_socket_address(client), flags); return sendmsg(mdp_sock2.poll.fd, &hdr, 0); } #define mdp_reply_error(A,B) mdp_reply2(A,B,MDP_FLAG_ERROR,NULL,0) -#define mdp_reply_ok(A,B) mdp_reply2(A,B,MDP_FLAG_OK,NULL,0) +#define mdp_reply_ok(A,B) mdp_reply2(A,B,MDP_FLAG_CLOSE,NULL,0) -static int mdp_process_identity_request(struct mdp_client *client, struct mdp_header *header, - const unsigned char *payload, size_t payload_len) +static int mdp_process_identity_request(struct socket_address *client, struct mdp_header *header, + const uint8_t *payload, size_t payload_len) { if (payload_lencontexts[cn]->identities[in]; unsigned char reply_payload[1200]; - int ofs=0; + size_t ofs=0; bcopy(id->subscriber->sid.binary, &reply_payload[ofs], sizeof(id->subscriber->sid)); ofs+=sizeof(id->subscriber->sid); - + // TODO return other details of this identity - + mdp_reply2(client, header, 0, reply_payload, ofs); kp++; } @@ -1127,54 +1157,268 @@ static int mdp_search_identities(struct mdp_client *client, struct mdp_header *h return 0; } -static void mdp_poll2(struct sched_ent *alarm) +static void mdp_process_packet(struct socket_address *client, struct mdp_header *header, + const uint8_t *payload, size_t payload_len) { - if (alarm->poll.revents & POLLIN) { - unsigned char buffer[1600]; - struct sockaddr_storage addr; - struct mdp_client client={ - .addr = (struct sockaddr_un *)&addr, - .addrlen = sizeof(addr) - }; - int ttl=-1; - - ssize_t len = recvwithttl(alarm->poll.fd, buffer, sizeof(buffer), &ttl, (struct sockaddr *)&addr, &client.addrlen); - - if (lenflags & MDP_FLAG_CLOSE) && header->local.port==0){ + int i; + for(i=0;isid):"All", + mdp_bindings[i].port, + alloca_socket_address(client)); + mdp_bindings[i].port=0; + } + } + // should we expect clients to wait for this? + // mdp_reply_ok(client, header); + return; + } + + // find the source subscriber + struct subscriber *source=NULL; + + if (is_sid_t_broadcast(header->local.sid)){ + // leave source NULL to indicate listening on all local SID's + // note that attempting anything else will fail + }else if (is_sid_t_any(header->local.sid)){ + // leaving the sid blank indicates that we should use our main identity + source = my_subscriber; + header->local.sid = source->sid; + }else{ + // find the matching sid from our keyring + source = find_subscriber(header->local.sid.binary, sizeof(header->local.sid), 0); + if (!source || source->reachable != REACHABLE_SELF){ + mdp_reply_error(client, header); + WHY("Subscriber is not local"); + } + } + + struct mdp_binding *binding=NULL, *free_slot=NULL; + + // assign the next available port number + if (header->local.port==0 && header->flags & MDP_FLAG_BIND){ + if (next_port_binding > 32*1024) + next_port_binding=256; + else + next_port_binding++; + header->local.port=next_port_binding; + } + + // find matching binding + { + int i; + for(i=0;ilocal.port + && mdp_bindings[i].subscriber == source){ + + binding = &mdp_bindings[i]; + break; + } + } + } + + if (header->flags & MDP_FLAG_BIND){ + if (binding){ + mdp_reply_error(client, header); + WHYF("Port %d already bound", header->local.port); return; } - struct mdp_header *header = (struct mdp_header *)buffer; - - unsigned char *payload = &buffer[sizeof(struct mdp_header)]; - size_t payload_len = len - sizeof(struct mdp_header); - - if (is_sid_t_any(header->remote.sid)){ - // process local commands - switch(header->remote.port){ - // lock and unlock identities - case MDP_IDENTITY: - if (config.debug.mdprequests) - DEBUGF("Processing MDP_IDENTITY from %s", alloca_sockaddr(client.addr, client.addrlen)); - mdp_process_identity_request(&client, header, payload, payload_len); - break; - // seach unlocked identities - case MDP_SEARCH_IDS: - if (config.debug.mdprequests) - DEBUGF("Processing MDP_SEARCH_IDS from %s", alloca_sockaddr(client.addr, client.addrlen)); - mdp_search_identities(&client, header, payload, payload_len); - break; - default: - mdp_reply_error(&client, header); - WHY("Unknown port number"); - break; - } - }else{ - // TODO transmit packet - mdp_reply_error(&client, header); - WHY("Transmitting packets is not yet supported"); + if (!free_slot){ + mdp_reply_error(client, header); + WHY("Max supported bindings reached"); + return; } + + if (config.debug.mdprequests) + DEBUGF("Bind MDP %s:%d to %s", + alloca_tohex_sid_t(header->local.sid), + header->local.port, + alloca_socket_address(client)); + + // claim binding + binding = free_slot; + binding->port = header->local.port; + binding->subscriber = source; + bcopy(&client->addr, &binding->client.addr, client->addrlen); + binding->client.addrlen = client->addrlen; + binding->binding_time=gettime_ms(); + binding->version=1; + + // tell the client what we actually bound (with flags & MDP_FLAG_BIND still set) + mdp_reply2(client, header, MDP_FLAG_BIND, NULL, 0); + } + + if (is_sid_t_any(header->remote.sid)){ + // process local commands + switch(header->remote.port){ + case MDP_LISTEN: + // double check that this binding belongs to this connection + if (!binding + || !compare_client(&binding->client, client)) + mdp_reply_error(client, header); + break; + case MDP_IDENTITY: + if (config.debug.mdprequests) + DEBUGF("Processing MDP_IDENTITY from %s", alloca_socket_address(client)); + mdp_process_identity_request(client, header, payload, payload_len); + break; + // seach unlocked identities + case MDP_SEARCH_IDS: + if (config.debug.mdprequests) + DEBUGF("Processing MDP_SEARCH_IDS from %s", alloca_socket_address(client)); + mdp_search_identities(client, header, payload, payload_len); + break; + default: + mdp_reply_error(client, header); + WHYF("Unknown command port %d", header->remote.port); + break; + } + + }else{ + // double check that this binding belongs to this connection + if (!binding + || !source + || header->local.port == 0 + || !compare_client(&binding->client, client)){ + mdp_reply_error(client, header); + WHY("No matching binding found"); + return; + } + + struct subscriber *destination=NULL; + if (!is_sid_t_broadcast(header->remote.sid)) + destination = find_subscriber(header->remote.sid.binary, SID_SIZE, 1); + + int modifiers=0; + if ((header->flags & MDP_FLAG_NO_CRYPT) == 0) + modifiers|=OF_CRYPTO_CIPHERED; + if ((header->flags & MDP_FLAG_NO_SIGN) == 0) + modifiers|=OF_CRYPTO_SIGNED; + + if (!destination || destination->reachable==REACHABLE_SELF){ + // TODO deprecate this mdp struct, deal with local delivery in send_frame + overlay_mdp_frame mdp; + mdp.out.src.sid = header->local.sid; + mdp.out.src.port = header->local.port; + mdp.out.dst.sid = header->remote.sid; + mdp.out.dst.port = header->remote.port; + bcopy(payload, mdp.out.payload, payload_len); + mdp.out.payload_length = payload_len; + mdp.out.ttl = header->ttl; + mdp.out.queue = header->qos; + mdp.packetTypeAndFlags=MDP_TX; + if (header->flags&MDP_FLAG_NO_CRYPT) + mdp.packetTypeAndFlags |= MDP_NOCRYPT; + if (header->flags&MDP_FLAG_NO_SIGN) + mdp.packetTypeAndFlags |= MDP_NOSIGN; + + if (config.debug.mdprequests) + DEBUGF("Attempting to process mdp packet locally"); + overlay_saw_mdp_frame(NULL, &mdp, gettime_ms()); + } + + if (config.debug.mdprequests) + DEBUGF("Attempting to queue mdp packet"); + + // construct, encrypt, sign and queue the packet + if (overlay_send_frame( + source, header->local.port, + destination, header->remote.port, + payload, payload_len, + header->ttl, header->qos, modifiers + )){ + mdp_reply_error(client, header); + return; + } + } + + // remove binding + if (binding + && header->flags & MDP_FLAG_CLOSE + && compare_client(&binding->client, client)){ + if (config.debug.mdprequests) + DEBUGF("Unbind MDP %s:%d from %s", + binding->subscriber?alloca_tohex_sid_t(binding->subscriber->sid):"All", + binding->port, + alloca_socket_address(client)); + binding->port=0; + binding=NULL; + } +} + +static int mdp_send2(struct socket_address *client, struct mdp_header *header, + const uint8_t *payload, size_t payload_len) +{ + struct iovec iov[]={ + { + .iov_base = (void *)header, + .iov_len = sizeof(struct mdp_header) + }, + { + .iov_base = (void *)payload, + .iov_len = payload_len + } + }; + + struct msghdr hdr={ + .msg_name=&client->addr, + .msg_namelen=client->addrlen, + .msg_iov=iov, + .msg_iovlen=2, + }; + + if (sendmsg(mdp_sock2.poll.fd, &hdr, 0)<0) + return WHY_perror("sendmsg"); + return 0; +} + +static void mdp_poll2(struct sched_ent *alarm) +{ + if (alarm->poll.revents & POLLIN) { + uint8_t payload[1200]; + struct mdp_header header; + struct socket_address client; + client.addrlen=sizeof(client.addr); + + struct iovec iov[]={ + { + .iov_base = (void *)&header, + .iov_len = sizeof(struct mdp_header) + }, + { + .iov_base = (void *)payload, + .iov_len = sizeof(payload) + } + }; + + struct msghdr hdr={ + .msg_name=&client.addr, + .msg_namelen=sizeof(client.store), + .msg_iov=iov, + .msg_iovlen=2, + }; + + ssize_t len = recvmsg(alarm->poll.fd, &hdr, 0); + if (len<0){ + WHY_perror("recvmsg"); + return; + } + if (lenpoll.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; + struct socket_address client; + client.addrlen=sizeof(client.store); ttl=-1; - bzero((void *)recvaddrbuffer,sizeof(recvaddrbuffer)); - ssize_t len = recvwithttl(alarm->poll.fd,buffer,sizeof(buffer),&ttl, recvaddr, &recvaddrlen); - recvaddr_un=(struct sockaddr_un *)recvaddr; + ssize_t len = recvwithttl(alarm->poll.fd,buffer,sizeof(buffer),&ttl, (struct sockaddr *)&client.addr, &client.addrlen); if (len > 0) { - if (recvaddrlen <= sizeof(sa_family_t)) - WHYF("got recvaddrlen=%d too short -- ignoring frame len=%zu", (int)recvaddrlen, (size_t)len); + if (client.addrlen <= sizeof(sa_family_t)) + WHYF("got client.addrlen=%d too short -- ignoring frame len=%zu", (int)client.addrlen, (size_t)len); else { /* Look at overlay_mdp_frame we have received */ overlay_mdp_frame *mdp=(overlay_mdp_frame *)&buffer[0]; @@ -1205,17 +1445,16 @@ static void overlay_mdp_poll(struct sched_ent *alarm) switch (mdp_type) { case MDP_GOODBYE: if (config.debug.mdprequests) - DEBUGF("MDP_GOODBYE from %s", alloca_sockaddr(recvaddr, recvaddrlen)); - overlay_mdp_releasebindings(recvaddr_un,recvaddrlen); + DEBUGF("MDP_GOODBYE from %s", alloca_socket_address(&client)); + overlay_mdp_releasebindings(&client); return; case MDP_ROUTING_TABLE: if (config.debug.mdprequests) - DEBUGF("MDP_ROUTING_TABLE from %s", alloca_sockaddr(recvaddr, recvaddrlen)); + DEBUGF("MDP_ROUTING_TABLE from %s", alloca_socket_address(&client)); { struct routing_state state={ - .recvaddr_un=recvaddr_un, - .recvaddrlen=recvaddrlen, + .client = &client, }; enum_subscribers(NULL, routing_table, &state); @@ -1225,7 +1464,7 @@ static void overlay_mdp_poll(struct sched_ent *alarm) case MDP_GETADDRS: if (config.debug.mdprequests) - DEBUGF("MDP_GETADDRS from %s", alloca_sockaddr(recvaddr, recvaddrlen)); + DEBUGF("MDP_GETADDRS from %s", alloca_socket_address(&client)); { overlay_mdp_frame mdpreply; bzero(&mdpreply, sizeof(overlay_mdp_frame)); @@ -1233,7 +1472,7 @@ static void overlay_mdp_poll(struct sched_ent *alarm) if (!overlay_mdp_address_list(&mdp->addrlist, &mdpreply.addrlist)) /* Send back to caller */ overlay_mdp_reply(alarm->poll.fd, - (struct sockaddr_un *)recvaddr,recvaddrlen, + &client, &mdpreply); return; @@ -1242,18 +1481,18 @@ static void overlay_mdp_poll(struct sched_ent *alarm) case MDP_TX: /* Send payload (and don't treat it as system privileged) */ if (config.debug.mdprequests) - DEBUGF("MDP_TX from %s", alloca_sockaddr(recvaddr, recvaddrlen)); + DEBUGF("MDP_TX from %s", alloca_socket_address(&client)); // Dont allow mdp clients to send very high priority payloads if (mdp->out.queue<=OQ_MESH_MANAGEMENT) mdp->out.queue=OQ_ORDINARY; - overlay_mdp_dispatch(mdp,1,(struct sockaddr_un*)recvaddr,recvaddrlen); + overlay_mdp_dispatch(mdp, &client); return; break; case MDP_BIND: /* Bind to port */ if (config.debug.mdprequests) - DEBUGF("MDP_BIND from %s", alloca_sockaddr(recvaddr, recvaddrlen)); + DEBUGF("MDP_BIND from %s", alloca_socket_address(&client)); { struct subscriber *subscriber=NULL; /* Make sure source address is either all zeros (listen on all), or a valid @@ -1264,24 +1503,24 @@ static void overlay_mdp_poll(struct sched_ent *alarm) if ((!subscriber) || subscriber->reachable != REACHABLE_SELF){ WHYF("Invalid bind request for sid=%s", alloca_tohex_sid_t(mdp->bind.sid)); /* Source address is invalid */ - overlay_mdp_reply_error(alarm->poll.fd, recvaddr_un, recvaddrlen, 7, + overlay_mdp_reply_error(alarm->poll.fd, &client, 7, "Bind address is not valid (must be a local MDP address, or all zeroes)."); return; } } if (overlay_mdp_process_bind_request(alarm->poll.fd, subscriber, mdp->bind.port, - mdp->packetTypeAndFlags, recvaddr_un, recvaddrlen)) - overlay_mdp_reply_error(alarm->poll.fd,recvaddr_un,recvaddrlen,3, "Port already in use"); + mdp->packetTypeAndFlags, &client)) + overlay_mdp_reply_error(alarm->poll.fd, &client, 3, "Port already in use"); else - overlay_mdp_reply_ok(alarm->poll.fd,recvaddr_un,recvaddrlen,"Port bound"); + overlay_mdp_reply_ok(alarm->poll.fd, &client, "Port bound"); return; } break; case MDP_SCAN: if (config.debug.mdprequests) - DEBUGF("MDP_SCAN from %s", alloca_sockaddr(recvaddr, recvaddrlen)); + DEBUGF("MDP_SCAN from %s", alloca_socket_address(&client)); { struct overlay_mdp_scan *scan = (struct overlay_mdp_scan *)&mdp->raw; time_ms_t start=gettime_ms(); @@ -1312,7 +1551,7 @@ static void overlay_mdp_poll(struct sched_ent *alarm) }else{ struct overlay_interface *interface = overlay_interface_find(scan->addr, 1); if (!interface){ - overlay_mdp_reply_error(alarm->poll.fd,recvaddr_un,recvaddrlen, 1, "Unable to find matching interface"); + overlay_mdp_reply_error(alarm->poll.fd, &client, 1, "Unable to find matching interface"); return; } int i = interface - overlay_interfaces; @@ -1327,22 +1566,14 @@ static void overlay_mdp_poll(struct sched_ent *alarm) } } - overlay_mdp_reply_ok(alarm->poll.fd,recvaddr_un,recvaddrlen,"Scan initiated"); + overlay_mdp_reply_ok(alarm->poll.fd, &client, "Scan initiated"); } break; default: /* Client is not allowed to send any other frame type */ - WARNF("Unsupported MDP frame type [%d] from %s", mdp_type, alloca_sockaddr(recvaddr, recvaddrlen)); - 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); + WARNF("Unsupported MDP frame type [%d] from %s", mdp_type, alloca_socket_address(&client)); + overlay_mdp_reply_error(alarm->poll.fd, &client, 2, "Illegal request type. Clients may use only MDP_TX or MDP_BIND."); } } } diff --git a/overlay_mdp_services.c b/overlay_mdp_services.c index 8298a135..3c1fbc57 100644 --- a/overlay_mdp_services.c +++ b/overlay_mdp_services.c @@ -99,7 +99,7 @@ int rhizome_mdp_send_block(struct subscriber *dest, const rhizome_bid_t *bid, ui reply.out.payload[0]='T'; // send packet - if (overlay_mdp_dispatch(&reply,0 /* system generated */, NULL,0)) + if (overlay_mdp_dispatch(&reply, NULL)) break; } @@ -252,8 +252,7 @@ int overlay_mdp_service_echo(overlay_mdp_frame *mdp) mdp->packetTypeAndFlags&=~(MDP_NOCRYPT|MDP_NOSIGN); /* queue frame for delivery */ - overlay_mdp_dispatch(mdp,0 /* system generated */, - NULL,0); + overlay_mdp_dispatch(mdp, NULL); mdp->packetTypeAndFlags=preserved; /* and switch addresses back around in case the caller was planning on @@ -342,20 +341,20 @@ static int overlay_mdp_service_trace(overlay_mdp_frame *mdp){ mdp->out.payload_length = ob_position(b); mdp->out.src.sid = my_subscriber->sid; mdp->out.dst.sid = next->sid; - ret = overlay_mdp_dispatch(mdp, 0, NULL, 0); + ret = overlay_mdp_dispatch(mdp, NULL); end: ob_free(b); RETURN(ret); } -static int overlay_mdp_service_manifest_requests(struct overlay_frame *frame, overlay_mdp_frame *mdp) +static int overlay_mdp_service_manifest_requests(struct overlay_frame *frame, const uint8_t *payload, size_t len) { int offset=0; - while (offsetout.payload_length) { + while (offsetout.payload[offset]; + const unsigned char *bar = &payload[offset]; if (!rhizome_retrieve_manifest_by_prefix(&bar[RHIZOME_BAR_PREFIX_OFFSET], RHIZOME_BAR_PREFIX_BYTES, m)){ rhizome_advertise_manifest(frame->source, m); // pre-emptively send the payload if it will fit in a single packet @@ -368,7 +367,7 @@ static int overlay_mdp_service_manifest_requests(struct overlay_frame *frame, ov return 0; } -int overlay_mdp_try_interal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp) +int overlay_mdp_try_internal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp) { IN(); switch(mdp->out.dst.port) { @@ -383,7 +382,7 @@ int overlay_mdp_try_interal_services(struct overlay_frame *frame, overlay_mdp_fr case MDP_PORT_STUN: RETURN(overlay_mdp_service_stun(mdp)); case MDP_PORT_RHIZOME_REQUEST: RETURN(overlay_mdp_service_rhizomerequest(frame, mdp)); case MDP_PORT_RHIZOME_RESPONSE: RETURN(overlay_mdp_service_rhizomeresponse(mdp)); - case MDP_PORT_RHIZOME_MANIFEST_REQUEST: RETURN(overlay_mdp_service_manifest_requests(frame, mdp)); + case MDP_PORT_RHIZOME_MANIFEST_REQUEST: RETURN(overlay_mdp_service_manifest_requests(frame, mdp->out.payload, mdp->out.payload_length)); case MDP_PORT_RHIZOME_SYNC: RETURN(overlay_mdp_service_rhizome_sync(frame, mdp)); } diff --git a/rhizome_fetch.c b/rhizome_fetch.c index 7f1d5d74..56071a02 100644 --- a/rhizome_fetch.c +++ b/rhizome_fetch.c @@ -26,6 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "str.h" #include "strbuf_helpers.h" #include "overlay_address.h" +#include "socket.h" /* Represents a queued fetch of a bundle payload, for which the manifest is already known. */ @@ -1122,7 +1123,7 @@ static int rhizome_fetch_mdp_requestblocks(struct rhizome_fetch_slot *slot) slot->write_state.file_offset, slot->bidVersion); - overlay_mdp_dispatch(&mdp,0 /* system generated */,NULL,0); + overlay_mdp_dispatch(&mdp, NULL); // remember when we sent the request so that we can adjust the inter-request // interval based on how fast the packets arrive. diff --git a/rhizome_packetformats.c b/rhizome_packetformats.c index 01af7c16..f6d845e5 100644 --- a/rhizome_packetformats.c +++ b/rhizome_packetformats.c @@ -482,7 +482,7 @@ next: lookup_time = (end_time - start_time); if (mdp.out.payload_length>0) - overlay_mdp_dispatch(&mdp,0 /* system generated */,NULL,0); + overlay_mdp_dispatch(&mdp, NULL); end: sqlite_set_tracefunc(oldfunc); diff --git a/rhizome_sync.c b/rhizome_sync.c index 98162614..be5c7fcb 100644 --- a/rhizome_sync.c +++ b/rhizome_sync.c @@ -93,7 +93,7 @@ static void rhizome_sync_request(struct subscriber *subscriber, uint64_t token, mdp.out.payload_length = ob_position(b); if (config.debug.rhizome) DEBUGF("Sending request to %s for BARs from %"PRIu64" %s", alloca_tohex_sid_t(subscriber->sid), token, forwards?"forwards":"backwards"); - overlay_mdp_dispatch(&mdp,0,NULL,0); + overlay_mdp_dispatch(&mdp, NULL); ob_free(b); } @@ -147,7 +147,7 @@ static void rhizome_sync_send_requests(struct subscriber *subscriber, struct rhi break; } if (mdp.out.payload_length!=0) - overlay_mdp_dispatch(&mdp,0,NULL,0); + overlay_mdp_dispatch(&mdp, NULL); // send request for more bars if we have room to cache them if (state->bar_count >= CACHE_BARS) @@ -440,7 +440,7 @@ static void sync_send_response(struct subscriber *dest, int forwards, uint64_t t mdp.out.payload_length = ob_position(b); if (config.debug.rhizome_ads) DEBUGF("Sending %d BARs from %"PRIu64" to %"PRIu64, count, token, last); - overlay_mdp_dispatch(&mdp,0,NULL,0); + overlay_mdp_dispatch(&mdp, NULL); } ob_free(b); OUT(); diff --git a/serval.h b/serval.h index eb775a10..b02199a5 100644 --- a/serval.h +++ b/serval.h @@ -195,28 +195,6 @@ int formf_serval_instance_path(struct __sourceloc, char *buf, size_t bufsiz, con int vformf_serval_instance_path(struct __sourceloc, char *buf, size_t bufsiz, const char *fmt, va_list); void serval_setinstancepath(const char *instancepath); -/* Basic socket operations. - */ -int _make_local_sockaddr(struct __sourceloc, struct sockaddr_un *sockname, socklen_t *addrlen, const char *fmt, ...) - __attribute__((format(printf, 4, 5))); -int _esocket(struct __sourceloc, int domain, int type, int protocol); -int _socket_bind(struct __sourceloc, int sock, const struct sockaddr *addr, socklen_t addrlen); -int _socket_connect(struct __sourceloc, int sock, const struct sockaddr *addr, socklen_t addrlen); -int _socket_listen(struct __sourceloc, int sock, int backlog); -int _socket_set_reuseaddr(struct __sourceloc, int sock, int reuseP); -int _socket_set_rcvbufsize(struct __sourceloc, int sock, unsigned buffer_size); - -#define make_local_sockaddr(sockname, addrlenp, fmt,...) _make_local_sockaddr(__WHENCE__, (sockname), (addrlenp), (fmt), ##__VA_ARGS__) -#define esocket(domain, type, protocol) _esocket(__WHENCE__, (domain), (type), (protocol)) -#define socket_bind(sock, addr, addrlen) _socket_bind(__WHENCE__, (sock), (addr), (addrlen)) -#define socket_connect(sock, addr, addrlen) _socket_connect(__WHENCE__, (sock), (addr), (addrlen)) -#define socket_listen(sock, backlog) _socket_listen(__WHENCE__, (sock), (backlog)) -#define socket_set_reuseaddr(sock, reuseP) _socket_set_reuseaddr(__WHENCE__, (sock), (reuseP)) -#define socket_set_rcvbufsize(sock, buffer_size) _socket_set_rcvbufsize(__WHENCE__, (sock), (buffer_size)) - -int real_sockaddr(const struct sockaddr_un *src_addr, socklen_t src_addrlen, struct sockaddr_un *dst_addr, socklen_t *dst_addrlen); -int cmp_sockaddr(const struct sockaddr *, socklen_t, const struct sockaddr *, socklen_t); - #define SERVER_CONFIG_RELOAD_INTERVAL_MS 1000 struct cli_parsed; @@ -508,9 +486,6 @@ int rhizome_opendb(); int parseCommandLine(struct cli_context *context, const char *argv0, int argc, const char *const *argv); int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax); -int overlay_mdp_reply_error(int sock, - struct sockaddr_un *recvaddr, socklen_t recvaddrlen, - int error_number,char *message); typedef uint32_t mdp_port_t; #define PRImdp_port_t "#08" PRIx32 @@ -572,10 +547,8 @@ typedef struct overlay_mdp_frame { /* Server-side MDP functions */ int overlay_mdp_swap_src_dst(overlay_mdp_frame *mdp); -int overlay_mdp_reply(int sock,struct sockaddr_un *recvaddr, socklen_t recvaddrlen, - overlay_mdp_frame *mdpreply); -int overlay_mdp_dispatch(overlay_mdp_frame *mdp,int userGeneratedFrameP, - struct sockaddr_un *recvaddr, socklen_t recvaddrlen); +struct socket_address; +int overlay_mdp_dispatch(overlay_mdp_frame *mdp, struct socket_address *client); void overlay_mdp_encode_ports(struct overlay_buffer *plaintext, mdp_port_t dst_port, mdp_port_t src_port); int overlay_mdp_dnalookup_reply(const sockaddr_mdp *dstaddr, const sid_t *resolved_sidp, const char *uri, const char *did, const char *name); @@ -688,7 +661,7 @@ int overlay_packetradio_tx_packet(struct overlay_frame *frame); void overlay_dummy_poll(struct sched_ent *alarm); void server_config_reload(struct sched_ent *alarm); void server_shutdown_check(struct sched_ent *alarm); -int overlay_mdp_try_interal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp); +int overlay_mdp_try_internal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp); int overlay_send_probe(struct subscriber *peer, struct network_destination *destination, int queue); int overlay_send_stun_request(struct subscriber *server, struct subscriber *request); void fd_periodicstats(struct sched_ent *alarm); diff --git a/socket.c b/socket.c index e9839d01..1839980e 100644 --- a/socket.c +++ b/socket.c @@ -25,6 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conf.h" #include "log.h" #include "strbuf_helpers.h" +#include "socket.h" /* Form the name of an AF_UNIX (local) socket in the instance directory as an absolute path. * Under Linux, this will create a socket name in the abstract namespace. This permits us to use @@ -40,25 +41,28 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * @author Andrew Bettison * @author Daniel O'Connor */ -int _make_local_sockaddr(struct __sourceloc __whence, struct sockaddr_un *addr, socklen_t *addrlen, const char *fmt, ...) +int _make_local_sockaddr(struct __sourceloc __whence, struct socket_address *addr, const char *fmt, ...) { bzero(addr, sizeof(*addr)); + addr->addr_un.sun_family = AF_UNIX; va_list ap; va_start(ap, fmt); - int r = vformf_serval_instance_path(__WHENCE__, addr->sun_path, sizeof addr->sun_path, fmt, ap); + int r = vformf_serval_instance_path(__WHENCE__, addr->addr_un.sun_path, sizeof addr->addr_un.sun_path, fmt, ap); va_end(ap); if (!r) return WHY("socket name overflow"); - if (real_sockaddr(addr, sizeof addr->sun_family + strlen(addr->sun_path) + 1, addr, addrlen) == -1) - return -1; + addr->addrlen=sizeof addr->addr_un.sun_family + strlen(addr->addr_un.sun_path) + 1; +// TODO perform real path transformation in making the serval instance path +// if (real_sockaddr(addr, addr) == -1) +// return -1; + #ifdef USE_ABSTRACT_NAMESPACE // For the abstract name we use the absolute path name with the initial '/' replaced by the // leading nul. This ensures that different instances of the Serval daemon have different socket // names. - addr->sun_path[0] = '\0'; // mark as Linux abstract socket - --*addrlen; // do not count trailing nul in abstract socket name + addr->addr_un.sun_path[0] = '\0'; // mark as Linux abstract socket + --addr->addrlen; // do not count trailing nul in abstract socket name #endif // USE_ABSTRACT_NAMESPACE - addr->sun_family = AF_UNIX; return 0; } @@ -74,31 +78,33 @@ int _make_local_sockaddr(struct __sourceloc __whence, struct sockaddr_un *addr, * * @author Andrew Bettison */ -int real_sockaddr(const struct sockaddr_un *src_addr, socklen_t src_addrlen, struct sockaddr_un *dst_addr, socklen_t *dst_addrlen) +int real_sockaddr(const struct socket_address *src_addr, struct socket_address *dst_addr) { - int src_path_len = src_addrlen - sizeof src_addr->sun_family; - if ( src_addrlen >= sizeof src_addr->sun_family + 1 - && src_addr->sun_family == AF_UNIX - && src_addr->sun_path[0] != '\0' - && src_addr->sun_path[src_path_len - 1] == '\0' + int src_path_len = src_addr->addrlen - sizeof src_addr->addr_un.sun_family; + if ( src_addr->addrlen >= sizeof src_addr->addr_un.sun_family + 1 + && src_addr->addr_un.sun_family == AF_UNIX + && src_addr->addr_un.sun_path[0] != '\0' + && src_addr->addr_un.sun_path[src_path_len - 1] == '\0' ) { char real_path[PATH_MAX]; size_t real_path_len; - if (realpath(src_addr->sun_path, real_path) == NULL) - return WHYF_perror("realpath(%s)", alloca_str_toprint(src_addr->sun_path)); - else if ((real_path_len = strlen(real_path) + 1) > sizeof dst_addr->sun_path) - return WHYF("sockaddr overrun: realpath(%s) returned %s", alloca_str_toprint(src_addr->sun_path), alloca_str_toprint(real_path)); + if (realpath(src_addr->addr_un.sun_path, real_path) == NULL) + return WHYF_perror("realpath(%s)", alloca_str_toprint(src_addr->addr_un.sun_path)); + else if ((real_path_len = strlen(real_path) + 1) > sizeof dst_addr->addr_un.sun_path) + return WHYF("sockaddr overrun: realpath(%s) returned %s", + alloca_str_toprint(src_addr->addr_un.sun_path), alloca_str_toprint(real_path)); else if ( real_path_len != src_path_len - || memcmp(real_path, src_addr->sun_path, src_path_len) != 0 + || memcmp(real_path, src_addr->addr_un.sun_path, src_path_len) != 0 ) { - memcpy(dst_addr->sun_path, real_path, real_path_len); - *dst_addrlen = real_path_len + sizeof dst_addr->sun_family; + memcpy(dst_addr->addr_un.sun_path, real_path, real_path_len); + dst_addr->addrlen = real_path_len + sizeof dst_addr->addr_un.sun_family; return 1; } } - if (dst_addr != src_addr) - memcpy(dst_addr, src_addr, src_addrlen); - *dst_addrlen = src_addrlen; + if (dst_addr != src_addr){ + memcpy(&dst_addr->addr, &src_addr->addr, src_addr->addrlen); + dst_addr->addrlen = src_addr->addrlen; + } return 0; } @@ -107,43 +113,43 @@ int real_sockaddr(const struct sockaddr_un *src_addr, socklen_t src_addrlen, str * * @author Andrew Bettison */ -int cmp_sockaddr(const struct sockaddr *addrA, socklen_t addrlenA, const struct sockaddr *addrB, socklen_t addrlenB) +int cmp_sockaddr(const struct socket_address *addrA, const struct socket_address *addrB) { // Two zero-length sockaddrs are equal. - if (addrlenA == 0 && addrlenB == 0) + if (addrA->addrlen == 0 && addrB->addrlen == 0) return 0; // If either sockaddr is truncated, then we compare the bytes we have. - if (addrlenA < sizeof addrA->sa_family || addrlenB < sizeof addrB->sa_family) { - int c = memcmp(addrA, addrB, addrlenA < addrlenB ? addrlenA : addrlenB); + if (addrA->addrlen < sizeof addrA->addr.sa_family || addrB->addrlen < sizeof addrB->addr.sa_family) { + int c = memcmp(addrA, addrB, addrA->addrlen < addrB->addrlen ? addrA->addrlen : addrB->addrlen); if (c == 0) - c = addrlenA < addrlenB ? -1 : addrlenA > addrlenB ? 1 : 0; + c = addrA->addrlen < addrB->addrlen ? -1 : addrA->addrlen > addrB->addrlen ? 1 : 0; return c; } // Order first by address family. - if (addrA->sa_family < addrB->sa_family) + if (addrA->addr.sa_family < addrB->addr.sa_family) return -1; - if (addrA->sa_family > addrB->sa_family) + if (addrA->addr.sa_family > addrB->addr.sa_family) return 1; // Both addresses are in the same family... - switch (addrA->sa_family) { + switch (addrA->addr.sa_family) { case AF_UNIX: { - unsigned pathlenA = addrlenA - sizeof ((const struct sockaddr_un *)addrA)->sun_family; - unsigned pathlenB = addrlenB - sizeof ((const struct sockaddr_un *)addrB)->sun_family; + unsigned pathlenA = addrA->addrlen - sizeof (addrA->addr_un.sun_family); + unsigned pathlenB = addrB->addrlen - sizeof (addrB->addr_un.sun_family); int c; if ( pathlenA > 1 && pathlenB > 1 - && ((const struct sockaddr_un *)addrA)->sun_path[0] == '\0' - && ((const struct sockaddr_un *)addrB)->sun_path[0] == '\0' + && addrA->addr_un.sun_path[0] == '\0' + && addrB->addr_un.sun_path[0] == '\0' ) { // Both abstract sockets - just compare names, nul bytes are not terminators. - c = memcmp(&((const struct sockaddr_un *)addrA)->sun_path[1], - &((const struct sockaddr_un *)addrB)->sun_path[1], + c = memcmp(&addrA->addr_un.sun_path[1], + &addrB->addr_un.sun_path[1], (pathlenA < pathlenB ? pathlenA : pathlenB) - 1); } else { // Either or both are named local file sockets. If the file names are identical up to the // first nul, then the addresses are equal. This collates abstract socket names, whose first // character is a nul, ahead of all non-empty file socket names. - c = strncmp(((const struct sockaddr_un *)addrA)->sun_path, - ((const struct sockaddr_un *)addrB)->sun_path, + c = strncmp(addrA->addr_un.sun_path, + addrB->addr_un.sun_path, (pathlenA < pathlenB ? pathlenA : pathlenB)); } if (c == 0) @@ -153,9 +159,10 @@ int cmp_sockaddr(const struct sockaddr *addrA, socklen_t addrlenA, const struct break; } // Fall back to comparing raw data bytes. - int c = memcmp(addrA->sa_data, addrB->sa_data, (addrlenA < addrlenB ? addrlenA : addrlenB) - sizeof addrA->sa_family); + int c = memcmp(addrA->addr.sa_data, addrB->addr.sa_data, + (addrA->addrlen < addrB->addrlen ? addrA->addrlen : addrB->addrlen) - sizeof addrA->addr.sa_family); if (c == 0) - c = addrlenA < addrlenB ? -1 : addrlenA > addrlenB ? 1 : 0; + c = addrA->addrlen < addrB->addrlen ? -1 : addrA->addrlen > addrB->addrlen ? 1 : 0; return c; } @@ -225,3 +232,32 @@ int _socket_set_rcvbufsize(struct __sourceloc __whence, int sock, unsigned buffe DEBUGF("setsockopt(%d, SOL_SOCKET, SO_RCVBUF, &%u, %u)", sock, buffer_size, (unsigned)sizeof buffer_size); return 0; } + +ssize_t _send_message(struct __sourceloc __whence, int fd, const struct socket_address *address, const struct fragmented_data *data) +{ + struct msghdr hdr={ + .msg_name=(void *)&address->addr, + .msg_namelen=address->addrlen, + .msg_iov=(struct iovec*)data->iov, + .msg_iovlen=data->fragment_count, + }; + + ssize_t ret = sendmsg(fd, &hdr, 0); + if (ret==-1) + WHYF_perror("sendmsg(%d,%s,%lu)", fd, alloca_socket_address(address), (unsigned long)address->addrlen); + return ret; +} + +ssize_t _recv_message(struct __sourceloc __whence, int fd, struct socket_address *address, struct fragmented_data *data) +{ + struct msghdr hdr={ + .msg_name=(void *)&address->addr, + .msg_namelen=address->addrlen, + .msg_iov=data->iov, + .msg_iovlen=data->fragment_count, + }; + ssize_t ret = recvmsg(fd, &hdr, 0); + if (ret==-1) + WHYF_perror("recvmsg(%d,%s,%lu)", fd, alloca_socket_address(address), (unsigned long)address->addrlen); + return ret; +} diff --git a/socket.h b/socket.h new file mode 100644 index 00000000..88a05549 --- /dev/null +++ b/socket.h @@ -0,0 +1,56 @@ +#ifndef __SERVALD_SOCKET_H +#define __SERVALD_SOCKET_H + +#ifndef WIN32 +#include +#endif + +struct socket_address{ + socklen_t addrlen; + union{ + struct sockaddr addr; + struct sockaddr_un addr_un; + struct sockaddr_storage store; + }; +}; + +/* Basic socket operations. + */ +int _make_local_sockaddr(struct __sourceloc, struct socket_address *addr, const char *fmt, ...) + __attribute__((format(printf, 3, 4))); +int _esocket(struct __sourceloc, int domain, int type, int protocol); +int _socket_bind(struct __sourceloc, int sock, const struct sockaddr *addr, socklen_t addrlen); +int _socket_connect(struct __sourceloc, int sock, const struct sockaddr *addr, socklen_t addrlen); +int _socket_listen(struct __sourceloc, int sock, int backlog); +int _socket_set_reuseaddr(struct __sourceloc, int sock, int reuseP); +int _socket_set_rcvbufsize(struct __sourceloc, int sock, unsigned buffer_size); + +#define make_local_sockaddr(sockname, fmt,...) _make_local_sockaddr(__WHENCE__, (sockname), (fmt), ##__VA_ARGS__) +#define esocket(domain, type, protocol) _esocket(__WHENCE__, (domain), (type), (protocol)) +#define socket_bind(sock, addr, addrlen) _socket_bind(__WHENCE__, (sock), (addr), (addrlen)) +#define socket_connect(sock, addr, addrlen) _socket_connect(__WHENCE__, (sock), (addr), (addrlen)) +#define socket_listen(sock, backlog) _socket_listen(__WHENCE__, (sock), (backlog)) +#define socket_set_reuseaddr(sock, reuseP) _socket_set_reuseaddr(__WHENCE__, (sock), (reuseP)) +#define socket_set_rcvbufsize(sock, buffer_size) _socket_set_rcvbufsize(__WHENCE__, (sock), (buffer_size)) + +int real_sockaddr(const struct socket_address *src_addr, struct socket_address *dst_addr); +int cmp_sockaddr(const struct socket_address *addrA, const struct socket_address *addrB); + +// helper functions for manipulating fragmented packet data +#define MAX_FRAGMENTS 8 +struct fragmented_data{ + int fragment_count; + struct iovec iov[MAX_FRAGMENTS]; +}; + +int prepend_fragment(struct fragmented_data *data, const uint8_t *payload, size_t len); +int append_fragment(struct fragmented_data *data, const uint8_t *payload, size_t len); +size_t copy_fragment(struct fragmented_data *src, uint8_t *dest, size_t length); + +ssize_t _send_message(struct __sourceloc, int fd, const struct socket_address *address, const struct fragmented_data *data); +ssize_t _recv_message(struct __sourceloc, int fd, struct socket_address *address, struct fragmented_data *data); + +#define send_message(fd, address, data) _send_message(__WHENCE__, (fd), (address), (data)) +#define recv_message(fd, address, data) _recv_message(__WHENCE__, (fd), (address), (data)) + +#endif \ No newline at end of file diff --git a/strbuf_helpers.c b/strbuf_helpers.c index 1e2c459e..363172f5 100644 --- a/strbuf_helpers.c +++ b/strbuf_helpers.c @@ -37,6 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "http_server.h" #include "strbuf_helpers.h" #include "str.h" +#include "socket.h" static inline strbuf _toprint(strbuf sb, char c) { @@ -374,6 +375,11 @@ strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr, socklen_t return sb; } +strbuf strbuf_append_socket_address(strbuf sb, const struct socket_address *addr) +{ + return strbuf_append_sockaddr(sb, &addr->addr, addr->addrlen); +} + strbuf strbuf_append_strftime(strbuf sb, const char *format, const struct tm *tm) { // First, try calling strftime(3) directly on the buffer in the strbuf, if there is one and it diff --git a/strbuf_helpers.h b/strbuf_helpers.h index e10a346a..4fee86cb 100644 --- a/strbuf_helpers.h +++ b/strbuf_helpers.h @@ -139,6 +139,10 @@ struct sockaddr; strbuf strbuf_append_sockaddr(strbuf sb, const struct sockaddr *addr, socklen_t addrlen); #define alloca_sockaddr(addr, addrlen) strbuf_str(strbuf_append_sockaddr(strbuf_alloca(200), (const struct sockaddr *)(addr), (addrlen))) +struct socket_address; +strbuf strbuf_append_socket_address(strbuf sb, const struct socket_address *addr); +#define alloca_socket_address(addr) strbuf_str(strbuf_append_socket_address(strbuf_alloca(200), (addr))) + /* Append a strftime(3) string. * @author Andrew Bettison */ diff --git a/vomp.c b/vomp.c index 72d03a36..f87fd688 100644 --- a/vomp.c +++ b/vomp.c @@ -523,7 +523,7 @@ static int vomp_send_status_remote(struct vomp_call_state *call) call->local.sequence++; - overlay_mdp_dispatch(&mdp,0,NULL,0); + overlay_mdp_dispatch(&mdp, NULL); return 0; } @@ -561,7 +561,7 @@ int vomp_received_audio(struct vomp_call_state *call, int audio_codec, int time, mdp.out.queue=OQ_ISOCHRONOUS_VOICE; - overlay_mdp_dispatch(&mdp,0,NULL,0); + overlay_mdp_dispatch(&mdp, NULL); return 0; }