First pass at fragmenting
parent
1acaa03799
commit
cfd1b2f957
|
@ -1,6 +1,4 @@
|
|||
*.o
|
||||
pass-1/wrapper
|
||||
pass-1/unwrapper
|
||||
pass-1/hide-eid
|
||||
pass-1/example-keys
|
||||
README.html
|
||||
|
|
|
@ -4,15 +4,13 @@ LDFLAGS := $(LDFLAGS) -ljson-c -lssl -lcrypto
|
|||
|
||||
.PHONY: clean
|
||||
|
||||
all: wrapper unwrapper hide-eid
|
||||
all: hide-eid
|
||||
|
||||
rlocs.o: util.o
|
||||
|
||||
packet.o: util.o
|
||||
|
||||
wrapper: util.o rlocs.o packet.o
|
||||
unwrapper: util.o rlocs.o packet.o
|
||||
hide-eid: util.o rlocs.o packet.o
|
||||
|
||||
clean:
|
||||
rm -f hide-eid wrapper unwrapper *.o
|
||||
rm -f hide-eid *.o
|
||||
|
|
|
@ -14,31 +14,34 @@ each RLOC. Both wrapper and unwrapper need a copy of this file to work. We also
|
|||
include a tiny library for reading it.
|
||||
|
||||
|
||||
wrapper
|
||||
=======
|
||||
This component only wraps packets. It reads the contents of the rloc-registry,
|
||||
outputs a bgpfeeder file that will redirect eid ranges to it, if honoured, opens
|
||||
a tun device, and waits for packets to be sent to it. Upon receiving a packet,
|
||||
it encrypts the start - including IP, TCP, UDP, etc headers, prepends a new IP
|
||||
header that will route it to the destination RLOC, and outputs the new packet.
|
||||
hide-eid
|
||||
========
|
||||
This program acts as an xTR (wraps and unwraps packets). It reads the
|
||||
contents of the rloc-registry, outputs a bgpfeeder file that will redirect eid
|
||||
ranges to it, if honoured, opens a tun device, and waits for packets to be sent
|
||||
to it.
|
||||
|
||||
Upon receiving a packet, it encrypts the start - including IP, TCP, UDP, etc
|
||||
headers - prepends a new IP header that will route it to the destination RLOC,
|
||||
and outputs the new packet.
|
||||
|
||||
If it doesn't recognise an EID, or can't encrypt the packet, it is dropped.
|
||||
|
||||
unwrapper
|
||||
=========
|
||||
The unwrapper is in operation to the wrapper, but is also given a list of RLOCs
|
||||
that is has private keys for. When a packet comes in, it tries to decrypt the
|
||||
encrypted portion, reassemble the original packet and forward it on. If it
|
||||
doesn't have the private key, or other problems arise, the packet is dropped.
|
||||
When it receives an already-wrapped packet, it tries to decrypt and reassemble it,
|
||||
and forward it on. It needs the private key for that, and if it doesn't have it,
|
||||
or other problems occur, the packet is dropped.
|
||||
|
||||
We also handle ICMP and fragmentation, in case the packet we receive is too big,
|
||||
according to the schemes in RFC6380. We keep track of the discovered path MTU for
|
||||
each of the other xTRs by parsing incoming ICMP messages.
|
||||
|
||||
For wrapped packets that are too large to fit down the discovered path, if the DF
|
||||
bit is set in the unwrapped packet, we return an ICMP packet informing the source
|
||||
of this. Otherwise, we fragment the nuwrapped packet according to standard IP
|
||||
rules, encrypt the two IP packets that result, and let the destination EID be
|
||||
responsible for reassembling it. This removes a responsibility from hide-eid
|
||||
at the destination, which won't have to keep track of encrypted fragments.
|
||||
|
||||
hide-eid
|
||||
========
|
||||
Most people will be more interested in hide-eid, which operates as a combined
|
||||
wrapper and unwrapper. Like those programs, it opens a tun device, but it can
|
||||
recognise whether a packet forwarded to it has been wrapped or not, and perform
|
||||
the opposite operation before forwarding the packet on. This makes it useful
|
||||
if you want to both receive and send traffic with a minimum of fuss - which is
|
||||
most people, I guess.
|
||||
|
||||
bgpfeeder
|
||||
=========
|
||||
|
@ -68,11 +71,10 @@ number as the wrapping IP header's payload length. It then writes the length of
|
|||
the encrypted portion of the total payload as the first 2 bytes of the payload,
|
||||
followed by the constructed blob.
|
||||
|
||||
The unwrapper receives the packet, reads the IP header, then reads the next two
|
||||
bytes. It takes the first n bytes of the remainder of the payload and decrypts
|
||||
it, then prepends that to the remaining bytes. What it ends up with should be a
|
||||
valid IP packet. It then alters the packet's TTL according to the wrapping
|
||||
packet's TTL field, and forwards it for further routing.
|
||||
The constructed blob currently consists of 16 bytes of PRNG data used as the IV,
|
||||
the encrypted data (using the symmetric aes256gcm authenticating cipher) and 16
|
||||
bytes of generated tag data.
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,81 @@
|
|||
|
||||
#include <sys/uio.h>
|
||||
|
||||
|
||||
int process_icmp_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 );
|
||||
if ( ntohs( packet->hdr.ip.tot_len ) < inner_ip_hdr_offset + sizeof( struct iphdr ) ) {
|
||||
debug( "Truncated ICMP packet is unidentifiable" );
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rloc *s_rloc;
|
||||
struct rloc *d_rloc;
|
||||
|
||||
struct icmphdr *icmp = (struct icmphdr *) packet->payload + ( packet->hdr.ip.ihl * 4 );
|
||||
|
||||
if ( icmp->type != ICMP_DEST_UNREACH && icmp->code != ICMP_FRAG_NEEDED ) {
|
||||
return 0; // It may be going elsewhere
|
||||
}
|
||||
|
||||
// Be careful with this - some of payload may be past allocated memory
|
||||
struct packet *inner_ip = (struct packet *) ((char *) packet + inner_ip_hdr_offset );
|
||||
|
||||
// Not much we can do with this case right now
|
||||
if ( inner_ip->hdr.ip.protocol != IPPROTO_HIDE_EID ) {
|
||||
debug( "ICMP Too Big response to an unwrapped packet. Peculiar." );
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( !rlocs_find_two_ipv4( reg, &s_rloc, (struct in_addr *)&inner_ip->hdr.ip.saddr, &d_rloc, (struct in_addr *)&inner_ip->hdr.ip.daddr ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// All we're interested in is setting path mtu
|
||||
uint16_t new_mtu = ntohs( icmp->un.frag.mtu );
|
||||
rlocs_set_path_mtu( reg, s_rloc, d_rloc, new_mtu );
|
||||
debug( "Set MTU for %s <-> %s to %u", s_rloc->presentation, d_rloc->presentation, new_mtu );
|
||||
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_packet( struct rlocs *reg, struct packet *packet, struct rsp_data *frag1, struct rsp_data *frag2 )
|
||||
{
|
||||
if ( packet->hdr.ip.version == 0x04 ) {
|
||||
return process_ipv4_packet( reg, packet, frag1, frag2 );
|
||||
}
|
||||
|
||||
warn( "Can't process IP protocol version %i yet; dropping packet", packet->hdr.ip.version );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Entry point. Expects an invocation like:
|
||||
* hide-eid <filename of rloc database> <listen_ifname> <output_ifname>
|
||||
|
@ -17,10 +92,11 @@
|
|||
int main(int argc, char** argv)
|
||||
{
|
||||
struct session session;
|
||||
struct recv_pkt recv_pkt;
|
||||
struct rsp_data to_send;
|
||||
struct packet recv_pkt;
|
||||
|
||||
struct rsp_data frag1;
|
||||
struct rsp_data frag2;
|
||||
ssize_t count;
|
||||
int result = 0;
|
||||
|
||||
if ( argc < 4 ) {
|
||||
warn( "Usage: %s <rloc database> <listen_ifname> <output_ifname> [ <rloc> <keyfile> ]n", argv[0] );
|
||||
|
@ -41,55 +117,41 @@ int main(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
|
||||
memset( &recv_pkt, 0, sizeof( struct recv_pkt ) );
|
||||
memset( &to_send, 0, sizeof( struct rsp_data ) );
|
||||
|
||||
memset( &recv_pkt, 0, sizeof( struct packet ) );
|
||||
memset( &frag1, 0, sizeof( struct rsp_data ) );
|
||||
memset( &frag2, 0, sizeof( struct rsp_data ) );
|
||||
|
||||
warn( "TODO: Write BGP interventions to file" );
|
||||
|
||||
info( "Processing packets" );
|
||||
while(1) {
|
||||
if ( ( count = read( session.listen_if, &recv_pkt, sizeof( struct recv_pkt ) ) ) < 0 ) {
|
||||
info( "Listening for packets" );
|
||||
while( 1 ) {
|
||||
int rsp_count;
|
||||
|
||||
if ( ( count = read( session.listen_if, &recv_pkt, sizeof( struct packet ) ) ) < 0 ) {
|
||||
warn( "Failed to get a packet (%s)", strerror( errno ) );
|
||||
break;
|
||||
}
|
||||
|
||||
info( "Got a packet \\o/. %zu bytes", count );
|
||||
|
||||
switch( recv_pkt.hdr.ip.version ) {
|
||||
case 0x04 :
|
||||
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 :
|
||||
/* 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 );
|
||||
}
|
||||
|
||||
if ( !result ) {
|
||||
warn( "Failed to process received packet, dropping." );
|
||||
continue;
|
||||
}
|
||||
|
||||
// no failure, but nothing to forward.
|
||||
if ( to_send.count == 0 ) {
|
||||
continue;
|
||||
if ( count == 0 ) {
|
||||
warn( "Got EOF" );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if ( ( count = writev( session.output_if, to_send.iovs, to_send.count ) ) < 0 ) {
|
||||
warn( "Error writing processed packet to output: %s", strerror(errno) );
|
||||
if ( ( rsp_count = process_packet( session.rlocs, &recv_pkt, &frag1, &frag2 ) ) < 0 ) {
|
||||
debug( "Error processing packet, dropping" );
|
||||
}
|
||||
|
||||
if ( rsp_count > 0 ) {
|
||||
if ( ( count = writev( session.output_if, frag1.iovs, frag1.count ) ) < 0 ) {
|
||||
debug( "Error writing processed packet to output: %s", strerror(errno) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( rsp_count == 2 ) {
|
||||
if ( ( count = writev( session.output_if, frag2.iovs, frag2.count ) ) < 0 ) {
|
||||
debug( "Error writing second processed packet to output: %s", strerror(errno) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
241
pass-1/packet.c
241
pass-1/packet.c
|
@ -33,24 +33,34 @@ unsigned short compute_checksum(unsigned short *addr, unsigned int count) {
|
|||
|
||||
}
|
||||
|
||||
void compute_ip_checksum(struct iphdr* pkt)
|
||||
void compute_ip_checksum(struct iphdr *pkt)
|
||||
{
|
||||
pkt->check = 0x0000;
|
||||
pkt->check = compute_checksum( (unsigned short*) pkt, pkt->ihl * 4 );
|
||||
}
|
||||
|
||||
|
||||
int wrap_ipv4_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data* out)
|
||||
int build_wrapped_ipv4_packet(struct rlocs *reg, struct rloc * s_rloc, struct rloc *d_rloc, struct packet *pkt, struct rsp_data *out)
|
||||
{
|
||||
out->count = 3;
|
||||
assert( out->count < MAX_IOVS );
|
||||
struct iphdr *wrap_hdr = (struct iphdr *) out->scratch;
|
||||
uint16_t wrap_hdr_size = sizeof( struct iphdr );
|
||||
|
||||
unsigned char *scratch = &out->scratch[0];
|
||||
ssize_t enc_size;
|
||||
size_t orig_data_size = ntohs( pkt->hdr.ip.tot_len );
|
||||
size_t bytes_to_encrypt = orig_data_size > 512 ? 512 : orig_data_size;
|
||||
|
||||
// iovec 0: wrapping header
|
||||
struct iphdr* wrap_hdr = (struct iphdr*) scratch;
|
||||
unsigned int wrap_hdr_size = sizeof( struct iphdr );
|
||||
scratch += wrap_hdr_size;
|
||||
debug( "Wrapping an IPv4 packet" );
|
||||
debug( "wrap_hdr_size: %u, orig_data_size: %zu, bytes_to_encrypt: %zu", wrap_hdr_size, orig_data_size, bytes_to_encrypt );
|
||||
|
||||
// Areas in scratch we'll be using later
|
||||
// We use two bytes to store the size of the encrypted blob
|
||||
uint16_t *pkt_enc_size = (uint16_t *) (out->scratch + wrap_hdr_size );
|
||||
unsigned char * pkt_enc_data = out->scratch + wrap_hdr_size + 2;
|
||||
|
||||
// Keep track of the total size of the data in out as we go
|
||||
uint16_t out_len = 0;
|
||||
|
||||
out->count = 0;
|
||||
|
||||
memset( wrap_hdr, 0, wrap_hdr_size );
|
||||
|
||||
|
@ -58,96 +68,171 @@ int wrap_ipv4_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data* o
|
|||
wrap_hdr->ihl = wrap_hdr_size / 4;
|
||||
wrap_hdr->ttl = IPDEFTTL;
|
||||
wrap_hdr->protocol = IPPROTO_HIDE_EID;
|
||||
wrap_hdr->frag_off = htons( 0x4000 ); // DF bit set
|
||||
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;
|
||||
// FIXME: Do we need to set an ID ?
|
||||
|
||||
// iovec 0: encapsulating IP header.
|
||||
out->iovs[0].iov_base = wrap_hdr;
|
||||
out->iovs[0].iov_len = wrap_hdr_size;
|
||||
out_len += wrap_hdr_size;
|
||||
out->count++;
|
||||
|
||||
// TODO: id, still needs filling now.
|
||||
|
||||
// We need to know source and destination rlocs to construct the packet
|
||||
struct rloc* s_rloc;
|
||||
struct rloc* d_rloc;
|
||||
struct in_addr tmp;
|
||||
|
||||
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" );
|
||||
// TODO: fallback behaviour here?
|
||||
return 0;
|
||||
}
|
||||
|
||||
tmp.s_addr = pkt->hdr.ip.daddr;
|
||||
if ( ( d_rloc = rloc_find_for_ipv4( reg, &tmp ) ) == NULL ) {
|
||||
warn( "Couldn't find destination rloc, dropping packet" );
|
||||
// TODO: fallback behaviour here?
|
||||
return 0;
|
||||
}
|
||||
|
||||
wrap_hdr->saddr = s_rloc->addr.ip4.s_addr;
|
||||
wrap_hdr->daddr = d_rloc->addr.ip4.s_addr;
|
||||
|
||||
// iovec 1: encrypted part.
|
||||
// FIXME: Need to inspect the protocol field and gobble up the TCP/UDP/etc
|
||||
// header as well, for decent anonymity. TCP/UDP ports are an obvious way
|
||||
// to perform a correlation attack.
|
||||
// RSA pubkey encryption with 4096-bit keys gobbles up at least 512 bytes
|
||||
// of space, so we make sure to use it.
|
||||
ssize_t enc_size;
|
||||
size_t orig_data_size = ntohs( pkt->hdr.ip.tot_len );
|
||||
size_t bytes_to_encrypt;
|
||||
|
||||
if ( orig_data_size > 512 ) {
|
||||
bytes_to_encrypt = 512; // No point wasting bytes on padding
|
||||
} else {
|
||||
bytes_to_encrypt = orig_data_size;
|
||||
}
|
||||
|
||||
off_t enc_max_len = IP_MAXPACKET - wrap_hdr_size - orig_data_size - bytes_to_encrypt;
|
||||
|
||||
// We use two bytes to store the size of the encrypted blob
|
||||
unsigned short *pkt_enc_size = (unsigned short *) scratch;
|
||||
scratch += 2;
|
||||
|
||||
// Encrypt the first 512 or so bytes of the data. FIXME: introspect and
|
||||
// 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,
|
||||
(unsigned char *)&pkt->hdr, bytes_to_encrypt, scratch, enc_max_len - 2
|
||||
(unsigned char *)&pkt->hdr, bytes_to_encrypt,
|
||||
pkt_enc_data, IP_MAXPACKET - wrap_hdr_size - 2
|
||||
);
|
||||
|
||||
if ( enc_size < 0 ) {
|
||||
warn( "failed to encrypt, dropping packet" );
|
||||
debug( "Failed to encrypt, dropping packet" );
|
||||
return 0;
|
||||
}
|
||||
debug( "enc_size: %li", enc_size );
|
||||
|
||||
*pkt_enc_size = htons( enc_size );
|
||||
enc_size += 2;
|
||||
scratch = (unsigned char*) pkt_enc_size;
|
||||
|
||||
warn( "Encrypted size: 2 + %zu", enc_size - 2);
|
||||
// iovec 1: encrypted portion of encpasulated packet
|
||||
out->iovs[1].iov_base = pkt_enc_size;
|
||||
out->iovs[1].iov_len = enc_size + 2;
|
||||
out_len += enc_size + 2;
|
||||
out->count++;
|
||||
|
||||
out->iovs[1].iov_base = scratch;
|
||||
out->iovs[1].iov_len = enc_size;
|
||||
scratch += enc_size;
|
||||
debug( "iovs[0]: %p, %zu", out->iovs[0].iov_base, out->iovs[0].iov_len );
|
||||
debug( "iovs[1]: %p, %zu", out->iovs[1].iov_base, out->iovs[1].iov_len );
|
||||
|
||||
// iovec 2: unencrypted remains
|
||||
if ( bytes_to_encrypt == orig_data_size ) {
|
||||
out->count = 2;
|
||||
out->iovs[2].iov_base = NULL;
|
||||
out->iovs[2].iov_len = 0;
|
||||
} else {
|
||||
out->iovs[2].iov_base = (char *) pkt + bytes_to_encrypt;
|
||||
out->iovs[2].iov_len = ntohs( pkt->hdr.ip.tot_len ) - bytes_to_encrypt;
|
||||
// iovec 2: unencrypted remains of encapsulated packet, if present
|
||||
if ( bytes_to_encrypt < orig_data_size ) {
|
||||
out->iovs[2].iov_base = ((char *) pkt) + bytes_to_encrypt;
|
||||
out->iovs[2].iov_len = orig_data_size - bytes_to_encrypt;
|
||||
out_len += orig_data_size - bytes_to_encrypt;
|
||||
out->count++;
|
||||
debug( "iovs[2]: %p, %zu", out->iovs[2].iov_base, out->iovs[2].iov_len );
|
||||
}
|
||||
|
||||
wrap_hdr->tot_len = htons( wrap_hdr_size + enc_size + out->iovs[2].iov_len );
|
||||
|
||||
wrap_hdr->tot_len = htons( out_len );
|
||||
compute_ip_checksum( wrap_hdr );
|
||||
|
||||
info( "Finished wrapping IPv4 packet" );
|
||||
|
||||
debug( "Finished wrapping IPv4 packet" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
int wrap_ipv6_packet(struct rlocs *reg, struct recv_pkt* pkt, struct rsp_data* out)
|
||||
void build_icmp_too_big( uint16_t max_mtu, struct in_addr *rloc_src, struct packet *pkt, struct rsp_data *out )
|
||||
{
|
||||
struct iphdr *ip = (struct iphdr*) out->scratch;
|
||||
struct icmphdr *icmp = (struct icmphdr *) ( out->scratch + sizeof( struct iphdr ) );
|
||||
uint16_t icmp_size = sizeof( struct icmphdr ) + ( pkt->hdr.ip.ihl * 4 ) + 8;
|
||||
|
||||
debug( "Building ICMP Too Big packet" );
|
||||
|
||||
memset( out->scratch, 0, sizeof( struct iphdr ) + sizeof( struct icmphdr ) );
|
||||
|
||||
ip->version = 4;
|
||||
ip->ihl = sizeof( struct iphdr ) / 4;
|
||||
ip->ttl = IPDEFTTL;
|
||||
ip->protocol = IPPROTO_ICMP;
|
||||
ip->saddr = rloc_src->s_addr;
|
||||
ip->daddr = pkt->hdr.ip.saddr;
|
||||
|
||||
icmp->type = ICMP_DEST_UNREACH;
|
||||
icmp->code = ICMP_FRAG_NEEDED;
|
||||
icmp->un.frag.mtu = htons( max_mtu );
|
||||
|
||||
out->iovs[0].iov_base = out->scratch;
|
||||
out->iovs[0].iov_len = sizeof( struct iphdr ) + icmp_size;
|
||||
|
||||
memcpy( ((char *)icmp) + sizeof( struct icmphdr ), pkt, icmp_size - sizeof( struct icmphdr ) );
|
||||
|
||||
//out->iovs[1].iov_base = pkt;
|
||||
//out->iovs[1].iov_len = ( pkt->hdr.ip.ihl * 4 ) + 8;
|
||||
|
||||
ip->tot_len = htons( out->iovs[0].iov_len );
|
||||
|
||||
icmp->checksum = compute_checksum( (unsigned short *)icmp, icmp_size );
|
||||
compute_ip_checksum( ip );
|
||||
out->count = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int wrap_ipv4_packet( struct rlocs *reg, struct packet *pkt, struct rsp_data *frag1, struct rsp_data *frag2 )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
uint16_t max_size = rlocs_get_path_mtu( reg, s_rloc, d_rloc );
|
||||
uint16_t pkt_tot_len = ntohs( pkt->hdr.ip.tot_len );
|
||||
uint16_t pkt_hdr_len = pkt->hdr.ip.ihl * 4;
|
||||
|
||||
int num_packets = 1;
|
||||
|
||||
// fragmentation is needed.
|
||||
if ( pkt_tot_len > max_size - WRAP_OVERHEAD ) {
|
||||
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 );
|
||||
return 1;
|
||||
}
|
||||
|
||||
num_packets = 2;
|
||||
|
||||
// good enough, it's getting encrypted and only needs to be unique for
|
||||
// a short period of time
|
||||
uint16_t frag_id = (uint16_t) rand();
|
||||
|
||||
// Must be an 8-byte offset
|
||||
uint16_t frag_off = ( pkt_tot_len - pkt_hdr_len ) / 2;
|
||||
frag_off += frag_off%8;
|
||||
uint16_t frag2_size = pkt_tot_len - pkt_hdr_len - frag_off;
|
||||
|
||||
if ( pkt_hdr_len > sizeof( struct iphdr ) ) {
|
||||
warn( "FIXME: options specified with IP header are not handled correctly during fragmentation yet" );
|
||||
}
|
||||
|
||||
// wrap_ipv4_packet only touches scratch upto IP_MAXPACKET. We allocate
|
||||
// double that.
|
||||
struct packet *pkt2 = (struct packet *) frag2->scratch + IP_MAXPACKET;
|
||||
|
||||
pkt->hdr.ip.tot_len = htons( pkt_hdr_len + frag_off );
|
||||
pkt->hdr.ip.id = htons( frag_id );
|
||||
pkt->hdr.ip.frag_off = htons( 0 | IP_MF );
|
||||
|
||||
memcpy( pkt2, pkt, pkt_hdr_len );
|
||||
|
||||
pkt2->hdr.ip.tot_len = htons( pkt_tot_len - frag_off );
|
||||
pkt2->hdr.ip.frag_off = htons( frag_off / 8 );
|
||||
memcpy( ((char *)pkt2) + pkt_hdr_len, ((char*)pkt)+pkt_hdr_len, frag2_size );
|
||||
|
||||
if ( !build_wrapped_ipv4_packet( reg, s_rloc, d_rloc, pkt2, frag2 ) ) {
|
||||
debug( "Couldn't wrap packet 2 of 2 ");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !build_wrapped_ipv4_packet( reg, s_rloc, d_rloc, pkt, frag1 ) ) {
|
||||
debug( "Couldn't wrap packet 1 of %i", num_packets );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return num_packets;
|
||||
}
|
||||
|
||||
int wrap_ipv6_packet(struct rlocs *reg, struct packet *pkt, struct rsp_data *out)
|
||||
{
|
||||
warn( "STUB: wrap_ipv6_packet" );
|
||||
return 0;
|
||||
|
@ -155,7 +240,7 @@ 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 packet *pkt, struct rsp_data *out)
|
||||
{
|
||||
out->count = 2;
|
||||
assert( out->count < MAX_IOVS );
|
||||
|
@ -222,7 +307,7 @@ int unwrap_ipv4_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data*
|
|||
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 packet *pkt, struct rsp_data *out)
|
||||
{
|
||||
warn( "STUB: unwrap_ipv6_packet" );
|
||||
|
||||
|
|
|
@ -4,26 +4,29 @@
|
|||
#include <arpa/inet.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
|
||||
#define IPPROTO_HIDE_EID 99
|
||||
|
||||
// IP header + IV + tag + block cipher max overhead
|
||||
#define WRAP_OVERHEAD 20 + 16 + 16 + 16 + 2
|
||||
|
||||
#ifndef IP_DF
|
||||
#define IP_DF 0x4000 /* dont fragment flag */
|
||||
#endif
|
||||
|
||||
#ifndef IP_MF
|
||||
#define IP_MF 0x2000 /* more fragments flag */
|
||||
#endif
|
||||
|
||||
struct packet {
|
||||
union {
|
||||
#ifdef __USE_BSD
|
||||
struct ip ip;
|
||||
#else
|
||||
struct iphdr ip;
|
||||
#endif
|
||||
struct ip6_hdr ip6;
|
||||
} hdr;
|
||||
char payload[IP_MAXPACKET]; /* payload is this - header size, but OK */
|
||||
char payload[IP_MAXPACKET]; /* payload can be this - header size, but OK */
|
||||
};
|
||||
|
||||
// wrapper.c expects this name
|
||||
#define recv_pkt packet
|
||||
|
||||
|
||||
// It's all our code that uses this. 12 is much more than we need to
|
||||
// construct a wrapped packet at the moment.
|
||||
//
|
||||
|
@ -35,14 +38,23 @@ struct packet {
|
|||
struct rsp_data {
|
||||
int count;
|
||||
struct iovec iovs[MAX_IOVS];
|
||||
unsigned char scratch[IP_MAXPACKET]; // somewhere easy to put results
|
||||
unsigned char scratch[IP_MAXPACKET * 2]; // somewhere easy to put results
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// If we need more fragments than this, I am a sad person
|
||||
#define MAX_PACKET_FRAGMENTS 4
|
||||
|
||||
void compute_ip_checksum( struct iphdr* pkt );
|
||||
|
||||
int wrap_ipv4_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data* out);
|
||||
int wrap_ipv6_packet(struct rlocs* reg, struct recv_pkt* pkt, struct rsp_data* out);
|
||||
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 unwrap_ipv4_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);
|
||||
#endif
|
||||
|
|
|
@ -87,6 +87,7 @@ int rlocs_rloc_from_json(struct rlocs* reg, const char* key, json_object* val )
|
|||
warn( "Couldn't parse %s as an IP address", key );
|
||||
return 0;
|
||||
}
|
||||
strncpy( rloc->presentation, key, 128 );
|
||||
|
||||
// Next, we need to read and store the PEM-encoded RSA public key
|
||||
pem_data = json_object_get_string( val );
|
||||
|
@ -371,7 +372,7 @@ struct rlocs* rlocs_new( char* filename )
|
|||
goto fail;
|
||||
}
|
||||
|
||||
int i, len = json_object_array_length( maps_field );
|
||||
int i, j, len = json_object_array_length( maps_field );
|
||||
for ( i = 0; i < len ; i++ ) {
|
||||
json_object *map_field = json_object_array_get_idx( maps_field, i );
|
||||
|
||||
|
@ -380,6 +381,13 @@ struct rlocs* rlocs_new( char* filename )
|
|||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
// Set our default path mtu for all peers
|
||||
for ( i = 0 ; i < MAX_RLOCS ; i++ ) {
|
||||
for( j = 0 ; j < MAX_RLOCS ; j++ ) {
|
||||
result->peer_contexts[i][j].path_mtu = DEFAULT_PATH_MTU;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
|
@ -444,6 +452,31 @@ struct rloc *rloc_find_by_address( struct rlocs *reg, struct in_addr *ipv4, stru
|
|||
return i < reg->num_entries ? current : NULL;
|
||||
}
|
||||
|
||||
int rlocs_find_two_ipv4(
|
||||
struct rlocs *reg,
|
||||
struct rloc **s_rloc_ptr, struct in_addr *s_rloc_addr,
|
||||
struct rloc **d_rloc_ptr, struct in_addr *d_rloc_addr
|
||||
)
|
||||
{
|
||||
struct rloc *s_rloc = *s_rloc_ptr;
|
||||
struct rloc *d_rloc = *d_rloc_ptr;
|
||||
|
||||
char addr_str[128];
|
||||
|
||||
if ( ( s_rloc = rloc_find_by_address( reg, s_rloc_addr, NULL ) ) == NULL ) {
|
||||
inet_ntop( AF_INET, s_rloc_addr, &addr_str[0], 128 );
|
||||
debug( "Couldn't find source rloc (%s) in DB", addr_str );
|
||||
return 0;
|
||||
}
|
||||
if ( ( d_rloc = rloc_find_by_address( reg, d_rloc_addr, NULL ) ) == NULL ) {
|
||||
inet_ntop( AF_INET, d_rloc_addr, &addr_str[0], 128 );
|
||||
debug( "Couldn't find destination rloc (%s) in DB", addr_str );
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Replaces the public key in the rloc struct with a private key so we can
|
||||
* unwrap, as well as wrap, packets.
|
||||
*/
|
||||
|
@ -474,9 +507,9 @@ fail:
|
|||
return 0;
|
||||
}
|
||||
|
||||
int rlocs_update_key_context(struct rlocs *reg, struct rloc *x, struct rloc *y)
|
||||
int rlocs_update_peer_context(struct rlocs *reg, struct rloc *x, struct rloc *y)
|
||||
{
|
||||
struct key_context *entry = ®->key_contexts[x->context_id][y->context_id];
|
||||
struct peer_context *entry = ®->peer_contexts[x->context_id][y->context_id];
|
||||
|
||||
unsigned char secret[1024]; // Should be enough buffer space
|
||||
size_t secret_len = 1024;
|
||||
|
@ -525,6 +558,7 @@ int rlocs_update_key_context(struct rlocs *reg, struct rloc *x, struct rloc *y)
|
|||
* decrypt packet data. */
|
||||
|
||||
EVP_CIPHER_CTX_init( &entry->ctx );
|
||||
entry->path_mtu = DEFAULT_PATH_MTU;
|
||||
entry->in_use = 1;
|
||||
|
||||
return 1;
|
||||
|
@ -539,11 +573,16 @@ fail:
|
|||
}
|
||||
|
||||
|
||||
static inline struct peer_context *rlocs_get_peer_ctx( struct rlocs *reg, struct rloc *x, struct rloc *y )
|
||||
{
|
||||
return ®->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 )
|
||||
{
|
||||
struct key_context *entry = ®->key_contexts[x->context_id][y->context_id];
|
||||
struct peer_context *entry = rlocs_get_peer_ctx( reg, x, y );
|
||||
|
||||
if ( !entry->in_use && !rlocs_update_key_context( reg, x, y ) ) {
|
||||
if ( !entry->in_use && !rlocs_update_peer_context( reg, x, y ) ) {
|
||||
warn( "Couldn't build an encryption context for these rlocs" );
|
||||
return -1;
|
||||
}
|
||||
|
@ -611,9 +650,9 @@ fail:
|
|||
|
||||
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 )
|
||||
{
|
||||
struct key_context *entry = ®->key_contexts[x->context_id][y->context_id];
|
||||
struct peer_context *entry = rlocs_get_peer_ctx( reg, x, y );
|
||||
|
||||
if ( !entry->in_use && !rlocs_update_key_context( reg, x, y ) ) {
|
||||
if ( !entry->in_use && !rlocs_update_peer_context( reg, x, y ) ) {
|
||||
warn( "Couldn't build a decryption context for these rlocs" );
|
||||
return -1;
|
||||
}
|
||||
|
@ -700,6 +739,20 @@ void rlocs_debug_output( struct rlocs *reg )
|
|||
return;
|
||||
}
|
||||
|
||||
unsigned short rlocs_get_path_mtu( struct rlocs *reg, struct rloc *x, struct rloc *y )
|
||||
{
|
||||
struct peer_context *entry = rlocs_get_peer_ctx( reg, x, y );
|
||||
|
||||
return entry->path_mtu;
|
||||
|
||||
}
|
||||
|
||||
void rlocs_set_path_mtu( struct rlocs *reg, struct rloc *x, struct rloc *y, unsigned short new_mtu )
|
||||
{
|
||||
struct peer_context *entry = rlocs_get_peer_ctx( reg, x, y );
|
||||
entry->path_mtu = new_mtu;
|
||||
return;
|
||||
}
|
||||
|
||||
void rlocs_free( struct rlocs* registry )
|
||||
{
|
||||
|
@ -710,6 +763,9 @@ void rlocs_free( struct rlocs* registry )
|
|||
EVP_PKEY_free( registry->entries[i].key );
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: free our ctxes and other peer_context items
|
||||
|
||||
// No need to do json_object_put() here.
|
||||
free( registry );
|
||||
return;
|
||||
|
|
|
@ -13,11 +13,15 @@
|
|||
#define MAX_RLOCS 64
|
||||
#define MAX_EID_MAPPINGS 256
|
||||
|
||||
// Just a guess, but 20-byte IP header, 16-byte IV, 16-byte tag, 16 bytes for symmetric block padding
|
||||
#define DEFAULT_PATH_MTU 1500 - ( 20 + 16 + 16 + 16 )
|
||||
|
||||
struct key_context {
|
||||
struct peer_context {
|
||||
int in_use;
|
||||
char secret[SHA256_DIGEST_LENGTH];
|
||||
EVP_CIPHER_CTX ctx;
|
||||
|
||||
unsigned int path_mtu;
|
||||
|
||||
/* Probably don't need these
|
||||
struct rloc *rloc_x;
|
||||
|
@ -35,6 +39,7 @@ struct rloc {
|
|||
EVP_PKEY *key;
|
||||
// We use this to index our rloc for shared keys
|
||||
int context_id;
|
||||
char presentation[128];
|
||||
};
|
||||
|
||||
|
||||
|
@ -72,7 +77,7 @@ struct rlocs {
|
|||
* Half of the allocated memory goes unused, but we can worry about dynamic
|
||||
* allocation at the same time as MAX_RLOCS and MAX_EID_MAPPINGS
|
||||
*/
|
||||
struct key_context key_contexts[MAX_RLOCS][MAX_RLOCS];
|
||||
struct peer_context peer_contexts[MAX_RLOCS][MAX_RLOCS];
|
||||
};
|
||||
|
||||
|
||||
|
@ -84,6 +89,12 @@ 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 rlocs_find_two_ipv4(
|
||||
struct rlocs *reg,
|
||||
struct rloc **s_rloc_ptr, struct in_addr *s_rloc_addr,
|
||||
struct rloc **d_rloc_ptr, struct in_addr *d_rloc_addr
|
||||
);
|
||||
|
||||
int rloc_add_private_key( struct rloc *rloc, char *filename );
|
||||
|
||||
void rlocs_debug_output( struct rlocs *reg );
|
||||
|
@ -92,6 +103,9 @@ void rlocs_debug_output( struct rlocs *reg );
|
|||
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 );
|
||||
|
||||
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
|
|
@ -1,91 +0,0 @@
|
|||
#include "util.h"
|
||||
#include "rlocs.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
#include <sys/uio.h>
|
||||
|
||||
/*
|
||||
* Entry point. Expects an invocation like:
|
||||
* unwrapper <filename of rloc database> <listen_ifname> <output_ifname>
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
struct session unwrap;
|
||||
struct recv_pkt recv_pkt;
|
||||
struct rsp_data to_send;
|
||||
ssize_t count;
|
||||
int result;
|
||||
|
||||
if ( argc < 6 ) {
|
||||
warn( "Usage: %s <rloc database> <listen_ifname> <output_ifname> <rloc> <keyfile> [<rloc> <keyfile>]n", argv[0] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
rlocs_init();
|
||||
if ( !session_setup( &unwrap, argv[1], argv[2], argv[3] ) ) {
|
||||
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 ) );
|
||||
|
||||
warn( "TODO: Write BGP interventions to file" );
|
||||
|
||||
info( "Processing packets" );
|
||||
while(1) {
|
||||
// TODO: this isn't zero-copy. Not even close
|
||||
if ( ( count = read( unwrap.listen_if, &recv_pkt, sizeof( struct recv_pkt ) ) ) < 0 ) {
|
||||
warn( "Failed to get a packet (%s)", strerror( errno ) );
|
||||
break;
|
||||
}
|
||||
|
||||
info( "Got a packet \\o/. %zu bytes", count );
|
||||
|
||||
switch( recv_pkt.hdr.ip.version ) {
|
||||
case 0x04 :
|
||||
result = unwrap_ipv4_packet( unwrap.rlocs, &recv_pkt, &to_send );
|
||||
break;
|
||||
case 0x06 :
|
||||
result = unwrap_ipv6_packet( unwrap.rlocs, &recv_pkt, &to_send );
|
||||
break;
|
||||
default:
|
||||
warn( "Unknown IP version: %i", recv_pkt.hdr.ip.version );
|
||||
}
|
||||
|
||||
// We can't send the unwrapped one - it'll just be returned to us
|
||||
// forever, given our bgp interventions, unless the router is clever.
|
||||
// TODO: make fallback-to-unwrapped a configurable option?
|
||||
if ( !result ) {
|
||||
warn( "Failed to unwrap received packet, dropping." );
|
||||
continue;
|
||||
}
|
||||
|
||||
// no failure, but nothing to forward.
|
||||
if ( to_send.count == 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// docs say this should never block and should always write everything -
|
||||
// trust that for now.
|
||||
if ( ( count = writev( unwrap.output_if, to_send.iovs, to_send.count ) ) < 0 ) {
|
||||
warn( "Error writing unwrapped packet to output: %s", strerror(errno) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
info( "Finished, cleaning up" );
|
||||
session_teardown( &unwrap );
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#define debug(msg, ...) { fprintf( stderr, msg, ##__VA_ARGS__ ) ; fprintf( stdout, "\n" ); }
|
||||
#define info(msg, ...) { fprintf( stdout, msg, ##__VA_ARGS__ ) ; fprintf( stdout, "\n" ); }
|
||||
#define warn(msg, ...) { fprintf( stderr, msg, ##__VA_ARGS__ ) ; fprintf( stderr, "\n" ); }
|
||||
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
#include "util.h"
|
||||
#include "rlocs.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "packet.h"
|
||||
|
||||
// We use writev() to send the packet, so we don't have to copy the
|
||||
// unencrypted part.
|
||||
#include <sys/uio.h>
|
||||
|
||||
|
||||
/*
|
||||
* Entry point. Expects an invocation like:
|
||||
* wrapper <filename of rloc database> <listen_ifname> <output_ifname>
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
struct session wrap;
|
||||
struct recv_pkt recv_pkt;
|
||||
struct rsp_data to_send;
|
||||
ssize_t count;
|
||||
int result;
|
||||
|
||||
if ( argc < 6 ) {
|
||||
warn( "Usage: %s <rloc database> <listen_ifname> <output_ifname> <rloc> <keyfile> [<rloc> <keyfile>]n", argv[0] );
|
||||
return 1;
|
||||
}
|
||||
|
||||
rlocs_init();
|
||||
if ( !session_setup( &wrap, argv[1], argv[2], argv[3] ) ) {
|
||||
warn( "Failed to set up session, exiting" );
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset( &recv_pkt, 0, sizeof( struct recv_pkt ) );
|
||||
memset( &to_send, 0, sizeof( struct rsp_data ) );
|
||||
|
||||
warn( "TODO: Write BGP interventions to file" );
|
||||
|
||||
info( "Processing packets" );
|
||||
while(1) {
|
||||
// TODO: this isn't zero-copy. Not even close
|
||||
if ( ( count = read( wrap.listen_if, &recv_pkt, sizeof( struct recv_pkt ) ) ) < 0 ) {
|
||||
warn( "Failed to get a packet (%s)", strerror( errno ) );
|
||||
break;
|
||||
}
|
||||
|
||||
info( "Got a packet \\o/. %zu bytes", count );
|
||||
|
||||
switch( recv_pkt.hdr.ip.version ) {
|
||||
case 0x04 :
|
||||
result = wrap_ipv4_packet( wrap.rlocs, &recv_pkt, &to_send );
|
||||
break;
|
||||
case 0x06 :
|
||||
result = wrap_ipv6_packet( wrap.rlocs, &recv_pkt, &to_send );
|
||||
break;
|
||||
default:
|
||||
warn( "Unknown IP version: %i", recv_pkt.hdr.ip.version );
|
||||
}
|
||||
|
||||
// We can't send the unwrapped one - it'll just be returned to us
|
||||
// forever, given our bgp interventions, unless the router is clever.
|
||||
// TODO: make fallback-to-unwrapped a configurable option?
|
||||
if ( !result ) {
|
||||
warn( "Failed to construct a wrapped version of received packet, dropping." );
|
||||
continue;
|
||||
}
|
||||
|
||||
// no failure, but nothing to forward.
|
||||
if ( to_send.count == 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Drop the packet if we would fragment. A real implementation
|
||||
// will need to fragment or inform the source, of course.
|
||||
|
||||
// docs say this should never block and should always write everything -
|
||||
// trust that for now.
|
||||
if ( ( count = writev( wrap.output_if, to_send.iovs, to_send.count ) ) < 0 ) {
|
||||
warn( "Error writing wrapped packet to output: %s", strerror(errno) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
info( "Finished, cleaning up" );
|
||||
session_teardown( &wrap );
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue