embedded IPsec source code documentation


sa.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 
00081 #include <string.h>
00082 
00083 #include "ipsec/debug.h"
00084 #include "ipsec/util.h"
00085 
00086 #include "ipsec/sa.h"
00087 #include "ipsec/ah.h"
00088 #include "ipsec/esp.h"
00089 
00090 
00096 db_set_netif    db_sets[IPSEC_NR_NETIFS] ;
00097 
00098 typedef struct ipsec_in_ip_struct 
00099 {
00100         ipsec_ip_header          ip ;   
00101         union 
00102         {
00103                 ipsec_ah_header  ah ;   
00104                 ipsec_esp_header esp ;  
00105                 ipsec_tcp_header tcp ;  
00106                 ipsec_udp_header udp ;  
00107         } inner_header ;        
00108 } ipsec_in_ip ;
00109 
00110 
00111 
00136 db_set_netif    *ipsec_spd_load_dbs(spd_entry *inbound_spd_data, spd_entry *outbound_spd_data, sad_entry *inbound_sad_data, sad_entry *outbound_sad_data)
00137 {
00138         int netif ;
00139         int index ;
00140         spd_entry       *sp, *sp_next, *sp_prev ;
00141         sad_entry       *sa, *sa_next, *sa_prev ;
00142 
00143         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00144                       "ipsec_spd_load_dbs", 
00145                                   ("inbound_spd_data=%p, outbound_spd_data=%p, inbound_sad_data=%p, outbound_sad_data=%p",
00146                               (void *)inbound_spd_data, (void *)outbound_spd_data, (void *)inbound_sad_data, (void *)outbound_sad_data)
00147                                  );
00148         
00149         /* get free entry */
00150         for(netif=0; netif < IPSEC_NR_NETIFS; netif++)
00151         {
00152                 if(db_sets[netif].use_flag == IPSEC_FREE) break ;
00153         }
00154         if(netif >= IPSEC_NR_NETIFS)
00155         {
00156                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_load_dbs", ("%p", (void *)NULL) );
00157                 return NULL;
00158         }
00159 
00160         /* index points now the a free entry which is filled with the initialization data */
00161         db_sets[netif].inbound_spd.table = inbound_spd_data ;
00162         db_sets[netif].outbound_spd.table = outbound_spd_data ;
00163         db_sets[netif].inbound_sad.table = inbound_sad_data ;
00164         db_sets[netif].outbound_sad.table = outbound_sad_data ;
00165 
00166         db_sets[netif].use_flag = IPSEC_USED ;
00167 
00168         /* set none used entries from the tables to FREE */
00169         for(index=0; index < IPSEC_MAX_SPD_ENTRIES; index++)
00170                 if(db_sets[netif].inbound_spd.table[index].use_flag != IPSEC_USED)
00171                         db_sets[netif].inbound_spd.table[index].use_flag = IPSEC_FREE ;
00172 
00173         for(index=0; index < IPSEC_MAX_SPD_ENTRIES; index++)
00174                 if(db_sets[netif].inbound_sad.table[index].use_flag != IPSEC_USED)
00175                         db_sets[netif].inbound_sad.table[index].use_flag = IPSEC_FREE ;
00176         
00177         for(index=0; index < IPSEC_MAX_SAD_ENTRIES; index++)
00178                 if(db_sets[netif].outbound_spd.table[index].use_flag != IPSEC_USED)
00179                         db_sets[netif].outbound_spd.table[index].use_flag = IPSEC_FREE ;
00180 
00181         for(index=0; index < IPSEC_MAX_SAD_ENTRIES; index++)
00182                 if(db_sets[netif].outbound_sad.table[index].use_flag != IPSEC_USED)
00183                         db_sets[netif].outbound_sad.table[index].use_flag = IPSEC_FREE ;
00184 
00185         /* link the database entries together */
00186 
00187         /* inbound spd data */
00188         sp = inbound_spd_data ;
00189         /* if first entry is IPSEC_FREE, then there is nothing */
00190         if(sp->use_flag == IPSEC_USED)
00191         {
00192                 db_sets[netif].inbound_spd.first = sp ; 
00193         
00194                 if ((sp+1)->use_flag == IPSEC_USED)
00195                 {
00196                         sp_next = (sp+1) ;
00197                 }
00198                 else
00199                 {
00200                         sp_next = NULL ;
00201                 }
00202         
00203                 for(index=0, sp_prev=NULL;
00204                         (index < IPSEC_MAX_SPD_ENTRIES) && (sp[index+1].use_flag == IPSEC_USED);
00205                     sp_prev = &sp[index], sp_next = &sp[index+2], index++)
00206                         {
00207                                 sp[index].prev = sp_prev ;
00208                                 sp[index].next = sp_next ;
00209                         }
00210         
00211                         sp[index].next = NULL ;
00212                         db_sets[netif].inbound_spd.last = &sp[index] ;  
00213         }
00214         else
00215         {
00216                 /* there was no data */
00217                 db_sets[netif].inbound_spd.first = NULL ;
00218                 db_sets[netif].inbound_spd.last = NULL ;
00219         }
00220 
00221         /* outbound spd data */
00222         sp = outbound_spd_data ;
00223         /* if first entry is IPSEC_FREE, then there is nothing */
00224         if(sp->use_flag == IPSEC_USED)
00225         {
00226                 db_sets[netif].outbound_spd.first = sp ;        
00227         
00228                 if ((sp+1)->use_flag == IPSEC_USED)
00229                 {
00230                         sp_next = (sp+1) ;
00231                 }
00232                 else
00233                 {
00234                         sp_next = NULL ;
00235                 }
00236         
00237                 for(index=0, sp_prev=NULL;
00238                         (index < IPSEC_MAX_SPD_ENTRIES) && (sp[index+1].use_flag == IPSEC_USED);
00239                     sp_prev = &sp[index], sp_next = &sp[index+2], index++)
00240                         {
00241                                 sp[index].prev = sp_prev ;
00242                                 sp[index].next = sp_next ;
00243                         }
00244         
00245                         sp[index].next = NULL ;
00246                         db_sets[netif].outbound_spd.last = &sp[index] ; 
00247         }
00248         else
00249         {
00250                 /* there was no data */
00251                 db_sets[netif].outbound_spd.first = NULL ;
00252                 db_sets[netif].outbound_spd.last = NULL ;
00253         }
00254 
00255 
00256         /* inbound sad data */
00257         sa = inbound_sad_data ;
00258         /* if first entry is IPSEC_FREE, then there is nothing */
00259         if(sa->use_flag == IPSEC_USED)
00260         {
00261                 db_sets[netif].inbound_sad.first = sa ; 
00262         
00263                 if ((sa+1)->use_flag == IPSEC_USED)
00264                 {
00265                         sa_next = (sa+1) ;
00266                 }
00267                 else
00268                 {
00269                         sa_next = NULL ;
00270                 }
00271         
00272                 for(index=0, sa_prev=NULL;
00273                         (index < IPSEC_MAX_SAD_ENTRIES) && (sa[index+1].use_flag == IPSEC_USED);
00274                     sa_prev = &sa[index], sa_next = &sa[index+2], index++)
00275                         {
00276                                 sa[index].prev = sa_prev ;
00277                                 sa[index].next = sa_next ;
00278                         }
00279         
00280                         sa[index].next = NULL ;
00281                         db_sets[netif].inbound_sad.last = &sa[index] ;  
00282         }
00283         else
00284         {
00285                 /* there was no data */
00286                 db_sets[netif].inbound_sad.first = NULL ;
00287                 db_sets[netif].inbound_sad.last = NULL ;
00288         }
00289 
00290         /* outbound sad data */
00291         sa = outbound_sad_data ;
00292         /* if first entry is IPSEC_FREE, then there is nothing */
00293         if(sa->use_flag == IPSEC_USED)
00294         {
00295                 db_sets[netif].outbound_sad.first = sa ;        
00296         
00297                 if ((sa+1)->use_flag == IPSEC_USED)
00298                 {
00299                         sa_next = (sa+1) ;
00300                 }
00301                 else
00302                 {
00303                         sa_next = NULL ;
00304                 }
00305         
00306                 for(index=0, sa_prev=NULL;
00307                         (index < IPSEC_MAX_SAD_ENTRIES) && (sa[index+1].use_flag == IPSEC_USED);
00308                     sa_prev = &sa[index], sa_next = &sa[index+2], index++)
00309                         {
00310                                 sa[index].prev = sa_prev ;
00311                                 sa[index].next = sa_next ;
00312                         }
00313         
00314                         sa[index].next = NULL ;
00315                         db_sets[netif].outbound_sad.last = &sa[index] ; 
00316         }
00317         else
00318         {
00319                 /* there was no data */
00320                 db_sets[netif].outbound_sad.first = NULL ;
00321                 db_sets[netif].outbound_sad.last = NULL ;
00322         }
00323 
00324         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_load_dbs", ("&db_sets[netif] = %p", &db_sets[netif]) );
00325         return &db_sets[netif] ;
00326 }
00327 
00336 ipsec_status ipsec_spd_release_dbs(db_set_netif *dbs)
00337 {
00338         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00339                       "ipsec_spd_release_dbs", 
00340                                   ("dbs=%p",
00341                               (void *)dbs)
00342                                  );
00343 
00344         dbs->inbound_spd.first = NULL ;
00345         dbs->inbound_spd.last = NULL ;
00346         dbs->inbound_spd.table = NULL ;
00347 
00348         dbs->outbound_spd.first = NULL ;
00349         dbs->outbound_spd.last = NULL ;
00350         dbs->outbound_spd.table = NULL ;
00351 
00352         dbs->inbound_sad.first = NULL ;
00353         dbs->inbound_sad.last = NULL ;
00354         dbs->inbound_sad.table = NULL ;
00355 
00356         dbs->outbound_sad.first = NULL ;
00357         dbs->outbound_sad.last = NULL ;
00358         dbs->outbound_sad.table = NULL ;
00359 
00360         dbs->use_flag = IPSEC_FREE ;
00361 
00362         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_load_dbs", ("return = %d", IPSEC_STATUS_SUCCESS));
00363         return IPSEC_STATUS_SUCCESS ;
00364 }
00365 
00375 spd_entry *ipsec_spd_get_free(spd_table *table)
00376 {
00377         int index ;
00378         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00379                       "ipsec_spd_get_free", 
00380                                   ("table=%p",
00381                               (void *)table)
00382                                  );
00383 
00384         /* find first free entry */
00385         for(index = 0; index < IPSEC_MAX_SPD_ENTRIES; index++)
00386         {
00387                 if (table->table[index].use_flag == IPSEC_FREE)
00388                         break ;
00389         }
00390         /* if no free entry */
00391         if (index >= IPSEC_MAX_SPD_ENTRIES)
00392         {
00393                 return NULL ;
00394         }
00395 
00396         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_get_free", ("&table->table[index] = %p", &table->table[index]));
00397         return &table->table[index] ;
00398 }
00399 
00428 spd_entry *ipsec_spd_add(__u32 src, __u32 src_net, __u32 dst, __u32 dst_net, __u8 proto, __u16 src_port, __u16 dst_port, __u8 policy, spd_table *table)
00429 {
00430         spd_entry       *free_entry ;
00431         spd_entry       *tmp_entry ;
00432         int                     table_size ;
00433 
00434         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00435               "ipsec_spd_add", 
00436                           ("src=%lu, src_net=%lu, dst=%lu, dst_net=%lu, proto=%u, src_port=%u, dst_port=%u, policy=%u, table=%p",
00437                       src, src_net, dst, dst_net, proto, src_port, dst_port, policy, (void *)table)
00438                          );
00439 
00440         table_size = table->size ;
00441 
00442         free_entry = ipsec_spd_get_free(table) ;
00443         if (free_entry == NULL) 
00444         {
00445                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_add", ("%p", (void *)NULL) );
00446                 return NULL ;
00447         }
00448 
00449         /* add the fields to the entry */
00450         free_entry->src = src ;
00451         free_entry->src_netaddr = src_net ;
00452         free_entry->dest = dst ;
00453         free_entry->dest_netaddr = dst_net ;
00454 
00455         free_entry->protocol = proto ;
00456         free_entry->src_port = src_port ;
00457         free_entry->dest_port = dst_port ;
00458         free_entry->policy = policy ;
00459 
00460         free_entry->use_flag = IPSEC_USED ;
00461 
00462         /* re-link entry */
00465         /* if added first entry in array */
00466         if(table->first == NULL)
00467         {
00468                 table->first = free_entry ;
00469                 table->first->next = NULL ;
00470                 table->first->prev = NULL ;
00471                 table->last = free_entry ;
00472         }
00473         else
00474         {
00475                 /* go till end of list */
00476                 for(tmp_entry = table->first; tmp_entry->next != NULL; tmp_entry = tmp_entry->next)
00477                 {
00478                 }
00479 
00480                 /* inset at end */
00481                 free_entry->prev = tmp_entry ;
00482                 tmp_entry->next = free_entry ;
00483                 free_entry->next = NULL ;
00484         }
00485 
00486         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_add", ("free_entry=%p", (void *)free_entry) );
00487         return free_entry ;
00488 }
00496 ipsec_status ipsec_spd_add_sa(spd_entry *entry, sad_entry *sa)
00497 {
00498         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00499               "ipsec_spd_add_sa", 
00500                           ("entry=%p, sa=%p",
00501                       (void *)entry, (void *)sa)
00502                          );
00503 
00504         entry->sa = sa ;
00505 
00506         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_add_sa", ("return = %d", IPSEC_STATUS_SUCCESS) );
00507         return IPSEC_STATUS_SUCCESS ;
00508 }
00509 
00523 ipsec_status ipsec_spd_del(spd_entry *entry, spd_table *table)
00524 {
00525         spd_entry               *next_ptr ;
00526         spd_entry               *prev_ptr ;
00527 
00528         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00529               "ipsec_spd_del", 
00530                           ("entry=%p, table=%p",
00531                       (void *)entry, (void *)table)
00532                          );
00533 
00534         /* check range */               
00535         if((entry >= table->table ) && (entry <= (table->table + (IPSEC_MAX_SPD_ENTRIES*sizeof(spd_entry)))))
00536         {
00537                 /* first clear associated SA if there is one */
00540                 /* relink table */
00541         
00542                 if(entry->use_flag != IPSEC_USED)
00543                 {
00544                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_del", ("return = %d", IPSEC_STATUS_FAILURE) );
00545                         return IPSEC_STATUS_FAILURE ;
00546                 }
00547 
00548                 /* relink previous with next */
00549                 prev_ptr = entry->prev ;
00550                 next_ptr = entry->next ;
00551                 if(prev_ptr)
00552                         prev_ptr->next = next_ptr ;
00553                 if(next_ptr)
00554                         next_ptr->prev = prev_ptr ;
00555 
00556                 /* if removed last entry */
00557                 if(entry->next == NULL)
00558                 {
00559                         table->last == entry->prev ;
00560                 }
00561 
00562                 /* if removed first entry */
00563                 if(entry == table->first)
00564                 {
00565                         table->first = entry->next ;
00566                 }
00567 
00568                 /* clear field */
00569                 entry->use_flag = IPSEC_FREE ;
00570 
00571                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_del", ("return = %d", IPSEC_STATUS_SUCCESS) );
00572                 return IPSEC_STATUS_SUCCESS ;
00573         }
00574 
00575         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_del", ("return = %d", IPSEC_STATUS_FAILURE) );
00576         return IPSEC_STATUS_FAILURE ;
00577 }
00578 
00597 spd_entry *ipsec_spd_lookup(ipsec_ip_header *header, spd_table *table)
00598 {
00599         spd_entry       *tmp_entry ;
00600         ipsec_in_ip     *ip ;
00601 
00602         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00603               "ipsec_spd_lookup", 
00604                           ("header=%p, table=%p",
00605                       (void *)header, (void *)table)
00606                          );
00607 
00608         ip = (ipsec_in_ip*) header ;
00609 
00610         /* compare and return when all fields match */
00611         for(tmp_entry = table->first; tmp_entry != NULL; tmp_entry = tmp_entry->next)
00612         {
00613                 if(ipsec_ip_addr_maskcmp(header->src, tmp_entry->src, tmp_entry->src_netaddr))
00614                 {
00615                         if(ipsec_ip_addr_maskcmp(header->dest, tmp_entry->dest, tmp_entry->dest_netaddr))
00616                         {
00617                                 if((tmp_entry->protocol == 0) || tmp_entry->protocol == header->protocol)
00618                                 {
00619                                         if(header->protocol == IPSEC_PROTO_TCP)
00620                                         {
00621                                                 if((tmp_entry->src_port == 0) || (tmp_entry->src_port == ip->inner_header.tcp.src)) 
00622                                                         if( (tmp_entry->dest_port == 0) || (tmp_entry->dest_port == ip->inner_header.tcp.dest)) 
00623                                                         {
00624                                                                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_lookup", ("tmp_entry = %p", (void *) tmp_entry) );
00625                                                                 return tmp_entry ;
00626                                                         }
00627                                         }
00628                                         else if(header->protocol == IPSEC_PROTO_UDP)
00629                                         {
00630                                                         if((tmp_entry->src_port == 0) || (tmp_entry->src_port == ip->inner_header.udp.src)) 
00631                                                                 if( (tmp_entry->dest_port == 0) || (tmp_entry->dest_port == ip->inner_header.udp.dest)) 
00632                                                                 {
00633                                                                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_lookup", ("tmp_entry = %p", (void *) tmp_entry) );
00634                                                                         return tmp_entry ;
00635                                                                 }
00636                                         } 
00637                                         else
00638                                         {
00639                                                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_lookup", ("tmp_entry = %p", (void *) tmp_entry) );
00640                                                 return tmp_entry ;
00641                                         }
00642                                 }
00643                         }
00644                 }
00645         }
00646         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_spd_lookup", ("return = %p", (void *) NULL) );
00647         return NULL ;
00648 }
00649 
00656 void ipsec_spd_print_single(spd_entry *entry)
00657 {
00658         char            log_message[IPSEC_LOG_MESSAGE_SIZE+1] ;
00659         char            ip_addr1[IPSEC_LOG_MESSAGE_SIZE+1] ;
00660         char            ip_addr2[IPSEC_LOG_MESSAGE_SIZE+1] ;
00661         char            ip_addr3[IPSEC_LOG_MESSAGE_SIZE+1] ;
00662         char            ip_addr4[IPSEC_LOG_MESSAGE_SIZE+1] ;
00663         char            protocol[10+1] ;
00664         char            policy[10+1] ;
00665 
00666         strcpy(ip_addr1, ipsec_inet_ntoa(entry->src)) ;
00667         strcpy(ip_addr2, ipsec_inet_ntoa(entry->src_netaddr)) ;
00668         strcpy(ip_addr3, ipsec_inet_ntoa(entry->dest)) ;
00669         strcpy(ip_addr4, ipsec_inet_ntoa(entry->dest_netaddr)) ;
00670 
00671         switch(entry->protocol)
00672         {
00673                 case IPSEC_PROTO_TCP:
00674                         strcpy(protocol, " TCP") ;
00675                         break ;
00676                 case IPSEC_PROTO_UDP:
00677                         strcpy(protocol, " UDP") ;
00678                         break ;
00679                 case IPSEC_PROTO_AH:
00680                         strcpy(protocol, "  AH") ;
00681                         break ;
00682                 case IPSEC_PROTO_ESP:
00683                         strcpy(protocol, " ESP") ;
00684                         break ;
00685                 case IPSEC_PROTO_ICMP:
00686                         strcpy(protocol, "ICMP") ;
00687                         break ;
00688                 default :
00689                         sprintf(protocol, "%4d", entry->protocol) ;
00690         }
00691 
00692         switch(entry->policy)
00693         {
00694                 case POLICY_APPLY:
00695                         strcpy(policy, "  APPLY") ; 
00696                         break ;
00697                 case POLICY_BYPASS:
00698                         strcpy(policy, " BYPASS") ; 
00699                         break ;
00700                 case POLICY_DISCARD:
00701                         strcpy(policy, "DISCARD") ; 
00702                         break ;
00703                 default:
00704                         strcpy(policy, "UNKNOWN") ;
00705         }
00706 
00707         sprintf(log_message,    "%15s/%15s   %15s/%15s %3s %5u %5u    %7s  0x%p",
00708                                                 ip_addr1, ip_addr2, ip_addr3, ip_addr4,
00709                                                         protocol,
00710                                                         ipsec_ntohs(entry->src_port),
00711                                                         ipsec_ntohs(entry->dest_port),
00712                                                         policy,
00713                                                         entry->sa) ;
00714 
00715         printf("    %s\n", log_message) ;
00716 
00717         return ;
00718 }
00719 
00726 void ipsec_spd_print(spd_table *table)
00727 {
00728         spd_entry       *tmp_ptr ;
00729 
00730         IPSEC_LOG_MSG("ipsec_spd_print", ("Printf Security Policy Database")) ;
00731         printf("      src-addr/net-addr               dst-addr/net-addr                proto prt:src/dest  policy  SA\n") ;
00732 
00733         if(table->first == NULL)
00734         {
00735                 printf("      SPD table is empty\n") ;
00736         }
00737 
00738         /* loop over all entries and print them */
00739         for(tmp_ptr = table->first; tmp_ptr != NULL; tmp_ptr = tmp_ptr->next)
00740         {
00741                 ipsec_spd_print_single(tmp_ptr) ;
00742         }
00743 
00744         return ;
00745 }
00746 
00756 sad_entry *ipsec_sad_get_free(sad_table *table)
00757 {
00758         int index ;
00759 
00760         /* find first free entry */
00761         for(index = 0; index < IPSEC_MAX_SAD_ENTRIES; index++)
00762         {
00763                 if (table->table[index].use_flag == IPSEC_FREE)
00764                         break ;
00765         }
00766         /* if no free entry */
00767         if (index >= IPSEC_MAX_SAD_ENTRIES)
00768         {
00769                 return NULL ;
00770         }
00771 
00772         return &table->table[index] ;
00773 }
00774 
00796 sad_entry *ipsec_sad_add(sad_entry *entry, sad_table *table) 
00797 {
00798         sad_entry       *free_entry ;
00799         sad_entry       *tmp_entry ;
00800 
00801         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00802                       "ipsec_sad_add", 
00803                                   ("entry=%p, table=%p",
00804                               (void *)entry, (void *)table )
00805                                  );
00806         free_entry = ipsec_sad_get_free(table) ;
00807         if (free_entry == NULL) 
00808         {
00809                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_add", ("return = %p", (void *) NULL) );
00810                 return NULL ;
00811         }
00812 
00813         /* copy the fields */
00814         free_entry->dest = entry->dest ;
00815         free_entry->dest_netaddr = entry->dest_netaddr ;
00816         free_entry->spi = entry->spi ;
00817         free_entry->protocol = entry->protocol ;
00818         free_entry->mode = entry->mode ;
00819         free_entry->sequence_number = entry->sequence_number ;
00820         free_entry->replay_win = entry->replay_win ;
00821         free_entry->lifetime = entry->lifetime ;
00822         free_entry->path_mtu = entry->path_mtu ;
00823         free_entry->enc_alg = entry->enc_alg ;
00824         memcpy(free_entry->enckey, entry->enckey, IPSEC_MAX_ENCKEY_LEN) ;
00825         free_entry->auth_alg = entry->auth_alg ;
00826         memcpy(free_entry->authkey, entry->authkey, IPSEC_MAX_AUTHKEY_LEN) ;
00827 
00828         free_entry->use_flag = IPSEC_USED ;
00829 
00830         /* re-link entry */
00833         /* if added first entry in array */
00834         if(table->first == NULL)
00835         {
00836                 table->first = free_entry ;
00837                 table->first->next = NULL ;
00838                 table->first->prev = NULL ;
00839                 table->last = free_entry ;
00840         }
00841         else
00842         {
00843                 /* go till end of list */
00844                 for(tmp_entry = table->first; tmp_entry->next != NULL; tmp_entry = tmp_entry->next)
00845                 {
00846                 }
00847                 /* inset at end */
00848                 free_entry->prev = tmp_entry ;
00849                 tmp_entry->next = free_entry ;
00850                 free_entry->next = NULL ;
00851         }
00852 
00853         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_add", ("free_entry = %p", (void *) free_entry) );
00854         return free_entry ;
00855 }
00856 
00870 ipsec_status ipsec_sad_del(sad_entry *entry, sad_table *table) 
00871 {
00872         sad_entry               *next_ptr ;
00873         sad_entry               *prev_ptr ;
00874 
00875         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00876                       "ipsec_sad_del", 
00877                                   ("entry=%p, table=%p",
00878                               (void *)entry, (void *)table )
00879                                  );
00880 
00881         /* check range */               
00882         if((entry >= table->table ) && (entry <= (table->table + (IPSEC_MAX_SAD_ENTRIES*sizeof(sad_entry)))))
00883         {
00884                 /* relink table */
00885         
00886                 if(entry->use_flag != IPSEC_USED)
00887                 {
00888                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_del", ("return = %d", IPSEC_STATUS_FAILURE) );
00889                         return IPSEC_STATUS_FAILURE ;
00890                 }
00891 
00892                 /* relink previous with next */
00893                 prev_ptr = entry->prev ;
00894                 next_ptr = entry->next ;
00895                 if(prev_ptr)
00896                         prev_ptr->next = next_ptr ;
00897                 if(next_ptr)
00898                         next_ptr->prev = prev_ptr ;
00899 
00900                 /* if removed last entry */
00901                 if(entry->next == NULL)
00902                 {
00903                         table->last == entry->prev ;
00904                 }
00905 
00906                 /* if removed first entry */
00907                 if(entry == table->first)
00908                 {
00909                         table->first = entry->next ;
00910                 }
00911 
00912                 /* clear field */
00913                 entry->use_flag = IPSEC_FREE ;
00914 
00915 
00916                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_del", ("return = %d", IPSEC_STATUS_SUCCESS) );
00917                 return IPSEC_STATUS_SUCCESS ;
00918         }
00919 
00920         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_del", ("return = %d", IPSEC_STATUS_FAILURE) );
00921         return IPSEC_STATUS_FAILURE ;
00922 }
00923 
00940 sad_entry *ipsec_sad_lookup(__u32 dest, __u8 proto, __u32 spi, sad_table *table)
00941 {
00942         sad_entry       *tmp_entry ;
00943 
00944         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
00945                       "ipsec_sad_lookup", 
00946                                   ("dest=%lu, proto=%d, spi=%lu, table=%p",
00947                               dest, proto, spi, (void *)table ) 
00948                                  );
00949 
00950         /* compare and return when all fields match */
00951         for(tmp_entry = table->first; tmp_entry != NULL; tmp_entry = tmp_entry->next)
00952         {
00953                 if(ipsec_ip_addr_maskcmp(dest, tmp_entry->dest, tmp_entry->dest_netaddr))
00954                 {
00955                         if(tmp_entry->protocol == proto)
00956                         {
00957                                 if(tmp_entry->spi == spi)
00958                                 {
00959                                         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_lookup", ("tmp_entry = %p", (void *)tmp_entry) );
00960                                         return tmp_entry ;
00961                                 }
00962                         }
00963                 }
00964         }
00965         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_lookup", ("return = %p", (void *)NULL) );
00966         return NULL ;
00967 }
00968 
00975 void ipsec_sad_print_single(sad_entry *entry)
00976 {
00977         char            log_message[IPSEC_LOG_MESSAGE_SIZE+1] ;
00978         char            dest[IPSEC_LOG_MESSAGE_SIZE+1] ;
00979         char            dest_netaddr[IPSEC_LOG_MESSAGE_SIZE+1] ;
00980         char            crypto[10+1] ;
00981 
00982         strcpy(dest, ipsec_inet_ntoa(entry->dest)) ;
00983         strcpy(dest_netaddr, ipsec_inet_ntoa(entry->dest_netaddr)) ;
00984 
00985         if (entry->protocol == IPSEC_PROTO_AH)
00986                 strcpy(crypto, entry->auth_alg == IPSEC_HMAC_MD5 ? " MD5" : "SHA1") ;
00987         else
00988                 strcpy(crypto, entry->enc_alg == IPSEC_DES ? " DES" : "3DES") ;
00989 
00990         sprintf(log_message,    "%15s/%15s %4s %5s  %4s   %10lu %5d %10lu %4d %8x 0x%p ",
00991                                                 dest, 
00992                                                         dest_netaddr,
00993                                                         entry->protocol == IPSEC_PROTO_ESP ? "ESP" : " AH", 
00994                                                         entry->mode == IPSEC_TUNNEL ? "  TUN" : "TRANS", 
00995                                                         crypto,
00996                                                         entry->sequence_number,
00997                                                         entry->replay_win,
00998                                                         entry->lifetime,
00999                                                         entry->path_mtu,
01000                                                         ipsec_ntohl(entry->spi),
01001                                                         entry
01002                                                         ) ;
01003         printf("     %s\n", log_message) ;
01004 
01005         return ;
01006 }
01007 
01014 void ipsec_sad_print(sad_table *table)
01015 {
01016         sad_entry       *tmp_ptr ;
01017 
01018         IPSEC_LOG_MSG("ipsec_sad_print", ("Print Security Association Database")) ;
01019         printf("     dest/dest netaddr                proto mode crypto seq          win   ltime    mtu      spi  addr\n") ;
01020 
01021         if(table->first == NULL)
01022         {
01023                 printf("      SAD table is empty\n") ;
01024         }
01025 
01026         /* loop over all entries and print them */
01027         for(tmp_ptr = table->first; tmp_ptr != NULL; tmp_ptr = tmp_ptr->next)
01028         {
01029                 ipsec_sad_print_single(tmp_ptr) ;
01030         }
01031 }
01032 
01040 __u32 ipsec_sad_get_spi(ipsec_ip_header *header)
01041 {
01042         ipsec_in_ip     *ptr ;
01043 
01044         IPSEC_LOG_TRC(IPSEC_TRACE_ENTER, 
01045                       "ipsec_sad_get_spi", 
01046                                   ("header=%p",
01047                               (void *)header)
01048                                  );
01049 
01050 
01051         ptr = (ipsec_in_ip*)header ;
01052 
01053         if (ptr->ip.protocol == IPSEC_PROTO_ESP)
01054         {
01055                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_get_spi", ("ptr->inner_header.esp.spi = %ul", ptr->inner_header.esp.spi) );
01056                 return ptr->inner_header.esp.spi ;
01057         }
01058 
01059         if (ptr->ip.protocol == IPSEC_PROTO_AH)
01060         {
01061                 IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_get_spi", ("ptr->inner_header.ah.spi = %ul", ptr->inner_header.ah.spi) );
01062                 return ptr->inner_header.ah.spi ;
01063         }
01064 
01065         IPSEC_LOG_TRC(IPSEC_TRACE_RETURN, "ipsec_sad_get_spi", ("return = 0") );
01066         return 0 ;
01067 }
01068 
01078 ipsec_status ipsec_spd_flush(spd_table *table, spd_entry *def_entry)
01079 {
01080         memset(table->table, 0, sizeof(spd_entry)*IPSEC_MAX_SPD_ENTRIES) ;
01081         table->first = NULL ;
01082         table->first = NULL ;
01083 
01084         if(ipsec_spd_add(       def_entry->src,
01085                                                 def_entry->src_netaddr,
01086                                                 def_entry->dest,
01087                                                 def_entry->dest_netaddr,
01088                                                 def_entry->protocol,
01089                                                 def_entry->src_port,
01090                                                 def_entry->dest_port,
01091                                                 def_entry->policy,
01092                                                 table) == NULL)
01093                 return IPSEC_STATUS_FAILURE ;
01094 
01095         return IPSEC_STATUS_SUCCESS ;
01096 }
01097 
01104 ipsec_status ipsec_sad_flush(sad_table *table)
01105 {
01106         memset(table->table, 0, sizeof(spd_entry)*IPSEC_MAX_SAD_ENTRIES) ;
01107         table->first = NULL ;
01108         table->first = NULL ;
01109         
01110         return IPSEC_STATUS_SUCCESS ;
01111 }

Copyright 2003 by Christian Scheurer and Niklaus Schild