Exemple #1
0
/**
 * Validates if the packet header is valid IPv4 header. This is wrapped around
 * by parse_ipv4 function.
 * @param buf Pointer to buffer containing packet header to verify for being ipv4 header
 * @param packet_len Length of packet passed in the buffer
 * @return bool True if the packet header is a valid IPv4 header, else False
 * @see bool parse_ipv4( buffer *buf )
 */
static bool
valid_ipv4_packet_header( buffer *buf, uint32_t packet_len ) {
  if ( ( size_t ) packet_len < sizeof( ipv4_header_t ) ) {
    debug( "Too short IPv4 packet ( length = %u ).", packet_len );
    return false;
  }

  if ( packet_info( buf )->l3_data.ipv4->version != IPVERSION ) {
    debug( "Unsupported IP version ( version = %#x ).",
           packet_info( buf )->l3_data.ipv4->version );
    return false;
  }

  size_t hdr_len = ( size_t ) packet_info( buf )->l3_data.ipv4->ihl * 4;
  if ( hdr_len < sizeof( ipv4_header_t ) ) {
    debug( "Too short IPv4 header length field value ( length = %u ).",
           hdr_len );
    return false;
  }

  if ( verify_checksum( ( uint16_t * ) packet_info( buf )->l3_data.ipv4, ( uint32_t ) hdr_len ) != 0 ) {
    debug( "Corrupted IPv4 header ( checksum verification error )." );
    return false;
  }

  return true;
}
Exemple #2
0
/**
 * Extracts fragment offset and IP packet length of IPv4 packet and validates
 * if packet's length is valid. This is wrapped around by parse_ipv4 function.
 * @param buf Pointer to buffer containing IPv4 packet header
 * @param packet_len Length of packet passed in the buffer
 * @return bool True if the packet length is valid IPv4 packet length, else False
 * @see bool parse_ipv4( buffer *buf )
 */
static bool
valid_ipv4_packet_more_fragments( buffer *buf, uint32_t packet_len ) {
  uint16_t ip_len = ntohs( packet_info( buf )->l3_data.ipv4->tot_len );
  uint32_t frag_offset = ntohs( packet_info( buf )->l3_data.ipv4->frag_off );

  frag_offset = ( frag_offset & IP_OFFMASK ) << 3;

  if ( ( frag_offset > 0 ) && ( ip_len == ( uint16_t ) sizeof( ipv4_header_t ) ) ) {
    debug( "Too short IPv4 fragment ( fragment offset = %u ).", frag_offset );
    return false;
  }

  if ( ( frag_offset + ip_len ) > IP_MAXPACKET ) {
    debug( "Too large IPv4 packet ( total length = %u, fragment offset = %u ).",
           ip_len, frag_offset );
    return false;
  }
  if ( ip_len > packet_len ) {
    debug( "Packet length is shorter than the total length header field value "
           "( total length = %u, packet length = %u ).", ip_len, packet_len );
    return false;
  }

  return true;
}
Exemple #3
0
/**
 * Extracts source and destination address of IPv4 packet and validates them.
 * This is wrapped around by parse_ipv4 function.
 * @param buf Pointer to buffer containing IPv4 packet header
 * @return bool True if source and destination address of IPv4 packet header are valid, else False
 * @see bool parse_ipv4( buffer *buf )
 */
static bool
valid_ipv4_packet_ip_address( buffer *buf ) {
  char addr[ 16 ];
  uint32_t ip_sa = ntohl( packet_info( buf )->l3_data.ipv4->saddr );
  struct in_addr in;

  if ( IPV4_IS_CLASSDE( ip_sa ) || IPV4_IS_LOOPBACK( ip_sa ) || IPV4_IS_LIMITEDBC( ip_sa ) ) {
    in.s_addr = packet_info( buf )->l3_data.ipv4->saddr;
    memset( addr, 0, sizeof( addr ) );
    inet_ntop( AF_INET, &in, addr, sizeof( addr ) );
    debug( "Invalid source IPv4 address ( source address = %s ).", addr );
    return false;
  }

  uint32_t ip_da = ntohl( packet_info( buf )->l3_data.ipv4->daddr );
  if ( IPV4_IS_LOOPBACK( ip_da ) ) {
    in.s_addr = packet_info( buf )->l3_data.ipv4->daddr;
    memset( addr, 0, sizeof( addr ) );
    inet_ntop( AF_INET, &in, addr, sizeof( addr ) );
    debug( "Destination IPv4 address must not be a loopback address ( destination address = %s ).", addr );
    return false;
  }
  if ( ip_sa == ip_da ) {
    in.s_addr = packet_info( buf )->l3_data.ipv4->saddr;
    memset( addr, 0, sizeof( addr ) );
    inet_ntop( AF_INET, &in, addr, sizeof( addr ) );
    debug( "Destination address and source address must not be the same ( address = %s ).", addr );
    return false;
  }

  return true;
}
Exemple #4
0
static buffer *
setup_dummy_snap_packet() {
  buffer *snap_buffer = setup_dummy_ether_packet( sizeof( ether_header_t ) + sizeof( snap_header_t ) );

  packet_info( snap_buffer )->l2_data.eth->type = htons( sizeof( ether_header_t ) + sizeof( snap_header_t ) - ETH_PREPADLEN );
  packet_info( snap_buffer )->vtag = ( void * ) ( packet_info( snap_buffer )->l2_data.eth + 1 );
  memcpy( ( char * ) packet_info( snap_buffer )->vtag, sntp_data, sizeof( snap_header_t ) );

  return snap_buffer;
}
Exemple #5
0
static buffer *
setup_dummy_vlan_packet() {
  buffer *vlan_buffer = setup_dummy_ether_packet( sizeof( ether_header_t ) + sizeof( vlantag_header_t ) );

  packet_info( vlan_buffer )->l2_data.eth->type = htons( sizeof( ether_header_t ) + sizeof( vlantag_header_t ) - ETH_PREPADLEN );
  packet_info( vlan_buffer )->l2_data.eth->type = htons( ETH_ETHTYPE_TPID );
  packet_info( vlan_buffer )->vtag = ( void * ) ( packet_info( vlan_buffer )->l2_data.eth + 1 );
  packet_info( vlan_buffer )->vtag->type = htons( ETH_ETHTYPE_IPV4 );

  return vlan_buffer;
}
Exemple #6
0
void
test_parse_ether_not_llc_header_succeeds() {
  buffer *buffer = setup_dummy_snap_packet( );
  ( ( snap_header_t * ) packet_info( buffer )->vtag )->llc[ 0 ] = 0xFF;
  ( ( snap_header_t * ) packet_info( buffer )->vtag )->llc[ 1 ] = 0xFF;

  assert_int_equal( parse_ether( buffer ), true );
  assert_int_equal( packet_info( buffer )->ethtype, ETH_ETHTYPE_UKNOWN );

  free_buffer( buffer );
}
Exemple #7
0
static buffer *
setup_dummy_ether_packet( size_t length ) {
  buffer *ether_buffer = alloc_buffer_with_length( length );
  alloc_packet( ether_buffer );
  append_back_buffer( ether_buffer, length );
  packet_info( ether_buffer )->l2_data.eth = ether_buffer->data;

  memcpy( ( char * ) packet_info( ether_buffer )->l2_data.eth->macda, macda, ETH_ADDRLEN );
  memcpy( ( char * ) packet_info( ether_buffer )->l2_data.eth->macsa, macsa, ETH_ADDRLEN );
  packet_info( ether_buffer )->l2_data.eth->type = htons( ETH_ETHTYPE_ARP );

  return ether_buffer;
}
void network_throttle::tick()
{
	double time_now = get_time_seconds();
	if (!m_any_packet_yet) m_start_time = time_now; // starting now

	network_time_seconds current_sample_time_slot = time_to_slot( time_now ); // T=13.7 --> 13  (for 1-second smallwindow)
	network_time_seconds last_sample_time_slot = time_to_slot( m_last_sample_time );

	// moving to next position, and filling gaps
	// !! during this loop the m_last_sample_time and last_sample_time_slot mean the variable moved in +1
	// TODO optimize when moving few slots at once
	while ( (!m_any_packet_yet) || (last_sample_time_slot < current_sample_time_slot))
	{
		_dbg3("Moving counter buffer by 1 second " << last_sample_time_slot << " < " << current_sample_time_slot << " (last time " << m_last_sample_time<<")");
		// rotate buffer 
		for (size_t i=m_history.size()-1; i>=1; --i) m_history[i] = m_history[i-1];
		m_history[0] = packet_info();
		if (! m_any_packet_yet) 
		{
			m_last_sample_time = time_now;	
		}
		m_last_sample_time += 1;	last_sample_time_slot = time_to_slot( m_last_sample_time ); // increase and recalculate time, time slot
		m_any_packet_yet=true;
	}
	m_last_sample_time = time_now; // the real exact last time
}
Exemple #9
0
void
test_parse_ether_fails_if_type_is_trancated_payload_ieee8023() {
  buffer *buffer = setup_dummy_snap_packet( );
  packet_info( buffer )->l2_data.eth->type = htons( sizeof( ether_header_t ) + sizeof( snap_header_t ) );

  assert_int_equal( parse_ether( buffer ), false );

  free_buffer( buffer );
}
Exemple #10
0
void
test_parse_ether_fails_if_llc_is_unsupported_llc_snap() {
  buffer *buffer = setup_dummy_snap_packet( );
  ( ( snap_header_t * ) packet_info( buffer )->vtag )->llc[ 2 ] = 1;

  assert_int_equal( parse_ether( buffer ), false );

  free_buffer( buffer );
}
Exemple #11
0
void
test_parse_ether_fails_if_mac_address_is_wrong_mac() {
  buffer *buffer = setup_dummy_ether_packet( sizeof( ether_header_t ) );
  packet_info( buffer )->l2_data.eth->macsa[ 0 ] = 0xff;

  assert_int_equal( parse_ether( buffer ), false );

  free_buffer( buffer );
}
Exemple #12
0
void
test_parse_ether_fails_if_type_is_trancated_vlan() {
  buffer *buffer = setup_dummy_ether_packet(sizeof( ether_header_t ) );
  packet_info( buffer )->l2_data.eth->type = htons( ETH_ETHTYPE_TPID );

  assert_int_equal( parse_ether( buffer ), false );

  free_buffer( buffer );
}
Exemple #13
0
void
test_parse_ether_fails_if_ether_data_is_NULL() {
  buffer *buffer = setup_dummy_vlan_packet( );
  packet_info( buffer )->l2_data.eth = NULL;

  expect_assert_failure( parse_ether( buffer ) );

  free_buffer( buffer );
}
Exemple #14
0
static buffer *
setup_dummy_ether_ipv4_packet() {
  buffer *ipv4_buffer = setup_dummy_ether_packet( sizeof( ether_header_t ) + sizeof( ipv4_header_t ) + ipv4_padding_size, ETH_ETHTYPE_IPV4 );

  ipv4_header_t *ipv4 = packet_info( ipv4_buffer )->l3_data.ipv4;
  ipv4->version = IPVERSION;
  ipv4->ihl = sizeof( ipv4_header_t ) / 4;
  ipv4->tot_len = htons( sizeof( ipv4_header_t ) );
  ipv4->ttl = 0;
  ipv4->check = 0;
  ipv4->protocol = IPPROTO_UDP;
  ipv4->saddr = htonl( 0xC0A80067 );
  ipv4->daddr = htonl( 0xC0A80036 );
  ipv4->frag_off = htons( 0 );
  ipv4->check = get_checksum( ( uint16_t * ) packet_info( ipv4_buffer )->l3_data.ipv4, sizeof( ipv4_header_t ) );

  free( ipv4_buffer->user_data );
  ipv4_buffer->user_data = NULL;

  remove_front_buffer( ipv4_buffer, ETH_PREPADLEN );

  return ipv4_buffer;
}
Exemple #15
0
/**
 * Parses the IPv4 packet for being valid IPv4 packet.
 * @param buf Pointer to buffer containing IPv4 packet
 * @return bool True if the buffer contains valid IPv4 packet, else False
 */
