blob: a28cedae926f69449c8c48d6ce13e3d001e4894c [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>
Thierry FOURNIER1e00d382014-02-11 11:31:40 +010020#include <types/pattern.h>
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010021
22#include <proto/arg.h>
Thierry FOURNIERb0c0a0f2013-12-10 15:05:34 +010023#include <proto/map.h>
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010024#include <proto/pattern.h>
25#include <proto/sample.h>
26
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +020027/* Parse an IPv4 or IPv6 address and store it into the sample.
28 * The output type is IPv4 or IPv6.
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010029 */
Thierry FOURNIER503bb092015-08-19 08:35:43 +020030int map_parse_ip(const char *text, struct sample_data *data)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010031{
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +020032 int len = strlen(text);
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010033
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +020034 if (buf2ip(text, len, &data->u.ipv4)) {
35 data->type = SMP_T_IPV4;
36 return 1;
37 }
38 if (buf2ip6(text, len, &data->u.ipv6)) {
39 data->type = SMP_T_IPV6;
40 return 1;
41 }
42 return 0;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010043}
44
45/* Parse a string and store a pointer to it into the sample. The original
46 * string must be left in memory because we return a direct memory reference.
Thierry FOURNIER7654c9f2013-12-17 00:20:33 +010047 * The output type is SMP_T_STR. There is no risk that the data will be
48 * overwritten because sample_conv_map() makes a const sample with this
49 * output.
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010050 */
Thierry FOURNIER503bb092015-08-19 08:35:43 +020051int map_parse_str(const char *text, struct sample_data *data)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010052{
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020053 data->u.str.str = (char *)text;
54 data->u.str.len = strlen(text);
55 data->u.str.size = data->u.str.len + 1;
Thierry FOURNIER503bb092015-08-19 08:35:43 +020056 data->type = SMP_T_STR;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010057 return 1;
58}
59
60/* Parse an integer and convert it to a sample. The output type is SINT if the
61 * number is negative, or UINT if it is positive or null. The function returns
62 * zero (error) if the number is too large.
63 */
Thierry FOURNIER503bb092015-08-19 08:35:43 +020064int map_parse_int(const char *text, struct sample_data *data)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010065{
Thierry FOURNIER503bb092015-08-19 08:35:43 +020066 data->type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +020067 data->u.sint = read_int64(&text, text + strlen(text));
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +020068 if (*text != '\0')
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010069 return 0;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010070 return 1;
71}
72
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010073/* This crete and initialize map descriptor.
74 * Return NULL if out of memory error
75 */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +010076static struct map_descriptor *map_create_descriptor(struct sample_conv *conv)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010077{
78 struct map_descriptor *desc;
79
80 desc = calloc(1, sizeof(*desc));
81 if (!desc)
82 return NULL;
83
84 desc->conv = conv;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010085
86 return desc;
87}
88
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010089/* This function load the map file according with data type declared into
90 * the "struct sample_conv".
91 *
92 * This function choose the indexation type (ebtree or list) according with
93 * the type of match needed.
94 */
Thierry FOURNIER3def3932015-04-07 11:27:54 +020095int sample_load_map(struct arg *arg, struct sample_conv *conv,
96 const char *file, int line, char **err)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010097{
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010098 struct map_descriptor *desc;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +010099
100 /* create new map descriptor */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100101 desc = map_create_descriptor(conv);
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100102 if (!desc) {
103 memprintf(err, "out of memory");
104 return 0;
105 }
106
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100107 /* Initialize pattern */
108 pattern_init_head(&desc->pat);
109
110 /* This is original pattern, must free */
111 desc->do_free = 1;
112
113 /* Set the match method. */
Thierry FOURNIER1edc9712014-12-15 16:18:39 +0100114 desc->pat.match = pat_match_fcts[(long)conv->private];
115 desc->pat.parse = pat_parse_fcts[(long)conv->private];
116 desc->pat.index = pat_index_fcts[(long)conv->private];
117 desc->pat.delete = pat_delete_fcts[(long)conv->private];
118 desc->pat.prune = pat_prune_fcts[(long)conv->private];
119 desc->pat.expect_type = pat_match_types[(long)conv->private];
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100120
121 /* Set the output parse method. */
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100122 switch (desc->conv->out_type) {
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100123 case SMP_T_STR: desc->pat.parse_smp = map_parse_str; break;
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200124 case SMP_T_SINT: desc->pat.parse_smp = map_parse_int; break;
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +0200125 case SMP_T_ADDR: desc->pat.parse_smp = map_parse_ip; break;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100126 default:
127 memprintf(err, "map: internal haproxy error: no default parse case for the input type <%d>.",
128 conv->out_type);
129 return 0;
130 }
131
Thierry FOURNIER39bef452014-01-29 13:29:45 +0100132 /* Load map. */
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +0200133 if (!pattern_read_from_file(&desc->pat, PAT_REF_MAP, arg[0].data.str.str, PAT_MF_NO_DNS,
Thierry FOURNIER94580c92014-02-11 14:36:45 +0100134 1, err, file, line))
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100135 return 0;
Thierry FOURNIER0ffe78c2013-12-05 14:40:25 +0100136
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +0200137 /* the maps of type IP have a string as defaultvalue. This
138 * string canbe anipv4 or an ipv6, we must convert it.
139 */
140 if (desc->conv->out_type == SMP_T_ADDR) {
141 struct sample_data data;
142 if (!map_parse_ip(arg[1].data.str.str, &data)) {
143 memprintf(err, "map: cannot parse default ip <%s>.", arg[1].data.str.str);
144 return 0;
145 }
146 if (data.type == SMP_T_IPV4) {
147 arg[1].type = ARGT_IPV4;
148 arg[1].data.ipv4 = data.u.ipv4;
149 } else {
150 arg[1].type = ARGT_IPV6;
151 arg[1].data.ipv6 = data.u.ipv6;
152 }
153 }
154
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100155 /* replace the first argument by this definition */
156 arg[0].type = ARGT_MAP;
157 arg[0].data.map = desc;
158
159 return 1;
160}
161
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200162static int sample_conv_map(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100163{
164 struct map_descriptor *desc;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100165 struct pattern *pat;
Thierry Fournier8feaa662016-02-10 22:55:20 +0100166 struct chunk *str;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100167
168 /* get config */
169 desc = arg_p[0].data.map;
170
171 /* Execute the match function. */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100172 pat = pattern_exec_match(&desc->pat, smp, 1);
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100173
174 /* Match case. */
175 if (pat) {
Thierry FOURNIER503bb092015-08-19 08:35:43 +0200176 if (pat->data) {
Thierry Fournier8feaa662016-02-10 22:55:20 +0100177 /* In the regm case, merge the sample with the input. */
178 if ((long)private == PAT_MATCH_REGM) {
179 str = get_trash_chunk();
180 str->len = exp_replace(str->str, str->size, smp->data.u.str.str,
181 pat->data->u.str.str,
182 (regmatch_t *)smp->ctx.a[0]);
183 if (str->len == -1)
184 return 0;
185 smp->data.u.str = *str;
186 return 1;
187 }
188 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200189 smp->data = *pat->data;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100190 smp->flags |= SMP_F_CONST;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100191 return 1;
192 }
193
194 /* Return just int sample containing 1. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200195 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200196 smp->data.u.sint = 1;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100197 return 1;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100198 }
199
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100200 /* If no default value avalaible, the converter fails. */
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100201 if (arg_p[1].type == ARGT_STOP)
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100202 return 0;
203
204 /* Return the default value. */
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100205 switch (desc->conv->out_type) {
206
207 case SMP_T_STR:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200208 smp->data.type = SMP_T_STR;
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100209 smp->flags |= SMP_F_CONST;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200210 smp->data.u.str = arg_p[1].data.str;
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100211 break;
212
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200213 case SMP_T_SINT:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200214 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200215 smp->data.u.sint = arg_p[1].data.sint;
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100216 break;
217
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +0200218 case SMP_T_ADDR:
219 if (arg_p[1].type == ARGT_IPV4) {
220 smp->data.type = SMP_T_IPV4;
221 smp->data.u.ipv4 = arg_p[1].data.ipv4;
222 } else {
223 smp->data.type = SMP_T_IPV6;
224 smp->data.u.ipv6 = arg_p[1].data.ipv6;
225 }
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100226 break;
227 }
228
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100229 return 1;
230}
231
232/* Note: must not be declared <const> as its list will be overwritten
233 *
234 * For the map_*_int keywords, the output is declared as SMP_T_UINT, but the converter function
235 * can provide SMP_T_UINT, SMP_T_SINT or SMP_T_BOOL depending on how the patterns found in the
236 * file can be parsed.
237 *
238 * For the map_*_ip keyword, the output is declared as SMP_T_IPV4, but the converter function
239 * can provide SMP_T_IPV4 or SMP_T_IPV6 depending on the patterns found in the file.
240 *
241 * The map_* keywords only emit strings.
242 *
243 * The output type is only used during the configuration parsing. It is used for detecting
244 * compatibility problems.
245 *
246 * The arguments are: <file>[,<default value>]
247 */
248static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Thierry FOURNIER1edc9712014-12-15 16:18:39 +0100249 { "map", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_STR },
250 { "map_str", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_STR },
251 { "map_beg", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_BEG },
252 { "map_sub", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_SUB },
253 { "map_dir", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_DIR },
254 { "map_dom", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_DOM },
255 { "map_end", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_END },
256 { "map_reg", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_REG },
Thierry Fournier8feaa662016-02-10 22:55:20 +0100257 { "map_regm", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_REGM},
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200258 { "map_int", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_SINT, SMP_T_STR, (void *)PAT_MATCH_INT },
Thierry FOURNIER1edc9712014-12-15 16:18:39 +0100259 { "map_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_ADDR, SMP_T_STR, (void *)PAT_MATCH_IP },
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100260
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200261 { "map_str_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_STR },
262 { "map_beg_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_BEG },
263 { "map_sub_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_SUB },
264 { "map_dir_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_DIR },
265 { "map_dom_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_DOM },
266 { "map_end_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_END },
267 { "map_reg_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_REG },
268 { "map_int_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_SINT, SMP_T_SINT, (void *)PAT_MATCH_INT },
269 { "map_ip_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_ADDR, SMP_T_SINT, (void *)PAT_MATCH_IP },
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100270
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +0200271 { "map_str_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_STR },
272 { "map_beg_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_BEG },
273 { "map_sub_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_SUB },
274 { "map_dir_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_DIR },
275 { "map_dom_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_DOM },
276 { "map_end_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_END },
277 { "map_reg_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_REG },
278 { "map_int_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_SINT, SMP_T_ADDR, (void *)PAT_MATCH_INT },
279 { "map_ip_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_ADDR, SMP_T_ADDR, (void *)PAT_MATCH_IP },
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100280
281 { /* END */ },
282}};
283
284__attribute__((constructor))
285static void __map_init(void)
286{
287 /* register format conversion keywords */
288 sample_register_convs(&sample_conv_kws);
289}