blob: c244bb7d315569dc8dbf16d16b7679b9b757e196 [file] [log] [blame]
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +01001/*
2 * MAP management functions.
3 *
4 * Copyright 2000-2013 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <limits.h>
14#include <stdio.h>
15
16#include <common/standard.h>
17
18#include <types/global.h>
19#include <types/map.h>
20
21#include <proto/arg.h>
Thierry FOURNIERb0c0a0f2013-12-10 15:05:34 +010022#include <proto/map.h>
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010023#include <proto/pattern.h>
24#include <proto/sample.h>
25
Thierry FOURNIER275db692013-12-06 10:39:36 +010026struct list maps = LIST_HEAD_INIT(maps); /* list of struct map_reference */
27
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010028/* This function return existing map reference or return NULL. */
Thierry FOURNIER2d4771b2013-12-06 10:39:48 +010029struct map_reference *map_get_reference(const char *reference)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010030{
31 struct map_reference *ref;
32
33 /* process the lookup */
34 list_for_each_entry(ref, &maps, list)
35 if (strcmp(ref->reference, reference) == 0)
36 return ref;
37 return NULL;
38}
39
40/* Parse an IPv4 address and store it into the sample.
41 * The output type is IPV4.
42 */
Thierry FOURNIERb0c0a0f2013-12-10 15:05:34 +010043int map_parse_ip(const char *text, struct sample_storage *smp)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010044{
45 if (!buf2ip(text, strlen(text), &smp->data.ipv4))
46 return 0;
47 smp->type = SMP_T_IPV4;
48 return 1;
49}
50
51/* Parse an IPv6 address and store it into the sample.
52 * The output type is IPV6.
53 */
Thierry FOURNIERb0c0a0f2013-12-10 15:05:34 +010054int map_parse_ip6(const char *text, struct sample_storage *smp)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010055{
56 if (!buf2ip6(text, strlen(text), &smp->data.ipv6))
57 return 0;
58 smp->type = SMP_T_IPV6;
59 return 1;
60}
61
62/* Parse a string and store a pointer to it into the sample. The original
63 * string must be left in memory because we return a direct memory reference.
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010064 * The output type is SMP_T_STR. There is no risk that the data will be
65 * overwritten because sample_conv_map() makes a const sample with this
66 * output.
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010067 */
Thierry FOURNIERb0c0a0f2013-12-10 15:05:34 +010068int map_parse_str(const char *text, struct sample_storage *smp)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010069{
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010070 smp->data.str.str = (char *)text;
71 smp->data.str.len = strlen(text);
72 smp->data.str.size = smp->data.str.len + 1;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010073 smp->type = SMP_T_STR;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010074 return 1;
75}
76
77/* Parse an integer and convert it to a sample. The output type is SINT if the
78 * number is negative, or UINT if it is positive or null. The function returns
79 * zero (error) if the number is too large.
80 */
Thierry FOURNIERb0c0a0f2013-12-10 15:05:34 +010081int map_parse_int(const char *text, struct sample_storage *smp)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010082{
83 long long int value;
84 char *error;
85
86 /* parse interger and convert it. Return the value in 64 format. */
87 value = strtoll(text, &error, 10);
88 if (*error != '\0')
89 return 0;
90
91 /* check sign iand limits */
92 if (value < 0) {
93 if (value < INT_MIN)
94 return 0;
95 smp->type = SMP_T_SINT;
96 smp->data.sint = value;
97 }
98 else {
99 if (value > UINT_MAX)
100 return 0;
101 smp->type = SMP_T_UINT;
102 smp->data.uint = value;
103 }
104
105 return 1;
106}
107
108/* This function creates and initializes a new map_reference entry. This
109 * function only fails in case of a memory allocation issue, in which case
110 * it returns NULL. <reference> here is a unique identifier for the map's
111 * contents, typically the name of the file used to build the map.
112 */
113static struct map_reference *map_create_reference(const char *reference)
114{
115 struct map_reference *ref;
116
117 /* create new entry */
118 ref = calloc(1, sizeof(*ref));
119 if (!ref)
120 return NULL;
121
122 ref->reference = strdup(reference);
123 if (!ref->reference)
124 return NULL;
125
126 LIST_INIT(&ref->entries);
127 LIST_INIT(&ref->maps);
128 LIST_ADDQ(&maps, &ref->list);
129
130 return ref;
131}
132
133/* This function just create new entry */
134static struct map_entry *map_create_entry(int line, char *key, char *value)
135{
136 struct map_entry *ent;
137
138 ent = calloc(1, sizeof(*ent));
139 if (!ent)
140 return NULL;
141
142 ent->line = line;
143
144 ent->key = strdup(key);
145 if (!ent->key) {
146 free(ent);
147 return NULL;
148 }
149
150 ent->value = strdup(value);
151 if (!ent->value) {
152 free(ent->key);
153 free(ent);
154 return NULL;
155 }
156
157 return ent;
158}
159
160/* This crete and initialize map descriptor.
161 * Return NULL if out of memory error
162 */
163static struct map_descriptor *map_create_descriptor(struct map_reference *ref,
164 struct sample_conv *conv)
165{
166 struct map_descriptor *desc;
167
168 desc = calloc(1, sizeof(*desc));
169 if (!desc)
170 return NULL;
171
172 desc->conv = conv;
Thierry FOURNIERa82d2022013-12-05 11:59:55 +0100173 desc->ref = ref;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100174
175 LIST_ADDQ(&ref->maps, &desc->list);
176
177 return desc;
178}
179
180/* This function just add entry into the list of pattern.
181 * It can return false only in memory problem case
182 */
183static int map_add_entry(struct map_reference *map, int line, char *key, char *value)
184{
185 struct map_entry *ent;
186
187 ent = map_create_entry(line, key, value);
188 if (!ent)
189 return 0;
190 LIST_ADDQ(&map->entries, &ent->list);
191 return 1;
192}
193
194/* Reads patterns from a file. If <err_msg> is non-NULL, an error message will
195 * be returned there on errors and the caller will have to free it.
196 *
197 * The file contains one key + value per line. Lines which start with '#' are
198 * ignored, just like empty lines. Leading tabs/spaces are stripped. The key is
199 * then the first "word" (series of non-space/tabs characters), and the value is
200 * what follows this series of space/tab till the end of the line excluding
201 * trailing spaces/tabs.
202 *
203 * Example :
204 *
205 * # this is a comment and is ignored
206 * 62.212.114.60 1wt.eu \n
207 * <-><-----------><---><----><---->
208 * | | | | `--- trailing spaces ignored
209 * | | | `-------- value
210 * | | `--------------- middle spaces ignored
211 * | `------------------------ key
212 * `-------------------------------- leading spaces ignored
213 *
214 * Return non-zero in case of succes, otherwise 0.
215 */
216static int map_read_entries_from_file(const char *filename,
217 struct map_reference *ref,
218 char **err)
219{
220 FILE *file;
221 char *c;
222 int ret = 0;
223 int line = 0;
224 char *key_beg;
225 char *key_end;
226 char *value_beg;
227 char *value_end;
228
229 file = fopen(filename, "r");
230 if (!file) {
231 memprintf(err, "failed to open pattern file <%s>", filename);
232 return 0;
233 }
234
235 /* now parse all patterns. The file may contain only one pattern
236 * followed by one value per line. The start spaces, separator spaces
237 * and and spaces are stripped. Each can contain comment started by '#'
238 */
239 while (fgets(trash.str, trash.size, file) != NULL) {
240 line++;
241 c = trash.str;
242
243 /* ignore lines beginning with a dash */
244 if (*c == '#')
245 continue;
246
247 /* strip leading spaces and tabs */
248 while (*c == ' ' || *c == '\t')
249 c++;
250
251 /* empty lines are ignored too */
Thierry FOURNIER338a0312014-02-26 18:30:13 +0100252 if (*c == '\0' || *c == '\r' || *c == '\n')
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100253 continue;
254
255 /* look for the end of the key */
256 key_beg = c;
257 while (*c && *c != ' ' && *c != '\t' && *c != '\n' && *c != '\r')
258 c++;
259
260 key_end = c;
261
262 /* strip middle spaces and tabs */
263 while (*c == ' ' || *c == '\t')
264 c++;
265
266 /* look for the end of the value, it is the end of the line */
267 value_beg = c;
268 while (*c && *c != '\n' && *c != '\r')
269 c++;
270 value_end = c;
271
272 /* trim possibly trailing spaces and tabs */
273 while (value_end > value_beg && (value_end[-1] == ' ' || value_end[-1] == '\t'))
274 value_end--;
275
276 /* set final \0 and check entries */
277 *key_end = '\0';
278 *value_end = '\0';
279
280 /* insert values */
281 if (!map_add_entry(ref, line, key_beg, value_beg)) {
282 memprintf(err, "out of memory");
283 goto out_close;
284 }
285 }
286
287 /* succes */
288 ret = 1;
289
290 out_close:
291 fclose(file);
292 return ret;
293}
294
295/* This function read the string entries of <ent>, parse it with
296 * the <desc> methods, and strore the result into <desc> dummy ACL.
297 * return 1 in succes case, else return 0 and <err> is filled.
298 *
299 * The acm parser use <pattern> for creating new pattern (list
300 * of values case) or using the same pattern (tree index case).
301 *
302 * <patflags> must be PAT_F_*.
303 */
304static int map_parse_and_index(struct map_descriptor *desc,
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100305 struct map_entry *ent,
306 int patflags,
307 char **err)
308{
309 struct sample_storage *smp;
310
311 /* use new smp for storing value */
312 smp = calloc(1, sizeof(*smp));
313 if (!smp)
314 return 0;
315
316 /* first read and convert value */
317 if (!desc->parse(ent->value, smp)) {
318 memprintf(err, "parse value failed at line %d of file <%s>",
319 ent->line, desc->ref->reference);
320 return 0;
321 }
322
Thierry FOURNIER7148ce62013-12-06 19:06:43 +0100323 /* register key */
Thierry FOURNIERb9b08462013-12-13 15:12:32 +0100324 if (!pattern_register(desc->pat, ent->key, smp, patflags, err))
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100325 return 0;
326
327 return 1;
328}
329
330/* This function load the map file according with data type declared into
331 * the "struct sample_conv".
332 *
333 * This function choose the indexation type (ebtree or list) according with
334 * the type of match needed.
335 */
336static int sample_load_map(struct arg *arg, struct sample_conv *conv, char **err)
337{
338 struct map_reference *ref;
339 struct map_descriptor *desc;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100340 struct map_entry *ent;
Thierry FOURNIER0ffe78c2013-12-05 14:40:25 +0100341 struct pattern_expr *pat = NULL;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100342
343 /* look for existing map reference. The reference is the
344 * file encountered in the first argument. arg[0] with string
345 * type is guaranteed by the parser.
346 */
347 ref = map_get_reference(arg[0].data.str.str);
348
349 /* The reference doesn't exist */
350 if (!ref) {
351
352 /* create new reference entry */
353 ref = map_create_reference(arg[0].data.str.str);
354 if (!ref) {
355 memprintf(err, "out of memory");
356 return 0;
357 }
358
359 /* load the file */
360 if (!map_read_entries_from_file(arg[0].data.str.str, ref, err))
361 return 0;
362 }
363
Thierry FOURNIER0ffe78c2013-12-05 14:40:25 +0100364 /* look for identical existing map. Two maps are identical if
365 * their in_type and out_type are the same. If is not found, pat
366 * is NULL.
367 */
368 else {
369 list_for_each_entry(desc, &ref->maps, list)
370 if (desc->conv->in_type == conv->in_type &&
Thierry FOURNIER736459e2013-12-11 11:20:24 +0100371 desc->conv->out_type == conv->out_type &&
372 desc->conv->private == conv->private)
Thierry FOURNIER0ffe78c2013-12-05 14:40:25 +0100373 break;
374 if (&desc->list != &ref->maps)
375 pat = desc->pat;
376 }
377
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100378 /* create new map descriptor */
379 desc = map_create_descriptor(ref, conv);
380 if (!desc) {
381 memprintf(err, "out of memory");
382 return 0;
383 }
384
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100385 /* check the output parse method */
386 switch (desc->conv->out_type) {
387 case SMP_T_STR: desc->parse = map_parse_str; break;
388 case SMP_T_UINT: desc->parse = map_parse_int; break;
389 case SMP_T_IPV4: desc->parse = map_parse_ip; break;
390 case SMP_T_IPV6: desc->parse = map_parse_ip6; break;
391 default:
392 memprintf(err, "map: internal haproxy error: no default parse case for the input type <%d>.",
393 conv->out_type);
394 return 0;
395 }
396
Thierry FOURNIER0ffe78c2013-12-05 14:40:25 +0100397 /* If identical pattern is not found, initialize his own pattern */
398 if (!pat) {
399
400 desc->pat = calloc(1, sizeof(*desc->pat));
401 if (!desc->pat) {
402 memprintf(err, "out of memory");
403 return 0;
404 }
405
406 pattern_init_expr(desc->pat);
407
408 /* This is original pattern, must free */
409 desc->do_free = 1;
410
411 /* set the match method */
412 desc->pat->match = pat_match_fcts[conv->private];
Thierry FOURNIER736459e2013-12-11 11:20:24 +0100413 desc->pat->parse = pat_parse_fcts[conv->private];
Thierry FOURNIERb9b08462013-12-13 15:12:32 +0100414 desc->pat->index = pat_index_fcts[conv->private];
Thierry FOURNIER0ffe78c2013-12-05 14:40:25 +0100415
416 /* parse each line of the file */
Thierry FOURNIER0ffe78c2013-12-05 14:40:25 +0100417 list_for_each_entry(ent, &ref->entries, list)
Thierry FOURNIERb9b08462013-12-13 15:12:32 +0100418 if (!map_parse_and_index(desc, ent, 0, err))
Thierry FOURNIER0ffe78c2013-12-05 14:40:25 +0100419 return 0;
420 }
421
422 /* identical pattern found. Use reference to this pattern, and mark
423 * the map_descriptor pattern as non freeable
424 */
425 else {
426 desc->pat = pat;
427 desc->do_free = 0;
428 }
429
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100430 /* The second argument is the default value */
431 if (arg[1].type == ARGT_STR) {
432 desc->default_value = strdup(arg[1].data.str.str);
433 if (!desc->default_value) {
434 memprintf(err, "out of memory");
435 return 0;
436 }
437 desc->def = calloc(1, sizeof(*desc->def));
438 if (!desc->def) {
439 memprintf(err, "out of memory");
440 return 0;
441 }
442 if (!desc->parse(desc->default_value, desc->def)) {
443 memprintf(err, "Cannot parse default value");
444 return 0;
445 }
446 }
447 else
448 desc->def = NULL;
449
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100450 /* replace the first argument by this definition */
451 arg[0].type = ARGT_MAP;
452 arg[0].data.map = desc;
453
454 return 1;
455}
456
457static int sample_conv_map(const struct arg *arg_p, struct sample *smp)
458{
459 struct map_descriptor *desc;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100460 struct pattern *pat;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100461
462 /* get config */
463 desc = arg_p[0].data.map;
464
465 /* Execute the match function. */
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100466 pat = pattern_exec_match(desc->pat, smp, 1);
467
468 /* Match case. */
469 if (pat) {
470 /* Copy sample. */
471 if (pat->smp) {
472 smp->type = pat->smp->type;
473 smp->flags |= SMP_F_CONST;
474 memcpy(&smp->data, &pat->smp->data, sizeof(smp->data));
475 return 1;
476 }
477
478 /* Return just int sample containing 1. */
479 smp->type = SMP_T_UINT;
480 smp->data.uint= 1;
481 return 1;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100482 }
483
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100484 /* If no default value avalaible, the converter fails. */
485 if (!desc->def)
486 return 0;
487
488 /* Return the default value. */
489 smp->type = desc->def->type;
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +0100490 smp->flags |= SMP_F_CONST;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100491 memcpy(&smp->data, &desc->def->data, sizeof(smp->data));
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100492 return 1;
493}
494
495/* Note: must not be declared <const> as its list will be overwritten
496 *
497 * For the map_*_int keywords, the output is declared as SMP_T_UINT, but the converter function
498 * can provide SMP_T_UINT, SMP_T_SINT or SMP_T_BOOL depending on how the patterns found in the
499 * file can be parsed.
500 *
501 * For the map_*_ip keyword, the output is declared as SMP_T_IPV4, but the converter function
502 * can provide SMP_T_IPV4 or SMP_T_IPV6 depending on the patterns found in the file.
503 *
504 * The map_* keywords only emit strings.
505 *
506 * The output type is only used during the configuration parsing. It is used for detecting
507 * compatibility problems.
508 *
509 * The arguments are: <file>[,<default value>]
510 */
511static struct sample_conv_kw_list sample_conv_kws = {ILH, {
512 { "map", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, PAT_MATCH_STR },
513 { "map_str", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, PAT_MATCH_STR },
514 { "map_beg", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, PAT_MATCH_BEG },
515 { "map_sub", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, PAT_MATCH_SUB },
516 { "map_dir", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, PAT_MATCH_DIR },
517 { "map_dom", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, PAT_MATCH_DOM },
518 { "map_end", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, PAT_MATCH_END },
519 { "map_reg", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, PAT_MATCH_REG },
520 { "map_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_UINT, SMP_T_STR, PAT_MATCH_INT },
521 { "map_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_ADDR, SMP_T_STR, PAT_MATCH_IP },
522
523 { "map_str_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_UINT, PAT_MATCH_STR },
524 { "map_beg_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_UINT, PAT_MATCH_BEG },
525 { "map_sub_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_UINT, PAT_MATCH_SUB },
526 { "map_dir_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_UINT, PAT_MATCH_DIR },
527 { "map_dom_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_UINT, PAT_MATCH_DOM },
528 { "map_end_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_UINT, PAT_MATCH_END },
529 { "map_reg_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_UINT, PAT_MATCH_REG },
530 { "map_int_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_UINT, SMP_T_UINT, PAT_MATCH_INT },
531 { "map_ip_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_ADDR, SMP_T_UINT, PAT_MATCH_IP },
532
533 { "map_str_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_IPV4, PAT_MATCH_STR },
534 { "map_beg_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_IPV4, PAT_MATCH_BEG },
535 { "map_sub_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_IPV4, PAT_MATCH_SUB },
536 { "map_dir_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_IPV4, PAT_MATCH_DIR },
537 { "map_dom_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_IPV4, PAT_MATCH_DOM },
538 { "map_end_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_IPV4, PAT_MATCH_END },
539 { "map_reg_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_IPV4, PAT_MATCH_REG },
540 { "map_int_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_UINT, SMP_T_IPV4, PAT_MATCH_INT },
541 { "map_ip_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_ADDR, SMP_T_IPV4, PAT_MATCH_IP },
542
543 { /* END */ },
544}};
545
546__attribute__((constructor))
547static void __map_init(void)
548{
549 /* register format conversion keywords */
550 sample_register_convs(&sample_conv_kws);
551}