Prep for 6-in-6, 4-in-6, 6-in-4

This commit is contained in:
Nick Thomas
2013-08-15 00:09:23 +01:00
parent 2ffff92d36
commit 1cdf838ac9
5 changed files with 212 additions and 113 deletions

View File

@@ -8,7 +8,7 @@
#include <sys/uio.h>
int process_icmp_rloc_update( struct rlocs *reg, struct packet *packet )
int process_icmpv4_rloc_update( struct rlocs *reg, struct packet *packet )
{
uint16_t hdr_len = packet->hdr.ip.ihl * 4;
uint16_t inner_ip_hdr_offset = hdr_len + sizeof( struct icmphdr );
@@ -46,40 +46,35 @@ int process_icmp_rloc_update( struct rlocs *reg, struct packet *packet )
return 1;
}
int process_ipv4_packet( struct rlocs *reg, struct packet *packet, struct rsp_data *frag1, struct rsp_data *frag2 )
{
int result, updated;
switch ( packet->hdr.ip.protocol ) {
case IPPROTO_HIDE_EID:
// doesn't need fragmenting, or if it does, tough
result = unwrap_ipv4_packet( reg, packet, frag1 );
break;
case IPPROTO_ICMP:
if ( ( updated = process_icmp_rloc_update( reg, packet ) ) != 0 ) {
result = 0;
break;
}
// intentional fallthrough for ICMP not addressed to us.
// -1 (error) and 1 ( dealt with ) don't need to respond.
default:
result = wrap_ipv4_packet( reg, packet, frag1, frag2 );
break;
}
return result;
int process_icmpv6_rloc_update( struct rlocs *reg, struct packet *packet )
{
warn( "STUB: process_icmpv6_rloc_update" );
return 0;
}
int process_packet( struct rlocs *reg, struct packet *packet, struct rsp_data *frag1, struct rsp_data *frag2 )
int process_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2 )
{
if ( packet->hdr.ip.version == 0x04 ) {
return process_ipv4_packet( reg, packet, frag1, frag2 );
int protocol = packet_find_protocol( pkt );
if ( protocol == -1 ) {
warn( "Couldn't work out version / protocol of received packet, discarding" );
return 0;
}
warn( "Can't process IP protocol version %i yet; dropping packet", packet->hdr.ip.version );
if ( protocol == IPPROTO_HIDE_EID ) {
return unwrap_packet( reg, pkt, frag1 );
}
return 0;
if ( protocol == IPPROTO_ICMP && process_icmpv4_rloc_update( reg, pkt ) ) {
return 0;
}
if ( protocol == IPPROTO_ICMPV6 && process_icmpv6_rloc_update( reg, pkt ) ) {
return 0;
}
return wrap_packet( reg, pkt, frag1, frag2 );
}
/*
@@ -160,4 +155,4 @@ int main(int argc, char** argv)
session_teardown( &session );
return 0;
}
}

View File

@@ -39,8 +39,7 @@ void compute_ip_checksum(struct iphdr *pkt)
pkt->check = compute_checksum( (unsigned short*) pkt, pkt->ihl * 4 );
}
int build_wrapped_ipv4_packet(struct rlocs *reg, struct rloc * s_rloc, struct rloc *d_rloc, struct packet *pkt, struct rsp_data *out)
int build_wrapped_ipv4_packet( struct peer_context *pctx, struct packet *pkt, struct rsp_data *out )
{
struct iphdr *wrap_hdr = (struct iphdr *) out->scratch;
uint16_t wrap_hdr_size = sizeof( struct iphdr );
@@ -69,8 +68,8 @@ int build_wrapped_ipv4_packet(struct rlocs *reg, struct rloc * s_rloc, struct rl
wrap_hdr->ttl = IPDEFTTL;
wrap_hdr->protocol = IPPROTO_HIDE_EID;
wrap_hdr->frag_off = htons( IP_DF ); // DF bit set
wrap_hdr->saddr = s_rloc->addr.ip4.s_addr;
wrap_hdr->daddr = d_rloc->addr.ip4.s_addr;
wrap_hdr->saddr = pctx->x->addr.ip4.s_addr;
wrap_hdr->daddr = pctx->y->addr.ip4.s_addr;
// FIXME: Do we need to set an ID ?
// iovec 0: encapsulating IP header.
@@ -84,7 +83,7 @@ int build_wrapped_ipv4_packet(struct rlocs *reg, struct rloc * s_rloc, struct rl
// calculate exactly how many bytes for TCP, UDP, etc. to do as little work
// as we can get away with, here. fragments > 0 don't need encrypting at all
enc_size = rlocs_encrypt(
reg, s_rloc, d_rloc,
pctx,
(unsigned char *)&pkt->hdr, bytes_to_encrypt,
pkt_enc_data, IP_MAXPACKET - wrap_hdr_size - 2
);
@@ -161,21 +160,62 @@ void build_icmp_too_big( uint16_t max_mtu, struct in_addr *rloc_src, struct pack
return;
}
int wrap_ipv4_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2 )
struct peer_context *packet_peer_context( struct rlocs *reg, struct packet *pkt, int wrapping )
{
struct rloc *s_rloc, *d_rloc;
if ( ( s_rloc = rloc_find_for_ipv4( reg, (struct in_addr *)&pkt->hdr.ip.saddr ) ) == NULL ) {
debug( "Couldn't find source RLOC for (TODO), dropping packet" );
return 0;
char bad_eid_txt[128] = {0};
struct rloc *src_rloc = NULL, *dst_rloc = NULL;
struct in_addr *ip4_src = (struct in_addr*) &pkt->hdr.ip.saddr;
struct in_addr *ip4_dst = (struct in_addr*) &pkt->hdr.ip.daddr;
switch( pkt->hdr.ip.version ) {
case 0x04: // ipv4
src_rloc = rloc_find_for_ipv4( reg, ip4_src );
if ( src_rloc == NULL ) {
inet_ntop( AF_INET, ip4_src, bad_eid_txt, 128 );
break;
}
dst_rloc = rloc_find_for_ipv4( reg, (struct in_addr *)&pkt->hdr.ip.daddr );
if ( dst_rloc == NULL ) {
inet_ntop( AF_INET, ip4_dst, bad_eid_txt, 128 );
}
break;
case 0x06: // ipv6
src_rloc = rloc_find_for_ipv6( reg, &pkt->hdr.ip6.ip6_src );
if ( src_rloc == NULL) {
inet_ntop( AF_INET6, &pkt->hdr.ip6.ip6_src, bad_eid_txt, 128 );
break;
}
dst_rloc = rloc_find_for_ipv6( reg, &pkt->hdr.ip6.ip6_dst );
if (dst_rloc == NULL ) {
inet_ntop( AF_INET6, &pkt->hdr.ip6.ip6_dst, bad_eid_txt, 128 );
}
break;
}
if ( ( d_rloc = rloc_find_for_ipv4( reg, (struct in_addr *)&pkt->hdr.ip.daddr ) ) == NULL ) {
debug( "Couldn't find destination RLOC for (TODO), dropping packet" );
return 0;
if ( src_rloc == NULL ) {
warn( "Couldn't find source RLOC for %s, discarding packet", bad_eid_txt );
return NULL;
}
uint16_t max_size = rlocs_get_path_mtu( reg, s_rloc, d_rloc );
if ( dst_rloc == NULL ) {
warn( "Couldn't find destination RLOC for %s, discarding packet", bad_eid_txt );
return NULL;
}
if ( wrapping ) { // when wrapping, src=x, dst=y
return rlocs_get_peer_ctx( reg, src_rloc, dst_rloc );
} else { // when unwrapping, src=y, dst=x
return rlocs_get_peer_ctx( reg, dst_rloc, src_rloc );
}
}
int wrap_ipv4_packet_in_ipv4( struct peer_context *pctx, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2 )
{
uint16_t max_size = pctx->path_mtu;
uint16_t pkt_tot_len = ntohs( pkt->hdr.ip.tot_len );
uint16_t pkt_hdr_len = pkt->hdr.ip.ihl * 4;
@@ -186,7 +226,7 @@ int wrap_ipv4_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *fr
debug( "Packet needs fragmenting" );
// DF bit set, so return ICMP Too Big
if ( ntohs( pkt->hdr.ip.frag_off ) & IP_DF ) {
build_icmp_too_big( max_size, &s_rloc->addr.ip4, pkt, frag1 );
build_icmp_too_big( max_size, &pctx->x->addr.ip4, pkt, frag1 );
return 1;
}
@@ -223,13 +263,13 @@ int wrap_ipv4_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *fr
compute_ip_checksum( &pkt->hdr.ip );
compute_ip_checksum( &pkt2->hdr.ip );
if ( !build_wrapped_ipv4_packet( reg, s_rloc, d_rloc, pkt2, frag2 ) ) {
if ( !build_wrapped_ipv4_packet( pctx, pkt2, frag2 ) ) {
debug( "Couldn't wrap packet 2 of 2 ");
return 0;
}
}
if ( !build_wrapped_ipv4_packet( reg, s_rloc, d_rloc, pkt, frag1 ) ) {
if ( !build_wrapped_ipv4_packet( pctx, pkt, frag1 ) ) {
debug( "Couldn't wrap packet 1 of %i", num_packets );
return 0;
}
@@ -237,15 +277,65 @@ int wrap_ipv4_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *fr
return num_packets;
}
int wrap_ipv6_packet(struct rlocs *reg, struct packet *pkt, struct rsp_data *out)
int wrap_ipv6_packet_in_ipv4(struct peer_context *pctx, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2)
{
warn( "STUB: wrap_ipv6_packet" );
warn( "STUB: wrap_ipv6_packet_in_ipv4" );
return 0;
}
int wrap_ipv4_packet_in_ipv6(struct peer_context *pctx, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2)
{
warn( "STUB: wrap_ipv4_packet_in_ipv6" );
return 0;
}
int wrap_ipv6_packet_in_ipv6(struct peer_context *pctx, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2)
{
warn( "STUB: wrap_ipv6_packet_in_ipv6" );
return 0;
}
int wrap_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2 )
{
struct peer_context *pctx = packet_peer_context( reg, pkt, 1 );
if ( pctx == NULL ) {
return 0;
}
int result = 0;
switch ( pctx->x->family ) {
case AF_INET:
switch ( pkt->hdr.ip.version ) {
case 0x04: // ipv4
result = wrap_ipv4_packet_in_ipv4( pctx, pkt, frag1, frag2 );
break;
case 0x06: // ipv6
result = wrap_ipv6_packet_in_ipv4( pctx, pkt, frag1, frag2 );
break;
}
break;
case AF_INET6:
switch ( pkt->hdr.ip.version ) {
case 0x04: // ipv4
result = wrap_ipv4_packet_in_ipv6( pctx, pkt, frag1, frag2 );
break;
case 0x06: // ipv6
result = wrap_ipv6_packet_in_ipv6( pctx, pkt, frag1, frag2 );
break;
}
break;
default:
warn( "Unknown family of peer context: %i", pctx->x->family );
}
return result;
}
int unwrap_ipv4_packet(struct rlocs* reg, struct packet *pkt, struct rsp_data *out)
int unwrap_ipv4_packet( struct peer_context *pctx, struct packet *pkt, struct rsp_data *out )
{
out->count = 2;
assert( out->count < MAX_IOVS );
@@ -256,24 +346,6 @@ int unwrap_ipv4_packet(struct rlocs* reg, struct packet *pkt, struct rsp_data *o
return 0;
}
// We need to know source and destination rloc to decrypt the packet
struct rloc *s_rloc, *d_rloc;
struct in_addr tmp;
tmp.s_addr = pkt->hdr.ip.saddr;
if ( ( s_rloc = rloc_find_by_address( reg, &tmp, NULL ) ) == NULL ) {
warn( "Couldn't find rloc from source IP, dropping packet" );
// TODO: we should be able to specify we need it to have a private key
return 0;
}
tmp.s_addr = pkt->hdr.ip.daddr;
if ( ( d_rloc = rloc_find_by_address( reg, &tmp, NULL ) ) == NULL ) {
warn( "Couldn't find rloc from destination IP, dropping packet" );
// TODO: we should be able to specify we need it to have a private key
return 0;
}
uint16_t hdr_size = pkt->hdr.ip.ihl * 4;
uint16_t encrypted_size = ntohs( *((uint16_t*)pkt + ( hdr_size / 2 )) );
info( "encrypted_size: %u", encrypted_size );
@@ -282,10 +354,7 @@ int unwrap_ipv4_packet(struct rlocs* reg, struct packet *pkt, struct rsp_data *o
unsigned char *encrypted_data = ((unsigned char *)pkt) + hdr_size + 2;
unsigned char *scratch = &out->scratch[0];
int decrypted_size = rlocs_decrypt(
reg, d_rloc, s_rloc,
encrypted_data, encrypted_size, scratch, IP_MAXPACKET
);
int decrypted_size = rlocs_decrypt( pctx, encrypted_data, encrypted_size, scratch, IP_MAXPACKET );
if ( decrypted_size < 0 ) {
warn( "Failed to decrypt packet!" );
@@ -306,15 +375,41 @@ int unwrap_ipv4_packet(struct rlocs* reg, struct packet *pkt, struct rsp_data *o
warn( "hdr_size = %u, encrypted_size = %u, tot_len = %u", hdr_size, encrypted_size, ntohs( pkt->hdr.ip.tot_len ) );
return 0;
}
info( "Finished unwrapping IPv4 packet" );
debug( "Finished unwrapping IPv4 packet" );
return 1;
}
int unwrap_ipv6_packet(struct rlocs *reg, struct packet *pkt, struct rsp_data *out)
int unwrap_ipv6_packet(struct peer_context *pctx, struct packet *pkt, struct rsp_data *out)
{
warn( "STUB: unwrap_ipv6_packet" );
return 0;
}
int unwrap_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *out )
{
int result;
struct peer_context *pctx = packet_peer_context( reg, pkt, 0 );
if ( pctx == NULL ) {
return 0;
}
switch ( pkt->hdr.ip.version ) {
case 0x04:
result = unwrap_ipv4_packet( pctx, pkt, out );
break;
case 0x06:
result = unwrap_ipv6_packet( pctx, pkt, out );
break;
default:
warn( "Couldn't unwrap packet with version %i, discarding", pkt->hdr.ip.version );
result = 0;
}
return result;
}

View File

@@ -34,7 +34,7 @@ struct packet {
// 0 - wrapping ip header, including enc_size
// 1 - encrypted portion of payload, in scratch.
// 2 - unencrypted portion of payload, in recv_pkt
#define MAX_IOVS 12
#define MAX_IOVS 3
struct rsp_data {
int count;
struct iovec iovs[MAX_IOVS];
@@ -42,19 +42,25 @@ struct rsp_data {
};
static inline int packet_find_protocol( struct packet *pkt )
{
if ( pkt->hdr.ip.version == 0x04 ) {
return pkt->hdr.ip.protocol;
}
if ( pkt->hdr.ip.version == 0x06 ) {
return pkt->hdr.ip6.ip6_nxt;
}
// If we need more fragments than this, I am a sad person
#define MAX_PACKET_FRAGMENTS 4
return -1;
}
void compute_ip_checksum( struct iphdr* pkt );
int wrap_ipv4_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2 );
int wrap_ipv6_packet(struct rlocs* reg, struct packet *pkt, struct rsp_data *out);
int unwrap_ipv4_packet(struct rlocs* reg, struct packet *pkt, struct rsp_data *out);
int unwrap_ipv6_packet(struct rlocs* reg, struct packet *pkt, struct rsp_data *out);
int wrap_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2 );
int unwrap_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *out );
struct peer_context *packet_peer_context( struct rlocs *reg, struct packet *pkt, int direction );
#endif

View File

@@ -558,6 +558,10 @@ int rlocs_update_peer_context(struct rlocs *reg, struct rloc *x, struct rloc *y)
* decrypt packet data. */
EVP_CIPHER_CTX_init( &entry->ctx );
entry->reg = reg;
entry->x = x;
entry->y = y;
entry->path_mtu = DEFAULT_PATH_MTU;
entry->in_use = 1;
@@ -573,16 +577,14 @@ fail:
}
static inline struct peer_context *rlocs_get_peer_ctx( struct rlocs *reg, struct rloc *x, struct rloc *y )
struct peer_context *rlocs_get_peer_ctx( struct rlocs *reg, struct rloc *x, struct rloc *y )
{
return &reg->peer_contexts[x->context_id][y->context_id];
}
ssize_t rlocs_encrypt( struct rlocs *reg, struct rloc *x, struct rloc *y, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len )
ssize_t rlocs_encrypt( struct peer_context *pctx, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len )
{
struct peer_context *entry = rlocs_get_peer_ctx( reg, x, y );
if ( !entry->in_use && !rlocs_update_peer_context( reg, x, y ) ) {
if ( !pctx->in_use && !rlocs_update_peer_context( pctx->reg, pctx->x, pctx->y ) ) {
warn( "Couldn't build an encryption context for these rlocs" );
return -1;
}
@@ -596,29 +598,29 @@ ssize_t rlocs_encrypt( struct rlocs *reg, struct rloc *x, struct rloc *y, unsign
}
unsigned char *iv = dest;
unsigned char *secret = (unsigned char *)&entry->secret[0];
unsigned char *secret = (unsigned char *)&pctx->secret[0];
size_t written = 16;
int outl = dest_len - written;
RAND_pseudo_bytes( iv, 16 );
if ( !EVP_EncryptInit_ex( &entry->ctx, EVP_aes_256_gcm(), NULL, NULL, NULL ) ) {
if ( !EVP_EncryptInit_ex( &pctx->ctx, EVP_aes_256_gcm(), NULL, NULL, NULL ) ) {
warn( "EVP_EncryptInit_ex() (1) failed" );
goto fail;
}
if ( !EVP_CIPHER_CTX_ctrl( &entry->ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL)) {
if ( !EVP_CIPHER_CTX_ctrl( &pctx->ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL)) {
warn ("Setting IV len to 16 failed" );
goto fail;
}
if ( !EVP_EncryptInit_ex( &entry->ctx, NULL, NULL, secret, iv ) ) {
if ( !EVP_EncryptInit_ex( &pctx->ctx, NULL, NULL, secret, iv ) ) {
warn( "EVP_EncryptInit_ex() (2) failed" );
goto fail;
}
if ( !EVP_EncryptUpdate( &entry->ctx, dest + written, &outl, data, data_len ) ) {
if ( !EVP_EncryptUpdate( &pctx->ctx, dest + written, &outl, data, data_len ) ) {
warn( "EVP_EncryptUpdate() failed" );
goto fail;
}
@@ -628,7 +630,7 @@ ssize_t rlocs_encrypt( struct rlocs *reg, struct rloc *x, struct rloc *y, unsign
written += outl;
outl = dest_len - written;
if ( !EVP_EncryptFinal_ex( &entry->ctx, dest + written, &outl ) ) {
if ( !EVP_EncryptFinal_ex( &pctx->ctx, dest + written, &outl ) ) {
warn( "EVP_EncryptFinal_ex() failed" );
goto fail;
}
@@ -636,7 +638,7 @@ ssize_t rlocs_encrypt( struct rlocs *reg, struct rloc *x, struct rloc *y, unsign
written += outl;
/* Get the tag */
if( !EVP_CIPHER_CTX_ctrl( &entry->ctx, EVP_CTRL_GCM_GET_TAG, 16, dest + written ) ) {
if( !EVP_CIPHER_CTX_ctrl( &pctx->ctx, EVP_CTRL_GCM_GET_TAG, 16, dest + written ) ) {
warn( "Getting GCM tag for our encrypted data failed" );
goto fail;
}
@@ -648,17 +650,15 @@ fail:
return -1;
}
ssize_t rlocs_decrypt( struct rlocs *reg, struct rloc *x, struct rloc *y, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len )
ssize_t rlocs_decrypt( struct peer_context *pctx, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len )
{
struct peer_context *entry = rlocs_get_peer_ctx( reg, x, y );
if ( !entry->in_use && !rlocs_update_peer_context( reg, x, y ) ) {
if ( !pctx->in_use && !rlocs_update_peer_context( pctx->reg, pctx->x, pctx->y ) ) {
warn( "Couldn't build a decryption context for these rlocs" );
return -1;
}
unsigned char *iv = data;
unsigned char *secret = (unsigned char *)&entry->secret[0];
unsigned char *secret = (unsigned char *)&pctx->secret[0];
size_t written = 0;
int outl = dest_len;
@@ -668,22 +668,22 @@ ssize_t rlocs_decrypt( struct rlocs *reg, struct rloc *x, struct rloc *y, unsign
goto fail;
}
if ( !EVP_DecryptInit_ex( &entry->ctx, EVP_aes_256_gcm(), NULL, NULL, NULL ) ) {
if ( !EVP_DecryptInit_ex( &pctx->ctx, EVP_aes_256_gcm(), NULL, NULL, NULL ) ) {
warn( "EVP_DecryptInit_ex() (1) failed" );
goto fail;
}
if ( !EVP_CIPHER_CTX_ctrl(&entry->ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL)) {
if ( !EVP_CIPHER_CTX_ctrl(&pctx->ctx, EVP_CTRL_GCM_SET_IVLEN, 16, NULL)) {
warn ("Setting IV len to 16 failed" );
goto fail;
}
if ( !EVP_DecryptInit_ex( &entry->ctx, NULL, NULL, secret, iv ) ) {
if ( !EVP_DecryptInit_ex( &pctx->ctx, NULL, NULL, secret, iv ) ) {
warn( "EVP_DecryptInit_ex() (2) failed" );
goto fail;
}
if ( !EVP_DecryptUpdate( &entry->ctx, dest, &outl, data + 16, data_len - 32 ) ) {
if ( !EVP_DecryptUpdate( &pctx->ctx, dest, &outl, data + 16, data_len - 32 ) ) {
warn( "EVP_DecryptUpdate() failed" );
goto fail;
}
@@ -691,12 +691,12 @@ ssize_t rlocs_decrypt( struct rlocs *reg, struct rloc *x, struct rloc *y, unsign
written += outl;
outl = dest_len - written;
if( !EVP_CIPHER_CTX_ctrl(&entry->ctx, EVP_CTRL_GCM_SET_TAG, 16, data + (data_len - 16 ) ) ) {
if( !EVP_CIPHER_CTX_ctrl(&pctx->ctx, EVP_CTRL_GCM_SET_TAG, 16, data + (data_len - 16 ) ) ) {
warn( "Failed to provide GCM tag to decrypt routine" );
goto fail;
}
if ( !EVP_DecryptFinal_ex( &entry->ctx, dest + written, &outl ) ) {
if ( !EVP_DecryptFinal_ex( &pctx->ctx, dest + written, &outl ) ) {
warn( "EVP_DecryptFinal_ex() failed - bad tag?" );
goto fail;
}

View File

@@ -23,12 +23,13 @@ struct peer_context {
unsigned int path_mtu;
/* Probably don't need these
struct rloc *rloc_x;
struct rloc *rloc_y;
*/
struct rlocs *reg;
struct rloc *x;
struct rloc *y;
};
typedef struct peer_context PeerCtx;
struct rloc {
short family;
union {
@@ -95,17 +96,19 @@ int rlocs_find_two_ipv4(
struct rloc **d_rloc_ptr, struct in_addr *d_rloc_addr
);
struct peer_context *rlocs_get_peer_ctx( struct rlocs *reg, struct rloc *x, struct rloc *y );
int rloc_add_private_key( struct rloc *rloc, char *filename );
void rlocs_debug_output( struct rlocs *reg );
/* Returns -1 on error, or number of bytes written */
ssize_t rlocs_encrypt( struct rlocs *reg, struct rloc *x, struct rloc *y, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len );
ssize_t rlocs_decrypt( struct rlocs *reg, struct rloc *x, struct rloc *y, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len );
ssize_t rlocs_encrypt( struct peer_context *pctx, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len );
ssize_t rlocs_decrypt( struct peer_context *pctx, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len );
unsigned short rlocs_get_path_mtu( struct rlocs *reg, struct rloc *x, struct rloc *y );
void rlocs_set_path_mtu( struct rlocs *reg, struct rloc *x, struct rloc *y, unsigned short new_mtu );
void rlocs_free( struct rlocs *registry );
#endif
#endif