Esempio n. 1
0
/*---------------------------------------------------------------------
 * Method: do_nat_interal
 *
 * Scope:  Local
 *
 * This function performs the decision logic for packets arriving on an
 * external interface. it determines if the NAT has should translate the
 * packet and route it to the internal interface, whether it should drop
 * the packet, or whether it should let the router route the packet or
 * process it as usual
 *
 *  parameters:
 *    sr          - a reference to the router structure
 *    iphdr       - a pointer to the packet received
 *    iface       - the interface through which the packet was received  
 *
 *---------------------------------------------------------------------*/
nat_action_type do_nat_external(struct sr_instance *sr, sr_ip_hdr_t *iphdr, sr_if_t *iface) 
{
  DebugNAT("+++ Applying external NAT interface logic +++\n");
  if (destined_to_nat_external(sr,iphdr->ip_dst)) {
    DebugNAT("+++ Inbound packet destined to NAT. handling... +++\n");
    //destined to nat and/or private network behind it
    if (iphdr->ip_p == ip_protocol_icmp) //ICMP
      return handle_incoming_icmp(&sr->nat,iphdr);
    
    if (iphdr->ip_p == ip_protocol_tcp) //TCP
      return handle_incoming_tcp(&sr->nat,iphdr);
    
    return nat_action_drop; //drop packet if not TCP/ICMP
  } 


  sr_rt_t *best_match = NULL;
  if (!longest_prefix_match(sr->routing_table, iphdr->ip_dst,&best_match)) {
    DebugNAT("+++ No entry in routing table. no action required +++\n\n");
    return nat_action_route;  //no match in routing table. need to generate ICMP host unreachable
                              //no action required on behalf of the NAT
                              //return route. let router figure out what he needs to do.
  }

  if  (strcmp(best_match->interface,iface->name)==0) {
    DebugNAT("+++ Routing back on same interface: external->external. no action required +++\n");
    return nat_action_route;  //routing back on same interface: external->external.
                  //no action required on behalf of the NAT
  }

  DebugNAT("+++ Packet destined directly to internal interface. refuse request +++\n");
  return nat_action_unrch; //ICMP host unreachable should be sent to packets trying to
                            //access hosts behind the NAT directly
}
Esempio n. 2
0
/*---------------------------------------------------------------------
 * Method: do_nat_interal
 *
 * Scope:  Local
 *
 * This function performs the decision logic for packets arriving on an
 * internal interface. it determines if the NAT has to process the packet
 * and create a mapping, or simply let the router route or process the
 * packet as usual.
 *
 *  parameters:
 *    sr          - a reference to the router structure
 *    iphdr       - a pointer to the packet received
 *    iface       - the interface through which the packet was received  
 *
 *---------------------------------------------------------------------*/
