/* Workhorse for destroy_all and error handler for create. `adapter' must 
   not be in the adapter table when this function is called. */
static Boolean
ssh_virtual_adapter_destroy(SshInterceptor interceptor,
                            SshVirtualAdapter adapter)
{
  SSH_ASSERT(adapter != NULL);

  ssh_kernel_mutex_assert_is_locked(interceptor->interceptor_lock);
  
  SSH_DEBUG(SSH_D_HIGHOK,
	    ("Destroying virtual adapter %d [%s]", 
	     (adapter->dev ? adapter->dev->ifindex : -1),
	     (adapter->dev ? adapter->dev->name : "unknown")));
  
  if (adapter->dev)
    {
      /* Detach and destroy net_device. */ 
      ssh_kernel_mutex_unlock(interceptor->interceptor_lock);
      local_bh_enable();
      
      /* This call will produce an interface event. */
      ssh_virtual_adapter_detach_low_level(adapter);
      
      local_bh_disable();
      ssh_kernel_mutex_lock(interceptor->interceptor_lock);
      adapter->dev = NULL;
    }
  
  /* Free adapter */
  ssh_free(adapter);
  
  /* All ok. */
  return TRUE;
}
void
sw_fastpath_release_trd(SshFastpath fastpath, SshUInt32 trd_index)
{






  ssh_kernel_mutex_assert_is_locked(fastpath->engine->flow_control_table_lock);













  /* Release the lock on the transform table element */
  FP_RELEASE_TRD(fastpath, trd_index);
}
Exemplo n.º 3
0
void engine_audit_new_event(SshEngine engine)
{
  ssh_kernel_mutex_assert_is_locked(engine->flow_control_table_lock);
#if SSH_PM_AUDIT_REQUESTS_PER_SECOND == 0
  if (!engine->audit_timeout_scheduled)
    {
      engine->audit_timeout_scheduled = 1;
      ssh_kernel_timeout_register(0L, 200000L,
				  engine_audit_request_poll_with_lock,
				  engine);
    }
#endif /* SSH_PM_AUDIT_REQUESTS_PER_SECOND */
}
SshEngineTransformData
sw_fastpath_get_trd(SshFastpath fastpath, SshUInt32 trd_index,
		    Boolean ronly, Boolean init)
{
  SshEngineTransformData trd;

  ssh_kernel_mutex_assert_is_locked(fastpath->engine->flow_control_table_lock);







  SSH_ASSERT((trd_index & 0xffffff) < fastpath->transform_table_size);

  /* Get the trd element and lock it */
  trd = swi_fastpath_get_trd_lock(fastpath, trd_index, TRUE);

  if (init)
    {
      trd->transform = 0;
      memset(&trd->spis, 0, sizeof(trd->spis));
      memset(&trd->old_spis, 0, sizeof(trd->old_spis));
      SSH_IP_UNDEFINE(&trd->own_addr);
      SSH_IP_UNDEFINE(&trd->gw_addr);
    }

  if (!ronly)
    {
      fastpath->trd_cache->transform = trd->transform;
      fastpath->trd_cache->own_addr = trd->own_addr;
      fastpath->trd_cache->gw_addr = trd->gw_addr;
      fastpath->trd_cache->remote_port = trd->remote_port;

      memcpy(fastpath->trd_cache->spis, trd->spis, 
	     sizeof(fastpath->trd_cache->spis));
      memcpy(fastpath->trd_cache->old_spis, trd->old_spis, 
	     sizeof(fastpath->trd_cache->old_spis));
      memcpy(fastpath->trd_cache->keymat, trd->keymat, 
	     sizeof(fastpath->trd_cache->keymat));
      memcpy(fastpath->trd_cache->old_keymat, trd->old_keymat, 
             sizeof(fastpath->trd_cache->old_keymat));
      fastpath->trd_cache->is_ipv6 = SSH_IP_IS6(&trd->own_addr);
    }



  
  return trd;
}
void
sw_fastpath_uninit_trd(SshFastpath fastpath, SshUInt32 trd_index,
		       SshEngineTransformData data)
{    
  SshEngineTransformData trd;

  ssh_kernel_mutex_assert_is_locked(fastpath->engine->flow_control_table_lock);






  SSH_ASSERT((trd_index & 0xffffff) < fastpath->transform_table_size);

  /* Fetch the trd element. trd is already locked. */
  trd = swi_fastpath_get_trd_lock(fastpath, trd_index, FALSE);
  SSH_ASSERT(data == trd);

#ifdef SSHDIST_IPSEC_TRANSFORM
  if (fastpath->trd_cache->old_spis[SSH_PME_SPI_AH_IN] != 0 ||
      fastpath->trd_cache->old_spis[SSH_PME_SPI_ESP_IN] != 0)
    ssh_fastpath_destroy_sa_tc(fastpath, fastpath->trd_cache->transform,
			       fastpath->trd_cache->old_keymat,
			       fastpath->trd_cache->
			       old_spis[SSH_PME_SPI_AH_IN],
			       fastpath->trd_cache->
			       old_spis[SSH_PME_SPI_ESP_IN],
			       FALSE, /* for_output */
			       fastpath->trd_cache->is_ipv6);
  
  ssh_fastpath_destroy_sa_tc(fastpath, fastpath->trd_cache->transform,
			     fastpath->trd_cache->keymat,
			     fastpath->trd_cache->spis[SSH_PME_SPI_AH_IN],
			     fastpath->trd_cache->spis[SSH_PME_SPI_ESP_IN],
			     FALSE, /* for_output */
			     fastpath->trd_cache->is_ipv6);
  
  ssh_fastpath_destroy_sa_tc(fastpath, fastpath->trd_cache->transform,
			     fastpath->trd_cache->keymat + 
			     (SSH_IPSEC_MAX_KEYMAT_LEN / 2),
			     fastpath->trd_cache->spis[SSH_PME_SPI_AH_OUT],
			     fastpath->trd_cache->spis[SSH_PME_SPI_ESP_OUT],
			     TRUE, /* for_output */
			     fastpath->trd_cache->is_ipv6);
#endif /* SSHDIST_IPSEC_TRANSFORM */

  /* Release the lock on the transform table element */
  FP_RELEASE_TRD(fastpath, trd_index);
}
static inline SshVirtualAdapter
ssh_virtual_adapter_ifnum_to_adapter(SshInterceptor interceptor,
				     SshInterceptorIfnum adapter_ifnum)
{
  SshVirtualAdapter adapter = NULL;
  SshUInt32 i;

  ssh_kernel_mutex_assert_is_locked(interceptor->interceptor_lock);

  for (i = 0; i < SSH_LINUX_MAX_VIRTUAL_ADAPTERS; i++)
    {
      adapter = interceptor->virtual_adapters[i];
      if (adapter && adapter->dev->ifindex == adapter_ifnum)	
	return adapter;
    }
  return NULL;
}
static SshEngineActionRet
engine_packet_handle_pmtu(SshEngine engine, SshEnginePacketContext pc)
{
  const unsigned char *ucp;

  ssh_kernel_mutex_assert_is_locked(engine->flow_control_table_lock);

#if defined (WITH_IPV6)
  if (pc->pp->protocol == SSH_PROTOCOL_IP6)
    {
      if (pc->ipproto == SSH_IPPROTO_IPV6ICMP
          && pc->icmp_type == SSH_ICMP6_TYPE_TOOBIG
          && (pc->pp->flags & SSH_ENGINE_P_TOLOCAL))
	return ssh_engine_handle_pmtu_icmp(engine, pc);
    }
  else
#endif /* WITH_IPV6 */
    {
      if (pc->ipproto == SSH_IPPROTO_ICMP)
        {
          /* Check if it is an ICMP Unreachable/Fragmentation Needed. */
          ucp = ssh_interceptor_packet_pullup_read(pc->pp, pc->hdrlen + 8);
          if (!ucp)
            {
              SSH_DEBUG(SSH_D_FAIL, ("pullup ICMP Unreach/FragNeeded failed"));
              pc->pp = NULL;
	      return SSH_ENGINE_RET_ERROR;
            }

          /* Check if it is a PMTU ICMP packet to our local stack. */
          if (SSH_IPH4_PROTO(ucp) == SSH_IPPROTO_ICMP &&
              ucp[pc->hdrlen] == SSH_ICMP_TYPE_UNREACH &&
              ucp[pc->hdrlen + 1] == SSH_ICMP_CODE_UNREACH_NEEDFRAG &&
              (pc->pp->flags & SSH_ENGINE_P_TOLOCAL))
            {
              /* We have an ICMP Unreachable/Fragmentation needed destined to
                 one of our own IP addresses. */
	      return ssh_engine_handle_pmtu_icmp(engine, pc);
	    }
	}
    }
  return SSH_ENGINE_RET_OK;
}
Exemplo n.º 8
0
SshUInt32 ssh_fastpath_fragmagic_drop_data(SshFastpath fastpath,
					   SshInterceptorPacket *frag_free_list)
{
  SshFastpathFragEntry fe;
  SshUInt32 num_frags;

  ssh_kernel_mutex_assert_is_locked(fastpath->frag_lock);
  /* Get the oldest entry from the data LRU. */
  fe = fastpath->frag_data_lru_tail;
  if (!fe)
    return 0;
  /* Sanity check that it has data. */
  SSH_ASSERT(fe->num_frags > 0);
  /* Clear the entry. */
  fe->flags |= SSH_ENGINE_FRAG_REJECT;
  num_frags = fe->num_frags;
  ssh_fastpath_fragmagic_remove_data_lru(fastpath, fe);
  ssh_fastpath_fragmagic_clear_entry(fastpath, fe, frag_free_list);
  /* "Add" the entry on the data LRU.  This does not actually add it, but
     instead may prepare it for sanity checks. */
  ssh_fastpath_fragmagic_add_data_lru(fastpath, fe);
  return num_frags;
}
Exemplo n.º 9
0
/* Frees any packets queued in the entry, and adjusts global statistics
   about fragments. */
void ssh_fastpath_fragmagic_clear_entry(SshFastpath fastpath, 
					SshFastpathFragEntry fe,
					SshInterceptorPacket *frag_free_list)
{
  SshInterceptorPacket pp;

  ssh_kernel_mutex_assert_is_locked(fastpath->frag_lock);

  /* Free all queued packets. */
  while (fe->pp_chain)
    {
      pp = fe->pp_chain;
      fe->pp_chain = pp->next;
      ssh_fastpath_fragmagic_packet_free(pp, frag_free_list);
    }

  /* Update global statistics. */
  fastpath->frag_num_fragments -= fe->num_frags;
  fastpath->frag_num_bytes -= fe->total_bytes;
  fe->num_frags = 0;
  fe->total_bytes = 0;
  fe->total_bytes = 0;
  fe->packet_size = 0;
}
Exemplo n.º 10
0
void engine_audit_busy(SshEngine engine)
{
#if SSH_PM_AUDIT_REQUESTS_PER_SECOND == 0
#ifdef SSH_IPSEC_UNIFIED_ADDRESS_SPACE
  SshEngineAuditPollRequest c;

  ssh_kernel_mutex_assert_is_locked(engine->flow_control_table_lock);
  if ((c = ssh_malloc(sizeof(*c))) == NULL)
    return;
  c->engine = engine;

  ssh_engine_record_upcall(engine);
  ssh_register_timeout(c->timeout, 0L, 0L,
		       engine_audit_request_poll_now, c);
#else /* SSH_IPSEC_UNIFIED_ADDRESS_SPACE */
  ssh_engine_send(engine, FALSE, TRUE,
		  SSH_ENCODE_UINT32((SshUInt32) 0),
		  SSH_ENCODE_CHAR((unsigned int)SSH_EPA_AUDIT_POLL_REQUEST),
		  SSH_ENCODE_UINT32(0),
		  SSH_FORMAT_END);
#endif /* SSH_IPSEC_UNIFIED_ADDRESS_SPACE */
#endif /* SSH_PM_AUDIT_REQUESTS_PER_SECOND */
  return;
}
Exemplo n.º 11
0
/* Performs fragment magic on a fragment.  This may queue the packet,
   reassemble, or process the packet according to a previously defined
   flow.  If `reassemble' is TRUE (significant for first frags only),
   that indicates that the packet should be reassembled before
   processing.  If `reassemble' is FALSE, that means that the packet
   should not be reassembled, but that all fragments should be
   processed as if their flow id was pc->flow_id.  This returns
   SSH_ENGINE_RET_DEINITIALIZE if processing of the packet is now
   complete, and SSH_ENGINE_RET_RESTART_FLOW_LOOKUP if processing of
   the packet should continue as a fragment.  If this successfully
   completes reassembly, this returns SSH_ENGINE_RET_RESTART, in which
   case processing the packet should be restarted (i.e., it should
   again go through sanity checks).  This may also return
   SSH_ENGINE_RET_ERROR if an error causes pc->pp to be freed, and
   SSH_ENGINE_RET_DROP if it should be dropped. */