bool
parse_ipv4( buffer *buf ) {
  assert( buf != NULL );
  assert( packet_info( buf )->l3_data.ipv4 != NULL );

  uint32_t packet_len = ( uint32_t ) buf->length - ( uint32_t ) ( ( char * ) ( packet_info( buf )->l3_data.l3 ) -  ( char * ) ( buf->data ) );

  if ( !valid_ipv4_packet_header( buf, packet_len ) ) {
    debug( "Invalid IPv4 header." );
    return false;
  }

  if ( !valid_ipv4_packet_more_fragments( buf, packet_len ) ) {
    debug( "Invalid fragmented IPv4 packet." );
    return false;
  }

  if ( !valid_ipv4_packet_ip_address( buf ) ) {
    debug( "IPv4 packet with an invalid address." );
    return false;
  }

  uint32_t hdr_len = ( uint32_t ) packet_info( buf )->l3_data.ipv4->ihl * 4;
  switch ( packet_info( buf )->l3_data.ipv4->protocol ) {
  case IPPROTO_AH:
    if ( ( hdr_len + 8 ) > packet_len ) {
      debug( "Too short IPv4 packet with an authentication header ( length = %u ).", packet_len );
      return false;
    }
    packet_info( buf )->ipproto = *( uint8_t * ) ( ( char * ) buf->data + hdr_len );
    hdr_len += *( uint8_t * ) ( ( char * ) buf->data + hdr_len + 1 );
    break;
  default:
    packet_info( buf )->ipproto = packet_info( buf )->l3_data.ipv4->protocol;
    break;
  }

  packet_info( buf )->l4_data.l4 = ( char * ) packet_info( buf )->l3_data.l3 + hdr_len;

  return true;
}
Exemple #16
0
static buffer *
setup_dummy_ether_arp_packet() {
  buffer *arp_buffer = setup_dummy_ether_packet( sizeof( ether_header_t ) + sizeof( arp_header_t ) + arp_padding_size, ETH_ETHTYPE_ARP );

  arp_header_t *arp = packet_info( arp_buffer )->l3_data.arp;
  arp->ar_hrd = htons( ARPHRD_ETHER );
  arp->ar_pro = htons( ETH_ETHTYPE_IPV4 );
  arp->ar_hln = ETH_ADDRLEN;
  arp->ar_pln = IPV4_ADDRLEN;
  arp->ar_op = htons( ARPOP_REPLY );

  free( arp_buffer->user_data );
  arp_buffer->user_data = NULL;

  remove_front_buffer( arp_buffer, ETH_PREPADLEN );

  return arp_buffer;
}
Exemple #17
0
static buffer *
setup_dummy_ether_packet( size_t length, uint16_t type ) {
  buffer *buf = alloc_buffer_with_length( length );
  alloc_packet( buf );
  append_back_buffer( buf, length );
  packet_info( buf )->l2_data.eth = buf->data;
  packet_info( buf )->ethtype = type;
  ether_header_t *ether = packet_info( buf )->l2_data.eth;
  ether->type = htons( type );

  memcpy( ( char * ) ether->macda, macda, ETH_ADDRLEN );
  memcpy( ( char * ) ether->macsa, macsa, ETH_ADDRLEN );

  packet_info( buf )->l3_data.l3 = ( char * ) packet_info( buf )->l2_data.l2 + sizeof( ether_header_t );
  vlantag_header_t *vtag = ( vlantag_header_t * ) ( ( void * ) ( ether + 1 ) );
  packet_info( buf )->vtag = vtag;

  return buf;
}
Exemple #18
0
/**
 * This function is to find if Ethernet header contained in passed buffer is
 * valid Ethernet header or not.
 * @param buf Buffer containing header to verify for being valid Ethernet header
 * @return bool True if buffer contains valid Ethernet header, else False
 */
