First pass at fragmenting
This commit is contained in:
@@ -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) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user