nat_action_type do_nat_internal(struct sr_instance *sr, sr_ip_hdr_t *iphdr, sr_if_t *iface) 
{ 
  DebugNAT("+++ Applying internal NAT interface logic +++\n");
  if (destined_to_nat_external(sr,iphdr->ip_dst)) {
    //hairpinning not supported
    DebugNAT("+++ Potential hairpinning detected. assuming NAT is final destination. +++\n");
    return nat_action_route;
  }


  sr_rt_t *best_match = NULL;
  if (!longest_prefix_match(sr->routing_table, iphdr->ip_dst,&best_match)) {
    DebugNAT("+++ No entry in routing table. no action required +++\n");
    return nat_action_route;  //no match in routing table. need to generate ICMP host unreachable
                              //no action required on behalf of the NAT. no objection by the nat
                              //to routing the packet. let router figure out his response
  }
  
  if  (strcmp(best_match->interface,iface->name)==0) {
    DebugNAT("+++ Routing back on same interface: internal->internal. no action required +++\n");
    return nat_action_route;  //routing back on same interface: internal->internal.
                              //no action required on behalf of the NAT
  }

  DebugNAT("+++ Outbound packet crossing NAT. handling... +++\n");
  //packet crossing the NAT outbound
  if (iphdr->ip_p == ip_protocol_icmp) //ICMP
    return handle_outgoing_icmp(sr,iphdr);
  
  if (iphdr->ip_p == ip_protocol_tcp) //TCP
     return handle_outgoing_tcp(sr,iphdr);

  return nat_action_drop; //drop packet if not TCP/ICMP
       
}
Esempio n. 3
0
/* Called from syscall or from eBPF program */
static void *trie_lookup_elem(struct bpf_map *map, void *_key)
{
	struct lpm_trie *trie = container_of(map, struct lpm_trie, map);
	struct lpm_trie_node *node, *found = NULL;
	struct bpf_lpm_trie_key *key = _key;

	/* Start walking the trie from the root node ... */

	for (node = rcu_dereference(trie->root); node;) {
		unsigned int next_bit;
		size_t matchlen;

		/* Determine the longest prefix of @node that matches @key.
		 * If it's the maximum possible prefix for this trie, we have
		 * an exact match and can return it directly.
		 */
		matchlen = longest_prefix_match(trie, node, key);
		if (matchlen == trie->max_prefixlen) {
			found = node;
			break;
		}

		/* If the number of bits that match is smaller than the prefix
		 * length of @node, bail out and return the node we have seen
		 * last in the traversal (ie, the parent).
		 */
		if (matchlen < node->prefixlen)
			break;

		/* Consider this node as return candidate unless it is an
		 * artificially added intermediate one.
		 */
		if (!(node->flags & LPM_TREE_NODE_FLAG_IM))
			found = node;

		/* If the node match is fully satisfied, let's see if we can
		 * become more specific. Determine the next bit in the key and
		 * traverse down.
		 */
		next_bit = extract_bit(key->data, node->prefixlen);
		node = rcu_dereference(node->child[next_bit]);
	}

	if (!found)
		return NULL;

	return found->data + trie->data_size;
}
Esempio n. 4
0
void test_match(struct sr_instance *sr,int a, int b, int c, int d, bool result, char * correct_match){
    in_addr_t x;

    char *y = (char *)&x; /* so that we can address the individual bytes */

    y[0] = a;
    y[1] = b;
    y[2] = c;
    y[3] = d;

    struct in_addr ip = *(struct in_addr *)&x;


    struct sr_rt * match = longest_prefix_match(sr, (uint32_t)ip.s_addr);
    assert(match && strcmp(match->interface, correct_match) == 0);
}
Esempio n. 5
0
/* Called from syscall or from eBPF program */
static int trie_update_elem(struct bpf_map *map,
			    void *_key, void *value, u64 flags)
{
	struct lpm_trie *trie = container_of(map, struct lpm_trie, map);
	struct lpm_trie_node *node, *im_node = NULL, *new_node = NULL;
	struct lpm_trie_node __rcu **slot;
	struct bpf_lpm_trie_key *key = _key;
	unsigned long irq_flags;
	unsigned int next_bit;
	size_t matchlen = 0;
	int ret = 0;

	if (unlikely(flags > BPF_EXIST))
		return -EINVAL;

	if (key->prefixlen > trie->max_prefixlen)
		return -EINVAL;

	raw_spin_lock_irqsave(&trie->lock, irq_flags);

	/* Allocate and fill a new node */

	if (trie->n_entries == trie->map.max_entries) {
		ret = -ENOSPC;
		goto out;
	}

	new_node = lpm_trie_node_alloc(trie, value);
	if (!new_node) {
		ret = -ENOMEM;
		goto out;
	}

	trie->n_entries++;

	new_node->prefixlen = key->prefixlen;
	RCU_INIT_POINTER(new_node->child[0], NULL);
	RCU_INIT_POINTER(new_node->child[1], NULL);
	memcpy(new_node->data, key->data, trie->data_size);

	/* Now find a slot to attach the new node. To do that, walk the tree
	 * from the root and match as many bits as possible for each node until
	 * we either find an empty slot or a slot that needs to be replaced by
	 * an intermediate node.
	 */
	slot = &trie->root;

	while ((node = rcu_dereference_protected(*slot,
					lockdep_is_held(&trie->lock)))) {
		matchlen = longest_prefix_match(trie, node, key);

		if (node->prefixlen != matchlen ||
		    node->prefixlen == key->prefixlen ||
		    node->prefixlen == trie->max_prefixlen)
			break;

		next_bit = extract_bit(key->data, node->prefixlen);
		slot = &node->child[next_bit];
	}

	/* If the slot is empty (a free child pointer or an empty root),
	 * simply assign the @new_node to that slot and be done.
	 */
	if (!node) {
		rcu_assign_pointer(*slot, new_node);
		goto out;
	}

	/* If the slot we picked already exists, replace it with @new_node
	 * which already has the correct data array set.
	 */
	if (node->prefixlen == matchlen) {
		new_node->child[0] = node->child[0];
		new_node->child[1] = node->child[1];

		if (!(node->flags & LPM_TREE_NODE_FLAG_IM))
			trie->n_entries--;

		rcu_assign_pointer(*slot, new_node);
		kfree_rcu(node, rcu);

		goto out;
	}

	/* If the new node matches the prefix completely, it must be inserted
	 * as an ancestor. Simply insert it between @node and *@slot.
	 */
	if (matchlen == key->prefixlen) {
		next_bit = extract_bit(node->data, matchlen);
		rcu_assign_pointer(new_node->child[next_bit], node);
		rcu_assign_pointer(*slot, new_node);
		goto out;
	}

	im_node = lpm_trie_node_alloc(trie, NULL);
	if (!im_node) {
		ret = -ENOMEM;
		goto out;
	}

	im_node->prefixlen = matchlen;
	im_node->flags |= LPM_TREE_NODE_FLAG_IM;
	memcpy(im_node->data, node->data, trie->data_size);

	/* Now determine which child to install in which slot */
	if (extract_bit(key->data, matchlen)) {
		rcu_assign_pointer(im_node->child[0], node);
		rcu_assign_pointer(im_node->child[1], new_node);
	} else {
		rcu_assign_pointer(im_node->child[0], new_node);
		rcu_assign_pointer(im_node->child[1], node);
	}

	/* Finally, assign the intermediate node to the determined spot */
	rcu_assign_pointer(*slot, im_node);

out:
	if (ret) {
		if (new_node)
			trie->n_entries--;

		kfree(new_node);
		kfree(im_node);
	}

	raw_spin_unlock_irqrestore(&trie->lock, irq_flags);

	return ret;
}