SshEngineActionRet
ssh_fastpath_fragmagic(SshFastpath fastpath, SshEnginePacketContext pc,
		       Boolean needs_reassembly)
{
  SshEngine engine = fastpath->engine;
  SshFastpathFragIdStruct frag_id[1];
  SshUInt32 hashvalue, num_frags, chain_len;
  SshFastpathFragEntry fe;
  SshInterceptorPacket pp_chain, *ppp, pp, frag_free_list = NULL;
  SshEnginePacketData pd;
  SshUInt16 packet_size;
  SshTime now;

  SSH_ASSERT(pc->pp != NULL);

  chain_len = 0;
  pc->audit.corruption = SSH_PACKET_CORRUPTION_NONE;

  SSH_DEBUG(SSH_D_MIDOK, ("fragmagic reassemble=%d%s%s",
                          (int)needs_reassembly,
                          (pc->pp->flags & SSH_ENGINE_P_FIRSTFRAG) ?
                          " FIRSTFRAG" : "",
                          (pc->pp->flags & SSH_ENGINE_P_LASTFRAG) ?
                          " LASTFRAG" : ""));
  SSH_ASSERT(pc->pp->flags & SSH_ENGINE_P_ISFRAG);

  /* Initialize number of previously queued fragments freed. */
  num_frags = 0;

  /* Compute fragpacketid for the packet. */
  if (!ssh_fastpath_fragmagic_compute_id(fastpath, pc, frag_id))
    return SSH_ENGINE_RET_ERROR;

  hashvalue = SSH_ENGINE_FRAG_ID_HASH(frag_id);
  hashvalue %= SSH_ENGINE_FRAGMENT_HASH_SIZE;

  ssh_interceptor_get_time(&now, NULL);
  ssh_kernel_mutex_lock(fastpath->frag_lock);

  /* If policy forbids fragments. discard them */
  if (fastpath->frag_policy == SSH_IPSEC_FRAGS_NO_FRAGS)
    {
      ssh_kernel_mutex_unlock(fastpath->frag_lock);
      return SSH_ENGINE_RET_DROP;
    }

  /* Find the fragment entry from the hash table. */
  for (fe = fastpath->frag_hash[hashvalue];
       fe != NULL
         && (fe->ifnum != pc->pp->ifnum_in
             || fe->tunnel_id != pc->tunnel_id
             || !SSH_ENGINE_FRAG_ID_EQUAL(frag_id, fe->frag_id));
       fe = fe->hash_next)
    ;
  /* If no such entry exists, create one now. */
  if (fe == NULL)
    {
      /* Allocate a fragment magic entry.  This will take one from the
         freelist. */
      SSH_DEBUG(SSH_D_LOWOK, ("Allocating new fragentry"));
      fe = ssh_fastpath_fragmagic_get_entry(fastpath, &frag_free_list);
      memcpy(fe->frag_id, frag_id, sizeof(fe->frag_id));
      fe->expiration = now + SSH_ENGINE_FRAGMENT_TIMEOUT;
      fe->flags = 0;
      fe->min_packet_size = 0;
      fe->next_offset = 0;
      fe->ifnum = pc->pp->ifnum_in;
      fe->tunnel_id = pc->tunnel_id;
      ssh_fastpath_fragmagic_add_hash(fastpath, fe);
      ssh_fastpath_fragmagic_add_all_lru(fastpath, fe);
      SSH_ASSERT(fe->pp_chain == NULL);
    }
  else if ((fe->expiration < engine->run_time)
           || (fastpath->frag_policy != SSH_IPSEC_FRAGS_STRICT_MONITOR
               && (fe->flags & SSH_ENGINE_FRAG_SENT_LAST)))
    {
      /* The fragment entry has expired.  Re-initialize it with new
         data. If fragment policy is "no policy" then allow fragment
         contexts to be reused immediately. */
      SSH_DEBUG(SSH_D_LOWOK, ("Reusing expired/unnecessary fragentry"));
      ssh_fastpath_fragmagic_remove_data_lru(fastpath, fe);
      ssh_fastpath_fragmagic_remove_all_lru(fastpath, fe);
      ssh_fastpath_fragmagic_clear_entry(fastpath, fe, &frag_free_list);
      fe->expiration = now + SSH_ENGINE_FRAGMENT_TIMEOUT;
      fe->flags = 0;
      fe->min_packet_size = 0;
      fe->next_offset = 0;
      fe->ifnum = pc->pp->ifnum_in;
      fe->tunnel_id = pc->tunnel_id;
      ssh_fastpath_fragmagic_add_all_lru(fastpath, fe);
      SSH_ASSERT(fe->pp_chain == NULL);
    }
  else
    {
      if ((fastpath->frag_policy == SSH_IPSEC_FRAGS_LOOSE_MONITOR)
          || (fastpath->frag_policy == SSH_IPSEC_FRAGS_STRICT_MONITOR))
        {
          if (fe->flags & SSH_ENGINE_FRAG_REJECT)
            {
              SSH_DEBUG(SSH_D_NETGARB,
                        ("fragment id collision within reject time window"));
              pc->audit.corruption
                = SSH_PACKET_CORRUPTION_FRAGMENT_ID_COLLISION;
              goto reject;
            }

          if ((fe->flags & SSH_ENGINE_FRAG_SENT_LAST)
              && (fastpath->frag_policy == SSH_IPSEC_FRAGS_LOOSE_MONITOR))
            {
              SSH_DEBUG(SSH_D_NETGARB,
                        ("discarding late extra fragment"));
              pc->audit.corruption =
                SSH_PACKET_CORRUPTION_FRAGMENT_LATE_AND_EXTRA;
              goto reject;
            }
        }
    }

  /* If any fragments require reassembly, mark fragmentation context
     for reassembly */
  if (needs_reassembly)
    fe->flags |= SSH_ENGINE_FRAG_REASSEMBLE;

  /* If the packet is not sane then mark the whole fragmentation
     context to be rejected */
  if (ssh_fastpath_fragmagic_is_sane(fastpath, fe, pc) == FALSE)
    goto reject;

  /* Should we dequeue fragments into the pending packets context
     from the fragmentation context. (E.g. do we now have enough
     information to process them better and does the policy
     allow it). */
  if (fe->pp_chain != NULL && ssh_fastpath_fragmagic_is_dequeue(fastpath, 
								fe, pc))
    {
      SSH_DEBUG(SSH_D_NICETOKNOW,
                ("Dequeing fragments into pending packets"));

      /* Grab relevant state from the dequeued packet, because
         a return value of SSH_ENGINE_RET_RESTART_FLOW_LOOKUP
         signals that the packetcontext can be passed directly. */
      ssh_fastpath_fragmagic_sent(fastpath, fe, pc);
      /* Check if the above function freed pc->pp */
      if (pc->pp == NULL)
	goto error;

      /* Find the end of the pc->pending_packets list (normally it is
         empty, unless we have just added something there). */
      for (ppp = &pc->pending_packets; *ppp; ppp = &(*ppp)->next)
        ;
      /* Move the fragments from the fe chain to the end of the
         pending_packets chain. */
      ssh_fastpath_fragmagic_remove_data_lru(fastpath, fe);
      *ppp = fe->pp_chain;
      fe->pp_chain = NULL;
      /* Update values in each fragment. */
      for (pp = *ppp; pp; pp = pp->next)
        {
          pd = SSH_INTERCEPTOR_PACKET_DATA(pp, SshEnginePacketData);
          memcpy(pd->pending_flow_id, fe->flow_id,
                 sizeof(pd->pending_flow_id));
          pd->pending_ret = SSH_ENGINE_RET_RESTART_FLOW_LOOKUP;
          SSH_DEBUG(SSH_D_MIDOK,
                    ("Dequeued pending fragment offset %u len %u "
                     "flags 0x%08x",
                     pd->frag_ofs, pd->frag_len, pd->frag_flags));
        }

      /* Update bookkeeping in the entry. */
      fastpath->frag_num_fragments -= fe->num_frags;
      fastpath->frag_num_bytes -= fe->total_bytes;
      fe->num_frags = 0;
      fe->total_bytes = 0;
      ssh_fastpath_fragmagic_add_data_lru(fastpath, fe);
      memcpy(pc->flow_id, fe->flow_id, sizeof(pc->flow_id));
      ssh_kernel_mutex_unlock(fastpath->frag_lock);
     
      ssh_fastpath_fragmagic_free_packet_list(frag_free_list);
      return SSH_ENGINE_RET_RESTART_FLOW_LOOKUP;
    }
  /* Check if pc->pp got freed by ssh_fastpath_fragmagic_is_dequeue() */
  if (pc->pp == NULL)
    goto error;






  /* Should we pass the fragment in this packet context through
     without reassembly? */
  if (ssh_fastpath_fragmagic_is_dequeue(fastpath, fe, pc))
    {
      /* Grab relevant state from the dequeued packet */
      ssh_fastpath_fragmagic_sent(fastpath, fe, pc);
      if (pc->pp == NULL)
	goto error;

      SSH_DEBUG(SSH_D_LOWOK,
                ("Passing fragment to flow lookup"));
      SSH_ASSERT(fe->pp_chain == NULL);
      memcpy(pc->flow_id, fe->flow_id, sizeof(pc->flow_id));
      ssh_kernel_mutex_unlock(fastpath->frag_lock);
      
      ssh_fastpath_fragmagic_free_packet_list(frag_free_list);
      return SSH_ENGINE_RET_RESTART_FLOW_LOOKUP;
    }
  /* Check if pc->pp got freed by ssh_fastpath_fragmagic_is_dequeue() */
  if (pc->pp == NULL)
    goto error;

  /* Remove this packet from the LRU lists so that we don't accidentally free
     it from under us. */
  ssh_fastpath_fragmagic_remove_all_lru(fastpath, fe);
  ssh_fastpath_fragmagic_remove_data_lru(fastpath, fe);

  SSH_ASSERT(fastpath->frag_num_fragments <= SSH_ENGINE_FRAGMENT_MAX_PACKETS);
  SSH_ASSERT(fastpath->frag_num_bytes <= SSH_ENGINE_FRAGMENT_MAX_BYTES);

  /* Drop excess old fragments */
  while (fastpath->frag_num_fragments + 1 >= 
	 SSH_ENGINE_FRAGMENT_MAX_PACKETS ||
         fastpath->frag_num_bytes + pc->packet_len >=
         SSH_ENGINE_FRAGMENT_MAX_BYTES)
    {
      SshUInt32 frags_dropped;
      SSH_DEBUG(SSH_D_LOWOK, ("Dropping oldest packet with data"));
      frags_dropped = ssh_fastpath_fragmagic_drop_data(fastpath, 
						       &frag_free_list);
      if (frags_dropped == 0)
        {
          /* If ssh_fastpath_fragmagic_drop_data() could not drop any data,
             it means that value of either SSH_ENGINE_FRAGMENT_MAX_PACKETS
             or SSH_ENGINE_FRAGMENT_MAX_BYTES (configured in ipsec_params.h)
             is too small to contain even this fragmented packet. In that case
             we can only reject this (current packet). */

          ssh_fastpath_fragmagic_add_data_lru(fastpath, fe);
          ssh_fastpath_fragmagic_add_all_lru(fastpath, fe);
          goto reject;
        }
      num_frags += frags_dropped;
    }

  /* Add the fragment into the queue. This will also put it on the data
     LRU if it is not already there and set flags in fe for _is_dequeue() */
  ssh_fastpath_fragmagic_enqueue(fastpath, fe, pc, &frag_free_list);

  pc->pp = NULL;
  pp_chain = NULL;
  chain_len = 0;
  packet_size = 0;

  /* If we have a full packet, take the fragment chain from the entry,
     mark the entry so that it will reject everything, and update global
     counters. */
  if (ssh_fastpath_fragmagic_full_packet(fe))
    {
      packet_size = fe->packet_size;
      SSH_DEBUG(SSH_D_MIDOK, ("Got full packet, size=%d", (int)packet_size));
      pp_chain = fe->pp_chain;
      chain_len = fe->num_frags;
      fe->pp_chain = NULL;
      fe->flags |= SSH_ENGINE_FRAG_REJECT;
      fastpath->frag_num_bytes -= fe->total_bytes;
      fastpath->frag_num_fragments -= fe->num_frags;
      fe->total_bytes = 0;
      fe->num_frags = 0;
      fe->packet_size = 0;
    }

  /* Re-insert the packet at the head of the LRU lists. */
  ssh_fastpath_fragmagic_add_data_lru(fastpath, fe);
  ssh_fastpath_fragmagic_add_all_lru(fastpath, fe);

  /* Unlock the fragment data structures. */
  ssh_kernel_mutex_unlock(fastpath->frag_lock);

  if (pp_chain)
    {
      /* Merge the fragments into a full chain.  This frees pp_chain. */
      SSH_DEBUG(SSH_D_LOWOK, ("Merging fragments into full packet"));
      pc->pp = 
        ssh_fastpath_fragmagic_merge(fastpath, packet_size, 
				     pp_chain, &frag_free_list);
      if (pc->pp == NULL)
        {
#ifdef SSH_IPSEC_STATISTICS
          SshFastpathGlobalStats stats;
	  
          ssh_kernel_critical_section_start(fastpath->stats_critical_section);
          stats = &fastpath->stats[ssh_kernel_get_cpu()];
          stats->counters[SSH_ENGINE_STAT_FRAGDROP] += num_frags;
          stats->counters[SSH_ENGINE_STAT_RESOURCEDROP] += chain_len;
          ssh_kernel_critical_section_end(fastpath->stats_critical_section);
#endif /* SSH_IPSEC_STATISTICS */
          SSH_DEBUG(SSH_D_MIDOK, ("Merge failed"));
      
	  ssh_fastpath_fragmagic_free_packet_list(frag_free_list);
	  return SSH_ENGINE_RET_ERROR;
        }
    }
  
  ssh_fastpath_fragmagic_free_packet_list(frag_free_list);
  if (pc->pp)
    return SSH_ENGINE_RET_RESTART;
  else
    return SSH_ENGINE_RET_DEINITIALIZE;

 reject:
  /* Reject this packet, free queued packets, and cause this entry to
     reject any further packets (until it times out).  The packet should
     be on all LRU lists when we come here. */
  SSH_DEBUG(SSH_D_MIDOK, ("Fragmentation rejecting packet"));
  ssh_kernel_mutex_assert_is_locked(fastpath->frag_lock);
  /* Cause this entry to reject all future packets. */
  fe->flags |= SSH_ENGINE_FRAG_REJECT;
  ssh_fastpath_fragmagic_remove_all_lru(fastpath, fe);
  ssh_fastpath_fragmagic_remove_data_lru(fastpath, fe);
  num_frags += fe->num_frags;
  ssh_fastpath_fragmagic_clear_entry(fastpath, fe, &frag_free_list);
  ssh_fastpath_fragmagic_add_all_lru(fastpath, fe);
  ssh_fastpath_fragmagic_add_data_lru(fastpath, fe);
  ssh_kernel_mutex_unlock(fastpath->frag_lock);
  SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_FRAGDROP);
