1 /* Copyright (C) 2000,2001 Salvatore Sanfilippo <antirez@invece.org>
2 * See the LICENSE file for more information.
3 *
4 * ARS Packet Description System.
5 *
6 * Please, prefix all the function with ars_d_ */
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <sys/types.h>
12 #include <netinet/in.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include "ars.h"
17
18 #define ARS_MAX_TSIZE 1024
ars_d_parser(char * t,char * next,size_t size)19 char *ars_d_parser(char *t, char *next, size_t size)
20 {
21 int i = 0;
22
23 if (size == 0 || next == NULL || *t == '\0')
24 return NULL;
25 size--; /* space for nul term */
26 while (1) {
27 /* no space for the next char */
28 if (i == size) {
29 next[i] = '\0';
30 return t;
31 }
32 switch(*t) {
33 case '\0':
34 case '{':
35 case '}':
36 case ',':
37 case '=':
38 case '+':
39 if (i == 0) {
40 next[i] = *t;
41 next[i+1] = '\0';
42 return t+1;
43 } else {
44 next[i] = '\0';
45 return t;
46 }
47 default:
48 next[i++] = *t++;
49 break;
50 }
51 }
52 return NULL; /* unreached */
53 }
54
55 /* states */
56 #define ARS_G_LAYER 0
57 #define ARS_G_FIELD 1
58 #define ARS_G_VALUE 2
59 #define ARS_G_OBRACE_OR_PLUS 3
60 #define ARS_G_CBRACE 4
61 #define ARS_G_COMMA_OR_CBRACE 5
62 #define ARS_G_LEN_OR_PLUS 6
63 #define ARS_G_PLUS 7
64 #define ARS_G_EQUAL 8
65
66 struct ars_d_keyword_info {
67 char *ki_keyword;
68 int ki_opt;
69 void *(*ki_add) (struct ars_packet *pkt, int opt);
70 int (*ki_set) (struct ars_packet *pkt, int layer, char *f, char *v);
71 };
72
73 #define ARS_DKINFO_SIZE 64
74
75 #define BOGUS_SET_F(x) \
76 int (x)(struct ars_packet *pkt, int layer, char *f, char *v) { return 0; }
77
78 int ars_d_set_ip(struct ars_packet *pkt, int layer, char *f, char *v);
79 int ars_d_set_udp(struct ars_packet *pkt, int layer, char *f, char *v);
80 int ars_d_set_tcp(struct ars_packet *pkt, int layer, char *f, char *v);
81 int ars_d_set_icmp(struct ars_packet *pkt, int layer, char *f, char *v);
82 int ars_d_set_data(struct ars_packet *pkt, int layer, char *f, char *v);
83 BOGUS_SET_F(ars_d_set_ipopt_sec)
84 BOGUS_SET_F(ars_d_set_ipopt_sid)
85 BOGUS_SET_F(ars_d_set_ipopt_lsrr)
86 BOGUS_SET_F(ars_d_set_ipopt_ssrr)
87 BOGUS_SET_F(ars_d_set_ipopt_rr)
88 BOGUS_SET_F(ars_d_set_ipopt_ts)
89 BOGUS_SET_F(ars_d_set_tcpopt_mss)
90 BOGUS_SET_F(ars_d_set_tcpopt_wscale)
91 BOGUS_SET_F(ars_d_set_tcpopt_sackperm)
92 BOGUS_SET_F(ars_d_set_tcpopt_sack)
93 BOGUS_SET_F(ars_d_set_tcpopt_echo)
94 BOGUS_SET_F(ars_d_set_tcpopt_echoreply)
95 BOGUS_SET_F(ars_d_set_tcpopt_ts)
96
97 struct ars_d_keyword_info ars_dkinfo[ARS_DKINFO_SIZE] = {
98 /* KEYWORD OPT ADD function SET function *
99 * --------------------------------------------------------- */
100 {"ip", 0, ars_add_iphdr, ars_d_set_ip},
101 {"ipopt.eol", ARS_IPOPT_EOL, ars_add_ipopt, NULL},
102 {"ipopt.nop", ARS_IPOPT_NOP, ars_add_ipopt, NULL},
103 {"ipopt.sec", ARS_IPOPT_SEC, ars_add_ipopt, ars_d_set_ipopt_sec},
104 {"ipopt.sid", ARS_IPOPT_SID, ars_add_ipopt, ars_d_set_ipopt_sid},
105 {"ipopt.lsrr", ARS_IPOPT_LSRR, ars_add_ipopt, ars_d_set_ipopt_lsrr},
106 {"ipopt.ssrr", ARS_IPOPT_SSRR, ars_add_ipopt, ars_d_set_ipopt_ssrr},
107 {"ipopt.rr", ARS_IPOPT_RR, ars_add_ipopt, ars_d_set_ipopt_rr},
108 {"ipopt.ts", ARS_IPOPT_TIMESTAMP, ars_add_ipopt, ars_d_set_ipopt_ts},
109 {"udp", 0, ars_add_udphdr, ars_d_set_udp},
110 {"tcp", 0, ars_add_tcphdr, ars_d_set_tcp},
111 {"tcpopt.end", ARS_TCPOPT_EOL, ars_add_tcpopt, NULL},
112 {"tcpopt.nop", ARS_TCPOPT_NOP, ars_add_tcpopt, NULL},
113 {"tcpopt.mss", ARS_TCPOPT_MAXSEG, ars_add_tcpopt, ars_d_set_tcpopt_mss},
114 {"tcpopt.wscale", ARS_TCPOPT_WINDOW, ars_add_tcpopt, ars_d_set_tcpopt_wscale},
115 {"tcpopt.sackperm", ARS_TCPOPT_SACK_PERM, ars_add_tcpopt, ars_d_set_tcpopt_sackperm},
116 {"tcpopt.sack", ARS_TCPOPT_SACK, ars_add_tcpopt, ars_d_set_tcpopt_sack},
117 {"tcpopt.echo", ARS_TCPOPT_ECHOREQUEST, ars_add_tcpopt, ars_d_set_tcpopt_echo},
118 {"tcpopt.echoreply", ARS_TCPOPT_ECHOREPLY, ars_add_tcpopt, ars_d_set_tcpopt_echoreply},
119 {"tcpopt.ts", ARS_TCPOPT_TIMESTAMP, ars_add_tcpopt, ars_d_set_tcpopt_ts},
120 {"icmp", 0, ars_add_icmphdr, ars_d_set_icmp},
121 {"data", 0, ars_add_data, ars_d_set_data},
122 {NULL, 0, NULL, NULL} /* nul term */
123 };
124
ars_get_keyword_by_name(char * name)125 struct ars_d_keyword_info *ars_get_keyword_by_name(char *name)
126 {
127 struct ars_d_keyword_info *k = ars_dkinfo;
128
129 while (k->ki_keyword) {
130 if (strcasecmp(k->ki_keyword, name) == 0)
131 return k;
132 k++;
133 }
134 return NULL;
135 }
136
ars_d_setlayer_size(struct ars_packet * pkt,int layer,char * size)137 int ars_d_setlayer_size(struct ars_packet *pkt, int layer, char *size)
138 {
139 size_t newsize;
140
141 if (layer == ARS_LAST_LAYER)
142 layer = pkt->p_layer_nr - 1;
143 if (ars_valid_layer(layer) != -ARS_OK)
144 return -ARS_INVALID;
145
146 newsize = ars_atou(size);
147 if (newsize < 1 || newsize > pkt->p_layer[layer].l_size) {
148 ars_set_error(pkt, "Invalid layer size in description");
149 return -ARS_INVALID;
150 }
151 pkt->p_layer[layer].l_size = newsize;
152
153 __D(printf("Setting the layer to size %s\n", size);)
154 return -ARS_OK;
155 }
156
ars_d_set_ip(struct ars_packet * pkt,int layer,char * f,char * v)157 int ars_d_set_ip(struct ars_packet *pkt, int layer, char *f, char *v)
158 {
159 struct ars_iphdr *ip;
160
161 if (layer == ARS_LAST_LAYER)
162 layer = pkt->p_layer_nr - 1;
163 if (ars_valid_layer(layer) != -ARS_OK)
164 return -ARS_INVALID;
165
166 ip = pkt->p_layer[layer].l_data;
167
168 if (strcasecmp(f, "saddr") == 0) {
169 return ars_resolve(pkt, &ip->saddr, v);
170 } else if (strcasecmp(f, "daddr") == 0) {
171 return ars_resolve(pkt, &ip->daddr, v);
172 } else if (strcasecmp(f, "ihl") == 0) {
173 ip->ihl = ars_atou(v);
174 pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_HDRLEN;
175 } else if (strcasecmp(f, "ver") == 0) {
176 ip->version = ars_atou(v);
177 pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_VERSION;
178 } else if (strcasecmp(f, "tos") == 0) {
179 ip->tos = ars_atou(v);
180 } else if (strcasecmp(f, "totlen") == 0) {
181 ip->tot_len = htons(ars_atou(v));
182 pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_TOTLEN;
183 } else if (strcasecmp(f, "id") == 0) {
184 ip->id = htons(ars_atou(v));
185 } else if (strcasecmp(f, "fragoff") == 0) {
186 ip->frag_off = ip->frag_off & 0xE000;
187 ip->frag_off = htons(ars_atou(v) >> 3);
188 } else if (strcasecmp(f, "mf") == 0) {
189 if (ars_atou(v) == 0)
190 ip->frag_off &= htons(~ARS_IP_MF);
191 else
192 ip->frag_off |= htons(ARS_IP_MF);
193 } else if (strcasecmp(f, "df") == 0) {
194 if (ars_atou(v) == 0)
195 ip->frag_off &= htons(~ARS_IP_DF);
196 else
197 ip->frag_off |= htons(ARS_IP_DF);
198 } else if (strcasecmp(f, "rf") == 0) {
199 if (ars_atou(v) == 0)
200 ip->frag_off &= htons((u_int16_t)~ARS_IP_RF);
201 else
202 ip->frag_off |= htons(ARS_IP_RF);
203 } else if (strcasecmp(f, "ttl") == 0) {
204 ip->ttl = ars_atou(v);
205 } else if (strcasecmp(f, "proto") == 0) {
206 ip->protocol = ars_atou(v);
207 pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_PROTOCOL;
208 } else if (strcasecmp(f, "cksum") == 0) {
209 ip->check = htons(ars_atou(v));
210 pkt->p_layer[layer].l_flags |= ARS_TAKE_IP_CKSUM;
211 } else {
212 ars_set_error(pkt, "Invalid field for IP layer");
213 return -ARS_INVALID;
214 }
215 return -ARS_OK;
216 }
217
ars_d_set_udp(struct ars_packet * pkt,int layer,char * f,char * v)218 int ars_d_set_udp(struct ars_packet *pkt, int layer, char *f, char *v)
219 {
220 struct ars_udphdr *udp;
221
222 if (layer == ARS_LAST_LAYER)
223 layer = pkt->p_layer_nr - 1;
224 if (ars_valid_layer(layer) != -ARS_OK)
225 return -ARS_INVALID;
226
227 udp = pkt->p_layer[layer].l_data;
228
229 if (strcasecmp(f, "sport") == 0) {
230 udp->uh_sport = htons(ars_atou(v));
231 } else if (strcasecmp(f, "dport") == 0) {
232 udp->uh_dport = htons(ars_atou(v));
233 } else if (strcasecmp(f, "len") == 0) {
234 udp->uh_ulen = htons(ars_atou(v));
235 pkt->p_layer[layer].l_flags |= ARS_TAKE_UDP_LEN;
236 } else if (strcasecmp(f, "cksum") == 0) {
237 udp->uh_sum = htons(ars_atou(v));
238 pkt->p_layer[layer].l_flags |= ARS_TAKE_UDP_CKSUM;
239 } else {
240 ars_set_error(pkt, "Invalid field for UDP layer");
241 return -ARS_INVALID;
242 }
243 return -ARS_OK;
244 }
245
ars_d_set_tcp(struct ars_packet * pkt,int layer,char * f,char * v)246 int ars_d_set_tcp(struct ars_packet *pkt, int layer, char *f, char *v)
247 {
248 struct ars_tcphdr *tcp;
249
250 if (layer == ARS_LAST_LAYER)
251 layer = pkt->p_layer_nr - 1;
252 if (ars_valid_layer(layer) != -ARS_OK)
253 return -ARS_INVALID;
254
255 tcp = pkt->p_layer[layer].l_data;
256
257 if (strcasecmp(f, "sport") == 0) {
258 tcp->th_sport = htons(ars_atou(v));
259 } else if (strcasecmp(f, "dport") == 0) {
260 tcp->th_dport = htons(ars_atou(v));
261 } else if (strcasecmp(f, "seq") == 0) {
262 tcp->th_seq = htonl(ars_atou(v));
263 } else if (strcasecmp(f, "ack") == 0) {
264 tcp->th_ack = htonl(ars_atou(v));
265 } else if (strcasecmp(f, "x2") == 0) {
266 tcp->th_x2 = ars_atou(v);
267 } else if (strcasecmp(f, "off") == 0) {
268 tcp->th_off = ars_atou(v);
269 pkt->p_layer[layer].l_flags |= ARS_TAKE_TCP_HDRLEN;
270 } else if (strcasecmp(f, "flags") == 0) {
271 tcp->th_flags = 0;
272 if (strchr(v, 'f') || strchr(v, 'F'))
273 tcp->th_flags |= ARS_TCP_TH_FIN;
274 if (strchr(v, 's') || strchr(v, 'S'))
275 tcp->th_flags |= ARS_TCP_TH_SYN;
276 if (strchr(v, 'r') || strchr(v, 'R'))
277 tcp->th_flags |= ARS_TCP_TH_RST;
278 if (strchr(v, 'p') || strchr(v, 'P'))
279 tcp->th_flags |= ARS_TCP_TH_PUSH;
280 if (strchr(v, 'a') || strchr(v, 'A'))
281 tcp->th_flags |= ARS_TCP_TH_ACK;
282 if (strchr(v, 'u') || strchr(v, 'U'))
283 tcp->th_flags |= ARS_TCP_TH_URG;
284 if (strchr(v, 'x') || strchr(v, 'X'))
285 tcp->th_flags |= ARS_TCP_TH_X;
286 if (strchr(v, 'y') || strchr(v, 'Y'))
287 tcp->th_flags |= ARS_TCP_TH_Y;
288 } else if (strcasecmp(f, "win") == 0) {
289 tcp->th_win = htons(ars_atou(v));
290 } else if (strcasecmp(f, "cksum") == 0) {
291 tcp->th_sum = htons(ars_atou(v));
292 pkt->p_layer[layer].l_flags |= ARS_TAKE_TCP_CKSUM;
293 } else if (strcasecmp(f, "urp") == 0) {
294 tcp->th_urp = htons(ars_atou(v));
295 } else {
296 ars_set_error(pkt, "Invalid field for TCP layer");
297 return -ARS_INVALID;
298 }
299 return -ARS_OK;
300 }
301
ars_d_set_icmp(struct ars_packet * pkt,int layer,char * f,char * v)302 int ars_d_set_icmp(struct ars_packet *pkt, int layer, char *f, char *v)
303 {
304 struct ars_icmphdr *icmp;
305
306 if (layer == ARS_LAST_LAYER)
307 layer = pkt->p_layer_nr - 1;
308 if (ars_valid_layer(layer) != -ARS_OK)
309 return -ARS_INVALID;
310
311 icmp = pkt->p_layer[layer].l_data;
312
313 if (strcasecmp(f, "type") == 0) {
314 icmp->type = ars_atou(v);
315 } else if (strcasecmp(f, "code") == 0) {
316 icmp->code = ars_atou(v);
317 } else if (strcasecmp(f, "cksum") == 0) {
318 icmp->checksum = htons(ars_atou(v));
319 pkt->p_layer[layer].l_flags |= ARS_TAKE_ICMP_CKSUM;
320 } else if (strcasecmp(f, "id") == 0) {
321 icmp->un.echo.id = htons(ars_atou(v));
322 } else if (strcasecmp(f, "seq") == 0) {
323 icmp->un.echo.sequence = htons(ars_atou(v));
324 } else if (strcasecmp(f, "gw") == 0) {
325 return ars_resolve(pkt, &icmp->un.gateway, v);
326 } else {
327 ars_set_error(pkt, "Invalid field for ICMP layer");
328 return -ARS_INVALID;
329 }
330 return -ARS_OK;
331 }
332
ars_push_data(struct ars_packet * pkt,int layer,void * data,size_t size)333 int ars_push_data(struct ars_packet *pkt, int layer, void *data, size_t size)
334 {
335 char *p;
336 int old_size;
337
338 if (layer == ARS_LAST_LAYER)
339 layer = pkt->p_layer_nr - 1;
340 if (ars_valid_layer(layer) != -ARS_OK)
341 return -ARS_INVALID;
342
343 old_size = pkt->p_layer[layer].l_size;
344 p = realloc(pkt->p_layer[layer].l_data, old_size + size);
345 if (p == NULL)
346 return -ARS_NOMEM;
347 memcpy(p+old_size, data, size);
348 pkt->p_layer[layer].l_data = p;
349 pkt->p_layer[layer].l_size += size;
350 return ARS_OK;
351 }
352
353 #define ARS_DATA_BUF_SIZE 4096
ars_d_set_data(struct ars_packet * pkt,int layer,char * f,char * v)354 int ars_d_set_data(struct ars_packet *pkt, int layer, char *f, char *v)
355 {
356 if (layer == ARS_LAST_LAYER)
357 layer = pkt->p_layer_nr - 1;
358 if (ars_valid_layer(layer) != -ARS_OK)
359 return -ARS_INVALID;
360
361 if (strcasecmp(f, "file") == 0) {
362 int fd, n_read;
363 unsigned char buffer[ARS_DATA_BUF_SIZE];
364
365 if ((fd = open(v, O_RDONLY)) == -1) {
366 ars_set_error(pkt, "Can't open the DATA file");
367 return -ARS_ERROR;
368 }
369 if ((n_read = read(fd, buffer, ARS_DATA_BUF_SIZE)) == -1) {
370 close(fd);
371 ars_set_error(pkt, "Can't read DATA from file");
372 return -ARS_ERROR;
373 }
374 close(fd);
375 if (n_read == 0)
376 return -ARS_OK;
377 return ars_push_data(pkt, layer, buffer, n_read);
378 } else if (strcasecmp(f, "str") == 0) {
379 return ars_push_data(pkt, layer, v, strlen(v));
380 } else {
381 ars_set_error(pkt, "Invalid field for DATA layer");
382 return -ARS_INVALID;
383 }
384 return -ARS_OK;
385 }
386
387 /* A Finite state machine to build the packet using the description */
ars_d_build(struct ars_packet * pkt,char * t)388 int ars_d_build(struct ars_packet *pkt, char *t)
389 {
390 struct ars_d_keyword_info *k = NULL;
391 char next[ARS_MAX_TSIZE];
392 char field[ARS_MAX_TSIZE];
393 int state = ARS_G_LAYER;
394 int error;
395 void *p;
396
397 while ((t = ars_d_parser(t, next, ARS_MAX_TSIZE)) != NULL) {
398 switch(state) {
399 case ARS_G_LAYER:
400 k = ars_get_keyword_by_name(next);
401 if (k == NULL) {
402 ars_set_error(pkt, "Unknown keyword");
403 return -ARS_INVALID;
404 }
405 __D(printf("Adding a new layer (%s)\n", next);)
406 p = k->ki_add(pkt, k->ki_opt);
407 if (p == NULL)
408 return -ARS_INVALID;
409 state = ARS_G_OBRACE_OR_PLUS;
410 break;
411 case ARS_G_FIELD:
412 strncpy(field, next, ARS_MAX_TSIZE);
413 state = ARS_G_EQUAL;
414 break;
415 case ARS_G_VALUE:
416 if (k->ki_set == NULL) {
417 ars_set_error(pkt, "Field specified for"
418 "a layer that doesn't support fields");
419 return -ARS_INVALID;
420 }
421 error = k->ki_set(pkt, ARS_LAST_LAYER, field, next);
422 if (error != -ARS_OK)
423 return error;
424 state = ARS_G_COMMA_OR_CBRACE;
425 break;
426 case ARS_G_OBRACE_OR_PLUS:
427 if (next[0] == '{' && next[1] == '\0') {
428 state = ARS_G_FIELD;
429 break;
430 } else if (next[0] == '+' && next[1] == '\0') {
431 state = ARS_G_LAYER;
432 break;
433 } else {
434 ars_set_error(pkt, "Missing brace or plus");
435 return -ARS_INVALID;
436 }
437 break;
438 case ARS_G_CBRACE:
439 if (next[0] != '}' || next[1] != '\0') {
440 ars_set_error(pkt, "Missing closed brace");
441 return -ARS_INVALID;
442 }
443 state = ARS_G_LEN_OR_PLUS;
444 break;
445 case ARS_G_COMMA_OR_CBRACE:
446 if (next[0] == '}' && next[1] == '\0') {
447 state = ARS_G_LEN_OR_PLUS;
448 break;
449 } else if (next[0] == ',' && next[1] == '\0') {
450 state = ARS_G_FIELD;
451 break;
452 } else {
453 ars_set_error(pkt, "Missing brace or comma");
454 return -ARS_INVALID;
455 }
456 break;
457 case ARS_G_LEN_OR_PLUS:
458 if (next[0] == '+' && next[1] == '\0') {
459 state = ARS_G_LAYER;
460 break;
461 }
462 error = ars_d_setlayer_size(pkt, ARS_LAST_LAYER, next);
463 if (error != -ARS_OK)
464 return error;
465 state = ARS_G_PLUS;
466 break;
467 case ARS_G_PLUS:
468 if (next[0] != '+' || next[1] != '\0') {
469 ars_set_error(pkt, "Missing plus");
470 return -ARS_INVALID;
471 }
472 state = ARS_G_LAYER;
473 break;
474 case ARS_G_EQUAL:
475 if (next[0] != '=' || next[1] != '\0') {
476 ars_set_error(pkt, "Missing equal");
477 return -ARS_INVALID;
478 }
479 state = ARS_G_VALUE;
480 break;
481 }
482 }
483 if (state != ARS_G_LEN_OR_PLUS && state != ARS_G_PLUS &&
484 state != ARS_G_OBRACE_OR_PLUS) {
485 ars_set_error(pkt, "Packet description truncated");
486 return -ARS_INVALID;
487 }
488 return -ARS_OK;
489 }
490