embedded IPsec source code documentation


ipsec.c

Go to the documentation of this file.
00001 /*
00002  * embedded IPsec       
00003  * Copyright (c) 2003 Niklaus Schild and Christian Scheurer, HTI Biel/Bienne
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without modification,
00007  * are permitted provided that the following conditions are met:
00008  *
00009  * 1. Redistributions of source code must retain the above copyright notice,
00010  *    this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright notice,
00012  *    this list of conditions and the following disclaimer in the documentation
00013  *    and/or other materials provided with the distribution.
00014  * 3. The name of the author may not be used to endorse or promote products
00015  *    derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00018  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00020  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00021  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00022  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00023  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00024  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00025  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00026  * OF SUCH DAMAGE.
00027  *
00028  */
00029 
00056 #include "ipsec/debug.h"
00057 
00058 #include "ipsec/ipsec.h"
00059 #include "ipsec/util.h"
00060 #include "ipsec/sa.h"
00061 #include "ipsec/ah.h"
00062 #include "ipsec/esp.h"
00063 
00064 
00065 
00081 int ipsec_input(unsigned char *packet, int packet_size, 
00082                 int *payload_offset, int *payload_size, 
00083                                 db_set_netif *databases)
00084 {
00085         int ret_val     = IPSEC_STATUS_NOT_INITIALIZED; /* by default, the return value is undefined  */
00086         int dummy       = packet_size;                                  /* dummy operation to avoid compiler warnings */
00087         sad_entry               *sa ;
00088         spd_entry               *spd ;
00089         ipsec_ip_header *ip ;
00090         ipsec_ip_header *inner_ip ;
00091         __u32                   spi ;
00092 
00093         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00094                       "ipsec_input", 
00095                                   ("*packet=%p, packet_size=%d, len=%u, *payload_offset=%d, *payload_size=%d databases=%p",
00096                               (void *)packet, packet_size, (int)*payload_offset, (int)*payload_size, (void *)databases)
00097                                  );
00098 
00099         IPSEC_DUMP_BUFFER(" INBOUND ESP or AH:", packet, 0, packet_size);
00100         
00101         ip = (ipsec_ip_header*)packet ;
00102         spi = ipsec_sad_get_spi(ip) ;
00103         sa = ipsec_sad_lookup(ip->dest, ip->protocol, spi, &databases->inbound_sad) ;
00104 
00105         if(sa == NULL)
00106         {
00107                 IPSEC_LOG_AUD("ipsec_input", IPSEC_AUDIT_FAILURE, ("no matching SA found")) ;
00108                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_input", ("return = %d", IPSEC_STATUS_FAILURE) );
00109                 return IPSEC_STATUS_FAILURE;
00110         }
00111 
00112         if(sa->mode != IPSEC_TUNNEL) 
00113         {
00114                 IPSEC_LOG_ERR("ipsec_input", IPSEC_STATUS_FAILURE, ("unsupported transmission mode (only IPSEC_TUNNEL is supported)") );
00115                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_input", ("return = %d", IPSEC_STATUS_FAILURE) );
00116                 return IPSEC_STATUS_FAILURE;
00117         }
00118 
00119         if(sa->protocol == IPSEC_PROTO_AH)
00120         {
00121                 ret_val = ipsec_ah_check((ipsec_ip_header *)packet, payload_offset, payload_size, sa);
00122                 if(ret_val != IPSEC_STATUS_SUCCESS) 
00123                 {
00124                         IPSEC_LOG_ERR("ipsec_input", ret_val, ("ah_packet_check() failed") );
00125                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_input", ("ret_val=%d", ret_val) );
00126                         return ret_val;
00127                 }
00128 
00129         } else if (sa->protocol == IPSEC_PROTO_ESP)
00130         {
00131                 ret_val = ipsec_esp_decapsulate((ipsec_ip_header *)packet, payload_offset, payload_size, sa);
00132                 if(ret_val != IPSEC_STATUS_SUCCESS) 
00133                 {
00134                         IPSEC_LOG_ERR("ipsec_input", ret_val, ("ipsec_esp_decapsulate() failed") );
00135                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_input", ("ret_val=%d", ret_val) );
00136                         return ret_val;
00137                 }
00138 
00139         } else
00140         {
00141                 IPSEC_LOG_ERR("ipsec_input", IPSEC_STATUS_FAILURE, ("invalid protocol from SA") );
00142                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_input", ("ret_val=%d", IPSEC_STATUS_FAILURE) );
00143                 return IPSEC_STATUS_FAILURE;
00144         }
00145 
00146         inner_ip = (ipsec_ip_header *)(((unsigned char *)ip) + *payload_offset) ;
00147 
00148         spd = ipsec_spd_lookup(inner_ip, &databases->inbound_spd) ;
00149         if(spd == NULL)
00150         {
00151                 IPSEC_LOG_AUD("ipsec_input", IPSEC_AUDIT_FAILURE, ("no matching SPD found")) ;
00152                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_input", ("ret_val=%d", IPSEC_STATUS_FAILURE) );
00153                 return IPSEC_STATUS_FAILURE;
00154         }
00155         
00156         if(spd->policy == POLICY_APPLY)
00157         {
00158                 if(spd->sa != sa)
00159                 {
00160                         IPSEC_LOG_AUD("ipsec_input", IPSEC_AUDIT_SPI_MISMATCH, ("SPI mismatch") );
00161                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_input", ("return = %d", IPSEC_AUDIT_SPI_MISMATCH) );
00162                         return IPSEC_STATUS_FAILURE;
00163                 }
00164         }
00165         else
00166         {
00167                         IPSEC_LOG_AUD("ipsec_input", IPSEC_AUDIT_POLICY_MISMATCH, ("matching SPD does not permit IPsec processing") );
00168                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_input", ("return = %d", IPSEC_STATUS_FAILURE) );
00169                         return IPSEC_STATUS_FAILURE;
00170         }
00171 
00172         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_input", ("return = %d", IPSEC_STATUS_SUCCESS) );
00173         return IPSEC_STATUS_SUCCESS;
00174 }
00175 
00176 
00193 int ipsec_output(unsigned char *packet, int packet_size, int *payload_offset, int *payload_size,
00194                  __u32 src, __u32 dst, spd_entry *spd)
00195 {
00196         int ret_val = IPSEC_STATUS_NOT_INITIALIZED;             /* by default, the return value is undefined */
00197         ipsec_ip_header         *ip ;
00198 
00199         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00200                       "ipsec_output", 
00201                                   ("*packet=%p, packet_size=%d, len=%u, *payload_offset=%d, *payload_size=%d src=%lx dst=%lx *spd=%p",
00202                               (void *)packet, packet_size, *payload_offset, *payload_size, (__u32) src, (__u32) dst, (void *)spd)
00203                                  );
00204 
00205         ip = (ipsec_ip_header*)packet;
00206 
00207         if((ip == NULL) || (ipsec_ntohs(ip->len) > packet_size)) 
00208         {
00209                 IPSEC_LOG_DBG("ipsec_output", IPSEC_STATUS_NOT_IMPLEMENTED, ("bad packet ip=%p, ip->len=%d (must not be >%d bytes)", (void *)ip, ipsec_ntohs(ip->len), packet_size) );
00210 
00211                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_output", ("return = %d", IPSEC_STATUS_BAD_PACKET) );
00212             return IPSEC_STATUS_BAD_PACKET;
00213         }
00214         
00215         if((spd == NULL) || (spd->sa == NULL))
00216         {
00218                 IPSEC_LOG_DBG("ipsec_output", IPSEC_STATUS_NOT_IMPLEMENTED, ("unable to generate dynamically an SA (IKE not implemented)") );
00219 
00220                 IPSEC_LOG_AUD("ipsec_output", IPSEC_STATUS_NO_SA_FOUND, ("no SA or SPD defined")) ;
00221                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_output", ("return = %d", IPSEC_STATUS_NO_SA_FOUND) );
00222             return IPSEC_STATUS_NO_SA_FOUND;
00223         }
00224 
00225         switch(spd->sa->protocol) {
00226                 case IPSEC_PROTO_AH:
00227                                 IPSEC_LOG_MSG("ipsec_output", ("have to encapsulate an AH packet")) ;
00228                                 ret_val = ipsec_ah_encapsulate((ipsec_ip_header *)packet, payload_offset, payload_size, spd->sa, src, dst);
00229                 
00230                                 if(ret_val != IPSEC_STATUS_SUCCESS) 
00231                                 {
00232                                         IPSEC_LOG_ERR("ipsec_output", ret_val, ("ipsec_ah_encapsulate() failed"));
00233                                 }
00234                         break;
00235 
00236                 case IPSEC_PROTO_ESP:
00237                                 IPSEC_LOG_MSG("ipsec_output", ("have to encapsulate an ESP packet")) ;
00238                                 ret_val = ipsec_esp_encapsulate((ipsec_ip_header *)packet, payload_offset, payload_size, spd->sa, src, dst);
00239                         
00240                                 if(ret_val != IPSEC_STATUS_SUCCESS) 
00241                                 {
00242                                         IPSEC_LOG_ERR("ipsec_output", ret_val, ("ipsec_esp_encapsulate() failed"));
00243                                 }
00244                         break;
00245 
00246                 default:
00247                                 ret_val = IPSEC_STATUS_BAD_PROTOCOL;
00248                                 IPSEC_LOG_ERR("ipsec_output", ret_val, ("unsupported protocol '%d' in spd->sa->protocol", spd->sa->protocol));
00249         }
00250 
00251         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_output", ("ret_val=%d", ret_val) );
00252         return ret_val;
00253 }
00254 
00255 

Copyright 2003 by Christian Scheurer and Niklaus Schild