mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-21 09:51:50 +00:00
Migrate VoMP & mdp trace
This commit is contained in:
parent
6822b58baa
commit
44512280c1
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
2
serval.h
2
serval.h
@ -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
79
vomp.c
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user