bool
parse_ether( buffer *buf ) {
  assert( buf != NULL );
  assert( packet_info( buf )->l2_data.eth != NULL );

  size_t frame_length = buf->length - ( size_t ) ( ( char * ) ( packet_info( buf )->l2_data.l2 ) - ( char * ) buf->data ) - ETH_PREPADLEN;
  ether_header_t *eth = packet_info( buf )->l2_data.eth;
  size_t ether_length = sizeof( ether_header_t ) - ETH_PREPADLEN;
  if ( frame_length < ether_length ) {
    debug( "Frame length is shorter than the length of an Ethernet header ( frame length = %u ).", frame_length );
    return false;
  }

  debug( "Parsing an Ethernet frame "
         "( source mac = %02x:%02x:%02x:%02x:%02x:%02x, "
         "destination mac = %02x:%02x:%02x:%02x:%02x:%02x ).",
         eth->macsa[ 0 ], eth->macsa[ 1 ], eth->macsa[ 2 ],
         eth->macsa[ 3 ], eth->macsa[ 4 ], eth->macsa[ 5 ],
         eth->macda[ 0 ], eth->macda[ 1 ], eth->macda[ 2 ],
         eth->macda[ 3 ], eth->macda[ 4 ], eth->macda[ 5 ] );

  if ( eth->macsa[ 0 ] & 0x01 ) {
    debug( "Source MAC address is multicast or broadcast." );
    return false;
  }

  uint16_t type = ntohs( eth->type );
  vlantag_header_t *vlan_tag = ( void * ) ( eth + 1 );
  uint8_t next_vlan_tags = 0;
  while ( type == ETH_ETHTYPE_TPID ) {
    ether_length += sizeof( vlantag_header_t );
    if ( frame_length < ether_length ) {
      debug( "Too short 802.1Q frame ( frame length = %u ).", frame_length );
      return false;
    }
    type = ntohs( vlan_tag->type );
    vlan_tag++;
    next_vlan_tags++;
    debug( "802.1Q header found ( type = %#x, # of headers = %u ).", type, next_vlan_tags );
  }

  if ( type <= ETH_ETHTYPE_8023 ) {
    snap_header_t *snap = ( snap_header_t * ) vlan_tag;

    // check frame length first
    if ( snap->llc[ 0 ] == 0xaa && snap->llc[ 1 ] == 0xaa ) {
      // LLC header with SNAP
      ether_length += sizeof( snap_header_t );
    }
    else {
      // LLC header without SNAP
      ether_length += offsetof( snap_header_t, oui );
    }
    if ( frame_length < ether_length ) {
      debug( "Too short LLC/SNAP frame ( minimun frame length = %u, frame length = %u ).",
             ether_length, frame_length );
      return false;
    }
    if ( frame_length < ( size_t ) type ) {
      debug( "Frame length is shorter than the length header field value "
             "( frame length = %u, length field value = %u ).", frame_length, type );
      return false;
    }

    // check header field values
    if ( snap->llc[ 0 ] == 0xaa && snap->llc[ 1 ] == 0xaa ) {
      // LLC header with SNAP
      if ( snap->llc[ 2 ] == 0x03 || snap->llc[ 2 ] == 0xf3 || snap->llc[ 2 ] == 0xe3
           || snap->llc[ 2 ] == 0xbf || snap->llc[ 2 ] == 0xaf ) {
        type = ntohs( snap->type );
      }
      else {
        debug( "Unexpected SNAP frame ( length = %u, llc = 0x%02x%02x%02x, oui = 0x%02x%02x%02x, type = %u ).",
               type, snap->llc[ 0 ], snap->llc[ 1 ], snap->llc[ 2 ],
               snap->oui[ 0 ], snap->oui[ 1 ], snap->oui[ 2 ], ntohs( snap->type ) );
        return false;
      }
    }
    else {
      // LLC header without SNAP
      debug( "Unhandled 802.3 frame ( length = %u, llc = 0x%02x%02x%02x ).",
             type, snap->llc[ 0 ], snap->llc[ 1 ], snap->llc[ 2 ] );
      type = ETH_ETHTYPE_UKNOWN;
    }
  }

  packet_info( buf )->nvtags = next_vlan_tags;
  if ( next_vlan_tags > 0 ) {
    packet_info( buf )->vtag = ( void * ) ( eth + 1 );
    debug( "802.1Q header found ( tci = %#x, type = %#x ).",
           ntohs( packet_info( buf )->vtag->tci ), ntohs( packet_info( buf )->vtag->type ) );
  }
  else {
    packet_info( buf )->vtag = NULL;
    debug( "No 802.1Q header found." );
  }

  debug( "Ethernet type = %#x.", type );

  packet_info( buf )->ethtype = type;
  packet_info( buf )->l3_data.l3 = ( char * ) packet_info( buf )->l2_data.l2 + ETH_PREPADLEN + ether_length;

  return true;
}
Exemple #19
0
static void
handle_packet_in( uint64_t datapath_id, uint32_t transaction_id,
                  uint32_t buffer_id, uint16_t total_len,
                  uint16_t in_port, uint8_t reason, const buffer *data,
                  void *user_data ) {
  assert( in_port != 0 );
  assert( data != NULL );
  assert( user_data != NULL );

  routing_switch *routing_switch = user_data;

  debug( "Packet-In received ( datapath_id = %#" PRIx64 ", transaction_id = %#lx, "
         "buffer_id = %#lx, total_len = %u, in_port = %u, reason = %#x, "
         "data_len = %u ).", datapath_id, transaction_id, buffer_id,
         total_len, in_port, reason, data->length );

  const port_info *port = lookup_outbound_port( routing_switch->switches, datapath_id, in_port );

  const uint8_t *src = packet_info( data )->l2_data.eth->macsa;
  const uint8_t *dst = packet_info( data )->l2_data.eth->macda;

  if ( in_port <= OFPP_MAX || in_port == OFPP_LOCAL ) {
    if ( port == NULL && !lookup_fdb( routing_switch->fdb, src, &datapath_id, &in_port ) ) {
      debug( "Ignoring Packet-In from switch-to-switch link" );
      return;
    }
  }
  else {
    error( "Packet-In from invalid port ( in_port = %#u ).", in_port );
    return;
  }

  if ( !update_fdb( routing_switch->fdb, src, datapath_id, in_port ) ) {
    return;
  }

  buffer *original_packet = duplicate_buffer( data );
  uint16_t out_port;
  uint64_t out_datapath_id;

  if ( lookup_fdb( routing_switch->fdb, dst, &out_datapath_id, &out_port ) ) {
    // Host is located, so resolve path and send flowmod
    if ( ( datapath_id == out_datapath_id ) && ( in_port == out_port ) ) {
      // in and out are same
      free_buffer( original_packet );
      return;
    }

    // Ask path resolver service to lookup a path
    // resolve_path_replied() will be called later
    resolve_path_replied_params *param = xmalloc( sizeof( *param ) );
    param->routing_switch = routing_switch;
    param->original_packet = original_packet;

    resolve_path( datapath_id, in_port, out_datapath_id, out_port,
                  param, resolve_path_replied );
  } else {
    // Host's location is unknown, so flood packet
    flood_packet( datapath_id, in_port, original_packet, routing_switch->switches );
  }
}
Exemple #20
0
/*
 * The MAC destination address.
 *
 * @return [Trema::Mac] macda MAC destination address.
 */
static VALUE
packet_in_macda( VALUE self ) {
    packet_in *cpacket_in = get_packet_in( self );
    VALUE macda = ULL2NUM( mac_to_uint64( packet_info( cpacket_in->data )->l2_data.eth->macda ) );
    return rb_funcall( rb_eval_string( "Trema::Mac" ), rb_intern( "new" ), 1, macda );
}