This gets us to the point of seemingly being able to wrap and unwrap IPv4
Remarkably hard to test this on a single computer
This commit is contained in:
@@ -23,7 +23,7 @@ int main(int argc, char** argv)
|
|||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
if ( argc < 4 ) {
|
if ( argc < 4 ) {
|
||||||
warn( "Usage: %s <rloc database> <listen_ifname> <output_ifname>", argv[0] );
|
warn( "Usage: %s <rloc database> <listen_ifname> <output_ifname> [ <rloc> <keyfile> ]n", argv[0] );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,10 +49,22 @@ int main(int argc, char** argv)
|
|||||||
|
|
||||||
switch( recv_pkt.hdr.ip.version ) {
|
switch( recv_pkt.hdr.ip.version ) {
|
||||||
case 0x04 :
|
case 0x04 :
|
||||||
//result = wrap_ipv4_packet( wrap.rlocs, &recv_pkt, &to_send );
|
if ( recv_pkt.hdr.ip.protocol == IPPROTO_HIDE_EID ) {
|
||||||
|
result = unwrap_ipv4_packet( session.rlocs, &recv_pkt, &to_send );
|
||||||
|
} else {
|
||||||
|
result = wrap_ipv4_packet( session.rlocs, &recv_pkt, &to_send );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 0x06 :
|
case 0x06 :
|
||||||
//result = wrap_ipv6_packet( wrap.rlocs, &recv_pkt, &to_send );
|
/* TODO: ip6.protocol doesn't exist. And we're not wrapping
|
||||||
|
* IPv6 packets yet anyway.
|
||||||
|
if ( recv_pkt.hdr.ip6.protocol == IPPROTO_HIDE_EID ) {
|
||||||
|
result = unwrap_ipv6_packet( wrap.rlocs, &recv_pkt, &to_send );
|
||||||
|
} else {
|
||||||
|
result = wrap_ipv6_packet( wrap.rlocs, &recv_pkt, &to_send );
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
warn( "TODO: wrap/unwrap IPv6 packets" );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
warn( "Unknown IP version: %i", recv_pkt.hdr.ip.version );
|
warn( "Unknown IP version: %i", recv_pkt.hdr.ip.version );
|
||||||
|
@@ -69,7 +69,6 @@ int wrap_ipv4_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data* o
|
|||||||
struct rloc* d_rloc;
|
struct rloc* d_rloc;
|
||||||
struct in_addr tmp;
|
struct in_addr tmp;
|
||||||
|
|
||||||
// TODO: check endianness of saddr/daddr
|
|
||||||
tmp.s_addr = pkt->hdr.ip.saddr;
|
tmp.s_addr = pkt->hdr.ip.saddr;
|
||||||
if ( ( s_rloc = rloc_find_for_ipv4( reg, &tmp ) ) == NULL ) {
|
if ( ( s_rloc = rloc_find_for_ipv4( reg, &tmp ) ) == NULL ) {
|
||||||
warn( "Couldn't find source rloc, dropping packet" );
|
warn( "Couldn't find source rloc, dropping packet" );
|
||||||
@@ -98,7 +97,7 @@ int wrap_ipv4_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data* o
|
|||||||
size_t bytes_to_encrypt;
|
size_t bytes_to_encrypt;
|
||||||
|
|
||||||
if ( orig_data_size > 512 ) {
|
if ( orig_data_size > 512 ) {
|
||||||
bytes_to_encrypt = pkt->hdr.ip.ihl * 4;
|
bytes_to_encrypt = 512; // No point wasting bytes on padding
|
||||||
} else {
|
} else {
|
||||||
bytes_to_encrypt = orig_data_size;
|
bytes_to_encrypt = orig_data_size;
|
||||||
}
|
}
|
||||||
@@ -140,7 +139,7 @@ int wrap_ipv4_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data* o
|
|||||||
wrap_hdr->tot_len = htons( wrap_hdr_size + enc_size + out->iovs[2].iov_len );
|
wrap_hdr->tot_len = htons( wrap_hdr_size + enc_size + out->iovs[2].iov_len );
|
||||||
compute_ip_checksum( wrap_hdr );
|
compute_ip_checksum( wrap_hdr );
|
||||||
|
|
||||||
info( "Finished building return packet" );
|
info( "Finished wrapping IPv4 packet" );
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -155,8 +154,60 @@ int wrap_ipv6_packet(struct rlocs *reg, struct recv_pkt* pkt, struct rsp_data* o
|
|||||||
|
|
||||||
int unwrap_ipv4_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data* out)
|
int unwrap_ipv4_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data* out)
|
||||||
{
|
{
|
||||||
warn( "STUB: unwrap_ipv4_packet" );
|
out->count = 2;
|
||||||
return 0;
|
assert( out->count < MAX_IOVS );
|
||||||
|
|
||||||
|
// first, check this is actually a hide-eid packet.
|
||||||
|
if ( pkt->hdr.ip.protocol != IPPROTO_HIDE_EID ) {
|
||||||
|
warn( "expected IP protocol %u, not %u", IPPROTO_HIDE_EID, pkt->hdr.ip.protocol );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to know destination rloc to decrypt the packet
|
||||||
|
struct rloc* rloc;
|
||||||
|
struct in_addr tmp;
|
||||||
|
|
||||||
|
// TODO: check endianness of saddr/daddr
|
||||||
|
tmp.s_addr = pkt->hdr.ip.daddr;
|
||||||
|
if ( ( rloc = rloc_find_for_ipv4( reg, &tmp ) ) == NULL ) {
|
||||||
|
warn( "Couldn't find destination rloc, 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 );
|
||||||
|
|
||||||
|
// iovec 0: decrypted data. This should be an IP header.
|
||||||
|
unsigned char *encrypted_data = ((unsigned char *)pkt) + hdr_size + 2;
|
||||||
|
unsigned char *scratch = &out->scratch[0];
|
||||||
|
|
||||||
|
int decrypted_size = rloc_decrypt( rloc, encrypted_data, encrypted_size, scratch, IP_MAXPACKET );
|
||||||
|
|
||||||
|
if ( decrypted_size < 0 ) {
|
||||||
|
warn( "Failed to decrypt packet!" );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
info( "decrypted_size: %u", decrypted_size );
|
||||||
|
|
||||||
|
out->iovs[0].iov_base = scratch;
|
||||||
|
out->iovs[0].iov_len = decrypted_size;
|
||||||
|
|
||||||
|
// iovec 1: never-encrypted part
|
||||||
|
out->iovs[1].iov_base = (unsigned char*) pkt + hdr_size + 2;
|
||||||
|
out->iovs[1].iov_len = ntohs( pkt->hdr.ip.tot_len ) - hdr_size - encrypted_size;
|
||||||
|
|
||||||
|
if ( out->iovs[0].iov_len + out->iovs[1].iov_len > IP_MAXPACKET ) {
|
||||||
|
warn( "Unwrapped packet is too large, dropping it" );
|
||||||
|
warn( "iovs[0] is %zu, iovs[1] is %zu", out->iovs[0].iov_len, out->iovs[1].iov_len );
|
||||||
|
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" );
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int unwrap_ipv6_packet(struct rlocs *reg, struct recv_pkt* pkt, struct rsp_data* out)
|
int unwrap_ipv6_packet(struct rlocs *reg, struct recv_pkt* pkt, struct rsp_data* out)
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/bio.h>
|
#include <openssl/bio.h>
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
#include <json/json_tokener.h>
|
#include <json/json_tokener.h>
|
||||||
#include <json/linkhash.h>
|
#include <json/linkhash.h>
|
||||||
@@ -404,11 +405,61 @@ struct rloc *rloc_find_by_address( struct rlocs *reg, struct in_addr *ipv4, stru
|
|||||||
return i < reg->num_entries ? current : NULL;
|
return i < reg->num_entries ? current : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Replaces the public key in the rloc struct with a private key so we can
|
||||||
|
* unwrap, as well as wrap, packets.
|
||||||
|
*/
|
||||||
|
int rloc_add_private_key( struct rloc *rloc, char *filename )
|
||||||
|
{
|
||||||
|
BIO *key_data = BIO_new_file( filename, "r" );
|
||||||
|
|
||||||
|
RSA* key = PEM_read_bio_RSAPrivateKey( key_data, NULL, NULL, NULL );
|
||||||
|
|
||||||
|
if ( key == NULL ) {
|
||||||
|
warn( "Failed to add private key %s", filename );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
RSA_free( rloc->key );
|
||||||
|
rloc->key = key;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_ssl_errors(void)
|
||||||
|
{
|
||||||
|
long err;
|
||||||
|
char msg[256];
|
||||||
|
|
||||||
|
while ( ( err = ERR_get_error() ) ) {
|
||||||
|
ERR_error_string( err, &msg[0] );
|
||||||
|
warn( "Error %lu in crypto: %s", err, &msg[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t rloc_encrypt( struct rloc *rloc, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len )
|
ssize_t rloc_encrypt( struct rloc *rloc, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len )
|
||||||
{
|
{
|
||||||
return RSA_public_encrypt( data_len, data, dest, rloc->key, RSA_PKCS1_OAEP_PADDING );
|
ssize_t result = RSA_public_encrypt( data_len, data, dest, rloc->key, RSA_PKCS1_OAEP_PADDING );
|
||||||
|
|
||||||
|
if ( result < 0 ) {
|
||||||
|
show_ssl_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t rloc_decrypt( struct rloc *rloc, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len )
|
||||||
|
{
|
||||||
|
ssize_t result = RSA_private_decrypt( data_len, data, dest, rloc->key, RSA_PKCS1_OAEP_PADDING );
|
||||||
|
|
||||||
|
if ( result < 0 ) {
|
||||||
|
show_ssl_errors();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void rlocs_debug_output( struct rlocs *reg )
|
void rlocs_debug_output( struct rlocs *reg )
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@@ -57,10 +57,13 @@ struct rloc *rloc_find_for_ipv4( struct rlocs *reg, struct in_addr *eid );
|
|||||||
struct rloc *rloc_find_for_ipv6( struct rlocs *reg, struct in6_addr *eid );
|
struct rloc *rloc_find_for_ipv6( struct rlocs *reg, struct in6_addr *eid );
|
||||||
struct rloc *rloc_find_by_address( struct rlocs *reg, struct in_addr *ipv4, struct in6_addr *ipv6 );
|
struct rloc *rloc_find_by_address( struct rlocs *reg, struct in_addr *ipv4, struct in6_addr *ipv6 );
|
||||||
|
|
||||||
|
int rloc_add_private_key( struct rloc *rloc, char *filename );
|
||||||
|
|
||||||
void rlocs_debug_output( struct rlocs *reg );
|
void rlocs_debug_output( struct rlocs *reg );
|
||||||
|
|
||||||
/* Returns -1 on error, or number of bytes written */
|
/* Returns -1 on error, or number of bytes written */
|
||||||
ssize_t rloc_encrypt( struct rloc *rloc, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len );
|
ssize_t rloc_encrypt( struct rloc *rloc, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len );
|
||||||
|
ssize_t rloc_decrypt( struct rloc *rloc, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len );
|
||||||
|
|
||||||
void rlocs_free( struct rlocs *registry );
|
void rlocs_free( struct rlocs *registry );
|
||||||
|
|
||||||
|
@@ -20,8 +20,8 @@ int main(int argc, char** argv)
|
|||||||
ssize_t count;
|
ssize_t count;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
if ( argc < 4 ) {
|
if ( argc < 6 ) {
|
||||||
warn( "Usage: %s <rloc database> <listen_ifname> <output_ifname>", argv[0] );
|
warn( "Usage: %s <rloc database> <listen_ifname> <output_ifname> <rloc> <keyfile> [<rloc> <keyfile>]n", argv[0] );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,6 +30,12 @@ int main(int argc, char** argv)
|
|||||||
warn( "Failed to set up session, exiting" );
|
warn( "Failed to set up session, exiting" );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !session_upgrade_rlocs( &unwrap, argc - 4, argv + 4 ) ) {
|
||||||
|
warn( "Failed to upgrade rlocs for session, exiting" );
|
||||||
|
session_teardown( &unwrap );
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
memset( &recv_pkt, 0, sizeof( struct recv_pkt ) );
|
memset( &recv_pkt, 0, sizeof( struct recv_pkt ) );
|
||||||
memset( &to_send, 0, sizeof( struct rsp_data ) );
|
memset( &to_send, 0, sizeof( struct rsp_data ) );
|
||||||
|
@@ -85,7 +85,7 @@ int link_set_up( char *link_name, int state )
|
|||||||
|
|
||||||
int session_setup( struct session *session, char *config_file, char *listen_if, char *output_if )
|
int session_setup( struct session *session, char *config_file, char *listen_if, char *output_if )
|
||||||
{
|
{
|
||||||
memset( &session, 0, sizeof( struct session ) );
|
memset( session, 0, sizeof( struct session ) );
|
||||||
session->listen_if = -1;
|
session->listen_if = -1;
|
||||||
session->output_if = -1;
|
session->output_if = -1;
|
||||||
|
|
||||||
@@ -130,6 +130,53 @@ int session_setup( struct session *session, char *config_file, char *listen_if,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int session_upgrade_rlocs( struct session *session, int argc, char** args )
|
||||||
|
{
|
||||||
|
int i, num_rlocs = argc / 2;
|
||||||
|
|
||||||
|
if ( argc%2 != 0 ) {
|
||||||
|
warn( "Odd number of arguments. Format: [<rlc> <filename>]n" );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( i = 0 ; i < num_rlocs ; i++ ) {
|
||||||
|
char *rloc_str = args[i*2];
|
||||||
|
char *filename = args[(i*2)+1];
|
||||||
|
struct rloc *rloc;
|
||||||
|
|
||||||
|
if ( strchr( rloc_str, ':' ) == NULL ) { /* IPv4 */
|
||||||
|
struct in_addr ip;
|
||||||
|
if ( inet_pton( AF_INET, rloc_str, &ip ) != 1 ) {
|
||||||
|
warn( "Couldn't parse %s as an IPv4 address", rloc_str );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rloc = rloc_find_by_address( session->rlocs, &ip, NULL );
|
||||||
|
} else { /* IPv6 */
|
||||||
|
struct in6_addr ip6;
|
||||||
|
if ( inet_pton( AF_INET6, rloc_str, &ip6 ) != 1 ) {
|
||||||
|
warn( "Couldn't parse %s as an IPv6 address", rloc_str );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
rloc = rloc_find_by_address( session->rlocs, NULL, &ip6 );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rloc == NULL ) {
|
||||||
|
warn( "Couldn't find rloc for %s", rloc_str );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !rloc_add_private_key( rloc, filename ) ) {
|
||||||
|
warn( "Couldn't upgrade rloc %s with %s", rloc_str, filename );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
info( "Upgraded RLOC %s with private key %s", rloc_str, filename );
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void session_teardown( struct session *session )
|
void session_teardown( struct session *session )
|
||||||
{
|
{
|
||||||
rlocs_free( session->rlocs );
|
rlocs_free( session->rlocs );
|
||||||
|
@@ -22,7 +22,13 @@ struct session {
|
|||||||
int same_if;
|
int same_if;
|
||||||
};
|
};
|
||||||
|
|
||||||
int session_setup( struct session *session, char *config_file, char *listen_if, char *output_if );
|
int session_setup( struct session *session, char *config_file, char *listen_if, char *output_if );
|
||||||
|
|
||||||
|
|
||||||
|
/* We take an array of 2n rlocs to upgrade. First element of each pair is
|
||||||
|
* IP address, second element of each pair is path to private key file
|
||||||
|
*/
|
||||||
|
int session_upgrade_rlocs( struct session *session, int argc, char** args );
|
||||||
void session_teardown( struct session *session );
|
void session_teardown( struct session *session );
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user