diff --git a/commandline.c b/commandline.c index 0d95ec6a..ca45367e 100644 --- a/commandline.c +++ b/commandline.c @@ -43,6 +43,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mdp_client.h" #include "cli.h" #include "overlay_address.h" +#include "overlay_buffer.h" extern struct cli_schema command_line_options[]; @@ -1070,6 +1071,68 @@ int app_mdp_ping(const struct cli_parsed *parsed, void *context) return ret; } +int app_trace(const struct cli_parsed *parsed, void *context){ + + const char *sidhex; + if (cli_arg(parsed, "SID", &sidhex, str_is_subscriber_id, NULL) == -1) + return -1; + + sid_t srcsid; + sid_t dstsid; + if (str_to_sid_t(&dstsid, sidhex) == -1) + return WHY("str_to_sid_t() failed"); + + overlay_mdp_frame mdp; + bzero(&mdp, sizeof(mdp)); + + int port=32768+(random()&32767); + if (overlay_mdp_getmyaddr(0, &srcsid)) return WHY("Could not get local address"); + if (overlay_mdp_bind(&srcsid, port)) return WHY("Could not bind to MDP socket"); + + bcopy(srcsid.binary, mdp.out.src.sid, SID_SIZE); + bcopy(srcsid.binary, mdp.out.dst.sid, SID_SIZE); + mdp.out.src.port=port; + mdp.out.dst.port=MDP_PORT_TRACE; + mdp.packetTypeAndFlags=MDP_TX; + struct overlay_buffer *b = ob_static(mdp.out.payload, sizeof(mdp.out.payload)); + + ob_append_byte(b, SID_SIZE); + ob_append_bytes(b, srcsid.binary, SID_SIZE); + + ob_append_byte(b, SID_SIZE); + ob_append_bytes(b, dstsid.binary, SID_SIZE); + + mdp.out.payload_length = ob_position(b); + cli_printf("Tracing the network path from %s to %s", + alloca_tohex_sid(srcsid.binary), alloca_tohex_sid(dstsid.binary)); + cli_delim("\n"); + int ret=overlay_mdp_send(&mdp,MDP_AWAITREPLY,5000); + ob_free(b); + if (ret) + DEBUGF("overlay_mdp_send returned %d", ret); + else{ + int offset=0; + { + // skip the first two sid's + int len = mdp.out.payload[offset++]; + offset+=len; + len = mdp.out.payload[offset++]; + offset+=len; + } + int i=0; + while(offset","[]",NULL},CLIFLAG_STANDALONE, + {app_mdp_ping,{"mdp","ping","","[]",NULL},0, "Attempts to ping specified node via Mesh Datagram Protocol (MDP)."}, + {app_trace,{"mdp","trace","",NULL},0, + "Trace through the network to the specified node via MDP."}, {app_config_schema,{"config","schema",NULL},CLIFLAG_STANDALONE|CLIFLAG_PERMISSIVE_CONFIG, "Dump configuration schema."}, {app_config_set,{"config","set","","","...",NULL},CLIFLAG_STANDALONE|CLIFLAG_PERMISSIVE_CONFIG, diff --git a/constants.h b/constants.h index d6e1e5bb..4f426d34 100644 --- a/constants.h +++ b/constants.h @@ -132,6 +132,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define MDP_PORT_STUN 5 #define MDP_PORT_PROBE 6 #define MDP_PORT_ECHO 7 +#define MDP_PORT_TRACE 8 #define MDP_PORT_DNALOOKUP 10 #define MDP_PORT_VOMP 12 #define MDP_PORT_RHIZOME_REQUEST 13 diff --git a/mdp_client.c b/mdp_client.c index c8f6b831..43281925 100644 --- a/mdp_client.c +++ b/mdp_client.c @@ -63,7 +63,7 @@ int overlay_mdp_send(overlay_mdp_frame *mdp,int flags,int timeout_ms) int port=0; if ((mdp->packetTypeAndFlags&MDP_TYPE_MASK) == MDP_TX) - port = mdp->out.dst.port; + port = mdp->out.src.port; time_ms_t started = gettime_ms(); while(timeout_ms>=0 && overlay_mdp_client_poll(timeout_ms)>0){ diff --git a/overlay_mdp.c b/overlay_mdp.c index 07c23d02..f04a8c29 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -502,6 +502,9 @@ int overlay_mdp_dnalookup_reply(const sockaddr_mdp *dstaddr, const unsigned char int overlay_mdp_check_binding(struct subscriber *subscriber, int port, int userGeneratedFrameP, struct sockaddr_un *recvaddr, int recvaddrlen) { + /* System generated frames can send anything they want */ + if (!userGeneratedFrameP) + return 0; /* Check if the address is in the list of bound addresses, and that the recvaddr matches. */ @@ -521,24 +524,6 @@ int overlay_mdp_check_binding(struct subscriber *subscriber, int port, int userG } } - /* Check for build-in port listeners */ - if (!userGeneratedFrameP){ - switch(port) { - case MDP_PORT_NOREPLY: - case MDP_PORT_ECHO: - case MDP_PORT_KEYMAPREQUEST: - case MDP_PORT_VOMP: - case MDP_PORT_DNALOOKUP: - case MDP_PORT_RHIZOME_RESPONSE: - case MDP_PORT_RHIZOME_REQUEST: - case MDP_PORT_RHIZOME_MANIFEST_REQUEST: - case MDP_PORT_PROBE: - case MDP_PORT_STUNREQ: - case MDP_PORT_STUN: - return 0; - } - } - 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)) : "", diff --git a/overlay_mdp_services.c b/overlay_mdp_services.c index eacbd83b..e27ed767 100644 --- a/overlay_mdp_services.c +++ b/overlay_mdp_services.c @@ -281,6 +281,91 @@ int overlay_mdp_service_echo(overlay_mdp_frame *mdp) RETURN(0); } +static int overlay_mdp_service_trace(overlay_mdp_frame *mdp){ + IN(); + int ret=0; + + struct overlay_buffer *b = ob_static(mdp->out.payload, sizeof(mdp->out.payload)); + ob_limitsize(b, mdp->out.payload_length); + + struct subscriber *src=NULL, *dst=NULL, *last=NULL, *next=NULL; + struct decode_context context; + bzero(&context, sizeof context); + + if (overlay_address_parse(&context, b, &src)){ + ret=WHYF("Invalid trace packet"); + goto end; + } + if (overlay_address_parse(&context, b, &dst)){ + ret=WHYF("Invalid trace packet"); + goto end; + } + if (context.invalid_addresses){ + ret=WHYF("Invalid address in trace packet"); + goto end; + } + + INFOF("Trace from %s to %s", alloca_tohex_sid(src->sid), alloca_tohex_sid(dst->sid)); + + while(ob_remaining(b)>0){ + struct subscriber *trace=NULL; + if (overlay_address_parse(&context, b, &trace)){ + ret=WHYF("Invalid trace packet"); + goto end; + } + if (context.invalid_addresses){ + ret=WHYF("Invalid address in trace packet"); + goto end; + } + INFOF("Via %s", alloca_tohex_sid(trace->sid)); + + if (trace->reachable==REACHABLE_SELF && !next) + // We're already in this trace, send the next packet to the node before us in the list + next = last; + last = trace; + } + + if (src->reachable==REACHABLE_SELF && last){ + // it came back to us, we can send the reply to our mdp client... + next=src; + mdp->out.dst.port=mdp->out.src.port; + mdp->out.src.port=MDP_PORT_TRACE; + } + + if (!next){ + // destination is our neighbour? + if (dst->reachable & REACHABLE_DIRECT) + next = dst; + // destination is indirect? + else if (dst->reachable & REACHABLE_INDIRECT) + next = dst->next_hop; + // destination is not reachable or is ourselves? bounce back to the previous node or the sender. + else if (last) + next = last; + else + next = src; + } + + INFOF("Next node is %s", alloca_tohex_sid(next->sid)); + + ob_unlimitsize(b); + // always write a full sid into the payload + my_subscriber->send_full=1; + if (overlay_address_append(&context, b, my_subscriber)){ + ret = WHYF("Unable to append my address to the trace"); + goto end; + } + + mdp->out.payload_length = ob_position(b); + bcopy(my_subscriber->sid, mdp->out.src.sid, SID_SIZE); + bcopy(next->sid, mdp->out.dst.sid, SID_SIZE); + + ret = overlay_mdp_dispatch(mdp, 0, NULL, 0); +end: + ob_free(b); + RETURN(ret); +} + static int overlay_mdp_service_manifest_response(overlay_mdp_frame *mdp){ int offset=0; char id_hex[RHIZOME_MANIFEST_ID_STRLEN]; @@ -310,6 +395,7 @@ int overlay_mdp_try_interal_services(overlay_mdp_frame *mdp) case MDP_PORT_KEYMAPREQUEST: RETURN(keyring_mapping_request(keyring,mdp)); case MDP_PORT_DNALOOKUP: RETURN(overlay_mdp_service_dnalookup(mdp)); case MDP_PORT_ECHO: RETURN(overlay_mdp_service_echo(mdp)); + case MDP_PORT_TRACE: RETURN(overlay_mdp_service_trace(mdp)); case MDP_PORT_PROBE: RETURN(overlay_mdp_service_probe(mdp)); case MDP_PORT_STUNREQ: RETURN(overlay_mdp_service_stun_req(mdp)); case MDP_PORT_STUN: RETURN(overlay_mdp_service_stun(mdp)); diff --git a/tests/routing b/tests/routing index d31e82ae..b3813218 100755 --- a/tests/routing +++ b/tests/routing @@ -229,6 +229,8 @@ test_multihop_linear() { set_instance +A executeOk_servald mdp ping $SIDD 1 tfw_cat --stdout --stderr + executeOk_servald mdp trace $SIDD + tfw_cat --stdout --stderr executeOk_servald route print assertStdoutGrep --matches=1 "^$SIDB:BROADCAST UNICAST :" assertStdoutGrep --matches=1 "^$SIDC:INDIRECT :"