Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

IpAddrSet.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 /*
00003  * Copyright(C) 2002 Sourcefire, Inc.
00004  * 
00005  * Author(s):  Andrew R. Baker <andrewb@snort.org>
00006  *             Martin Roesch   <roesch@sourcefire.com>
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  * 
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00021  *
00022  */
00023 
00024 /* includes */
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #include "config.h"
00028 #endif
00029 
00030 #include <errno.h>
00031 #include <stdio.h>
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #ifndef WIN32
00035 #include <netdb.h>
00036 #include <ctype.h>
00037 #include <sys/types.h>
00038 #include <sys/socket.h>
00039 #include <netinet/in.h>
00040 #include <arpa/inet.h>
00041 #endif
00042 
00043 #ifdef HAVE_STRINGS_H
00044 #include <strings.h>
00045 #endif
00046 
00047 #include "util.h"
00048 #include "mstring.h"
00049 #include "parser.h"
00050 #include "debug.h"
00051 
00052 #include "IpAddrSet.h"
00053 
00054 IpAddrSet *IpAddrSetCreate()
00055 {
00056     IpAddrSet *tmp;
00057 
00058     tmp = (IpAddrSet *) SnortAlloc(sizeof(IpAddrSet));
00059 
00060     return tmp;
00061 }
00062 
00063 
00064 void IpAddrSetDestroy(IpAddrSet *ipAddrSet)
00065 {
00066     IpAddrSet *next;
00067 
00068     while(ipAddrSet)
00069     {
00070         next = ipAddrSet->next;
00071         free(ipAddrSet);
00072         ipAddrSet = next;
00073     }
00074 }
00075 
00076 static char buffer[1024];
00077 
00078 void IpAddrSetPrint(char *prefix, IpAddrSet *ipAddrSet)
00079 {
00080     struct in_addr in;
00081     size_t offset = 0;
00082     while(ipAddrSet)
00083     {
00084         offset = 0;
00085         if(ipAddrSet->addr_flags & EXCEPT_IP)
00086             offset += snprintf(buffer, 1024 - offset, "NOT ");
00087         in.s_addr = ipAddrSet->ip_addr;
00088         offset += snprintf(buffer + offset, 1024 - offset, "%s/", 
00089                 inet_ntoa(in));
00090         in.s_addr = ipAddrSet->netmask;
00091         offset += snprintf(buffer + offset, 1024 - offset, "%s", inet_ntoa(in));
00092         buffer[offset] = '\0';
00093         if (prefix)
00094             LogMessage("%s%s\n", prefix, buffer);
00095         else
00096             LogMessage("%s%s\n", buffer);
00097         ipAddrSet = ipAddrSet->next;
00098     }
00099 }
00100 
00101 IpAddrSet *IpAddrSetCopy(IpAddrSet *ipAddrSet)
00102 {
00103     IpAddrSet *newIpAddrSet = NULL;
00104     IpAddrSet *current = NULL;
00105     IpAddrSet *prev = NULL;
00106 
00107     while(ipAddrSet)
00108     {
00109         if(!(current = (IpAddrSet *)malloc(sizeof(IpAddrSet))))
00110         {
00111             /* ENOMEM */
00112             goto failed;
00113         }
00114         
00115         current->ip_addr = ipAddrSet->ip_addr;
00116         current->netmask = ipAddrSet->netmask;
00117         current->addr_flags = ipAddrSet->addr_flags;
00118         current->next = NULL;
00119 
00120         if(!prev)
00121             newIpAddrSet = current;
00122         else
00123             prev->next = current;
00124 
00125         ipAddrSet = ipAddrSet->next;
00126         prev = current;
00127     }
00128 
00129     return newIpAddrSet;
00130 
00131 failed:
00132     if(newIpAddrSet)
00133         IpAddrSetDestroy(newIpAddrSet);
00134     return NULL; /* XXX ENOMEM */
00135 }
00136 
00137 
00138 /* XXX: legacy support function */
00139 /*
00140  * Function: ParseIP(char *, IpAddrSet *)
00141  *
00142  * Purpose: Convert a supplied IP address to it's network order 32-bit long
00143  *          value.  Also convert the CIDR block notation into a real
00144  *          netmask.
00145  *
00146  * Arguments: char *addr  => address string to convert
00147  *            IpAddrSet * =>
00148  *            
00149  *
00150  * Returns: 0 for normal addresses, 1 for an "any" address
00151  */
00152 int ParseIP(char *paddr, IpAddrSet *address_data)
00153 {
00154     char **toks;        /* token dbl buffer */
00155     int num_toks;       /* number of tokens found by mSplit() */
00156     int cidr = 1;       /* is network expressed in CIDR format */
00157     int nmask = -1;     /* netmask temporary storage */
00158     char *addr;         /* string to parse, eventually a
00159                          * variable-contents */
00160     struct hostent *host_info;  /* various struct pointers for stuff */
00161     struct sockaddr_in sin; /* addr struct */
00162     char broadcast_addr_set = 0;
00163 
00164     addr = paddr;
00165 
00166     if(*addr == '!')
00167     {
00168         address_data->addr_flags |= EXCEPT_IP;
00169 
00170         addr++;  /* inc past the '!' */
00171     }
00172 
00173     /* check for wildcards */
00174     if(!strcasecmp(addr, "any"))
00175     {
00176         address_data->ip_addr = 0;
00177         address_data->netmask = 0;
00178         return 1;
00179     }
00180     /* break out the CIDR notation from the IP address */
00181     toks = mSplit(addr, "/", 2, &num_toks, 0);
00182 
00183     /* "/" was not used as a delimeter, try ":" */
00184     if(num_toks == 1)
00185     {
00186         mSplitFree(&toks, num_toks);
00187         toks = mSplit(addr, ":", 2, &num_toks, 0);
00188     }
00189 
00190     /*
00191      * if we have a mask spec and it is more than two characters long, assume
00192      * it is netmask format
00193      */
00194     if((num_toks > 1) && strlen(toks[1]) > 2)
00195     {
00196         cidr = 0;
00197     }
00198 
00199     switch(num_toks)
00200     {
00201         case 1:
00202             address_data->netmask = netmasks[32];
00203             break;
00204 
00205         case 2:
00206             if(cidr)
00207             {
00208                 /* convert the CIDR notation into a real live netmask */
00209                 nmask = atoi(toks[1]);
00210 
00211                 /* it's pain to differ whether toks[1] is correct if netmask */
00212                 /* is /0, so we deploy some sort of evil hack with isdigit */
00213 
00214                 if(!isdigit((int) toks[1][0]))
00215                     nmask = -1;
00216 
00217                 /* if second char is != '\0', it must be a digit
00218                  * by Daniel B. Cid, dcid@sourcefire.com
00219                  */ 
00220                 if((toks[1][1] != '\0')&&(!isdigit((int) toks[1][1]) ))
00221                     nmask = -1;
00222                 
00223                 if((nmask > -1) && (nmask < 33))
00224                 {
00225                     address_data->netmask = netmasks[nmask];
00226                 }
00227                 else
00228                 {
00229                     FatalError("ERROR %s(%d): Invalid CIDR block for IP addr "
00230                             "%s\n", file_name, file_line, addr);
00231                            
00232                 }
00233             }
00234             else
00235             {
00236                 /* convert the netmask into its 32-bit value */
00237 
00238                 /* broadcast address fix from 
00239                  * Steve Beaty <beaty@emess.mscd.edu> 
00240                  */
00241 
00242                 /*
00243                  * if the address is the (v4) broadcast address, inet_addr *
00244                  * returns -1 which usually signifies an error, but in the *
00245                  * broadcast address case, is correct.  we'd use inet_aton() *
00246                  * here, but it's less portable.
00247                  */
00248                 if(!strncmp(toks[1], "255.255.255.255", 15))
00249                 {
00250                     address_data->netmask = INADDR_BROADCAST;
00251                 }
00252                 else if((address_data->netmask = inet_addr(toks[1])) == -1)
00253                 {
00254                     FatalError("ERROR %s(%d): Unable to parse rule netmask "
00255                             "(%s)\n", file_name, file_line, toks[1]);
00256                 }
00257                 /* Set nmask so we don't try to do a host lookup below.
00258                  * The value of 0 is irrelevant. */
00259                 nmask = 0;
00260             }
00261             break;
00262 
00263         default:
00264             FatalError("ERROR %s(%d) => Unrecognized IP address/netmask %s\n",
00265                     file_name, file_line, addr);
00266             break;
00267     }
00268     sin.sin_addr.s_addr = inet_addr(toks[0]);
00269 
00270 #ifndef WORDS_BIGENDIAN
00271     /*
00272      * since PC's store things the "wrong" way, shuffle the bytes into the
00273      * right order.  Non-CIDR netmasks are already correct.
00274      */
00275     if(cidr)
00276     {
00277         address_data->netmask = htonl(address_data->netmask);
00278     }
00279 #endif
00280     /* broadcast address fix from Steve Beaty <beaty@emess.mscd.edu> */
00281     /* Changed location */
00282     if(!strncmp(toks[0], "255.255.255.255", 15))
00283     {
00284         address_data->ip_addr = INADDR_BROADCAST;
00285         broadcast_addr_set = 1;
00286     }
00287     else if (nmask == -1)
00288     {
00289         /* Try to do a host lookup if the address didn't
00290          * convert to a valid IP and there were not any
00291          * mask bits specified (CIDR or dot notation). */
00292         if(sin.sin_addr.s_addr == INADDR_NONE)
00293         {
00294             /* get the hostname and fill in the host_info struct */
00295             if((host_info = gethostbyname(toks[0])))
00296             {
00297                 /* protecting against malicious DNS servers */
00298                 if(host_info->h_length <= sizeof(sin.sin_addr))
00299                 {
00300                     bcopy(host_info->h_addr, (char *) &sin.sin_addr, host_info->h_length);
00301                 }
00302                 else
00303                 {
00304                     bcopy(host_info->h_addr, (char *) &sin.sin_addr, sizeof(sin.sin_addr));
00305                 }
00306             }
00307             /* Using h_errno */
00308             else if(h_errno == HOST_NOT_FOUND)
00309             /*else if((sin.sin_addr.s_addr = inet_addr(toks[0])) == INADDR_NONE)*/
00310             {
00311                 FatalError("ERROR %s(%d): Couldn't resolve hostname %s\n",
00312                     file_name, file_line, toks[0]);
00313             }
00314         }
00315         else
00316         {
00317             /* It was a valid IP address with no netmask specified. */
00318             /* Noop */
00319         }
00320     }
00321     else
00322     {
00323         if(sin.sin_addr.s_addr == INADDR_NONE)
00324         {
00325             /* It was not a valid IP address but had a valid netmask. */
00326             FatalError("ERROR %s(%d): Rule IP addr (%s) didn't translate\n",
00327                 file_name, file_line, toks[0]);
00328         }
00329     }
00330 
00331     /* Only set this if we haven't set it above as 255.255.255.255 */
00332     if (!broadcast_addr_set)
00333     {
00334         address_data->ip_addr = ((u_long) (sin.sin_addr.s_addr) &
00335             (address_data->netmask));
00336     }
00337     mSplitFree(&toks, num_toks);
00338     return 0;
00339 }                                                                                            
00340 
00341 
00342 IpAddrSet *IpAddrSetParse(char *addr)
00343 {
00344     IpAddrSet *ias = NULL;
00345     IpAddrSet *tmp_ias = NULL;
00346     char **toks;
00347     int num_toks;
00348     int i;
00349     char *tmp;
00350     char *enbracket;
00351     char *index;
00352     int flags = 0;
00353 
00354     index = addr;
00355     
00356     while(isspace((int)*index)) index++;
00357     
00358     if(*index == '!')
00359     {
00360         flags = EXCEPT_IP;
00361     }
00362 
00363     if(*index == '$')
00364     {
00365         if((tmp = VarGet(index+1)) == NULL)
00366         {
00367             FatalError("%s(%d) => Undefined variable %s\n", file_name, file_line,
00368                     index);
00369         }
00370     }
00371     else
00372     {
00373         tmp = index;
00374     }
00375 
00376     if(*tmp == '[')
00377     {
00378         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"Found IP list!\n"););
00379 
00380         enbracket = strrchr(tmp, (int)']'); /* null out the en-bracket */
00381 
00382         if(enbracket) 
00383             *enbracket = '\x0';
00384         else
00385             FatalError("%s(%d) => Unterminated IP List\n", file_name, file_line);
00386 
00387         toks = mSplit(tmp+1, ",", 128, &num_toks, 0);
00388 
00389         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"mSplit got %d tokens...\n", 
00390                     num_toks););
00391 
00392         for(i=0; i< num_toks; i++)
00393         {
00394             DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,"adding %s to IP "
00395                         "address list\n", toks[i]););
00396             tmp = toks[i];
00397 
00398             while (isspace((int)*tmp)||*tmp=='[') tmp++;
00399 
00400             enbracket = strrchr(tmp, (int)']'); /* null out the en-bracket */
00401 
00402             if(enbracket) 
00403                 *enbracket = '\x0';
00404 
00405             if (!strlen(tmp))
00406                 continue;
00407                 
00408             if(!ias)
00409             {
00410                 ias = (IpAddrSet *) SnortAlloc(sizeof(IpAddrSet));
00411                 tmp_ias = ias;
00412             }
00413             else
00414             {
00415                 tmp_ias->next = (IpAddrSet *) SnortAlloc(sizeof(IpAddrSet));
00416                 tmp_ias = tmp_ias->next;
00417             }
00418             
00419             ParseIP(tmp, tmp_ias);
00420         }
00421 
00422         mSplitFree(&toks, num_toks);
00423     }
00424     else
00425     {
00426         DEBUG_WRAP(DebugMessage(DEBUG_CONFIGRULES,
00427                     "regular IP address, processing...\n"););
00428 
00429         ias = (IpAddrSet *) SnortAlloc(sizeof(IpAddrSet));
00430 
00431         ParseIP(tmp, ias);
00432     }
00433 
00434     return ias;
00435 }
00436 
00437 
00438 int IpAddrSetContains(IpAddrSet *ias, struct in_addr test_addr)
00439 {
00440     IpAddrSet *index;
00441     u_int32_t raw_addr;
00442     int exception_flag = 0;
00443 
00444 
00445     raw_addr = test_addr.s_addr;
00446     
00447     for(index = ias; index != NULL; index = index->next)
00448     {
00449         if(index->addr_flags & EXCEPT_IP) exception_flag = 1;
00450 
00451         if(((index->ip_addr == (raw_addr & index->netmask)) ^ exception_flag))
00452         {
00453             return 1;
00454         }
00455     }
00456 
00457     return 0;
00458 }

Generated on Sun May 14 14:51:14 2006 by  doxygen 1.4.2