blob: ac1c00ab16c73a931c82aa19454955b24e3220c7 [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);
Andreas Seltenreich78f35952016-03-03 20:32:23 +0100129 free(desc);
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100130 return 0;
131 }
132
Thierry FOURNIER39bef452014-01-29 13:29:45 +0100133 /* Load map. */
Thierry FOURNIERe47e4e22014-04-28 11:18:57 +0200134 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 +0100135 1, err, file, line))
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100136 return 0;
Thierry FOURNIER0ffe78c2013-12-05 14:40:25 +0100137
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +0200138 /* the maps of type IP have a string as defaultvalue. This
139 * string canbe anipv4 or an ipv6, we must convert it.
140 */
141 if (desc->conv->out_type == SMP_T_ADDR) {
142 struct sample_data data;
143 if (!map_parse_ip(arg[1].data.str.str, &data)) {
144 memprintf(err, "map: cannot parse default ip <%s>.", arg[1].data.str.str);
145 return 0;
146 }
147 if (data.type == SMP_T_IPV4) {
148 arg[1].type = ARGT_IPV4;
149 arg[1].data.ipv4 = data.u.ipv4;
150 } else {
151 arg[1].type = ARGT_IPV6;
152 arg[1].data.ipv6 = data.u.ipv6;
153 }
154 }
155
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100156 /* replace the first argument by this definition */
157 arg[0].type = ARGT_MAP;
158 arg[0].data.map = desc;
159
160 return 1;
161}
162
Thierry FOURNIER0a9a2b82015-05-11 15:20:49 +0200163static int sample_conv_map(const struct arg *arg_p, struct sample *smp, void *private)
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100164{
165 struct map_descriptor *desc;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100166 struct pattern *pat;
Thierry Fournier8feaa662016-02-10 22:55:20 +0100167 struct chunk *str;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100168
169 /* get config */
170 desc = arg_p[0].data.map;
171
172 /* Execute the match function. */
Thierry FOURNIER1e00d382014-02-11 11:31:40 +0100173 pat = pattern_exec_match(&desc->pat, smp, 1);
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100174
175 /* Match case. */
176 if (pat) {
Thierry FOURNIER503bb092015-08-19 08:35:43 +0200177 if (pat->data) {
Thierry Fournier8feaa662016-02-10 22:55:20 +0100178 /* In the regm case, merge the sample with the input. */
179 if ((long)private == PAT_MATCH_REGM) {
180 str = get_trash_chunk();
181 str->len = exp_replace(str->str, str->size, smp->data.u.str.str,
182 pat->data->u.str.str,
183 (regmatch_t *)smp->ctx.a[0]);
184 if (str->len == -1)
185 return 0;
186 smp->data.u.str = *str;
187 return 1;
188 }
189 /* Copy sample. */
Thierry FOURNIER5cc18d42015-08-19 09:02:36 +0200190 smp->data = *pat->data;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100191 smp->flags |= SMP_F_CONST;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100192 return 1;
193 }
194
195 /* Return just int sample containing 1. */
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200196 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200197 smp->data.u.sint = 1;
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100198 return 1;
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100199 }
200
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100201 /* If no default value avalaible, the converter fails. */
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100202 if (arg_p[1].type == ARGT_STOP)
Thierry FOURNIER1794fdf2014-01-17 15:25:13 +0100203 return 0;
204
205 /* Return the default value. */
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100206 switch (desc->conv->out_type) {
207
208 case SMP_T_STR:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200209 smp->data.type = SMP_T_STR;
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100210 smp->flags |= SMP_F_CONST;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200211 smp->data.u.str = arg_p[1].data.str;
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100212 break;
213
Thierry FOURNIER07ee64e2015-07-06 23:43:03 +0200214 case SMP_T_SINT:
Thierry FOURNIER8c542ca2015-08-19 09:00:18 +0200215 smp->data.type = SMP_T_SINT;
Thierry FOURNIER136f9d32015-08-19 09:07:19 +0200216 smp->data.u.sint = arg_p[1].data.sint;
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100217 break;
218
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +0200219 case SMP_T_ADDR:
220 if (arg_p[1].type == ARGT_IPV4) {
221 smp->data.type = SMP_T_IPV4;
222 smp->data.u.ipv4 = arg_p[1].data.ipv4;
223 } else {
224 smp->data.type = SMP_T_IPV6;
225 smp->data.u.ipv6 = arg_p[1].data.ipv6;
226 }
Thierry FOURNIER933e5de2015-03-13 00:10:16 +0100227 break;
228 }
229
Thierry FOURNIERd5f624d2013-11-26 11:52:33 +0100230 return 1;
231}
232
233/* Note: must not be declared <const> as its list will be overwritten
234 *
235 * For the map_*_int keywords, the output is declared as SMP_T_UINT, but the converter function
236 * can provide SMP_T_UINT, SMP_T_SINT or SMP_T_BOOL depending on how the patterns found in the
237 * file can be parsed.
238 *
239 * For the map_*_ip keyword, the output is declared as SMP_T_IPV4, but the converter function
240 * can provide SMP_T_IPV4 or SMP_T_IPV6 depending on the patterns found in the file.
241 *
242 * The map_* keywords only emit strings.
243 *
244 * The output type is only used during the configuration parsing. It is used for detecting
245 * compatibility problems.
246 *
247 * The arguments are: <file>[,<default value>]
248 */
249static struct sample_conv_kw_list sample_conv_kws = {ILH, {
Thierry FOURNIER1edc9712014-12-15 16:18:39 +0100250 { "map", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_STR },
251 { "map_str", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_STR },
252 { "map_beg", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_BEG },
253 { "map_sub", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_SUB },
254 { "map_dir", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_DIR },
255 { "map_dom", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_DOM },
256 { "map_end", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_STR, (void *)PAT_MATCH_END },
257 { "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 +0100258 { "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 +0200259 { "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 +0100260 { "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 +0100261
Thierry FOURNIERbf65cd42015-07-20 17:45:02 +0200262 { "map_str_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_STR },
263 { "map_beg_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_BEG },
264 { "map_sub_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_SUB },
265 { "map_dir_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_DIR },
266 { "map_dom_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_DOM },
267 { "map_end_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_END },
268 { "map_reg_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_STR, SMP_T_SINT, (void *)PAT_MATCH_REG },
269 { "map_int_int", sample_conv_map, ARG2(1,STR,SINT), sample_load_map, SMP_T_SINT, SMP_T_SINT, (void *)PAT_MATCH_INT },
270 { "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 +0100271
Thierry FOURNIERb2f8f082015-08-04 19:35:46 +0200272 { "map_str_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_STR },
273 { "map_beg_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_BEG },
274 { "map_sub_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_SUB },
275 { "map_dir_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_DIR },
276 { "map_dom_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_DOM },
277 { "map_end_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_END },
278 { "map_reg_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_STR, SMP_T_ADDR, (void *)PAT_MATCH_REG },
279 { "map_int_ip", sample_conv_map, ARG2(1,STR,STR), sample_load_map, SMP_T_SINT, SMP_T_ADDR, (void *)PAT_MATCH_INT },
280 { "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 +0100281
282 { /* END */ },
283}};
284
285__attribute__((constructor))
286static void __map_init(void)
287{
288 /* register format conversion keywords */
289 sample_register_convs(&sample_conv_kws);
290}