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