1 /*
2 ** Copyright (C) 1998-2009 Sourcefire, Inc.
3 **
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU General Public License Version 2 as
6 ** published by the Free Software Foundation.  You may not use, modify or
7 ** distribute this program under any other version of the GNU General
8 ** Public License.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 
20 /*
21  * Adam Keeton
22  * sf_vartable.c
23  * 11/17/06
24  *
25  * Library for managing IP variables.
26 */
27 
28 #include <stdlib.h>
29 #include <string.h>
30 #include <ctype.h>
31 #include "sf_vartable.h"
32 #include "util.h"
33 
sfvt_alloc_table(void)34 vartable_t * sfvt_alloc_table(void)
35 {
36     return (vartable_t *)SnortAlloc(sizeof(vartable_t));
37 }
38 
39 // XXX this implementation is just used to support
40 // Snort's underlying implementation better
sfvt_define(vartable_t * table,char * name,char * value)41 SFIP_RET sfvt_define(vartable_t *table, char *name, char *value)
42 {
43     char *buf;
44     int len;
45     SFIP_RET ret;
46 
47     if(!name || !value) return SFIP_ARG_ERR;
48 
49     len = strlen(name) + strlen(value) + 2;
50 
51     if((buf = (char*)malloc(len)) == NULL)
52     {
53         return SFIP_FAILURE;
54     }
55 
56     SnortSnprintf(buf, len, "%s %s", name, value);
57 
58     ret = sfvt_add_str(table, buf);
59     free(buf);
60     return ret;
61 }
62 
63 /* Adds the variable described by "str" to the table "table" */
sfvt_add_str(vartable_t * table,char * str)64 SFIP_RET sfvt_add_str(vartable_t *table, char *str)
65 {
66     sfip_var_t *var;
67     sfip_var_t *swp;
68     sfip_var_t *p;
69     int ret;
70     SFIP_RET status;
71 
72     if(!table || !str) return SFIP_FAILURE;
73 
74     /* Creates the variable */
75     if( (var = sfvar_alloc(table, str, &status)) == NULL )
76     {
77          return status;
78     }
79 
80     /* Insertion sort */
81 
82     if(!table->head)
83     {
84         table->head = var;
85         return SFIP_SUCCESS;
86     }
87 
88     if((ret = strcmp(var->name, table->head->name)) < 0)
89     {
90         var->next = table->head;
91         table->head = var;
92         return SFIP_SUCCESS;
93     }
94     /* Redefinition */
95     else if(ret == 0)
96     {
97         var->next = table->head->next;
98         sfvar_free(table->head);
99         table->head = var;
100         return SFIP_DUPLICATE;
101     }
102 
103     /* The loop below checks table->head->next->name in the first iteration.
104      * Make sure there is a table->head->next first */
105     if(!table->head->next)
106     {
107         table->head->next = var;
108         return SFIP_SUCCESS;
109     }
110     else if(!strcmp(var->name, table->head->next->name))
111     {
112         var->next = table->head->next->next;
113         sfvar_free(table->head->next);
114         table->head->next = var;
115         return SFIP_DUPLICATE;
116     }
117 
118     for(p = table->head; p->next; p=p->next)
119     {
120         if((ret = strcmp(var->name, p->next->name)) < 0)
121         {
122             swp = p->next;
123             p->next = var;
124             var->next = swp;
125 
126             return SFIP_SUCCESS;
127         }
128         /* Redefinition */
129         else if(ret == 0)
130         {
131             var->next = p->next->next;
132             sfvar_free(p->next);
133             p->next = var;
134             return SFIP_DUPLICATE;
135         }
136     }
137 
138     p->next = var;
139     return SFIP_SUCCESS;
140 }
141 
142 /* Adds the variable described by "src" to the variable "dst",
143  * using the vartable for looking variables used within "src" */
sfvt_add_to_var(vartable_t * table,sfip_var_t * dst,char * src)144 SFIP_RET sfvt_add_to_var(vartable_t *table, sfip_var_t *dst, char *src)
145 {
146     int ret;
147 
148     if(!table || !dst || !src) return SFIP_ARG_ERR;
149 
150     if((ret = sfvar_parse_iplist(table, dst, src, 0)) == SFIP_SUCCESS)
151         return sfvar_validate(dst);
152 
153     return ret;
154 }
155 
156 /* Looks up a variable from the table by the variable's name  */
sfvt_lookup_var(vartable_t * table,char * name)157 sfip_var_t *sfvt_lookup_var(vartable_t *table, char *name)
158 {
159     sfip_var_t *p;
160     int len;
161     char *end;
162 
163     if(!table || !name) return NULL;
164 
165     if(*name == '$') name++;
166 
167     /* XXX should I assume there will be trailing garbage or
168      * should I automatically find where the variable ends? */
169     for(end=name;
170         *end && !isspace((int)*end) && *end != '\\' && *end != ']';
171         end++) ;
172     len = end - name;
173 
174     for(p=table->head; len && p; p=p->next)
175     {
176         int name_len = strlen(p->name);
177         if((len == name_len) && !strncmp(p->name, name, len)) return p;
178     }
179 
180     return NULL;
181 }
182 
sfvt_free_table(vartable_t * table)183 void sfvt_free_table(vartable_t *table)
184 {
185     sfip_var_t *p, *tmp;
186 
187     if (!table) return;
188 
189     p = table->head;
190     while (p)
191     {
192         tmp = p->next;
193         sfvar_free(p);
194         p = tmp;
195     }
196     free(table);
197 }
198 
199 /* Prints a table's contents */
sfip_print_table(FILE * f,vartable_t * table)200 void sfip_print_table(FILE *f, vartable_t *table)
201 {
202     sfip_var_t *p;
203 
204     if(!f || !table) return;
205 
206     fprintf(f, "(Table %p)\n", (void*)table);
207     for(p=table->head; p; p=p->next)
208     {
209         sfvar_print(f, p);
210         puts("");
211     }
212 }
213 
214 //#define TESTER
215 
216 #ifdef TESTER
217 int failures = 0;
218 #define TEST(x) if(x) printf("\tSuccess: line %d\n", __LINE__);\
219                 else { printf("\tFAILURE: line %d\n", __LINE__); failures++; }
220 
main()221 int main()
222 {
223     vartable_t *table;
224     sfip_var_t *var;
225     sfip_t *ip;
226 
227     puts("********************************************************************");
228     puts("Testing variable table parsing:");
229     table = sfvt_alloc_table();
230     /* These are all valid */
231     TEST(sfvt_add_str(table, "foo [ 1.2.0.0/16, ffff:dead:beef::0 ] ") == SFIP_SUCCESS);
232     TEST(sfvt_add_str(table, " goo [ ffff:dead:beef::0 ] ") == SFIP_SUCCESS);
233     TEST(sfvt_add_str(table, " moo [ any ] ") == SFIP_SUCCESS);
234 
235     /* Test variable redefine */
236     TEST(sfvt_add_str(table, " goo [ 192.168.0.1, 192.168.0.2, 192.168.255.0 255.255.248.0 ] ") == SFIP_DUPLICATE);
237 
238     /* These should fail since it's a variable name with bogus arguments */
239     TEST(sfvt_add_str(table, " phlegm ") == SFIP_FAILURE);
240     TEST(sfvt_add_str(table, " phlegm [") == SFIP_FAILURE);
241     TEST(sfvt_add_str(table, " phlegm [ ") == SFIP_FAILURE);
242     TEST(sfvt_add_str(table, " phlegm [sdfg ") == SFIP_FAILURE);
243     TEST(sfvt_add_str(table, " phlegm [ sdfg, 12.123.1.4.5 }") == SFIP_FAILURE);
244     TEST(sfvt_add_str(table, " [ 12.123.1.4.5 ]") == SFIP_FAILURE);
245     TEST(sfvt_add_str(table, NULL) == SFIP_FAILURE);
246     TEST(sfvt_add_str(table, "") == SFIP_FAILURE);
247 
248     puts("");
249     puts("********************************************************************");
250     puts("Expansions:");
251     /* Note: used this way leaks memory */
252     printf("\t%s\n", sfvt_alloc_expanded(table, "$foo"));
253     printf("\t%s\n", sfvt_alloc_expanded(table, "goo $goo sf sfasdfasdf $moo"));
254     printf("\t%s\n", sfvt_alloc_expanded(table, " ssdf $moo $moo asdf $fooadff $foo "));
255     printf("\t%s\n", sfvt_alloc_expanded(table, " ssdf $moo $moo\\sdf $foo adff"));
256 
257     puts("");
258     puts("********************************************************************");
259     puts("Containment checks:");
260     var = sfvt_lookup(table, "goo");
261     ip = sfip_alloc("192.168.248.255");
262     TEST(sfvar_ip_in(var, ip) == SFIP_SUCCESS);
263 
264     /* Check against the 'any' variable */
265     var = sfvt_lookup_var(table, "moo");
266     TEST(sfvar_ip_in(var, ip) == SFIP_SUCCESS);
267 
268     /* Verify it's not in this variable */
269     var = sfvt_lookup_var(table, "foo");
270     TEST(sfvar_ip_in(var, ip) == SFIP_FAILURE);
271 
272     /* Check boundary cases */
273     var = sfvt_lookup_var(table, "goo");
274     free_ip(ip);
275     ip = sfip_alloc_str("192.168.0.3");
276     TEST(sfvar_ip_in(var, ip) == SFIP_FAILURE);
277     free_ip(ip);
278     ip = sfip_alloc_str("192.168.0.2");
279     TEST(sfvar_ip_in(var, ip) == SFIP_SUCCESS);
280 
281 
282     puts("");
283     puts("********************************************************************");
284 
285     printf("\n\tTotal Failures: %d\n", failures);
286     return 0;
287 }
288 #endif
289