Migrate VoMP & mdp trace

This commit is contained in:
Jeremy Lakeman 2014-01-31 15:02:35 +10:30
parent 6822b58baa
commit 44512280c1
4 changed files with 99 additions and 83 deletions

View File

@ -768,6 +768,7 @@ static struct overlay_buffer * encrypt_payload(
}
// encrypt or sign the plaintext, then queue the frame for transmission.
// Note, the position of the payload MUST be at the start of the data, the limit MUST be used to specify the end
int overlay_send_frame(struct internal_mdp_header *header,
struct overlay_buffer *payload)
{

View File

@ -257,87 +257,111 @@ int overlay_mdp_service_echo(struct internal_mdp_header *header, struct overlay_
OUT();
}
static int overlay_mdp_service_trace(overlay_mdp_frame *mdp){
/*
* Trace packets are a little weird so that they can be modified by every node
* and so they can bypass the routing table.
*
* The true source and destination addresses are encoded inside the payload
* each node that processes the packet appends their own address before forwarding it to the next hop
* if their SID is already in the packet, the next hop is chosen from the immediately preceeding SID in the list.
* otherwise the next SID is chosen based on the current routing table.
*
* In this way the packet can follow the path defined by each node's routing table
* Until the packet reaches the destination, the destination is unreachable, or the packet loops around the network
* Once any of these end states occurs, the packet attempts to travel back to the source node,
* while using the source addresses in the trace packet for guidance instead of trusting the routing table.
*
* It is hoped that this information can be useful to better understand the current network state
* in situations where a routing protocol is in development.
*/
static int overlay_mdp_service_trace(struct internal_mdp_header *header, struct overlay_buffer *payload){
IN();
struct overlay_buffer *next_payload = ob_new();
if (!next_payload)
RETURN(-1);
ob_append_bytes(next_payload, ob_current_ptr(payload), ob_remaining(payload));
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 subscriber *src=NULL, *dst=NULL, *last=NULL;
struct decode_context context;
bzero(&context, sizeof context);
if (overlay_address_parse(&context, b, &src)){
ret=WHYF("Invalid trace packet");
if (header->source_port == MDP_PORT_TRACE){
ret=WHYF("Invalid source port");
goto end;
}
if (overlay_address_parse(&context, b, &dst)){
ret=WHYF("Invalid trace packet");
if (overlay_address_parse(&context, payload, &src)){
ret=WHYF("Invalid source SID");
goto end;
}
if (overlay_address_parse(&context, payload, &dst)){
ret=WHYF("Invalid destination SID");
goto end;
}
if (context.invalid_addresses){
ret=WHYF("Invalid address in trace packet");
ret=WHYF("Unknown address in trace packet");
goto end;
}
INFOF("Trace from %s to %s", alloca_tohex_sid_t(src->sid), alloca_tohex_sid_t(dst->sid));
struct internal_mdp_header next_header;
next_header = *header;
next_header.source = my_subscriber;
next_header.destination = NULL;
while(ob_remaining(b)>0){
while(ob_remaining(payload)>0){
struct subscriber *trace=NULL;
if (overlay_address_parse(&context, b, &trace)){
ret=WHYF("Invalid trace packet");
if (overlay_address_parse(&context, payload, &trace)){
ret=WHYF("Invalid SID in packet payload");
goto end;
}
if (context.invalid_addresses){
ret=WHYF("Invalid address in trace packet");
ret=WHYF("Unknown SID in packet payload");
goto end;
}
INFOF("Via %s", alloca_tohex_sid_t(trace->sid));
if (trace->reachable==REACHABLE_SELF && !next)
if (trace->reachable==REACHABLE_SELF && !next_header.destination)
// We're already in this trace, send the next packet to the node before us in the list
next = last;
next_header.destination = 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;
next_header.destination=src;
next_header.destination_port = header->source_port;
next_header.source_port = MDP_PORT_TRACE;
}
if (!next){
if (!next_header.destination){
// destination is our neighbour?
if (dst->reachable & REACHABLE_DIRECT)
next = dst;
next_header.destination = dst;
// destination is indirect?
else if (dst->reachable & REACHABLE_INDIRECT)
next = dst->next_hop;
next_header.destination = dst->next_hop;
// destination is not reachable or is ourselves? bounce back to the previous node or the sender.
else if (last)
next = last;
next_header.destination = last;
else
next = src;
next_header.destination = src;
}
INFOF("Next node is %s", alloca_tohex_sid_t(next->sid));
INFOF("Next node is %s", alloca_tohex_sid_t(next_header.destination->sid));
ob_unlimitsize(b);
// always write a full sid into the payload
my_subscriber->send_full=1;
overlay_address_append(&context, b, my_subscriber);
if (ob_overrun(b)) {
overlay_address_append(&context, next_payload, my_subscriber);
if (ob_overrun(next_payload)) {
ret = WHYF("Unable to append my address to the trace");
goto end;
}
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, NULL);
ob_flip(next_payload);
ret = overlay_send_frame(&next_header, next_payload);
end:
ob_free(b);
ob_free(next_payload);
RETURN(ret);
}
@ -373,6 +397,8 @@ void overlay_mdp_bind_internal_services()
mdp_bind_internal(NULL, MDP_PORT_STUNREQ, overlay_mdp_service_stun_req);
mdp_bind_internal(NULL, MDP_PORT_STUN, overlay_mdp_service_stun);
mdp_bind_internal(NULL, MDP_PORT_DNALOOKUP, overlay_mdp_service_dnalookup);
mdp_bind_internal(NULL, MDP_PORT_VOMP, vomp_mdp_received);
mdp_bind_internal(NULL, MDP_PORT_TRACE, overlay_mdp_service_trace);
}
int overlay_mdp_try_internal_services(
@ -383,15 +409,9 @@ int overlay_mdp_try_internal_services(
// TODO convert to internal bindings
switch(header->destination_port) {
case MDP_PORT_VOMP:
overlay_mdp_fill_legacy(header, payload, &mdp);
RETURN(vomp_mdp_received(&mdp));
case MDP_PORT_KEYMAPREQUEST:
overlay_mdp_fill_legacy(header, payload, &mdp);
RETURN(keyring_mapping_request(keyring, header, &mdp));
case MDP_PORT_TRACE:
overlay_mdp_fill_legacy(header, payload, &mdp);
RETURN(overlay_mdp_service_trace(&mdp));
}
/* Unbound socket. We won't be sending ICMP style connection refused

View File

@ -437,7 +437,7 @@ struct vomp_call_state;
void set_codec_flag(int codec, unsigned char *flags);
struct vomp_call_state *vomp_find_call_by_session(unsigned int session_token);
int vomp_mdp_received(overlay_mdp_frame *mdp);
int vomp_mdp_received(struct internal_mdp_header *header, struct overlay_buffer *payload);
int vomp_parse_dtmf_digit(char c);
int vomp_dial(struct subscriber *local, struct subscriber *remote, const char *local_did, const char *remote_did);
int vomp_pickup(struct vomp_call_state *call);

79
vomp.c
View File

@ -30,7 +30,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "conf.h"
#include "strbuf.h"
#include "strlcpy.h"
#include "mdp_client.h"
#include "overlay_address.h"
#include "overlay_buffer.h"
#include "overlay_packet.h"
/*
Typical call state lifecycle between 2 parties.
@ -707,19 +710,15 @@ static uint32_t to_absolute_value(uint16_t short_value, unsigned int reference_v
return abs_value;
}
static int vomp_process_audio(struct vomp_call_state *call, overlay_mdp_frame *mdp, time_ms_t now)
static int vomp_process_audio(struct vomp_call_state *call, struct overlay_buffer *payload, time_ms_t now)
{
size_t ofs=6;
if(ofs>=mdp->in.payload_length)
if(ob_remaining(payload)<1)
return 0;
int codec=mdp->in.payload[ofs++];
uint8_t codec=ob_get(payload);
uint16_t time = mdp->in.payload[ofs]<<8 | mdp->in.payload[ofs+1]<<0;
ofs+=2;
uint16_t sequence = mdp->in.payload[ofs]<<8 | mdp->in.payload[ofs+1]<<0;
ofs+=2;
uint16_t time = ob_get_ui16(payload);
uint16_t sequence = ob_get_ui16(payload);
// rebuild absolute time value from short relative time.
uint32_t decoded_time = to_absolute_value(time, call->remote_audio_clock);
@ -739,7 +738,7 @@ static int vomp_process_audio(struct vomp_call_state *call, overlay_mdp_frame *m
decoded_time=decoded_time * 20;
int audio_len = mdp->in.payload_length - ofs;
int audio_len = ob_remaining(payload);
int delay=0;
if (store_jitter_sample(&call->jitter, decoded_time, now, &delay))
@ -748,7 +747,7 @@ static int vomp_process_audio(struct vomp_call_state *call, overlay_mdp_frame *m
/* Pass audio frame to all registered listeners */
if (monitor_socket_count)
monitor_send_audio(call, codec, decoded_time, decoded_sequence,
&mdp->in.payload[ofs],
ob_current_ptr(payload),
audio_len, delay);
return 0;
}
@ -852,23 +851,23 @@ int vomp_hangup(struct vomp_call_state *call)
return 0;
}
static int vomp_extract_remote_codec_list(struct vomp_call_state *call,overlay_mdp_frame *mdp)
static int vomp_extract_remote_codec_list(struct vomp_call_state *call, struct overlay_buffer *payload)
{
int ofs=6;
if (config.debug.vomp)
dump("codec list mdp frame", (unsigned char *)&mdp->in.payload[0],mdp->in.payload_length);
ob_dump(payload, "codec list mdp frame");
for (;ofs<mdp->in.payload_length && mdp->in.payload[ofs];ofs++){
int codec = mdp->in.payload[ofs];
while(ob_remaining(payload)>0){
uint8_t codec = ob_get(payload);
set_codec_flag(codec, call->remote_codec_flags);
}
if (!call->initiated_call){
ofs++;
if (ofs<mdp->in.payload_length)
ofs+=strlcpy(call->remote.did, (char *)(mdp->in.payload+ofs), sizeof(call->remote.did))+1;
if (ofs<mdp->in.payload_length)
ofs+=strlcpy(call->local.did, (char *)(mdp->in.payload+ofs), sizeof(call->local.did));
const char *p;
if (ob_remaining(payload)>0 && (p=ob_get_str_ptr(payload))){
strlcpy(call->remote.did, p, sizeof(call->remote.did));
if (ob_remaining(payload)>0 && (p=ob_get_str_ptr(payload)))
strlcpy(call->local.did, p, sizeof(call->local.did));
}
}
return 0;
}
@ -876,27 +875,25 @@ static int vomp_extract_remote_codec_list(struct vomp_call_state *call,overlay_m
/* At this point we know the MDP frame is addressed to the VoMP port, but
we have not inspected the contents. As these frames are wire-format, we
must pay attention to endianness. */
int vomp_mdp_received(overlay_mdp_frame *mdp)
int vomp_mdp_received(struct internal_mdp_header *header, struct overlay_buffer *payload)
{
time_ms_t now = gettime_ms();
if (mdp->packetTypeAndFlags&(MDP_NOCRYPT|MDP_NOSIGN))
{
/* stream-crypted audio frame */
return WHY("not implemented");
}
/* only auth-crypted frames make it this far */
if (header->crypt_flags & (MDP_FLAG_NO_CRYPT | MDP_FLAG_NO_SIGN))
return WHY("not implemented");
/* only auth-crypted frames are allowed */
struct vomp_call_state *call=NULL;
switch(mdp->in.payload[0]) {
unsigned char version = ob_get(payload);
switch(version) {
case VOMP_VERSION:
{
unsigned int sender_session=(mdp->in.payload[1]<<8)|mdp->in.payload[2];
unsigned int recvr_session=(mdp->in.payload[3]<<8)|mdp->in.payload[4];
int recvr_state=mdp->in.payload[5]>>4;
int sender_state=mdp->in.payload[5]&0xf;
unsigned int sender_session=ob_get_ui16(payload);
unsigned int recvr_session=ob_get_ui16(payload);
unsigned char state = ob_get(payload);
unsigned char recvr_state=state>>4;
unsigned char sender_state=state&0xf;
/* wants to create a call session.
Main aim here: replay protection. An adversary should not be able to
@ -905,10 +902,8 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
trying to use such replays to cause a denial of service attack we need
to be able to track multiple potential session numbers even from the
same SID. */
struct subscriber *local=find_subscriber(mdp->in.dst.sid.binary, SID_SIZE, 0);
struct subscriber *remote=find_subscriber(mdp->in.src.sid.binary, SID_SIZE, 0);
call=vomp_find_or_create_call(remote,local,
call=vomp_find_or_create_call(header->source, header->destination,
sender_session,recvr_session,
sender_state,recvr_state);
@ -945,7 +940,7 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
int i, found=0;
// the other party should have given us their list of supported codecs
vomp_extract_remote_codec_list(call,mdp);
vomp_extract_remote_codec_list(call, payload);
// make sure we have at least one codec in common
monitor_get_all_supported_codecs(supported_codecs);
@ -1048,7 +1043,7 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
// Fall through
case (VOMP_STATE_INCALL<<3)|VOMP_STATE_INCALL:
/* play any audio that they have sent us. */
vomp_process_audio(call,mdp,now);
vomp_process_audio(call, payload, now);
break;
case (VOMP_STATE_CALLENDED<<3)|VOMP_STATE_NOCALL:
@ -1083,7 +1078,7 @@ int vomp_mdp_received(overlay_mdp_frame *mdp)
break;
default:
/* unsupported VoMP frame */
WHYF("Unsupported VoMP frame type = 0x%02x",mdp->in.payload[0]);
WHYF("Unsupported VoMP frame type = 0x%02x", version);
break;
}