blob: 06fb52d8bde592843cc336129444a6f5382889f2 [file] [log] [blame]
Christopher Faulet4ff3e572017-02-24 14:31:11 +01001/*
2 * include/proto/spoe.h
3 * Encoding/Decoding functions for the SPOE filters (and other helpers).
4 *
5 * Copyright (C) 2017 HAProxy Technologies, Christopher Faulet <cfaulet@haproxy.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation, version 2.1
10 * exclusively.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef _PROTO_SPOE_H
23#define _PROTO_SPOE_H
24
25#include <types/spoe.h>
26
27#include <proto/sample.h>
28
29
30/* Encode the integer <i> into a varint (variable-length integer). The encoded
31 * value is copied in <*buf>. Here is the encoding format:
32 *
33 * 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
34 * 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
35 * 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
36 * 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
37 * 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
38 * ...
39 *
40 * On success, it returns the number of written bytes and <*buf> is moved after
41 * the encoded value. Otherwise, it returns -1. */
42int
43spoe_encode_varint(uint64_t i, char **buf, char *end)
44{
45 unsigned char *p = (unsigned char *)*buf;
46 int r;
47
48 if (p >= (unsigned char *)end)
49 return -1;
50
51 if (i < 240) {
52 *p++ = i;
53 *buf = (char *)p;
54 return 1;
55 }
56
57 *p++ = (unsigned char)i | 240;
58 i = (i - 240) >> 4;
59 while (i >= 128) {
60 if (p >= (unsigned char *)end)
61 return -1;
62 *p++ = (unsigned char)i | 128;
63 i = (i - 128) >> 7;
64 }
65
66 if (p >= (unsigned char *)end)
67 return -1;
68 *p++ = (unsigned char)i;
69
70 r = ((char *)p - *buf);
71 *buf = (char *)p;
72 return r;
73}
74
75/* Decode a varint from <*buf> and save the decoded value in <*i>. See
76 * 'spoe_encode_varint' for details about varint.
77 * On success, it returns the number of read bytes and <*buf> is moved after the
78 * varint. Otherwise, it returns -1. */
79int
80spoe_decode_varint(char **buf, char *end, uint64_t *i)
81{
82 unsigned char *p = (unsigned char *)*buf;
83 int r;
84
85 if (p >= (unsigned char *)end)
86 return -1;
87
88 *i = *p++;
89 if (*i < 240) {
90 *buf = (char *)p;
91 return 1;
92 }
93
94 r = 4;
95 do {
96 if (p >= (unsigned char *)end)
97 return -1;
98 *i += (uint64_t)*p << r;
99 r += 7;
100 } while (*p++ >= 128);
101
102 r = ((char *)p - *buf);
103 *buf = (char *)p;
104 return r;
105}
106
107/* Encode a buffer. Its length <len> is encoded as a varint, followed by a copy
108 * of <str>. It must have enough space in <*buf> to encode the buffer, else an
109 * error is triggered.
110 * On success, it returns <len> and <*buf> is moved after the encoded value. If
111 * an error occurred, it returns -1. */
112int
113spoe_encode_buffer(const char *str, size_t len, char **buf, char *end)
114{
115 char *p = *buf;
116 int ret;
117
118 if (p >= end)
119 return -1;
120
121 if (!len) {
122 *p++ = 0;
123 *buf = p;
124 return 0;
125 }
126
127 ret = spoe_encode_varint(len, &p, end);
128 if (ret == -1 || p + len > end)
129 return -1;
130
131 memcpy(p, str, len);
132 *buf = p + len;
133 return len;
134}
135
136/* Encode a buffer, possibly partially. It does the same thing than
137 * 'spoe_encode_buffer', but if there is not enough space, it does not fail.
138 * On success, it returns the number of copied bytes and <*buf> is moved after
139 * the encoded value. If an error occured, it returns -1. */
140int
141spoe_encode_frag_buffer(const char *str, size_t len, char **buf, char *end)
142{
143 char *p = *buf;
144 int ret;
145
146 if (p >= end)
147 return -1;
148
149 if (!len) {
150 *p++ = 0;
151 *buf = p;
152 return 0;
153 }
154
155 ret = spoe_encode_varint(len, &p, end);
156 if (ret == -1 || p >= end)
157 return -1;
158
159 ret = (p+len < end) ? len : (end - p);
160 memcpy(p, str, ret);
161 *buf = p + ret;
162 return ret;
163}
164
165/* Decode a buffer. The buffer length is decoded and saved in <*len>. <*str>
166 * points on the first byte of the buffer.
167 * On success, it returns the buffer length and <*buf> is moved after the
168 * encoded buffer. Otherwise, it returns -1. */
169int
170spoe_decode_buffer(char **buf, char *end, char **str, size_t *len)
171{
172 char *p = *buf;
173 uint64_t sz;
174 int ret;
175
176 *str = NULL;
177 *len = 0;
178
179 ret = spoe_decode_varint(&p, end, &sz);
180 if (ret == -1 || p + sz > end)
181 return -1;
182
183 *str = p;
184 *len = sz;
185 *buf = p + sz;
186 return sz;
187}
188
189/* Encode a typed data using value in <smp>. On success, it returns the number
190 * of copied bytes and <*buf> is moved after the encoded value. If an error
191 * occured, it returns -1.
192 *
193 * If the value is too big to be encoded, depending on its type, then encoding
194 * failed or the value is partially encoded. Only strings and binaries can be
195 * partially encoded. In this case, the offset <*off> is updated to known how
196 * many bytes has been encoded. If <*off> is zero at the end, it means that all
197 * data has been encoded. */
198int
199spoe_encode_data(struct sample *smp, unsigned int *off, char **buf, char *end)
200{
201 char *p = *buf;
202 int ret;
203
204 if (p >= end)
205 return -1;
206
207 if (smp == NULL) {
208 *p++ = SPOE_DATA_T_NULL;
209 goto end;
210 }
211
212 switch (smp->data.type) {
213 case SMP_T_BOOL:
214 *p = SPOE_DATA_T_BOOL;
215 *p++ |= ((!smp->data.u.sint) ? SPOE_DATA_FL_FALSE : SPOE_DATA_FL_TRUE);
216 break;
217
218 case SMP_T_SINT:
219 *p++ = SPOE_DATA_T_INT64;
220 if (spoe_encode_varint(smp->data.u.sint, &p, end) == -1)
221 return -1;
222 break;
223
224 case SMP_T_IPV4:
225 if (p + 5 > end)
226 return -1;
227 *p++ = SPOE_DATA_T_IPV4;
228 memcpy(p, &smp->data.u.ipv4, 4);
229 p += 4;
230 break;
231
232 case SMP_T_IPV6:
233 if (p + 17 > end)
234 return -1;
235 *p++ = SPOE_DATA_T_IPV6;
236 memcpy(p, &smp->data.u.ipv6, 16);
237 p += 16;
238 break;
239
240 case SMP_T_STR:
241 case SMP_T_BIN: {
242 struct chunk *chk = &smp->data.u.str;
243
244 /* Here, we need to know if the sample has already been
245 * partially encoded. If yes, we only need to encode the
246 * remaining, <*off> reprensenting the number of bytes
247 * already encoded. */
248 if (!*off) {
249 /* First evaluation of the sample : encode the
250 * type (string or binary), the buffer length
251 * (as a varint) and at least 1 byte of the
252 * buffer. */
253 struct chunk *chk = &smp->data.u.str;
254
255 *p++ = (smp->data.type == SMP_T_STR)
256 ? SPOE_DATA_T_STR
257 : SPOE_DATA_T_BIN;
258 ret = spoe_encode_frag_buffer(chk->str, chk->len, &p, end);
259 if (ret == -1)
260 return -1;
261 }
262 else {
263 /* The sample has been fragmented, encode remaining data */
264 ret = MIN(chk->len - *off, end - p);
265 memcpy(p, chk->str + *off, ret);
266 p += ret;
267 }
268 /* Now update <*off> */
269 if (ret + *off != chk->len)
270 *off += ret;
271 else
272 *off = 0;
273 break;
274 }
275
276 case SMP_T_METH: {
277 char *m;
278 size_t len;
279
280 *p++ = SPOE_DATA_T_STR;
281 switch (smp->data.u.meth.meth) {
282 case HTTP_METH_OPTIONS: m = "OPTIONS"; len = 7; break;
283 case HTTP_METH_GET : m = "GET"; len = 3; break;
284 case HTTP_METH_HEAD : m = "HEAD"; len = 4; break;
285 case HTTP_METH_POST : m = "POST"; len = 4; break;
286 case HTTP_METH_PUT : m = "PUT"; len = 3; break;
287 case HTTP_METH_DELETE : m = "DELETE"; len = 6; break;
288 case HTTP_METH_TRACE : m = "TRACE"; len = 5; break;
289 case HTTP_METH_CONNECT: m = "CONNECT"; len = 7; break;
290
291 default :
292 m = smp->data.u.meth.str.str;
293 len = smp->data.u.meth.str.len;
294 }
295 if (spoe_encode_buffer(m, len, &p, end) == -1)
296 return -1;
297 break;
298 }
299
300 default:
301 *p++ = SPOE_DATA_T_NULL;
302 break;
303 }
304
305 end:
306 ret = (p - *buf);
307 *buf = p;
308 return ret;
309}
310
311/* Skip a typed data. If an error occurred, -1 is returned, otherwise the number
312 * of skipped bytes is returned and the <*buf> is moved after skipped data.
313 *
314 * A types data is composed of a type (1 byte) and corresponding data:
315 * - boolean: non additional data (0 bytes)
316 * - integers: a variable-length integer (see spoe_decode_varint)
317 * - ipv4: 4 bytes
318 * - ipv6: 16 bytes
319 * - binary and string: a buffer prefixed by its size, a variable-length
320 * integer (see spoe_decode_buffer) */
321int
322spoe_skip_data(char **buf, char *end)
323{
324 char *str, *p = *buf;
325 int type, ret;
326 size_t sz;
327 uint64_t v;
328
329 if (p >= end)
330 return -1;
331
332 type = *p++;
333 switch (type & SPOE_DATA_T_MASK) {
334 case SPOE_DATA_T_BOOL:
335 break;
336 case SPOE_DATA_T_INT32:
337 case SPOE_DATA_T_INT64:
338 case SPOE_DATA_T_UINT32:
339 case SPOE_DATA_T_UINT64:
340 if (spoe_decode_varint(&p, end, &v) == -1)
341 return -1;
342 break;
343 case SPOE_DATA_T_IPV4:
344 if (p+4 > end)
345 return -1;
346 p += 4;
347 break;
348 case SPOE_DATA_T_IPV6:
349 if (p+16 > end)
350 return -1;
351 p += 16;
352 break;
353 case SPOE_DATA_T_STR:
354 case SPOE_DATA_T_BIN:
355 /* All the buffer must be skipped */
356 if (spoe_decode_buffer(&p, end, &str, &sz) == -1)
357 return -1;
358 break;
359 }
360
361 ret = (p - *buf);
362 *buf = p;
363 return ret;
364}
365
366/* Decode a typed data and fill <smp>. If an error occurred, -1 is returned,
367 * otherwise the number of read bytes is returned and <*buf> is moved after the
368 * decoded data. See spoe_skip_data for details. */
369int
370spoe_decode_data(char **buf, char *end, struct sample *smp)
371{
372 char *str, *p = *buf;
373 int type, r = 0;
374 size_t sz;
375
376 if (p >= end)
377 return -1;
378
379 type = *p++;
380 switch (type & SPOE_DATA_T_MASK) {
381 case SPOE_DATA_T_BOOL:
382 smp->data.u.sint = ((type & SPOE_DATA_FL_MASK) == SPOE_DATA_FL_TRUE);
383 smp->data.type = SMP_T_BOOL;
384 break;
385 case SPOE_DATA_T_INT32:
386 case SPOE_DATA_T_INT64:
387 case SPOE_DATA_T_UINT32:
388 case SPOE_DATA_T_UINT64:
389 if (spoe_decode_varint(&p, end, (uint64_t *)&smp->data.u.sint) == -1)
390 return -1;
391 smp->data.type = SMP_T_SINT;
392 break;
393 case SPOE_DATA_T_IPV4:
394 if (p+4 > end)
395 return -1;
396 smp->data.type = SMP_T_IPV4;
397 memcpy(&smp->data.u.ipv4, p, 4);
398 p += 4;
399 break;
400 case SPOE_DATA_T_IPV6:
401 if (p+16 > end)
402 return -1;
403 memcpy(&smp->data.u.ipv6, p, 16);
404 smp->data.type = SMP_T_IPV6;
405 p += 16;
406 break;
407 case SPOE_DATA_T_STR:
408 case SPOE_DATA_T_BIN:
409 /* All the buffer must be decoded */
410 if (spoe_decode_buffer(&p, end, &str, &sz) == -1)
411 return -1;
412 smp->data.u.str.str = str;
413 smp->data.u.str.len = sz;
414 smp->data.type = (type == SPOE_DATA_T_STR) ? SMP_T_STR : SMP_T_BIN;
415 break;
416 }
417
418 r = (p - *buf);
419 *buf = p;
420 return r;
421}
422
423#endif /* _PROTO_SPOE_H */