#ifdef SSH_IPSEC_STATISTICS
  /* Count the previously queued packets that we are dropping. */
  ssh_kernel_critical_section_start(fastpath->stats_critical_section);
  fastpath->stats[ssh_kernel_get_cpu()].counters[SSH_ENGINE_STAT_FRAGDROP] +=
    num_frags;
  ssh_kernel_critical_section_end(fastpath->stats_critical_section);
#endif /* SSH_IPSEC_STATISTICS */

  ssh_fastpath_fragmagic_free_packet_list(frag_free_list);
  return SSH_ENGINE_RET_DROP;

error:
  ssh_kernel_mutex_assert_is_locked(fastpath->frag_lock);
  ssh_kernel_mutex_unlock(fastpath->frag_lock);
#ifdef SSH_IPSEC_STATISTICS
  ssh_kernel_critical_section_start(fastpath->stats_critical_section);
  fastpath->stats[ssh_kernel_get_cpu()].counters[SSH_ENGINE_STAT_FRAGDROP]
    += num_frags;
  fastpath->stats[ssh_kernel_get_cpu()].counters[SSH_ENGINE_STAT_RESOURCEDROP]
    += chain_len;
  ssh_kernel_critical_section_end(fastpath->stats_critical_section);
#endif /* SSH_IPSEC_STATISTICS */

  ssh_fastpath_fragmagic_free_packet_list(frag_free_list);
  return SSH_ENGINE_RET_ERROR;
}
Exemplo n.º 12
0
static void
ssh_fastpath_fragmagic_enqueue(SshFastpath fastpath,
			       SshFastpathFragEntry fe,
			       SshEnginePacketContext pc,
			       SshInterceptorPacket *frag_free_list)
{
  const unsigned char *ucp;
  SshEnginePacketData pd, pd2, prev_pd;
  SshInterceptorPacket pp, *ppp, prev_pp;
  SshInterceptorPacket newfrag;

  ssh_kernel_mutex_assert_is_locked(fastpath->frag_lock);

  newfrag = pc->pp;

#if defined (WITH_IPV6)
  if (newfrag->protocol == SSH_PROTOCOL_IP6)
    {
      pd = SSH_INTERCEPTOR_PACKET_DATA(newfrag, SshEnginePacketData);
      pd->frag_ofs = pc->fragment_offset;
      pd->frag_hdrlen = pc->fragh_offset;
      pd->frag_offset_prevnh = pc->fragh_offset_prevnh;
      /* The fragment's payload is from after the fragmentation header
         to the end of the packet. */
     pd->frag_len =
        pc->packet_len - (pc->fragh_offset + SSH_IP6_EXT_FRAGMENT_HDRLEN);
    }
  else
#endif /* WITH_IPV6 */
    {
      if (fastpath->frag_policy == SSH_IPSEC_FRAGS_NO_FRAGS)
        {
	  pc->pp = NULL;
          ssh_fastpath_fragmagic_packet_free(newfrag, frag_free_list);
          return;
        }

#ifndef SSH_IPSEC_IP_ONLY_INTERCEPTOR
      SSH_ASSERT(pc->protocol_offset == 0);
#endif /* not SSH_IPSEC_IP_ONLY_INTERCEPTOR */

      ucp = ssh_interceptor_packet_pullup(newfrag, SSH_IPH4_HDRLEN);
      if (!ucp)
	{
	  pc->pp = NULL;
	  return;
	}

      SSH_ASSERT(pc->packet_len == SSH_IPH4_LEN(ucp));
      pd = SSH_INTERCEPTOR_PACKET_DATA(newfrag, SshEnginePacketData);
      pd->frag_ofs = 8 * (SSH_IPH4_FRAGOFF(ucp) & SSH_IPH4_FRAGOFF_OFFMASK);
      pd->frag_hdrlen = pc->hdrlen;
      pd->frag_len = pc->packet_len - pc->hdrlen;
    }
  pd->pending_tunnel_id = pc->tunnel_id;

  if (newfrag->flags & SSH_ENGINE_P_FIRSTFRAG)
    pd->frag_flags = SSH_ENGINE_FRAG_QUEUED_FIRST;
  else if (newfrag->flags & SSH_ENGINE_P_LASTFRAG)
    pd->frag_flags = SSH_ENGINE_FRAG_QUEUED_LAST;
  else
    pd->frag_flags = 0;

  SSH_DEBUG(SSH_D_NICETOKNOW,
            ("enqueueing fragment offset %d len %d hdrlen %d flags 0x%08x",
             pd->frag_ofs, pd->frag_len, pd->frag_hdrlen, pd->frag_flags));

  pd->frag_overlap = 0;

  /* Detach fragment from any operating system context data */
  ssh_interceptor_packet_detach(newfrag);

  /* Remove all fragments which overlap with the current fragment */
  for (ppp = &fe->pp_chain; *ppp != NULL;)
    {
      pp = *ppp;
      pd2 = SSH_INTERCEPTOR_PACKET_DATA(pp, SshEnginePacketData);

      if ((pd2->frag_ofs + pd2->frag_len <= pd->frag_ofs)
          && ((pd2->frag_flags & SSH_ENGINE_FRAG_QUEUED_LAST) == 0))
        {
          ppp = &pp->next;
          continue;
        }

      if (pd2->frag_ofs >= pd->frag_len + pd->frag_ofs
          && ((pd->frag_flags & SSH_ENGINE_FRAG_QUEUED_LAST) == 0))
        break;

      fe->flags &= ~pd2->frag_flags;
      fastpath->frag_num_bytes -= pd2->frag_len;
      fe->total_bytes -= pd2->frag_len;

      *ppp = pp->next;
      ssh_fastpath_fragmagic_packet_free(pp, frag_free_list);
    }

  /* Find the place to insert the new packet. */
  prev_pp = NULL;
  prev_pd = NULL;
  pp = NULL;
  pd2 = NULL;
  for (ppp = &fe->pp_chain; *ppp; ppp = &pp->next)
    {
      prev_pp = pp;
      prev_pd = pd2;
      pp = *ppp;
      pd2 = SSH_INTERCEPTOR_PACKET_DATA(pp, SshEnginePacketData);
      if (pd->frag_ofs <= pd2->frag_ofs)
        break;
    }

  /* Just insert the packet */
  newfrag->next = *ppp;
  *ppp = newfrag;
  fe->total_bytes += pd->frag_len;
  fastpath->frag_num_bytes += pd->frag_len;
  fe->num_frags++;
  fastpath->frag_num_fragments++;

  if (!fastpath->frag_timeout_scheduled)
    {
      SSH_DEBUG(SSH_D_MIDOK, ("Fragmagic timer; scheduled"));
      fastpath->frag_timeout_scheduled = 1;
      ssh_kernel_timeout_register(5, 0,
				  ssh_fastpath_fragmagic_timeout, fastpath);
    }

  fe->flags |= pd->frag_flags;
  ssh_fastpath_fragmagic_pullup(fastpath,fe,pc);
  return;
}
Exemplo n.º 13
0
Boolean
ssh_engine_copy_transform_data(SshEngine engine, SshEnginePacketContext pc)
{
  SshEngineTransformData d_trd;
  SshEngineFlowData d_flow = NULL;
  SshEngineFlowControl c_flow;
  SshEngineTransformControl c_trd;
  Boolean rv = FALSE;

  ssh_kernel_mutex_assert_is_locked(engine->flow_control_table_lock);

  /* Perform some checks to verify that the flow and transform objects
     belonging to the packet context are still valid. */

  if (pc->transform_index != SSH_IPSEC_INVALID_INDEX)
    {
      c_trd = SSH_ENGINE_GET_TRD(engine, pc->transform_index);
      if (c_trd == NULL)
	{
	  SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP);
	  SSH_DEBUG(SSH_D_FAIL, ("Transform index is not valid anymore"));
	  return FALSE;
	}
    }

  if (pc->flow_index != SSH_IPSEC_INVALID_INDEX)
    {
      c_flow = SSH_ENGINE_GET_FLOW(engine, pc->flow_index);

      if ((c_flow->control_flags & SSH_ENGINE_FLOW_C_VALID) == 0)
	{
	  SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP);
	  SSH_DEBUG(SSH_D_FAIL, ("Flow disappeared."));
	  return FALSE;
	}
    }

  if (pc->flow_index != SSH_IPSEC_INVALID_INDEX)
    {
      d_flow = FASTPATH_GET_READ_ONLY_FLOW(engine->fastpath, pc->flow_index);

      /* Check the flow is still valid */
      if (d_flow->generation != pc->flow_generation)
	{
	  SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP);
	  SSH_DEBUG(SSH_D_FAIL, ("Flow disappeared."));

	  FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index);
	  return FALSE;
	}
    }

  fastpath_copy_flow_data(engine->fastpath, d_flow, pc);

  if (pc->flow_index != SSH_IPSEC_INVALID_INDEX)
    FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index);
  
  if (pc->transform_index != SSH_IPSEC_INVALID_INDEX)
    {
      d_trd = FASTPATH_GET_READ_ONLY_TRD(engine->fastpath, 
					 pc->transform_index);






      if (d_trd == NULL || d_trd->transform == 0)
	{
	  SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP);
	  SSH_DEBUG(SSH_D_FAIL, ("Transform disappeared."));

	  FASTPATH_RELEASE_TRD(engine->fastpath, pc->transform_index);
	  return FALSE;
	}
      FASTPATH_RELEASE_TRD(engine->fastpath, pc->transform_index);
    }

  rv = fastpath_copy_transform_data(engine->fastpath, pc);

  return rv;
}
Exemplo n.º 14
0
static SshEngineActionRet
engine_packet_handle_flow(SshEngine engine, SshEnginePacketContext pc)
{
  SshEngineFlowControl c_flow;
  SshEngineFlowData d_flow;
  SshEnginePolicyRule rule;
  SshEngineFlowStatus undangle_status;
  SshEngineActionRet ret;
  Boolean forward;

  forward = (pc->flags & SSH_ENGINE_PC_FORWARD) != 0;
  
  /* We are now in "non-fastpath context" */

  ssh_kernel_mutex_assert_is_locked(engine->flow_control_table_lock);

  c_flow = SSH_ENGINE_GET_FLOW(engine, pc->flow_index);
  SSH_ASSERT(c_flow->rule_index != SSH_IPSEC_INVALID_INDEX);
  d_flow = FASTPATH_GET_FLOW(engine->fastpath, pc->flow_index);

  /* Check the flow is still valid */
  if (d_flow->generation != pc->flow_generation
      || (c_flow->control_flags & SSH_ENGINE_FLOW_C_VALID) == 0)
    {
      SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP);
      SSH_DEBUG(SSH_D_FAIL, ("Flow disappeared."));
      
      FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index);
      return SSH_ENGINE_RET_FAIL;
    }

  /* Check if flow is in drop mode. */
  if (d_flow->data_flags & SSH_ENGINE_FLOW_D_DROP_PKTS)
    {
      SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_DROP);
      SSH_DEBUG(SSH_D_NICETOKNOW, ("Flow is in drop mode."));

      FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index);
      return SSH_ENGINE_RET_FAIL;
    }
  
  /* If this is a trigger flow, then it may be that
     our destination next hop node is still undefined, and
     it must be defined, before we can undangle this flow. */
  if ((c_flow->control_flags & SSH_ENGINE_FLOW_C_TRIGGER) && forward)
    {
      SSH_ASSERT((pc->flags & SSH_ENGINE_PC_HIT_TRIGGER) == 0);
      SSH_DEBUG(SSH_D_NICETOKNOW,
		("Packet hit a trigger flow, doing rule execution"));
      pc->flags |= SSH_ENGINE_PC_HIT_TRIGGER;
      SSH_ASSERT(pc->rule == NULL);

      FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index);
      return SSH_ENGINE_RET_OK;
    }

  /* Check if rx_transform_index needs to be updated. */
  if (pc->tunnel_id > 1 && 
      (pc->flags & SSH_ENGINE_PC_SKIP_TRD_VERIFY) == 0 &&
      pc->prev_transform_index != SSH_IPSEC_INVALID_INDEX)
    {
      int i = 0;
      Boolean found_match = FALSE;

      /* Check if packet was decapsulated using transform index in the
         opposite direction. */
      if ((forward
	   && (pc->prev_transform_index == d_flow->reverse_transform_index)) ||
	  (!forward
	   && (pc->prev_transform_index == d_flow->forward_transform_index)))
        found_match = TRUE;
      
      /* Check if packet was decapsulated using one of allowed rx transform
         indexes. */
      else
        {
          for (i = 0; i < SSH_ENGINE_NUM_RX_TRANSFORMS; i++)
            {
	      if ((forward
		   && (d_flow->forward_rx_transform_index[i] 
		       == SSH_IPSEC_INVALID_INDEX))
		  || (!forward
		      && (d_flow->reverse_rx_transform_index[i]
			  == SSH_IPSEC_INVALID_INDEX)))
		break;
	      
              if ((forward
		   && (pc->prev_transform_index
		       == d_flow->forward_rx_transform_index[i]))
		  || (!forward
		      && (pc->prev_transform_index
			  == d_flow->reverse_rx_transform_index[i])))
                {
                  found_match = TRUE;
                  break;
                }
            }
        }
      
      /* Packets's prev_transform_index did not match any allowed transform
         indexes, check packet against rule. */
      if (found_match == FALSE)
	{
	  SSH_DEBUG(SSH_D_LOWOK, 
		    ("Packet was decapsulated using a mismatching "
		     "transform index %lx",
		     (unsigned long) pc->prev_transform_index));
      
	  ret = engine_packet_handler_verify_sa_selectors(engine, pc);
	  if (ret == SSH_ENGINE_RET_OK)
	    {
	      /* Use an unused slot or move all trd indexes one slot
		 earlier and reuse last slot. */
	      if (i == SSH_ENGINE_NUM_RX_TRANSFORMS)
		{
		  for (i = 0; (i + 1) < SSH_ENGINE_NUM_RX_TRANSFORMS; i++)
		    {
		      if (forward)
			d_flow->forward_rx_transform_index[i]
			  = d_flow->forward_rx_transform_index[i+1];
		      else
			d_flow->reverse_rx_transform_index[i]
			  = d_flow->reverse_rx_transform_index[i+1];
		    }
		}
	      SSH_ASSERT(i < SSH_ENGINE_NUM_RX_TRANSFORMS);

	      if (forward)
		d_flow->forward_rx_transform_index[i] 
		  = pc->prev_transform_index;
	      else
		d_flow->reverse_rx_transform_index[i] 
		  = pc->prev_transform_index;
	      
	      SSH_DEBUG(SSH_D_LOWOK,
			("Inbound %s transform index for flow %d "
			 "updated to %lx",
			 (forward ? "forward" : "reverse"),
			 (int) pc->flow_index, 
			 (unsigned long) pc->prev_transform_index));
	      
	      pc->flags |= SSH_ENGINE_PC_SKIP_TRD_VERIFY;
	      
	      FASTPATH_COMMIT_FLOW(engine->fastpath, pc->flow_index, d_flow);
	      return SSH_ENGINE_RET_RESTART_FLOW_LOOKUP;
	    }
	  
	  FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index);
	  return ret;
	}
    }

  FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index);

  rule = SSH_ENGINE_GET_RULE(engine, c_flow->rule_index);

  SSH_DEBUG(SSH_D_NICETOKNOW,
	    ("Packet hit a non-trigger dangling flow!"));
  /* We should try to undangle the flow and restart the packet */

  undangle_status = ssh_engine_flow_undangle(engine, pc->flow_index);

  switch (undangle_status)
    {
    case SSH_ENGINE_FLOW_STATUS_ERROR:
      SSH_DEBUG(SSH_D_NICETOKNOW, ("Error in undangling flow!"));
      ssh_engine_free_flow(engine, pc->flow_index);
      pc->flow_index = SSH_IPSEC_INVALID_INDEX;

      SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP);
      return SSH_ENGINE_RET_FAIL;
      break;

    case SSH_ENGINE_FLOW_STATUS_REVERSE_TRIGGER:
      if (!forward)
	{
	  SSH_DEBUG(SSH_D_FAIL,
		    ("required reverse trigger for tunnel_id=%d",
		     (int) rule->tunnel_id));
	  /* Fall-through to dangle! */
	}
      
    case SSH_ENGINE_FLOW_STATUS_DANGLING:
      SSH_DEBUG(SSH_D_NICETOKNOW,
		("Flow still dangling!"));
      /* Do nothing. Fall-through to trigger generation and THEN
	 drop! */
      break;

      /* The found_flow label requires that flow_table_lock
	 be held. */
    case SSH_ENGINE_FLOW_STATUS_WELL_DEFINED:
      SSH_DEBUG(SSH_D_NICETOKNOW,
		("Flow became well-defined. Handling packet!"));

      /* Pass packet back to fastpath */
      engine_packet_continue(pc, SSH_ENGINE_RET_RESTART_FLOW_LOOKUP);
      return SSH_ENGINE_RET_ASYNC;
      break;

    default:
      SSH_NOTREACHED;
    }

  if (rule->type == SSH_ENGINE_RULE_TRIGGER
      && forward
      && pc->flow_index != SSH_IPSEC_INVALID_INDEX)
    {
      /* This guarantees that we hit a trigger in engine_rule_execute.c */
      pc->flags |= SSH_ENGINE_PC_HIT_TRIGGER;
      /* Ensure that refcounts do not leak. */
      SSH_ASSERT(pc->rule == NULL);
      pc->rule = SSH_ENGINE_GET_RULE(engine, c_flow->rule_index);
      pc->rule->refcnt++;

      return SSH_ENGINE_RET_OK;
    }

  SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP);
  return SSH_ENGINE_RET_FAIL;
}
Exemplo n.º 15
0
static SshEngineActionRet
engine_packet_handler_verify_sa_selectors(SshEngine engine, 
					  SshEnginePacketContext pc)
{
  unsigned char src_ip[SSH_IP_ADDR_SIZE], dst_ip[SSH_IP_ADDR_SIZE];
  SshUInt16 src_port, dst_port;
  size_t ip_len;
  SshEngineTransformControl c_trd;
  SshUInt32 rule_index;
  SshEnginePolicyRule rule;
#ifdef SSHDIST_L2TP
  SshEngineTransformData d_trd;
#endif /* SSHDIST_L2TP */

  SSH_ASSERT(pc->pp != NULL);
  SSH_ASSERT(pc->prev_transform_index != SSH_IPSEC_INVALID_INDEX);

  ssh_kernel_mutex_assert_is_locked(engine->flow_control_table_lock);
  
  SSH_DEBUG(SSH_D_MIDOK, 
	    ("Verifying that decapsulated packet matches the SA selectors "
	     "of transform 0x%lx",
	     (unsigned long) pc->prev_transform_index));





  /* Fetch transform used for decapsulation. */
  c_trd = SSH_ENGINE_GET_TRD(engine, pc->prev_transform_index);
  if (c_trd == NULL)
    {
      SSH_DEBUG(SSH_D_FAIL, 
		("Transform has 0x%lx disappeared for decapsulated packet",
		 (unsigned long) pc->prev_transform_index));
      SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP);
      return SSH_ENGINE_RET_FAIL;
    }

