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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -49,10 +49,22 @@ int main(int argc, char** argv)
|
||||
|
||||
switch( recv_pkt.hdr.ip.version ) {
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
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 in_addr tmp;
|
||||
|
||||
// TODO: check endianness of saddr/daddr
|
||||
tmp.s_addr = pkt->hdr.ip.saddr;
|
||||
if ( ( s_rloc = rloc_find_for_ipv4( reg, &tmp ) ) == NULL ) {
|
||||
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;
|
||||
|
||||
if ( orig_data_size > 512 ) {
|
||||
bytes_to_encrypt = pkt->hdr.ip.ihl * 4;
|
||||
bytes_to_encrypt = 512; // No point wasting bytes on padding
|
||||
} else {
|
||||
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 );
|
||||
compute_ip_checksum( wrap_hdr );
|
||||
|
||||
info( "Finished building return packet" );
|
||||
info( "Finished wrapping IPv4 packet" );
|
||||
|
||||
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)
|
||||
{
|
||||
warn( "STUB: unwrap_ipv4_packet" );
|
||||
return 0;
|
||||
out->count = 2;
|
||||
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)
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include <json/json_tokener.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;
|
||||
}
|
||||
|
||||
/* 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 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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_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 );
|
||||
|
||||
/* 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_decrypt( struct rloc *rloc, unsigned char *data, size_t data_len, unsigned char *dest, size_t dest_len );
|
||||
|
||||
void rlocs_free( struct rlocs *registry );
|
||||
|
||||
|
@@ -20,8 +20,8 @@ int main(int argc, char** argv)
|
||||
ssize_t count;
|
||||
int result;
|
||||
|
||||
if ( argc < 4 ) {
|
||||
warn( "Usage: %s <rloc database> <listen_ifname> <output_ifname>", argv[0] );
|
||||
if ( argc < 6 ) {
|
||||
warn( "Usage: %s <rloc database> <listen_ifname> <output_ifname> <rloc> <keyfile> [<rloc> <keyfile>]n", argv[0] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,12 @@ int main(int argc, char** argv)
|
||||
warn( "Failed to set up session, exiting" );
|
||||
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( &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 )
|
||||
{
|
||||
memset( &session, 0, sizeof( struct session ) );
|
||||
memset( session, 0, sizeof( struct session ) );
|
||||
session->listen_if = -1;
|
||||
session->output_if = -1;
|
||||
|
||||
@@ -130,6 +130,53 @@ int session_setup( struct session *session, char *config_file, char *listen_if,
|
||||
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 )
|
||||
{
|
||||
rlocs_free( session->rlocs );
|
||||
|
@@ -22,7 +22,13 @@ struct session {
|
||||
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 );
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user