blob: 0c568efa0a2c066b377d2c34b0bb643d161e0571 [file] [log] [blame]
Emeric Brun107ca302010-01-04 16:16:05 +01001/*
2 * Patterns management functions.
3 *
4 * Copyright 2009-2010 EXCELIANCE, Emeric Brun <ebrun@exceliance.fr>
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 <string.h>
14#include <arpa/inet.h>
Emeric Brun107ca302010-01-04 16:16:05 +010015
Willy Tarreau9fcb9842012-04-20 14:45:49 +020016#include <proto/arg.h>
Emeric Brun107ca302010-01-04 16:16:05 +010017#include <proto/pattern.h>
Emeric Brun485479d2010-09-23 18:02:19 +020018#include <proto/buffers.h>
Emeric Brun107ca302010-01-04 16:16:05 +010019#include <common/standard.h>
20
21/* static structure used on pattern_process if <p> is NULL*/
Willy Tarreau5e6cc4a2011-12-16 15:23:14 +010022struct pattern temp_pattern = { };
Emeric Brun107ca302010-01-04 16:16:05 +010023
24/* trash chunk used for pattern conversions */
25static struct chunk trash_chunk;
26
27/* trash buffers used or pattern conversions */
28static char pattern_trash_buf1[BUFSIZE];
29static char pattern_trash_buf2[BUFSIZE];
30
31/* pattern_trash_buf point on used buffer*/
32static char *pattern_trash_buf = pattern_trash_buf1;
33
Emeric Brun107ca302010-01-04 16:16:05 +010034/* list head of all known pattern fetch keywords */
35static struct pattern_fetch_kw_list pattern_fetches = {
36 .list = LIST_HEAD_INIT(pattern_fetches.list)
37};
38
39/* list head of all known pattern format conversion keywords */
40static struct pattern_conv_kw_list pattern_convs = {
41 .list = LIST_HEAD_INIT(pattern_convs.list)
42};
43
44/*
45 * Registers the pattern fetch keyword list <kwl> as a list of valid keywords for next
46 * parsing sessions.
47 */
48void pattern_register_fetches(struct pattern_fetch_kw_list *pfkl)
49{
50 LIST_ADDQ(&pattern_fetches.list, &pfkl->list);
51}
52
53/*
54 * Registers the pattern format coverstion keyword list <pckl> as a list of valid keywords for next
55 * parsing sessions.
56 */
57void pattern_register_convs(struct pattern_conv_kw_list *pckl)
58{
59 LIST_ADDQ(&pattern_convs.list, &pckl->list);
60}
61
62/*
63 * Returns the pointer on pattern fetch keyword structure identified by
64 * string of <len> in buffer <kw>.
65 *
66 */
67struct pattern_fetch *find_pattern_fetch(const char *kw, int len)
68{
69 int index;
70 struct pattern_fetch_kw_list *kwl;
71
72 list_for_each_entry(kwl, &pattern_fetches.list, list) {
73 for (index = 0; kwl->kw[index].kw != NULL; index++) {
74 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
75 kwl->kw[index].kw[len] == '\0')
76 return &kwl->kw[index];
77 }
78 }
79 return NULL;
80}
81
82/*
83 * Returns the pointer on pattern format conversion keyword structure identified by
84 * string of <len> in buffer <kw>.
85 *
86 */
87struct pattern_conv *find_pattern_conv(const char *kw, int len)
88{
89 int index;
90 struct pattern_conv_kw_list *kwl;
91
92 list_for_each_entry(kwl, &pattern_convs.list, list) {
93 for (index = 0; kwl->kw[index].kw != NULL; index++) {
94 if (strncmp(kwl->kw[index].kw, kw, len) == 0 &&
95 kwl->kw[index].kw[len] == '\0')
96 return &kwl->kw[index];
97 }
98 }
99 return NULL;
100}
101
102
103/*
104* Returns a static trash struct chunk to use in pattern casts or format conversions
105* Swiths the 2 available trash buffers to protect data during convert
106*/
107static struct chunk *get_trash_chunk(void)
108{
109 if (pattern_trash_buf == pattern_trash_buf1)
110 pattern_trash_buf = pattern_trash_buf2;
111 else
112 pattern_trash_buf = pattern_trash_buf1;
113
Emeric Brun485479d2010-09-23 18:02:19 +0200114 chunk_init(&trash_chunk, pattern_trash_buf, BUFSIZE);
Emeric Brun107ca302010-01-04 16:16:05 +0100115
116 return &trash_chunk;
117}
118
Emeric Brun107ca302010-01-04 16:16:05 +0100119/******************************************************************/
120/* Pattern casts functions */
121/******************************************************************/
122
123static int c_ip2int(union pattern_data *data)
124{
125 data->integer = ntohl(data->ip.s_addr);
126 return 1;
127}
128
129static int c_ip2str(union pattern_data *data)
130{
131 struct chunk *trash = get_trash_chunk();
132
133 if (!inet_ntop(AF_INET, (void *)&data->ip, trash->str, trash->size))
134 return 0;
135
136 trash->len = strlen(trash->str);
Willy Tarreau1ded6052011-12-16 15:35:46 +0100137 data->str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100138
139 return 1;
140}
141
David du Colombier4f92d322011-03-24 11:09:31 +0100142static int c_ip2ipv6(union pattern_data *data)
143{
144 v4tov6(&data->ipv6, &data->ip);
145 return 1;
146}
147
148static int c_ipv62str(union pattern_data *data)
149{
150 struct chunk *trash = get_trash_chunk();
151
152 if (!inet_ntop(AF_INET6, (void *)&data->ipv6, trash->str, trash->size))
153 return 0;
154
155 trash->len = strlen(trash->str);
Willy Tarreau1ded6052011-12-16 15:35:46 +0100156 data->str = *trash;
David du Colombier4f92d322011-03-24 11:09:31 +0100157 return 1;
158}
159
160/*
161static int c_ipv62ip(union pattern_data *data)
162{
163 return v6tov4(&data->ip, &data->ipv6);
164}
165*/
166
Emeric Brun107ca302010-01-04 16:16:05 +0100167static int c_int2ip(union pattern_data *data)
168{
169 data->ip.s_addr = htonl(data->integer);
170 return 1;
171}
172
Emeric Brun107ca302010-01-04 16:16:05 +0100173static int c_str2ip(union pattern_data *data)
174{
175 if (!buf2ip(data->str.str, data->str.len, &data->ip))
176 return 0;
177 return 1;
178}
179
David du Colombier4f92d322011-03-24 11:09:31 +0100180static int c_str2ipv6(union pattern_data *data)
181{
182 return inet_pton(AF_INET6, data->str.str, &data->ipv6);
183}
184
Emeric Brun107ca302010-01-04 16:16:05 +0100185static int c_int2str(union pattern_data *data)
186{
187 struct chunk *trash = get_trash_chunk();
188 char *pos;
189
190 pos = ultoa_r(data->integer, trash->str, trash->size);
191
192 if (!pos)
193 return 0;
194
Emeric Brun485479d2010-09-23 18:02:19 +0200195 trash->size = trash->size - (pos - trash->str);
Emeric Brun107ca302010-01-04 16:16:05 +0100196 trash->str = pos;
197 trash->len = strlen(pos);
Willy Tarreau1ded6052011-12-16 15:35:46 +0100198 data->str = *trash;
Emeric Brun107ca302010-01-04 16:16:05 +0100199 return 1;
200}
201
Emeric Brun485479d2010-09-23 18:02:19 +0200202static int c_datadup(union pattern_data *data)
203{
204 struct chunk *trash = get_trash_chunk();
205
206 trash->len = data->str.len < trash->size ? data->str.len : trash->size;
207 memcpy(trash->str, data->str.str, trash->len);
Willy Tarreau1ded6052011-12-16 15:35:46 +0100208 data->str = *trash;
Emeric Brun485479d2010-09-23 18:02:19 +0200209 return 1;
210}
211
212
Emeric Brun107ca302010-01-04 16:16:05 +0100213static int c_donothing(union pattern_data *data)
214{
215 return 1;
216}
217
218static int c_str2int(union pattern_data *data)
219{
220 int i;
221 uint32_t ret = 0;
222
223 for (i = 0; i < data->str.len; i++) {
224 uint32_t val = data->str.str[i] - '0';
225
226 if (val > 9)
227 break;
228
229 ret = ret * 10 + val;
230 }
231
232 data->integer = ret;
233 return 1;
234}
235
236/*****************************************************************/
237/* Pattern casts matrix: */
238/* pattern_casts[from type][to type] */
239/* NULL pointer used for impossible pattern casts */
240/*****************************************************************/
Emeric Brun107ca302010-01-04 16:16:05 +0100241
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200242typedef int (*pattern_cast_fct)(union pattern_data *data);
243static pattern_cast_fct pattern_casts[PATTERN_TYPES][PATTERN_TYPES] = {
David du Colombier4f92d322011-03-24 11:09:31 +0100244/* to: IP IPV6 INTEGER STRING DATA CONSTSTRING CONSTDATA */
245/* from: IP */ { c_donothing, c_ip2ipv6, c_ip2int, c_ip2str, NULL, c_ip2str, NULL },
246/* IPV6 */ { NULL, c_donothing, NULL, c_ipv62str, NULL, c_ipv62str, NULL },
247/* INTEGER */ { c_int2ip, NULL, c_donothing, c_int2str, NULL, c_int2str, NULL },
248/* STRING */ { c_str2ip, c_str2ipv6, c_str2int, c_donothing, c_donothing, c_donothing, c_donothing },
249/* DATA */ { NULL, NULL, NULL, NULL, c_donothing, NULL, c_donothing },
250/* CONSTSTRING */ { c_str2ip, c_str2ipv6, c_str2int, c_datadup, c_datadup, c_donothing, c_donothing },
251/* CONSTDATA */ { NULL, NULL, NULL, NULL, c_datadup, NULL, c_donothing },
Willy Tarreauf0b38bf2010-06-06 13:22:23 +0200252};
Emeric Brun107ca302010-01-04 16:16:05 +0100253
Emeric Brun107ca302010-01-04 16:16:05 +0100254
Emeric Brun107ca302010-01-04 16:16:05 +0100255/*
256 * Parse a pattern expression configuration:
257 * fetch keyword followed by format conversion keywords.
258 * Returns a pointer on allocated pattern expression structure.
259 */
Emeric Brun485479d2010-09-23 18:02:19 +0200260struct pattern_expr *pattern_parse_expr(char **str, int *idx, char *err, int err_size)
Emeric Brun107ca302010-01-04 16:16:05 +0100261{
262 const char *endw;
263 const char *end;
264 struct pattern_expr *expr;
265 struct pattern_fetch *fetch;
266 struct pattern_conv *conv;
267 unsigned long prev_type;
Emeric Brun485479d2010-09-23 18:02:19 +0200268 char *p;
Emeric Brun107ca302010-01-04 16:16:05 +0100269
Emeric Brun485479d2010-09-23 18:02:19 +0200270 snprintf(err, err_size, "memory error.");
271 if (!str[*idx]) {
272
273 snprintf(err, err_size, "missing fetch method.");
Emeric Brun107ca302010-01-04 16:16:05 +0100274 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200275 }
Emeric Brun107ca302010-01-04 16:16:05 +0100276
277 end = str[*idx] + strlen(str[*idx]);
278 endw = strchr(str[*idx], '(');
279
280 if (!endw)
281 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200282 else if ((end-1)[0] != ')') {
283 p = my_strndup(str[*idx], endw - str[*idx]);
284 if (p) {
285 snprintf(err, err_size, "syntax error: missing ')' after keyword '%s'.", p);
286 free(p);
287 }
Emeric Brun107ca302010-01-04 16:16:05 +0100288 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200289 }
Emeric Brun107ca302010-01-04 16:16:05 +0100290
291 fetch = find_pattern_fetch(str[*idx], endw - str[*idx]);
Emeric Brun485479d2010-09-23 18:02:19 +0200292 if (!fetch) {
293 p = my_strndup(str[*idx], endw - str[*idx]);
294 if (p) {
295 snprintf(err, err_size, "unknown fetch method '%s'.", p);
296 free(p);
297 }
Emeric Brun107ca302010-01-04 16:16:05 +0100298 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200299 }
300 if (fetch->out_type >= PATTERN_TYPES) {
Emeric Brun107ca302010-01-04 16:16:05 +0100301
Emeric Brun485479d2010-09-23 18:02:19 +0200302 p = my_strndup(str[*idx], endw - str[*idx]);
303 if (p) {
304 snprintf(err, err_size, "returns type of fetch method '%s' is unknown.", p);
305 free(p);
306 }
Emeric Brun107ca302010-01-04 16:16:05 +0100307 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200308 }
Emeric Brun107ca302010-01-04 16:16:05 +0100309
310 prev_type = fetch->out_type;
311 expr = calloc(1, sizeof(struct pattern_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200312 if (!expr)
313 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100314
315 LIST_INIT(&(expr->conv_exprs));
316 expr->fetch = fetch;
317
318 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200319 char *err_msg = NULL;
320 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200321
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200322 if (!fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200323 p = my_strndup(str[*idx], endw - str[*idx]);
324 if (p) {
325 snprintf(err, err_size, "fetch method '%s' does not support any args.", p);
326 free(p);
327 }
328 goto out_error;
329 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200330
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200331 if (make_arg_list(endw + 1, end - endw - 2, fetch->arg_mask, &expr->arg_p, &err_msg, NULL, &err_arg) < 0) {
Emeric Brun485479d2010-09-23 18:02:19 +0200332 p = my_strndup(str[*idx], endw - str[*idx]);
333 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200334 snprintf(err, err_size, "invalid arg %d in fetch method '%s' : %s.", err_arg+1, p, err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200335 free(p);
336 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200337 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200338 goto out_error;
339 }
340
341 if (fetch->val_args && !fetch->val_args(expr->arg_p, &err_msg)) {
342 p = my_strndup(str[*idx], endw - str[*idx]);
343 if (p) {
344 snprintf(err, err_size, "invalid args in fetch method '%s' : %s.", p, err_msg);
345 free(p);
346 }
347 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200348 goto out_error;
349 }
350 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200351 else if (fetch->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200352 p = my_strndup(str[*idx], endw - str[*idx]);
353 if (p) {
354 snprintf(err, err_size, "missing args for fetch method '%s'.", p);
355 free(p);
356 }
357 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100358 }
359
360 for (*idx += 1; *(str[*idx]); (*idx)++) {
361 struct pattern_conv_expr *conv_expr;
362
363 end = str[*idx] + strlen(str[*idx]);
364 endw = strchr(str[*idx], '(');
365
366 if (!endw)
367 endw = end;
Emeric Brun485479d2010-09-23 18:02:19 +0200368 else if ((end-1)[0] != ')') {
369 p = my_strndup(str[*idx], endw - str[*idx]);
370 if (p) {
371 snprintf(err, err_size, "syntax error, missing ')' after keyword '%s'.", p);
372 free(p);
373 }
Emeric Brun107ca302010-01-04 16:16:05 +0100374 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200375 }
Emeric Brun107ca302010-01-04 16:16:05 +0100376
377 conv = find_pattern_conv(str[*idx], endw - str[*idx]);
378 if (!conv)
379 break;
380
381 if (conv->in_type >= PATTERN_TYPES ||
Emeric Brun485479d2010-09-23 18:02:19 +0200382 conv->out_type >= PATTERN_TYPES) {
383 p = my_strndup(str[*idx], endw - str[*idx]);
384 if (p) {
385 snprintf(err, err_size, "returns type of conv method '%s' is unknown.", p);
386 free(p);
387 }
Emeric Brun107ca302010-01-04 16:16:05 +0100388 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200389 }
Emeric Brun107ca302010-01-04 16:16:05 +0100390
391 /* If impossible type conversion */
Emeric Brun485479d2010-09-23 18:02:19 +0200392 if (!pattern_casts[prev_type][conv->in_type]) {
393 p = my_strndup(str[*idx], endw - str[*idx]);
394 if (p) {
395 snprintf(err, err_size, "conv method '%s' cannot be applied.", p);
396 free(p);
397 }
Emeric Brun107ca302010-01-04 16:16:05 +0100398 goto out_error;
Emeric Brun485479d2010-09-23 18:02:19 +0200399 }
Emeric Brun107ca302010-01-04 16:16:05 +0100400
401 prev_type = conv->out_type;
402 conv_expr = calloc(1, sizeof(struct pattern_conv_expr));
Emeric Brun485479d2010-09-23 18:02:19 +0200403 if (!conv_expr)
404 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100405
406 LIST_ADDQ(&(expr->conv_exprs), &(conv_expr->list));
407 conv_expr->conv = conv;
408
409 if (end != endw) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200410 char *err_msg = NULL;
411 int err_arg;
Willy Tarreau21d68a62012-04-20 15:52:36 +0200412
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200413 if (!conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200414 p = my_strndup(str[*idx], endw - str[*idx]);
415
416 if (p) {
417 snprintf(err, err_size, "conv method '%s' does not support any args.", p);
418 free(p);
419 }
420 goto out_error;
421 }
Willy Tarreau9e92d322010-01-26 17:58:06 +0100422
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200423 if (make_arg_list(endw + 1, end - endw - 2, conv->arg_mask, &conv_expr->arg_p, &err_msg, NULL, &err_arg) < 0) {
Emeric Brun485479d2010-09-23 18:02:19 +0200424 p = my_strndup(str[*idx], endw - str[*idx]);
425 if (p) {
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200426 snprintf(err, err_size, "invalid arg %d in conv method '%s' : %s.", err_arg+1, p, err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200427 free(p);
428 }
Willy Tarreaub27c0d32012-04-20 16:04:47 +0200429 free(err_msg);
Willy Tarreau21d68a62012-04-20 15:52:36 +0200430 goto out_error;
431 }
432
433 if (conv->val_args && !conv->val_args(conv_expr->arg_p, &err_msg)) {
434 p = my_strndup(str[*idx], endw - str[*idx]);
435 if (p) {
436 snprintf(err, err_size, "invalid args in conv method '%s' : %s.", p, err_msg);
437 free(p);
438 }
439 free(err_msg);
Emeric Brun485479d2010-09-23 18:02:19 +0200440 goto out_error;
441 }
442 }
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200443 else if (conv->arg_mask) {
Emeric Brun485479d2010-09-23 18:02:19 +0200444 p = my_strndup(str[*idx], endw - str[*idx]);
445 if (p) {
446 snprintf(err, err_size, "missing args for conv method '%s'.", p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100447 free(p);
Willy Tarreau9e92d322010-01-26 17:58:06 +0100448 }
Emeric Brun485479d2010-09-23 18:02:19 +0200449 goto out_error;
Emeric Brun107ca302010-01-04 16:16:05 +0100450 }
Emeric Brun485479d2010-09-23 18:02:19 +0200451
Emeric Brun107ca302010-01-04 16:16:05 +0100452 }
Emeric Brun485479d2010-09-23 18:02:19 +0200453
Emeric Brun107ca302010-01-04 16:16:05 +0100454 return expr;
455
456out_error:
457 /* TODO: prune_pattern_expr(expr); */
458 return NULL;
459}
460
461/*
462 * Process a fetch + format conversion of defined by the pattern expression <expr>
463 * on request or response considering the <dir> parameter.
464 * Returns a pointer on a typed pattern structure containing the result or NULL if
465 * pattern is not found or when format conversion failed.
466 * If <p> is not null, function returns results in structure pointed by <p>.
467 * If <p> is null, functions returns a pointer on a static pattern structure.
468 */
469struct pattern *pattern_process(struct proxy *px, struct session *l4, void *l7, int dir,
470 struct pattern_expr *expr, struct pattern *p)
471{
472 struct pattern_conv_expr *conv_expr;
473
474 if (p == NULL)
Willy Tarreau5e6cc4a2011-12-16 15:23:14 +0100475 p = &temp_pattern;
Emeric Brun107ca302010-01-04 16:16:05 +0100476
Willy Tarreauf9954102012-04-20 14:03:29 +0200477 if (!expr->fetch->process(px, l4, l7, dir, expr->arg_p, &p->data))
Emeric Brun107ca302010-01-04 16:16:05 +0100478 return NULL;
479
480 p->type = expr->fetch->out_type;
481
482 list_for_each_entry(conv_expr, &expr->conv_exprs, list) {
483 if (!pattern_casts[p->type][conv_expr->conv->in_type](&p->data))
484 return NULL;
485
486 p->type = conv_expr->conv->in_type;
Willy Tarreauf9954102012-04-20 14:03:29 +0200487 if (!conv_expr->conv->process(conv_expr->arg_p, &p->data))
Emeric Brun107ca302010-01-04 16:16:05 +0100488 return NULL;
489
490 p->type = conv_expr->conv->out_type;
491 }
492 return p;
493}
494
Emeric Brun107ca302010-01-04 16:16:05 +0100495/*****************************************************************/
496/* Pattern format convert functions */
497/*****************************************************************/
498
Willy Tarreauf9954102012-04-20 14:03:29 +0200499static int pattern_conv_str2lower(const struct arg *arg_p, union pattern_data *data)
Emeric Brun107ca302010-01-04 16:16:05 +0100500{
501 int i;
502
Emeric Brun485479d2010-09-23 18:02:19 +0200503 if (!data->str.size)
504 return 0;
505
Emeric Brun107ca302010-01-04 16:16:05 +0100506 for (i = 0; i < data->str.len; i++) {
507 if ((data->str.str[i] >= 'A') && (data->str.str[i] <= 'Z'))
508 data->str.str[i] += 'a' - 'A';
509 }
510 return 1;
511}
512
Willy Tarreauf9954102012-04-20 14:03:29 +0200513static int pattern_conv_str2upper(const struct arg *arg_p, union pattern_data *data)
Emeric Brun107ca302010-01-04 16:16:05 +0100514{
515 int i;
516
Emeric Brun485479d2010-09-23 18:02:19 +0200517 if (!data->str.size)
518 return 0;
519
Emeric Brun107ca302010-01-04 16:16:05 +0100520 for (i = 0; i < data->str.len; i++) {
521 if ((data->str.str[i] >= 'a') && (data->str.str[i] <= 'z'))
522 data->str.str[i] += 'A' - 'a';
523 }
524 return 1;
525}
526
Willy Tarreauf9954102012-04-20 14:03:29 +0200527/* takes the netmask in arg_p */
528static int pattern_conv_ipmask(const struct arg *arg_p, union pattern_data *data)
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100529{
Willy Tarreauecfb8e82012-04-20 12:29:52 +0200530 data->ip.s_addr &= arg_p->data.ipv4.s_addr;
Willy Tarreaud31d6eb2010-01-26 18:01:41 +0100531 return 1;
532}
533
Emeric Brun107ca302010-01-04 16:16:05 +0100534/* Note: must not be declared <const> as its list will be overwritten */
535static struct pattern_conv_kw_list pattern_conv_kws = {{ },{
Willy Tarreau21d68a62012-04-20 15:52:36 +0200536 { "upper", pattern_conv_str2upper, 0, NULL, PATTERN_TYPE_STRING, PATTERN_TYPE_STRING },
537 { "lower", pattern_conv_str2lower, 0, NULL, PATTERN_TYPE_STRING, PATTERN_TYPE_STRING },
538 { "ipmask", pattern_conv_ipmask, ARG1(1,MSK4), NULL, PATTERN_TYPE_IP, PATTERN_TYPE_IP },
Willy Tarreau9fcb9842012-04-20 14:45:49 +0200539 { NULL, NULL, 0, 0, 0 },
Emeric Brun107ca302010-01-04 16:16:05 +0100540}};
541
542__attribute__((constructor))
543static void __pattern_init(void)
544{
545 /* register pattern format convert keywords */
546 pattern_register_convs(&pattern_conv_kws);
547}