#ifdef SSHDIST_L2TP
  d_trd = FASTPATH_GET_READ_ONLY_TRD(engine->fastpath, 
				     pc->prev_transform_index);
  if (d_trd->transform & SSH_PM_IPSEC_L2TP)
    {      
      FASTPATH_RELEASE_TRD(engine->fastpath, pc->prev_transform_index);
      SSH_DEBUG(SSH_D_LOWOK, ("Skipping SA selector check for l2tp packet"));
      return SSH_ENGINE_RET_OK;
    }

  FASTPATH_RELEASE_TRD(engine->fastpath, pc->prev_transform_index);
#endif /* SSHDIST_L2TP */

  engine_packet_handler_lookup_prepare(pc,
				       src_ip, &src_port, 
				       dst_ip, &dst_port,
				       &ip_len);

  /* Find APPLY rule to the transform. */
  for (rule_index = c_trd->rules; 
       rule_index != SSH_IPSEC_INVALID_INDEX; 
       rule_index = rule->trd_next)
    {
      rule = SSH_ENGINE_GET_RULE(engine, rule_index);
      SSH_ASSERT(rule != NULL);      
      if (rule->type == SSH_ENGINE_RULE_APPLY)
	{
	  /* Compare packet 5-tupple to SA selectors in APPLY rule.
	     Note that APPLY rule is for reverse direction, thus packet 
	     source/destination addresses and ports must be compared to 
	     the opposite rule selector. */
	  if (rule->protocol != pc->pp->protocol)
	    {
	      SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: protocol mismatch",
				      (int) rule_index));
	      continue;
	    }

	  if ((rule->selectors & SSH_SELECTOR_SRCIP)
	      && (memcmp(rule->src_ip_low, dst_ip, ip_len) > 0
		  || memcmp(rule->src_ip_high, dst_ip, ip_len) < 0))
	    {
	      SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: destination IP mismatch",
				      (int) rule_index));
	      continue;
	    }
	  
	  if ((rule->selectors & SSH_SELECTOR_DSTIP)
	      && (memcmp(rule->dst_ip_low, src_ip, ip_len) > 0
		  || memcmp(rule->dst_ip_high, src_ip, ip_len) < 0))
	    {
	      SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: source IP mismatch",
				      (int) rule_index));
	      continue;
	    }
	  
	  if ((rule->selectors & SSH_SELECTOR_IPPROTO) 
	      && rule->ipproto != pc->ipproto)
	    {
	      SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: IP protocol mismatch",
				      (int) rule_index));
	      continue;
	    }

	  if ((rule->selectors & SSH_SELECTOR_SRCPORT)
	      && (rule->src_port_low > dst_port 
		  || rule->src_port_high < dst_port))
	    {
	      SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: destination port mismatch",
				      (int) rule_index));
	      continue;
	    }

	  if (rule->selectors & SSH_SELECTOR_DSTPORT)
	    {
	      if ((rule->selectors & SSH_SELECTOR_ICMPTYPE)
		  && ((rule->dst_port_low & 0xff00) != (dst_port & 0xff00)))
		{
		  SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: ICMP type mismatch",
					  (int) rule_index));
		  continue;
		}

	      if ((rule->selectors & SSH_SELECTOR_ICMPCODE)
		  && ((rule->dst_port_low & 0x00ff) != (dst_port & 0x00ff)))
		{
		  SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: ICMP code mismatch",
					  (int) rule_index));
		  continue;
		}
		
	      if ((rule->selectors & 
		   (SSH_SELECTOR_ICMPTYPE | SSH_SELECTOR_ICMPCODE)) == 0
		  && (rule->dst_port_low > src_port 
		      || rule->dst_port_high < src_port))
		{
		  SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: source port mismatch",
					  (int) rule_index));
		  continue;
		}
	    }

	  /* Packet fits into SA selectors. */
	  SSH_DEBUG(SSH_D_MIDOK, 
		    ("Rule %d: decapsulated packet matches SA selectors",
		     (int) rule_index));
	  return SSH_ENGINE_RET_OK;
	}
    }

  SSH_ASSERT(rule_index == SSH_IPSEC_INVALID_INDEX);
  
  SSH_DEBUG(SSH_D_MIDOK, 
	    ("Decapsulated packet does not match the SA selectors, "
	     "dropping packet."));
  pc->audit.corruption = SSH_PACKET_CORRUPTION_IPSEC_INVALID_SELECTORS;
  return SSH_ENGINE_RET_DROP;
}
Exemplo n.º 16
0
void
sw_fastpath_commit_trd(SshFastpath fastpath, SshUInt32 trd_index,
		       SshEngineTransformData data)
{
  SshEngineTransformData trd;

  ssh_kernel_mutex_assert_is_locked(fastpath->engine->flow_control_table_lock);







  trd = swi_fastpath_get_trd_lock(fastpath, trd_index, FALSE);
  SSH_ASSERT(data == trd);

  SSH_ASSERT((trd_index & 0xffffff) < fastpath->transform_table_size);

#ifdef SSHDIST_IPSEC_TRANSFORM
  /* SA addresses and/or NAT-T remote port has been updated */
  if (SSH_IP_DEFINED(&fastpath->trd_cache->own_addr) && 
      SSH_IP_DEFINED(&fastpath->trd_cache->gw_addr) &&
      (SSH_IP_CMP(&data->own_addr, &fastpath->trd_cache->own_addr) ||
       SSH_IP_CMP(&data->gw_addr, &fastpath->trd_cache->gw_addr) 
       || data->remote_port != fastpath->trd_cache->remote_port
       ))
    {
      ssh_fastpath_update_sa_tc(fastpath, fastpath->trd_cache->transform, 
				fastpath->trd_cache->old_keymat,
				fastpath->trd_cache->
				old_spis[SSH_PME_SPI_AH_IN],
				fastpath->trd_cache->
				old_spis[SSH_PME_SPI_ESP_IN],
				FALSE, /* for_output */
				fastpath->trd_cache->is_ipv6,
				&data->own_addr,
				&data->gw_addr, 
				data->remote_port);
      
      ssh_fastpath_update_sa_tc(fastpath, fastpath->trd_cache->transform, 
				fastpath->trd_cache->keymat,
				fastpath->trd_cache->spis[SSH_PME_SPI_AH_IN],
				fastpath->trd_cache->spis[SSH_PME_SPI_ESP_IN],
				FALSE, /* for_output */
				fastpath->trd_cache->is_ipv6,
				&data->own_addr,
				&data->gw_addr, 
				data->remote_port);
      
      ssh_fastpath_update_sa_tc(fastpath, fastpath->trd_cache->transform, 
				fastpath->trd_cache->keymat +
				(SSH_IPSEC_MAX_KEYMAT_LEN / 2),
				fastpath->trd_cache->spis[SSH_PME_SPI_AH_OUT],
				fastpath->trd_cache->spis[SSH_PME_SPI_ESP_OUT],
				TRUE, /* for_output */
				fastpath->trd_cache->is_ipv6,
				&data->own_addr,
				&data->gw_addr, 
				data->remote_port);
    }

  /* Inbound SPI was rekeyed */  
  if ((data->spis[SSH_PME_SPI_ESP_IN] 
       != fastpath->trd_cache->spis[SSH_PME_SPI_ESP_IN]) ||
      (data->spis[SSH_PME_SPI_AH_IN] 
       != fastpath->trd_cache->spis[SSH_PME_SPI_AH_IN]))
    {
      /* If we still have previous old SA around, free any transform
	 contexts relating to it now. */
      if (fastpath->trd_cache->old_spis[SSH_PME_SPI_AH_IN] != 0 ||
	  fastpath->trd_cache->old_spis[SSH_PME_SPI_ESP_IN] != 0)
	ssh_fastpath_destroy_sa_tc(fastpath, fastpath->trd_cache->transform,
				   fastpath->trd_cache->old_keymat,
				   fastpath->trd_cache->
				   old_spis[SSH_PME_SPI_AH_IN],
				   fastpath->trd_cache->
				   old_spis[SSH_PME_SPI_ESP_IN],
				   FALSE, /* for_output */
				   fastpath->trd_cache->is_ipv6);
    }
  
  /* Old inbound SPI's are invalidated */
  if ((data->old_spis[SSH_PME_SPI_ESP_IN] 
       != fastpath->trd_cache->old_spis[SSH_PME_SPI_ESP_IN] && 
       data->old_spis[SSH_PME_SPI_ESP_IN] == 0) ||
      (data->old_spis[SSH_PME_SPI_AH_IN] 
       != fastpath->trd_cache->old_spis[SSH_PME_SPI_AH_IN] && 
       data->old_spis[SSH_PME_SPI_AH_IN] == 0))
    
    {
      ssh_fastpath_destroy_sa_tc(fastpath, fastpath->trd_cache->transform,
				 fastpath->trd_cache->old_keymat,
				 fastpath->trd_cache->
				 old_spis[SSH_PME_SPI_AH_IN],
				 fastpath->trd_cache->
				 old_spis[SSH_PME_SPI_ESP_IN],
				 FALSE, /* for_output */
				 fastpath->trd_cache->is_ipv6);
    }

  /* Outbound SA was rekeyed */
  if ((data->spis[SSH_PME_SPI_ESP_OUT] 
       != fastpath->trd_cache->spis[SSH_PME_SPI_ESP_OUT]) ||
      (data->spis[SSH_PME_SPI_AH_OUT] 
       != fastpath->trd_cache->spis[SSH_PME_SPI_AH_OUT]))
    {
      /* Outbound SA was rekeyed. Destroy any old transform contexts for 
	 the outbound SA. */
      ssh_fastpath_destroy_sa_tc(fastpath, fastpath->trd_cache->transform,
				 fastpath->trd_cache->keymat +
				 (SSH_IPSEC_MAX_KEYMAT_LEN / 2),
				 fastpath->trd_cache->spis[SSH_PME_SPI_AH_OUT],
				 fastpath->trd_cache->
				 spis[SSH_PME_SPI_ESP_OUT],
				 TRUE, /* for_output */
				 fastpath->trd_cache->is_ipv6);
    }
#endif /* SSHDIST_IPSEC_TRANSFORM */

  /* Release the lock on the transform table element */
  FP_COMMIT_TRD(fastpath, trd_index, trd);
}