1 /*
2 * Copyright (c) 2014 Yandex LLC
3 * Copyright (c) 2014 Alexander V. Chernikov
4 *
5 * Redistribution and use in source forms, with and without modification,
6 * are permitted provided that this entire comment appears intact.
7 *
8 * Redistribution in binary form may occur without any restrictions.
9 * Obviously, it would be nice if you gave credit where credit is due
10 * but requiring it would be too onerous.
11 *
12 * This software is provided ``AS IS'' without any warranties of any kind.
13 *
14 * in-kernel ipfw tables support.
15 *
16 * $FreeBSD$
17 */
18
19
20 #include <sys/types.h>
21 #include <sys/param.h>
22 #include <sys/socket.h>
23 #include <sys/sysctl.h>
24
25 #include <ctype.h>
26 #include <err.h>
27 #include <errno.h>
28 #include <netdb.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sysexits.h>
33
34 #include <net/if.h>
35 #include <netinet/in.h>
36 #include <netinet/ip_fw.h>
37 #include <arpa/inet.h>
38 #include <netdb.h>
39
40 #include "ipfw2.h"
41
42 static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[],
43 int add, int quiet, int update, int atomic);
44 static int table_flush(ipfw_obj_header *oh);
45 static int table_destroy(ipfw_obj_header *oh);
46 static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i);
47 static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i);
48 static int table_do_swap(ipfw_obj_header *oh, char *second);
49 static void table_create(ipfw_obj_header *oh, int ac, char *av[]);
50 static void table_modify(ipfw_obj_header *oh, int ac, char *av[]);
51 static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]);
52 static void table_lock(ipfw_obj_header *oh, int lock);
53 static int table_swap(ipfw_obj_header *oh, char *second);
54 static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i);
55 static int table_show_info(ipfw_xtable_info *i, void *arg);
56
57 static int table_destroy_one(ipfw_xtable_info *i, void *arg);
58 static int table_flush_one(ipfw_xtable_info *i, void *arg);
59 static int table_show_one(ipfw_xtable_info *i, void *arg);
60 static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh);
61 static void table_show_list(ipfw_obj_header *oh, int need_header);
62 static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent);
63
64 static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
65 char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi);
66 static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent,
67 char *arg, uint8_t type, uint32_t vmask);
68 static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
69 uint32_t vmask, int print_ip);
70
71 typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg);
72 static int tables_foreach(table_cb_t *f, void *arg, int sort);
73
74 #ifndef s6_addr32
75 #define s6_addr32 __u6_addr.__u6_addr32
76 #endif
77
78 static struct _s_x tabletypes[] = {
79 { "addr", IPFW_TABLE_ADDR },
80 { "iface", IPFW_TABLE_INTERFACE },
81 { "number", IPFW_TABLE_NUMBER },
82 { "flow", IPFW_TABLE_FLOW },
83 { NULL, 0 }
84 };
85
86 static struct _s_x tablevaltypes[] = {
87 { "skipto", IPFW_VTYPE_SKIPTO },
88 { "pipe", IPFW_VTYPE_PIPE },
89 { "fib", IPFW_VTYPE_FIB },
90 { "nat", IPFW_VTYPE_NAT },
91 { "dscp", IPFW_VTYPE_DSCP },
92 { "tag", IPFW_VTYPE_TAG },
93 { "divert", IPFW_VTYPE_DIVERT },
94 { "netgraph", IPFW_VTYPE_NETGRAPH },
95 { "limit", IPFW_VTYPE_LIMIT },
96 { "ipv4", IPFW_VTYPE_NH4 },
97 { "ipv6", IPFW_VTYPE_NH6 },
98 { NULL, 0 }
99 };
100
101 static struct _s_x tablecmds[] = {
102 { "add", TOK_ADD },
103 { "delete", TOK_DEL },
104 { "create", TOK_CREATE },
105 { "destroy", TOK_DESTROY },
106 { "flush", TOK_FLUSH },
107 { "modify", TOK_MODIFY },
108 { "swap", TOK_SWAP },
109 { "info", TOK_INFO },
110 { "detail", TOK_DETAIL },
111 { "list", TOK_LIST },
112 { "lookup", TOK_LOOKUP },
113 { "atomic", TOK_ATOMIC },
114 { "lock", TOK_LOCK },
115 { "unlock", TOK_UNLOCK },
116 { NULL, 0 }
117 };
118
119 static int
lookup_host(char * host,struct in_addr * ipaddr)120 lookup_host (char *host, struct in_addr *ipaddr)
121 {
122 struct hostent *he;
123
124 if (!inet_aton(host, ipaddr)) {
125 if ((he = gethostbyname(host)) == NULL)
126 return(-1);
127 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
128 }
129 return(0);
130 }
131
132 /*
133 * This one handles all table-related commands
134 * ipfw table NAME create ...
135 * ipfw table NAME modify ...
136 * ipfw table {NAME | all} destroy
137 * ipfw table NAME swap NAME
138 * ipfw table NAME lock
139 * ipfw table NAME unlock
140 * ipfw table NAME add addr[/masklen] [value]
141 * ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] ..
142 * ipfw table NAME delete addr[/masklen] [addr[/masklen]] ..
143 * ipfw table NAME lookup addr
144 * ipfw table {NAME | all} flush
145 * ipfw table {NAME | all} list
146 * ipfw table {NAME | all} info
147 * ipfw table {NAME | all} detail
148 */
149 void
ipfw_table_handler(int ac,char * av[])150 ipfw_table_handler(int ac, char *av[])
151 {
152 int do_add, is_all;
153 int atomic, error, tcmd;
154 ipfw_xtable_info i;
155 ipfw_obj_header oh;
156 char *tablename;
157 uint8_t set;
158 void *arg;
159
160 memset(&oh, 0, sizeof(oh));
161 is_all = 0;
162 if (co.use_set != 0)
163 set = co.use_set - 1;
164 else
165 set = 0;
166
167 ac--; av++;
168 NEED1("table needs name");
169 tablename = *av;
170
171 if (table_check_name(tablename) == 0) {
172 table_fill_ntlv(&oh.ntlv, *av, set, 1);
173 oh.idx = 1;
174 } else {
175 if (strcmp(tablename, "all") == 0)
176 is_all = 1;
177 else
178 errx(EX_USAGE, "table name %s is invalid", tablename);
179 }
180 ac--; av++;
181 NEED1("table needs command");
182
183 tcmd = get_token(tablecmds, *av, "table command");
184 /* Check if atomic operation was requested */
185 atomic = 0;
186 if (tcmd == TOK_ATOMIC) {
187 ac--; av++;
188 NEED1("atomic needs command");
189 tcmd = get_token(tablecmds, *av, "table command");
190 switch (tcmd) {
191 case TOK_ADD:
192 break;
193 default:
194 errx(EX_USAGE, "atomic is not compatible with %s", *av);
195 }
196 atomic = 1;
197 }
198
199 switch (tcmd) {
200 case TOK_LIST:
201 case TOK_INFO:
202 case TOK_DETAIL:
203 case TOK_FLUSH:
204 case TOK_DESTROY:
205 break;
206 default:
207 if (is_all != 0)
208 errx(EX_USAGE, "table name required");
209 }
210
211 switch (tcmd) {
212 case TOK_ADD:
213 case TOK_DEL:
214 do_add = **av == 'a';
215 ac--; av++;
216 table_modify_record(&oh, ac, av, do_add, co.do_quiet,
217 co.do_quiet, atomic);
218 break;
219 case TOK_CREATE:
220 ac--; av++;
221 table_create(&oh, ac, av);
222 break;
223 case TOK_MODIFY:
224 ac--; av++;
225 table_modify(&oh, ac, av);
226 break;
227 case TOK_DESTROY:
228 if (is_all == 0) {
229 if (table_destroy(&oh) == 0)
230 break;
231 if (errno != ESRCH)
232 err(EX_OSERR, "failed to destroy table %s",
233 tablename);
234 /* ESRCH isn't fatal, warn if not quiet mode */
235 if (co.do_quiet == 0)
236 warn("failed to destroy table %s", tablename);
237 } else {
238 error = tables_foreach(table_destroy_one, &oh, 1);
239 if (error != 0)
240 err(EX_OSERR,
241 "failed to destroy tables list");
242 }
243 break;
244 case TOK_FLUSH:
245 if (is_all == 0) {
246 if ((error = table_flush(&oh)) == 0)
247 break;
248 if (errno != ESRCH)
249 err(EX_OSERR, "failed to flush table %s info",
250 tablename);
251 /* ESRCH isn't fatal, warn if not quiet mode */
252 if (co.do_quiet == 0)
253 warn("failed to flush table %s info",
254 tablename);
255 } else {
256 error = tables_foreach(table_flush_one, &oh, 1);
257 if (error != 0)
258 err(EX_OSERR, "failed to flush tables list");
259 /* XXX: we ignore errors here */
260 }
261 break;
262 case TOK_SWAP:
263 ac--; av++;
264 NEED1("second table name required");
265 table_swap(&oh, *av);
266 break;
267 case TOK_LOCK:
268 case TOK_UNLOCK:
269 table_lock(&oh, (tcmd == TOK_LOCK));
270 break;
271 case TOK_DETAIL:
272 case TOK_INFO:
273 arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL;
274 if (is_all == 0) {
275 if ((error = table_get_info(&oh, &i)) != 0)
276 err(EX_OSERR, "failed to request table info");
277 table_show_info(&i, arg);
278 } else {
279 error = tables_foreach(table_show_info, arg, 1);
280 if (error != 0)
281 err(EX_OSERR, "failed to request tables list");
282 }
283 break;
284 case TOK_LIST:
285 arg = is_all ? (void*)1 : NULL;
286 if (is_all == 0) {
287 ipfw_xtable_info i;
288 if ((error = table_get_info(&oh, &i)) != 0)
289 err(EX_OSERR, "failed to request table info");
290 table_show_one(&i, arg);
291 } else {
292 error = tables_foreach(table_show_one, arg, 1);
293 if (error != 0)
294 err(EX_OSERR, "failed to request tables list");
295 }
296 break;
297 case TOK_LOOKUP:
298 ac--; av++;
299 table_lookup(&oh, ac, av);
300 break;
301 }
302 }
303
304 void
table_fill_ntlv(ipfw_obj_ntlv * ntlv,const char * name,uint8_t set,uint16_t uidx)305 table_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint8_t set,
306 uint16_t uidx)
307 {
308
309 ntlv->head.type = IPFW_TLV_TBL_NAME;
310 ntlv->head.length = sizeof(ipfw_obj_ntlv);
311 ntlv->idx = uidx;
312 ntlv->set = set;
313 strlcpy(ntlv->name, name, sizeof(ntlv->name));
314 }
315
316 static void
table_fill_objheader(ipfw_obj_header * oh,ipfw_xtable_info * i)317 table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i)
318 {
319
320 oh->idx = 1;
321 table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
322 }
323
324 static struct _s_x tablenewcmds[] = {
325 { "type", TOK_TYPE },
326 { "valtype", TOK_VALTYPE },
327 { "algo", TOK_ALGO },
328 { "limit", TOK_LIMIT },
329 { "locked", TOK_LOCK },
330 { "missing", TOK_MISSING },
331 { "or-flush", TOK_ORFLUSH },
332 { NULL, 0 }
333 };
334
335 static struct _s_x flowtypecmds[] = {
336 { "src-ip", IPFW_TFFLAG_SRCIP },
337 { "proto", IPFW_TFFLAG_PROTO },
338 { "src-port", IPFW_TFFLAG_SRCPORT },
339 { "dst-ip", IPFW_TFFLAG_DSTIP },
340 { "dst-port", IPFW_TFFLAG_DSTPORT },
341 { NULL, 0 }
342 };
343
344 int
table_parse_type(uint8_t ttype,char * p,uint8_t * tflags)345 table_parse_type(uint8_t ttype, char *p, uint8_t *tflags)
346 {
347 uint32_t fset, fclear;
348 char *e;
349
350 /* Parse type options */
351 switch(ttype) {
352 case IPFW_TABLE_FLOW:
353 fset = fclear = 0;
354 if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0)
355 errx(EX_USAGE,
356 "unable to parse flow option %s", e);
357 *tflags = fset;
358 break;
359 default:
360 return (EX_USAGE);
361 }
362
363 return (0);
364 }
365
366 void
table_print_type(char * tbuf,size_t size,uint8_t type,uint8_t tflags)367 table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags)
368 {
369 const char *tname;
370 int l;
371
372 if ((tname = match_value(tabletypes, type)) == NULL)
373 tname = "unknown";
374
375 l = snprintf(tbuf, size, "%s", tname);
376 tbuf += l;
377 size -= l;
378
379 switch(type) {
380 case IPFW_TABLE_FLOW:
381 if (tflags != 0) {
382 *tbuf++ = ':';
383 l--;
384 print_flags_buffer(tbuf, size, flowtypecmds, tflags);
385 }
386 break;
387 }
388 }
389
390 /*
391 * Creates new table
392 *
393 * ipfw table NAME create [ type { addr | iface | number | flow } ]
394 * [ algo algoname ] [missing] [or-flush]
395 */
396 static void
table_create(ipfw_obj_header * oh,int ac,char * av[])397 table_create(ipfw_obj_header *oh, int ac, char *av[])
398 {
399 ipfw_xtable_info xi, xie;
400 int error, missing, orflush, tcmd, val;
401 uint32_t fset, fclear;
402 char *e, *p;
403 char tbuf[128];
404
405 missing = orflush = 0;
406 memset(&xi, 0, sizeof(xi));
407 while (ac > 0) {
408 tcmd = get_token(tablenewcmds, *av, "option");
409 ac--; av++;
410
411 switch (tcmd) {
412 case TOK_LIMIT:
413 NEED1("limit value required");
414 xi.limit = strtol(*av, NULL, 10);
415 ac--; av++;
416 break;
417 case TOK_TYPE:
418 NEED1("table type required");
419 /* Type may have suboptions after ':' */
420 if ((p = strchr(*av, ':')) != NULL)
421 *p++ = '\0';
422 val = match_token(tabletypes, *av);
423 if (val == -1) {
424 concat_tokens(tbuf, sizeof(tbuf), tabletypes,
425 ", ");
426 errx(EX_USAGE,
427 "Unknown tabletype: %s. Supported: %s",
428 *av, tbuf);
429 }
430 xi.type = val;
431 if (p != NULL) {
432 error = table_parse_type(val, p, &xi.tflags);
433 if (error != 0)
434 errx(EX_USAGE,
435 "Unsupported suboptions: %s", p);
436 }
437 ac--; av++;
438 break;
439 case TOK_VALTYPE:
440 NEED1("table value type required");
441 fset = fclear = 0;
442 val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear);
443 if (val != -1) {
444 xi.vmask = fset;
445 ac--; av++;
446 break;
447 }
448 concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", ");
449 errx(EX_USAGE, "Unknown value type: %s. Supported: %s",
450 e, tbuf);
451 break;
452 case TOK_ALGO:
453 NEED1("table algorithm name required");
454 if (strlen(*av) > sizeof(xi.algoname))
455 errx(EX_USAGE, "algorithm name too long");
456 strlcpy(xi.algoname, *av, sizeof(xi.algoname));
457 ac--; av++;
458 break;
459 case TOK_LOCK:
460 xi.flags |= IPFW_TGFLAGS_LOCKED;
461 break;
462 case TOK_ORFLUSH:
463 orflush = 1;
464 /* FALLTHROUGH */
465 case TOK_MISSING:
466 missing = 1;
467 break;
468 }
469 }
470
471 /* Set some defaults to preserve compatibility. */
472 if (xi.algoname[0] == '\0' && xi.type == 0)
473 xi.type = IPFW_TABLE_ADDR;
474 if (xi.vmask == 0)
475 xi.vmask = IPFW_VTYPE_LEGACY;
476
477 error = table_do_create(oh, &xi);
478
479 if (error == 0)
480 return;
481
482 if (errno != EEXIST || missing == 0)
483 err(EX_OSERR, "Table creation failed");
484
485 /* Check that existing table is the same we are trying to create */
486 if (table_get_info(oh, &xie) != 0)
487 err(EX_OSERR, "Existing table check failed");
488
489 if (xi.limit != xie.limit || xi.type != xie.type ||
490 xi.tflags != xie.tflags || xi.vmask != xie.vmask || (
491 xi.algoname[0] != '\0' && strcmp(xi.algoname,
492 xie.algoname) != 0) || xi.flags != xie.flags)
493 errx(EX_DATAERR, "The existing table is not compatible "
494 "with one you are creating.");
495
496 /* Flush existing table if instructed to do so */
497 if (orflush != 0 && table_flush(oh) != 0)
498 err(EX_OSERR, "Table flush on creation failed");
499 }
500
501 /*
502 * Creates new table
503 *
504 * Request: [ ipfw_obj_header ipfw_xtable_info ]
505 *
506 * Returns 0 on success.
507 */
508 static int
table_do_create(ipfw_obj_header * oh,ipfw_xtable_info * i)509 table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i)
510 {
511 char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
512 int error;
513
514 memcpy(tbuf, oh, sizeof(*oh));
515 memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
516 oh = (ipfw_obj_header *)tbuf;
517
518 error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf));
519
520 return (error);
521 }
522
523 /*
524 * Modifies existing table
525 *
526 * ipfw table NAME modify [ limit number ]
527 */
528 static void
table_modify(ipfw_obj_header * oh,int ac,char * av[])529 table_modify(ipfw_obj_header *oh, int ac, char *av[])
530 {
531 ipfw_xtable_info xi;
532 int tcmd;
533
534 memset(&xi, 0, sizeof(xi));
535
536 while (ac > 0) {
537 tcmd = get_token(tablenewcmds, *av, "option");
538 ac--; av++;
539
540 switch (tcmd) {
541 case TOK_LIMIT:
542 NEED1("limit value required");
543 xi.limit = strtol(*av, NULL, 10);
544 xi.mflags |= IPFW_TMFLAGS_LIMIT;
545 ac--; av++;
546 break;
547 default:
548 errx(EX_USAGE, "cmd is not supported for modification");
549 }
550 }
551
552 if (table_do_modify(oh, &xi) != 0)
553 err(EX_OSERR, "Table modification failed");
554 }
555
556 /*
557 * Modifies existing table.
558 *
559 * Request: [ ipfw_obj_header ipfw_xtable_info ]
560 *
561 * Returns 0 on success.
562 */
563 static int
table_do_modify(ipfw_obj_header * oh,ipfw_xtable_info * i)564 table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i)
565 {
566 char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
567 int error;
568
569 memcpy(tbuf, oh, sizeof(*oh));
570 memcpy(tbuf + sizeof(*oh), i, sizeof(*i));
571 oh = (ipfw_obj_header *)tbuf;
572
573 error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf));
574
575 return (error);
576 }
577
578 /*
579 * Locks or unlocks given table
580 */
581 static void
table_lock(ipfw_obj_header * oh,int lock)582 table_lock(ipfw_obj_header *oh, int lock)
583 {
584 ipfw_xtable_info xi;
585
586 memset(&xi, 0, sizeof(xi));
587
588 xi.mflags |= IPFW_TMFLAGS_LOCK;
589 xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0;
590
591 if (table_do_modify(oh, &xi) != 0)
592 err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock");
593 }
594
595 /*
596 * Destroys given table specified by @oh->ntlv.
597 * Returns 0 on success.
598 */
599 static int
table_destroy(ipfw_obj_header * oh)600 table_destroy(ipfw_obj_header *oh)
601 {
602
603 if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0)
604 return (-1);
605
606 return (0);
607 }
608
609 static int
table_destroy_one(ipfw_xtable_info * i,void * arg)610 table_destroy_one(ipfw_xtable_info *i, void *arg)
611 {
612 ipfw_obj_header *oh;
613
614 oh = (ipfw_obj_header *)arg;
615 table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
616 if (table_destroy(oh) != 0) {
617 if (co.do_quiet == 0)
618 warn("failed to destroy table(%s) in set %u",
619 i->tablename, i->set);
620 return (-1);
621 }
622 return (0);
623 }
624
625 /*
626 * Flushes given table specified by @oh->ntlv.
627 * Returns 0 on success.
628 */
629 static int
table_flush(ipfw_obj_header * oh)630 table_flush(ipfw_obj_header *oh)
631 {
632
633 if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0)
634 return (-1);
635
636 return (0);
637 }
638
639 static int
table_do_swap(ipfw_obj_header * oh,char * second)640 table_do_swap(ipfw_obj_header *oh, char *second)
641 {
642 char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)];
643 int error;
644
645 memset(tbuf, 0, sizeof(tbuf));
646 memcpy(tbuf, oh, sizeof(*oh));
647 oh = (ipfw_obj_header *)tbuf;
648 table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1);
649
650 error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf));
651
652 return (error);
653 }
654
655 /*
656 * Swaps given table with @second one.
657 */
658 static int
table_swap(ipfw_obj_header * oh,char * second)659 table_swap(ipfw_obj_header *oh, char *second)
660 {
661
662 if (table_check_name(second) != 0)
663 errx(EX_USAGE, "table name %s is invalid", second);
664
665 if (table_do_swap(oh, second) == 0)
666 return (0);
667
668 switch (errno) {
669 case EINVAL:
670 errx(EX_USAGE, "Unable to swap table: check types");
671 case EFBIG:
672 errx(EX_USAGE, "Unable to swap table: check limits");
673 }
674
675 return (0);
676 }
677
678
679 /*
680 * Retrieves table in given table specified by @oh->ntlv.
681 * it inside @i.
682 * Returns 0 on success.
683 */
684 static int
table_get_info(ipfw_obj_header * oh,ipfw_xtable_info * i)685 table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i)
686 {
687 char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)];
688 size_t sz;
689
690 sz = sizeof(tbuf);
691 memset(tbuf, 0, sizeof(tbuf));
692 memcpy(tbuf, oh, sizeof(*oh));
693 oh = (ipfw_obj_header *)tbuf;
694
695 if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) != 0)
696 return (errno);
697
698 if (sz < sizeof(tbuf))
699 return (EINVAL);
700
701 *i = *(ipfw_xtable_info *)(oh + 1);
702
703 return (0);
704 }
705
706 static struct _s_x tablealgoclass[] = {
707 { "hash", IPFW_TACLASS_HASH },
708 { "array", IPFW_TACLASS_ARRAY },
709 { "radix", IPFW_TACLASS_RADIX },
710 { NULL, 0 }
711 };
712
713 struct ta_cldata {
714 uint8_t taclass;
715 uint8_t spare4;
716 uint16_t itemsize;
717 uint16_t itemsize6;
718 uint32_t size;
719 uint32_t count;
720 };
721
722 /*
723 * Print global/per-AF table @i algorithm info.
724 */
725 static void
table_show_tainfo(ipfw_xtable_info * i,struct ta_cldata * d,const char * af,const char * taclass)726 table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d,
727 const char *af, const char *taclass)
728 {
729
730 switch (d->taclass) {
731 case IPFW_TACLASS_HASH:
732 case IPFW_TACLASS_ARRAY:
733 printf(" %salgorithm %s info\n", af, taclass);
734 if (d->itemsize == d->itemsize6)
735 printf(" size: %u items: %u itemsize: %u\n",
736 d->size, d->count, d->itemsize);
737 else
738 printf(" size: %u items: %u "
739 "itemsize4: %u itemsize6: %u\n",
740 d->size, d->count,
741 d->itemsize, d->itemsize6);
742 break;
743 case IPFW_TACLASS_RADIX:
744 printf(" %salgorithm %s info\n", af, taclass);
745 if (d->itemsize == d->itemsize6)
746 printf(" items: %u itemsize: %u\n",
747 d->count, d->itemsize);
748 else
749 printf(" items: %u "
750 "itemsize4: %u itemsize6: %u\n",
751 d->count, d->itemsize, d->itemsize6);
752 break;
753 default:
754 printf(" algo class: %s\n", taclass);
755 }
756 }
757
758 static void
table_print_valheader(char * buf,size_t bufsize,uint32_t vmask)759 table_print_valheader(char *buf, size_t bufsize, uint32_t vmask)
760 {
761
762 if (vmask == IPFW_VTYPE_LEGACY) {
763 snprintf(buf, bufsize, "legacy");
764 return;
765 }
766
767 memset(buf, 0, bufsize);
768 print_flags_buffer(buf, bufsize, tablevaltypes, vmask);
769 }
770
771 /*
772 * Prints table info struct @i in human-readable form.
773 */
774 static int
table_show_info(ipfw_xtable_info * i,void * arg)775 table_show_info(ipfw_xtable_info *i, void *arg)
776 {
777 const char *vtype;
778 ipfw_ta_tinfo *tainfo;
779 int afdata, afitem;
780 struct ta_cldata d;
781 char ttype[64], tvtype[64];
782
783 table_print_type(ttype, sizeof(ttype), i->type, i->tflags);
784 table_print_valheader(tvtype, sizeof(tvtype), i->vmask);
785
786 printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
787 if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0)
788 printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype);
789 else
790 printf(" kindex: %d, type: %s\n", i->kidx, ttype);
791 printf(" references: %u, valtype: %s\n", i->refcnt, tvtype);
792 printf(" algorithm: %s\n", i->algoname);
793 printf(" items: %u, size: %u\n", i->count, i->size);
794 if (i->limit > 0)
795 printf(" limit: %u\n", i->limit);
796
797 /* Print algo-specific info if requested & set */
798 if (arg == NULL)
799 return (0);
800
801 if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0)
802 return (0);
803 tainfo = &i->ta_info;
804
805 afdata = 0;
806 afitem = 0;
807 if (tainfo->flags & IPFW_TATFLAGS_AFDATA)
808 afdata = 1;
809 if (tainfo->flags & IPFW_TATFLAGS_AFITEM)
810 afitem = 1;
811
812 memset(&d, 0, sizeof(d));
813 d.taclass = tainfo->taclass4;
814 d.size = tainfo->size4;
815 d.count = tainfo->count4;
816 d.itemsize = tainfo->itemsize4;
817 if (afdata == 0 && afitem != 0)
818 d.itemsize6 = tainfo->itemsize6;
819 else
820 d.itemsize6 = d.itemsize;
821 if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
822 vtype = "unknown";
823
824 if (afdata == 0) {
825 table_show_tainfo(i, &d, "", vtype);
826 } else {
827 table_show_tainfo(i, &d, "IPv4 ", vtype);
828 memset(&d, 0, sizeof(d));
829 d.taclass = tainfo->taclass6;
830 if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL)
831 vtype = "unknown";
832 d.size = tainfo->size6;
833 d.count = tainfo->count6;
834 d.itemsize = tainfo->itemsize6;
835 d.itemsize6 = d.itemsize;
836 table_show_tainfo(i, &d, "IPv6 ", vtype);
837 }
838
839 return (0);
840 }
841
842
843 /*
844 * Function wrappers which can be used either
845 * as is or as foreach function parameter.
846 */
847
848 static int
table_show_one(ipfw_xtable_info * i,void * arg)849 table_show_one(ipfw_xtable_info *i, void *arg)
850 {
851 ipfw_obj_header *oh;
852 int error;
853 int is_all;
854
855 is_all = arg == NULL ? 0 : 1;
856
857 if ((error = table_do_get_list(i, &oh)) != 0) {
858 err(EX_OSERR, "Error requesting table %s list", i->tablename);
859 return (error);
860 }
861
862 table_show_list(oh, is_all);
863
864 free(oh);
865 return (0);
866 }
867
868 static int
table_flush_one(ipfw_xtable_info * i,void * arg)869 table_flush_one(ipfw_xtable_info *i, void *arg)
870 {
871 ipfw_obj_header *oh;
872
873 oh = (ipfw_obj_header *)arg;
874
875 table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1);
876
877 return (table_flush(oh));
878 }
879
880 static int
table_do_modify_record(int cmd,ipfw_obj_header * oh,ipfw_obj_tentry * tent,int count,int atomic)881 table_do_modify_record(int cmd, ipfw_obj_header *oh,
882 ipfw_obj_tentry *tent, int count, int atomic)
883 {
884 ipfw_obj_ctlv *ctlv;
885 ipfw_obj_tentry *tent_base;
886 caddr_t pbuf;
887 char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)];
888 int error, i;
889 size_t sz;
890
891 sz = sizeof(*ctlv) + sizeof(*tent) * count;
892 if (count == 1) {
893 memset(xbuf, 0, sizeof(xbuf));
894 pbuf = xbuf;
895 } else {
896 if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL)
897 return (ENOMEM);
898 }
899
900 memcpy(pbuf, oh, sizeof(*oh));
901 oh = (ipfw_obj_header *)pbuf;
902 oh->opheader.version = 1;
903
904 ctlv = (ipfw_obj_ctlv *)(oh + 1);
905 ctlv->count = count;
906 ctlv->head.length = sz;
907 if (atomic != 0)
908 ctlv->flags |= IPFW_CTF_ATOMIC;
909
910 tent_base = tent;
911 memcpy(ctlv + 1, tent, sizeof(*tent) * count);
912 tent = (ipfw_obj_tentry *)(ctlv + 1);
913 for (i = 0; i < count; i++, tent++) {
914 tent->head.length = sizeof(ipfw_obj_tentry);
915 tent->idx = oh->idx;
916 }
917
918 sz += sizeof(*oh);
919 error = do_get3(cmd, &oh->opheader, &sz);
920 if (error != 0)
921 error = errno;
922 tent = (ipfw_obj_tentry *)(ctlv + 1);
923 /* Copy result back to provided buffer */
924 memcpy(tent_base, ctlv + 1, sizeof(*tent) * count);
925
926 if (pbuf != xbuf)
927 free(pbuf);
928
929 return (error);
930 }
931
932 static void
table_modify_record(ipfw_obj_header * oh,int ac,char * av[],int add,int quiet,int update,int atomic)933 table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add,
934 int quiet, int update, int atomic)
935 {
936 ipfw_obj_tentry *ptent, tent, *tent_buf;
937 ipfw_xtable_info xi;
938 uint8_t type;
939 uint32_t vmask;
940 int cmd, count, error, i, ignored;
941 char *texterr, *etxt, *px;
942
943 if (ac == 0)
944 errx(EX_USAGE, "address required");
945
946 if (add != 0) {
947 cmd = IP_FW_TABLE_XADD;
948 texterr = "Adding record failed";
949 } else {
950 cmd = IP_FW_TABLE_XDEL;
951 texterr = "Deleting record failed";
952 }
953
954 /*
955 * Calculate number of entries:
956 * Assume [key val] x N for add
957 * and
958 * key x N for delete
959 */
960 count = (add != 0) ? ac / 2 + 1 : ac;
961
962 if (count <= 1) {
963 /* Adding single entry with/without value */
964 memset(&tent, 0, sizeof(tent));
965 tent_buf = &tent;
966 } else {
967
968 if ((tent_buf = calloc(count, sizeof(tent))) == NULL)
969 errx(EX_OSERR,
970 "Unable to allocate memory for all entries");
971 }
972 ptent = tent_buf;
973
974 memset(&xi, 0, sizeof(xi));
975 count = 0;
976 while (ac > 0) {
977 tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi);
978
979 /*
980 * Compatibility layer: auto-create table if not exists.
981 */
982 if (xi.tablename[0] == '\0') {
983 xi.type = type;
984 xi.vmask = vmask;
985 strlcpy(xi.tablename, oh->ntlv.name,
986 sizeof(xi.tablename));
987 if (quiet == 0)
988 warnx("DEPRECATED: inserting data into "
989 "non-existent table %s. (auto-created)",
990 xi.tablename);
991 table_do_create(oh, &xi);
992 }
993
994 oh->ntlv.type = type;
995 ac--; av++;
996
997 if (add != 0 && ac > 0) {
998 tentry_fill_value(oh, ptent, *av, type, vmask);
999 ac--; av++;
1000 }
1001
1002 if (update != 0)
1003 ptent->head.flags |= IPFW_TF_UPDATE;
1004
1005 count++;
1006 ptent++;
1007 }
1008
1009 error = table_do_modify_record(cmd, oh, tent_buf, count, atomic);
1010
1011 /*
1012 * Compatibility stuff: do not yell on duplicate keys or
1013 * failed deletions.
1014 */
1015 if (error == 0 || (error == EEXIST && add != 0) ||
1016 (error == ENOENT && add == 0)) {
1017 if (quiet != 0) {
1018 if (tent_buf != &tent)
1019 free(tent_buf);
1020 return;
1021 }
1022 }
1023
1024 /* Report results back */
1025 ptent = tent_buf;
1026 for (i = 0; i < count; ptent++, i++) {
1027 ignored = 0;
1028 switch (ptent->result) {
1029 case IPFW_TR_ADDED:
1030 px = "added";
1031 break;
1032 case IPFW_TR_DELETED:
1033 px = "deleted";
1034 break;
1035 case IPFW_TR_UPDATED:
1036 px = "updated";
1037 break;
1038 case IPFW_TR_LIMIT:
1039 px = "limit";
1040 ignored = 1;
1041 break;
1042 case IPFW_TR_ERROR:
1043 px = "error";
1044 ignored = 1;
1045 break;
1046 case IPFW_TR_NOTFOUND:
1047 px = "notfound";
1048 ignored = 1;
1049 break;
1050 case IPFW_TR_EXISTS:
1051 px = "exists";
1052 ignored = 1;
1053 break;
1054 case IPFW_TR_IGNORED:
1055 px = "ignored";
1056 ignored = 1;
1057 break;
1058 default:
1059 px = "unknown";
1060 ignored = 1;
1061 }
1062
1063 if (error != 0 && atomic != 0 && ignored == 0)
1064 printf("%s(reverted): ", px);
1065 else
1066 printf("%s: ", px);
1067
1068 table_show_entry(&xi, ptent);
1069 }
1070
1071 if (tent_buf != &tent)
1072 free(tent_buf);
1073
1074 if (error == 0)
1075 return;
1076 /* Get real OS error */
1077 error = errno;
1078
1079 /* Try to provide more human-readable error */
1080 switch (error) {
1081 case EEXIST:
1082 etxt = "record already exists";
1083 break;
1084 case EFBIG:
1085 etxt = "limit hit";
1086 break;
1087 case ESRCH:
1088 etxt = "table not found";
1089 break;
1090 case ENOENT:
1091 etxt = "record not found";
1092 break;
1093 case EACCES:
1094 etxt = "table is locked";
1095 break;
1096 default:
1097 etxt = strerror(error);
1098 }
1099
1100 errx(EX_OSERR, "%s: %s", texterr, etxt);
1101 }
1102
1103 static int
table_do_lookup(ipfw_obj_header * oh,char * key,ipfw_xtable_info * xi,ipfw_obj_tentry * xtent)1104 table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi,
1105 ipfw_obj_tentry *xtent)
1106 {
1107 char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)];
1108 ipfw_obj_tentry *tent;
1109 uint8_t type;
1110 uint32_t vmask;
1111 size_t sz;
1112
1113 memcpy(xbuf, oh, sizeof(*oh));
1114 oh = (ipfw_obj_header *)xbuf;
1115 tent = (ipfw_obj_tentry *)(oh + 1);
1116
1117 memset(tent, 0, sizeof(*tent));
1118 tent->head.length = sizeof(*tent);
1119 tent->idx = 1;
1120
1121 tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi);
1122 oh->ntlv.type = type;
1123
1124 sz = sizeof(xbuf);
1125 if (do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz) != 0)
1126 return (errno);
1127
1128 if (sz < sizeof(xbuf))
1129 return (EINVAL);
1130
1131 *xtent = *tent;
1132
1133 return (0);
1134 }
1135
1136 static void
table_lookup(ipfw_obj_header * oh,int ac,char * av[])1137 table_lookup(ipfw_obj_header *oh, int ac, char *av[])
1138 {
1139 ipfw_obj_tentry xtent;
1140 ipfw_xtable_info xi;
1141 char key[64];
1142 int error;
1143
1144 if (ac == 0)
1145 errx(EX_USAGE, "address required");
1146
1147 strlcpy(key, *av, sizeof(key));
1148
1149 memset(&xi, 0, sizeof(xi));
1150 error = table_do_lookup(oh, key, &xi, &xtent);
1151
1152 switch (error) {
1153 case 0:
1154 break;
1155 case ESRCH:
1156 errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name);
1157 case ENOENT:
1158 errx(EX_UNAVAILABLE, "Entry %s not found", *av);
1159 case ENOTSUP:
1160 errx(EX_UNAVAILABLE, "Table %s algo does not support "
1161 "\"lookup\" method", oh->ntlv.name);
1162 default:
1163 err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)");
1164 }
1165
1166 table_show_entry(&xi, &xtent);
1167 }
1168
1169 static void
tentry_fill_key_type(char * arg,ipfw_obj_tentry * tentry,uint8_t type,uint8_t tflags)1170 tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type,
1171 uint8_t tflags)
1172 {
1173 char *p, *pp;
1174 int mask, af;
1175 struct in6_addr *paddr, tmp;
1176 struct tflow_entry *tfe;
1177 uint32_t key, *pkey;
1178 uint16_t port;
1179 struct protoent *pent;
1180 struct servent *sent;
1181 int masklen;
1182
1183 masklen = 0;
1184 af = 0;
1185 paddr = (struct in6_addr *)&tentry->k;
1186
1187 switch (type) {
1188 case IPFW_TABLE_ADDR:
1189 /* Remove / if exists */
1190 if ((p = strchr(arg, '/')) != NULL) {
1191 *p = '\0';
1192 mask = atoi(p + 1);
1193 }
1194
1195 if (inet_pton(AF_INET, arg, paddr) == 1) {
1196 if (p != NULL && mask > 32)
1197 errx(EX_DATAERR, "bad IPv4 mask width: %s",
1198 p + 1);
1199
1200 masklen = p ? mask : 32;
1201 af = AF_INET;
1202 } else if (inet_pton(AF_INET6, arg, paddr) == 1) {
1203 if (IN6_IS_ADDR_V4COMPAT(paddr))
1204 errx(EX_DATAERR,
1205 "Use IPv4 instead of v4-compatible");
1206 if (p != NULL && mask > 128)
1207 errx(EX_DATAERR, "bad IPv6 mask width: %s",
1208 p + 1);
1209
1210 masklen = p ? mask : 128;
1211 af = AF_INET6;
1212 } else {
1213 /* Assume FQDN */
1214 if (lookup_host(arg, (struct in_addr *)paddr) != 0)
1215 errx(EX_NOHOST, "hostname ``%s'' unknown", arg);
1216
1217 masklen = 32;
1218 type = IPFW_TABLE_ADDR;
1219 af = AF_INET;
1220 }
1221 break;
1222 case IPFW_TABLE_INTERFACE:
1223 /* Assume interface name. Copy significant data only */
1224 mask = MIN(strlen(arg), IF_NAMESIZE - 1);
1225 memcpy(paddr, arg, mask);
1226 /* Set mask to exact match */
1227 masklen = 8 * IF_NAMESIZE;
1228 break;
1229 case IPFW_TABLE_NUMBER:
1230 /* Port or any other key */
1231 key = strtol(arg, &p, 10);
1232 if (*p != '\0')
1233 errx(EX_DATAERR, "Invalid number: %s", arg);
1234
1235 pkey = (uint32_t *)paddr;
1236 *pkey = key;
1237 masklen = 32;
1238 break;
1239 case IPFW_TABLE_FLOW:
1240 /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */
1241 tfe = &tentry->k.flow;
1242 af = 0;
1243
1244 /* Handle <ipv4|ipv6> */
1245 if ((tflags & IPFW_TFFLAG_SRCIP) != 0) {
1246 if ((p = strchr(arg, ',')) != NULL)
1247 *p++ = '\0';
1248 /* Determine family using temporary storage */
1249 if (inet_pton(AF_INET, arg, &tmp) == 1) {
1250 if (af != 0 && af != AF_INET)
1251 errx(EX_DATAERR,
1252 "Inconsistent address family\n");
1253 af = AF_INET;
1254 memcpy(&tfe->a.a4.sip, &tmp, 4);
1255 } else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1256 if (af != 0 && af != AF_INET6)
1257 errx(EX_DATAERR,
1258 "Inconsistent address family\n");
1259 af = AF_INET6;
1260 memcpy(&tfe->a.a6.sip6, &tmp, 16);
1261 }
1262
1263 arg = p;
1264 }
1265
1266 /* Handle <proto-num|proto-name> */
1267 if ((tflags & IPFW_TFFLAG_PROTO) != 0) {
1268 if (arg == NULL)
1269 errx(EX_DATAERR, "invalid key: proto missing");
1270 if ((p = strchr(arg, ',')) != NULL)
1271 *p++ = '\0';
1272
1273 key = strtol(arg, &pp, 10);
1274 if (*pp != '\0') {
1275 if ((pent = getprotobyname(arg)) == NULL)
1276 errx(EX_DATAERR, "Unknown proto: %s",
1277 arg);
1278 else
1279 key = pent->p_proto;
1280 }
1281
1282 if (key > 255)
1283 errx(EX_DATAERR, "Bad protocol number: %u",key);
1284
1285 tfe->proto = key;
1286
1287 arg = p;
1288 }
1289
1290 /* Handle <port-num|service-name> */
1291 if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1292 if (arg == NULL)
1293 errx(EX_DATAERR, "invalid key: src port missing");
1294 if ((p = strchr(arg, ',')) != NULL)
1295 *p++ = '\0';
1296
1297 port = htons(strtol(arg, &pp, 10));
1298 if (*pp != '\0') {
1299 if ((sent = getservbyname(arg, NULL)) == NULL)
1300 errx(EX_DATAERR, "Unknown service: %s",
1301 arg);
1302 port = sent->s_port;
1303 }
1304 tfe->sport = port;
1305 arg = p;
1306 }
1307
1308 /* Handle <ipv4|ipv6>*/
1309 if ((tflags & IPFW_TFFLAG_DSTIP) != 0) {
1310 if (arg == NULL)
1311 errx(EX_DATAERR, "invalid key: dst ip missing");
1312 if ((p = strchr(arg, ',')) != NULL)
1313 *p++ = '\0';
1314 /* Determine family using temporary storage */
1315 if (inet_pton(AF_INET, arg, &tmp) == 1) {
1316 if (af != 0 && af != AF_INET)
1317 errx(EX_DATAERR,
1318 "Inconsistent address family");
1319 af = AF_INET;
1320 memcpy(&tfe->a.a4.dip, &tmp, 4);
1321 } else if (inet_pton(AF_INET6, arg, &tmp) == 1) {
1322 if (af != 0 && af != AF_INET6)
1323 errx(EX_DATAERR,
1324 "Inconsistent address family");
1325 af = AF_INET6;
1326 memcpy(&tfe->a.a6.dip6, &tmp, 16);
1327 }
1328
1329 arg = p;
1330 }
1331
1332 /* Handle <port-num|service-name> */
1333 if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1334 if (arg == NULL)
1335 errx(EX_DATAERR, "invalid key: dst port missing");
1336 if ((p = strchr(arg, ',')) != NULL)
1337 *p++ = '\0';
1338
1339 port = htons(strtol(arg, &pp, 10));
1340 if (*pp != '\0') {
1341 if ((sent = getservbyname(arg, NULL)) == NULL)
1342 errx(EX_DATAERR, "Unknown service: %s",
1343 arg);
1344 port = sent->s_port;
1345 }
1346 tfe->dport = port;
1347 arg = p;
1348 }
1349
1350 tfe->af = af;
1351
1352 break;
1353
1354 default:
1355 errx(EX_DATAERR, "Unsupported table type: %d", type);
1356 }
1357
1358 tentry->subtype = af;
1359 tentry->masklen = masklen;
1360 }
1361
1362 /*
1363 * Tries to guess table key type.
1364 * This procedure is used in legacy table auto-create
1365 * code AND in `ipfw -n` ruleset checking.
1366 *
1367 * Imported from old table_fill_xentry() parse code.
1368 */
1369 static int
guess_key_type(char * key,uint8_t * ptype)1370 guess_key_type(char *key, uint8_t *ptype)
1371 {
1372 char *p;
1373 struct in6_addr addr;
1374 uint32_t kv;
1375
1376 if (ishexnumber(*key) != 0 || *key == ':') {
1377 /* Remove / if exists */
1378 if ((p = strchr(key, '/')) != NULL)
1379 *p = '\0';
1380
1381 if ((inet_pton(AF_INET, key, &addr) == 1) ||
1382 (inet_pton(AF_INET6, key, &addr) == 1)) {
1383 *ptype = IPFW_TABLE_CIDR;
1384 if (p != NULL)
1385 *p = '/';
1386 return (0);
1387 } else {
1388 /* Port or any other key */
1389 /* Skip non-base 10 entries like 'fa1' */
1390 kv = strtol(key, &p, 10);
1391 if (*p == '\0') {
1392 *ptype = IPFW_TABLE_NUMBER;
1393 return (0);
1394 } else if ((p != key) && (*p == '.')) {
1395 /*
1396 * Warn on IPv4 address strings
1397 * which are "valid" for inet_aton() but not
1398 * in inet_pton().
1399 *
1400 * Typical examples: '10.5' or '10.0.0.05'
1401 */
1402 return (1);
1403 }
1404 }
1405 }
1406
1407 if (strchr(key, '.') == NULL) {
1408 *ptype = IPFW_TABLE_INTERFACE;
1409 return (0);
1410 }
1411
1412 if (lookup_host(key, (struct in_addr *)&addr) != 0)
1413 return (1);
1414
1415 *ptype = IPFW_TABLE_CIDR;
1416 return (0);
1417 }
1418
1419 static void
tentry_fill_key(ipfw_obj_header * oh,ipfw_obj_tentry * tent,char * key,int add,uint8_t * ptype,uint32_t * pvmask,ipfw_xtable_info * xi)1420 tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key,
1421 int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi)
1422 {
1423 uint8_t type, tflags;
1424 uint32_t vmask;
1425 int error;
1426
1427 type = 0;
1428 tflags = 0;
1429 vmask = 0;
1430
1431 if (xi->tablename[0] == '\0')
1432 error = table_get_info(oh, xi);
1433 else
1434 error = 0;
1435
1436 if (error == 0) {
1437 if (co.test_only == 0) {
1438 /* Table found */
1439 type = xi->type;
1440 tflags = xi->tflags;
1441 vmask = xi->vmask;
1442 } else {
1443 /*
1444 * We're running `ipfw -n`
1445 * Compatibility layer: try to guess key type
1446 * before failing.
1447 */
1448 if (guess_key_type(key, &type) != 0) {
1449 /* Inknown key */
1450 errx(EX_USAGE, "Cannot guess "
1451 "key '%s' type", key);
1452 }
1453 vmask = IPFW_VTYPE_LEGACY;
1454 }
1455 } else {
1456 if (error != ESRCH)
1457 errx(EX_OSERR, "Error requesting table %s info",
1458 oh->ntlv.name);
1459 if (add == 0)
1460 errx(EX_DATAERR, "Table %s does not exist",
1461 oh->ntlv.name);
1462 /*
1463 * Table does not exist
1464 * Compatibility layer: try to guess key type before failing.
1465 */
1466 if (guess_key_type(key, &type) != 0) {
1467 /* Inknown key */
1468 errx(EX_USAGE, "Table %s does not exist, cannot guess "
1469 "key '%s' type", oh->ntlv.name, key);
1470 }
1471
1472 vmask = IPFW_VTYPE_LEGACY;
1473 }
1474
1475 tentry_fill_key_type(key, tent, type, tflags);
1476
1477 *ptype = type;
1478 *pvmask = vmask;
1479 }
1480
1481 static void
set_legacy_value(uint32_t val,ipfw_table_value * v)1482 set_legacy_value(uint32_t val, ipfw_table_value *v)
1483 {
1484 v->tag = val;
1485 v->pipe = val;
1486 v->divert = val;
1487 v->skipto = val;
1488 v->netgraph = val;
1489 v->fib = val;
1490 v->nat = val;
1491 v->nh4 = val;
1492 v->dscp = (uint8_t)val;
1493 v->limit = val;
1494 }
1495
1496 static void
tentry_fill_value(ipfw_obj_header * oh,ipfw_obj_tentry * tent,char * arg,uint8_t type,uint32_t vmask)1497 tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg,
1498 uint8_t type, uint32_t vmask)
1499 {
1500 struct addrinfo hints, *res;
1501 uint32_t a4, flag, val;
1502 ipfw_table_value *v;
1503 uint32_t i;
1504 int dval;
1505 char *comma, *e, *etype, *n, *p;
1506 struct in_addr ipaddr;
1507
1508 v = &tent->v.value;
1509
1510 /* Compat layer: keep old behavior for legacy value types */
1511 if (vmask == IPFW_VTYPE_LEGACY) {
1512 /* Try to interpret as number first */
1513 val = strtoul(arg, &p, 0);
1514 if (*p == '\0') {
1515 set_legacy_value(val, v);
1516 return;
1517 }
1518 if (inet_pton(AF_INET, arg, &val) == 1) {
1519 set_legacy_value(ntohl(val), v);
1520 return;
1521 }
1522 /* Try hostname */
1523 if (lookup_host(arg, &ipaddr) == 0) {
1524 set_legacy_value(ntohl(ipaddr.s_addr), v);
1525 return;
1526 }
1527 errx(EX_OSERR, "Unable to parse value %s", arg);
1528 }
1529
1530 /*
1531 * Shorthands: handle single value if vmask consists
1532 * of numbers only. e.g.:
1533 * vmask = "fib,skipto" -> treat input "1" as "1,1"
1534 */
1535
1536 n = arg;
1537 etype = NULL;
1538 for (i = 1; i < (1 << 31); i *= 2) {
1539 if ((flag = (vmask & i)) == 0)
1540 continue;
1541 vmask &= ~flag;
1542
1543 if ((comma = strchr(n, ',')) != NULL)
1544 *comma = '\0';
1545
1546 switch (flag) {
1547 case IPFW_VTYPE_TAG:
1548 v->tag = strtol(n, &e, 10);
1549 if (*e != '\0')
1550 etype = "tag";
1551 break;
1552 case IPFW_VTYPE_PIPE:
1553 v->pipe = strtol(n, &e, 10);
1554 if (*e != '\0')
1555 etype = "pipe";
1556 break;
1557 case IPFW_VTYPE_DIVERT:
1558 v->divert = strtol(n, &e, 10);
1559 if (*e != '\0')
1560 etype = "divert";
1561 break;
1562 case IPFW_VTYPE_SKIPTO:
1563 v->skipto = strtol(n, &e, 10);
1564 if (*e != '\0')
1565 etype = "skipto";
1566 break;
1567 case IPFW_VTYPE_NETGRAPH:
1568 v->netgraph = strtol(n, &e, 10);
1569 if (*e != '\0')
1570 etype = "netgraph";
1571 break;
1572 case IPFW_VTYPE_FIB:
1573 v->fib = strtol(n, &e, 10);
1574 if (*e != '\0')
1575 etype = "fib";
1576 break;
1577 case IPFW_VTYPE_NAT:
1578 v->nat = strtol(n, &e, 10);
1579 if (*e != '\0')
1580 etype = "nat";
1581 break;
1582 case IPFW_VTYPE_LIMIT:
1583 v->limit = strtol(n, &e, 10);
1584 if (*e != '\0')
1585 etype = "limit";
1586 break;
1587 case IPFW_VTYPE_NH4:
1588 if (strchr(n, '.') != NULL &&
1589 inet_pton(AF_INET, n, &a4) == 1) {
1590 v->nh4 = ntohl(a4);
1591 break;
1592 }
1593 if (lookup_host(n, &ipaddr) == 0) {
1594 v->nh4 = ntohl(ipaddr.s_addr);
1595 break;
1596 }
1597 etype = "ipv4";
1598 break;
1599 case IPFW_VTYPE_DSCP:
1600 if (isalpha(*n)) {
1601 if ((dval = match_token(f_ipdscp, n)) != -1) {
1602 v->dscp = dval;
1603 break;
1604 } else
1605 etype = "DSCP code";
1606 } else {
1607 v->dscp = strtol(n, &e, 10);
1608 if (v->dscp > 63 || *e != '\0')
1609 etype = "DSCP value";
1610 }
1611 break;
1612 case IPFW_VTYPE_NH6:
1613 if (strchr(n, ':') != NULL) {
1614 memset(&hints, 0, sizeof(hints));
1615 hints.ai_family = AF_INET6;
1616 hints.ai_flags = AI_NUMERICHOST;
1617 if (getaddrinfo(n, NULL, &hints, &res) == 0) {
1618 v->nh6 = ((struct sockaddr_in6 *)
1619 res->ai_addr)->sin6_addr;
1620 v->zoneid = ((struct sockaddr_in6 *)
1621 res->ai_addr)->sin6_scope_id;
1622 freeaddrinfo(res);
1623 break;
1624 }
1625 }
1626 etype = "ipv6";
1627 break;
1628 }
1629
1630 if (etype != NULL)
1631 errx(EX_USAGE, "Unable to parse %s as %s", n, etype);
1632
1633 if (comma != NULL)
1634 *comma++ = ',';
1635
1636 if ((n = comma) != NULL)
1637 continue;
1638
1639 /* End of input. */
1640 if (vmask != 0)
1641 errx(EX_USAGE, "Not enough fields inside value");
1642 }
1643 }
1644
1645 /*
1646 * Compare table names.
1647 * Honor number comparison.
1648 */
1649 static int
tablename_cmp(const void * a,const void * b)1650 tablename_cmp(const void *a, const void *b)
1651 {
1652 ipfw_xtable_info *ia, *ib;
1653
1654 ia = (ipfw_xtable_info *)a;
1655 ib = (ipfw_xtable_info *)b;
1656
1657 return (stringnum_cmp(ia->tablename, ib->tablename));
1658 }
1659
1660 /*
1661 * Retrieves table list from kernel,
1662 * optionally sorts it and calls requested function for each table.
1663 * Returns 0 on success.
1664 */
1665 static int
tables_foreach(table_cb_t * f,void * arg,int sort)1666 tables_foreach(table_cb_t *f, void *arg, int sort)
1667 {
1668 ipfw_obj_lheader *olh;
1669 ipfw_xtable_info *info;
1670 size_t sz;
1671 int i, error;
1672
1673 /* Start with reasonable default */
1674 sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info);
1675
1676 for (;;) {
1677 if ((olh = calloc(1, sz)) == NULL)
1678 return (ENOMEM);
1679
1680 olh->size = sz;
1681 if (do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz) != 0) {
1682 sz = olh->size;
1683 free(olh);
1684 if (errno != ENOMEM)
1685 return (errno);
1686 continue;
1687 }
1688
1689 if (sort != 0)
1690 qsort(olh + 1, olh->count, olh->objsize,
1691 tablename_cmp);
1692
1693 info = (ipfw_xtable_info *)(olh + 1);
1694 for (i = 0; i < olh->count; i++) {
1695 if (co.use_set == 0 || info->set == co.use_set - 1)
1696 error = f(info, arg);
1697 info = (ipfw_xtable_info *)((caddr_t)info +
1698 olh->objsize);
1699 }
1700 free(olh);
1701 break;
1702 }
1703 return (0);
1704 }
1705
1706
1707 /*
1708 * Retrieves all entries for given table @i in
1709 * eXtended format. Allocate buffer large enough
1710 * to store result. Called needs to free it later.
1711 *
1712 * Returns 0 on success.
1713 */
1714 static int
table_do_get_list(ipfw_xtable_info * i,ipfw_obj_header ** poh)1715 table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh)
1716 {
1717 ipfw_obj_header *oh;
1718 size_t sz;
1719 int c;
1720
1721 sz = 0;
1722 oh = NULL;
1723 for (c = 0; c < 8; c++) {
1724 if (sz < i->size)
1725 sz = i->size + 44;
1726 if (oh != NULL)
1727 free(oh);
1728 if ((oh = calloc(1, sz)) == NULL)
1729 continue;
1730 table_fill_objheader(oh, i);
1731 oh->opheader.version = 1; /* Current version */
1732 if (do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz) == 0) {
1733 *poh = oh;
1734 return (0);
1735 }
1736
1737 if (errno != ENOMEM)
1738 break;
1739 }
1740 free(oh);
1741
1742 return (errno);
1743 }
1744
1745 /*
1746 * Shows all entries from @oh in human-readable format
1747 */
1748 static void
table_show_list(ipfw_obj_header * oh,int need_header)1749 table_show_list(ipfw_obj_header *oh, int need_header)
1750 {
1751 ipfw_obj_tentry *tent;
1752 uint32_t count;
1753 ipfw_xtable_info *i;
1754
1755 i = (ipfw_xtable_info *)(oh + 1);
1756 tent = (ipfw_obj_tentry *)(i + 1);
1757
1758 if (need_header)
1759 printf("--- table(%s), set(%u) ---\n", i->tablename, i->set);
1760
1761 count = i->count;
1762 while (count > 0) {
1763 table_show_entry(i, tent);
1764 tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length);
1765 count--;
1766 }
1767 }
1768
1769 static void
table_show_value(char * buf,size_t bufsize,ipfw_table_value * v,uint32_t vmask,int print_ip)1770 table_show_value(char *buf, size_t bufsize, ipfw_table_value *v,
1771 uint32_t vmask, int print_ip)
1772 {
1773 char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2];
1774 struct sockaddr_in6 sa6;
1775 uint32_t flag, i, l;
1776 size_t sz;
1777 struct in_addr a4;
1778
1779 sz = bufsize;
1780
1781 /*
1782 * Some shorthands for printing values:
1783 * legacy assumes all values are equal, so keep the first one.
1784 */
1785 if (vmask == IPFW_VTYPE_LEGACY) {
1786 if (print_ip != 0) {
1787 flag = htonl(v->tag);
1788 inet_ntop(AF_INET, &flag, buf, sz);
1789 } else
1790 snprintf(buf, sz, "%u", v->tag);
1791 return;
1792 }
1793
1794 for (i = 1; i < (1 << 31); i *= 2) {
1795 if ((flag = (vmask & i)) == 0)
1796 continue;
1797 l = 0;
1798
1799 switch (flag) {
1800 case IPFW_VTYPE_TAG:
1801 l = snprintf(buf, sz, "%u,", v->tag);
1802 break;
1803 case IPFW_VTYPE_PIPE:
1804 l = snprintf(buf, sz, "%u,", v->pipe);
1805 break;
1806 case IPFW_VTYPE_DIVERT:
1807 l = snprintf(buf, sz, "%d,", v->divert);
1808 break;
1809 case IPFW_VTYPE_SKIPTO:
1810 l = snprintf(buf, sz, "%d,", v->skipto);
1811 break;
1812 case IPFW_VTYPE_NETGRAPH:
1813 l = snprintf(buf, sz, "%u,", v->netgraph);
1814 break;
1815 case IPFW_VTYPE_FIB:
1816 l = snprintf(buf, sz, "%u,", v->fib);
1817 break;
1818 case IPFW_VTYPE_NAT:
1819 l = snprintf(buf, sz, "%u,", v->nat);
1820 break;
1821 case IPFW_VTYPE_LIMIT:
1822 l = snprintf(buf, sz, "%u,", v->limit);
1823 break;
1824 case IPFW_VTYPE_NH4:
1825 a4.s_addr = htonl(v->nh4);
1826 inet_ntop(AF_INET, &a4, abuf, sizeof(abuf));
1827 l = snprintf(buf, sz, "%s,", abuf);
1828 break;
1829 case IPFW_VTYPE_DSCP:
1830 l = snprintf(buf, sz, "%d,", v->dscp);
1831 break;
1832 case IPFW_VTYPE_NH6:
1833 sa6.sin6_family = AF_INET6;
1834 sa6.sin6_len = sizeof(sa6);
1835 sa6.sin6_addr = v->nh6;
1836 sa6.sin6_port = 0;
1837 sa6.sin6_scope_id = v->zoneid;
1838 if (getnameinfo((const struct sockaddr *)&sa6,
1839 sa6.sin6_len, abuf, sizeof(abuf), NULL, 0,
1840 NI_NUMERICHOST) == 0)
1841 l = snprintf(buf, sz, "%s,", abuf);
1842 break;
1843 }
1844
1845 buf += l;
1846 sz -= l;
1847 }
1848
1849 if (sz != bufsize)
1850 *(buf - 1) = '\0';
1851 }
1852
1853 static void
table_show_entry(ipfw_xtable_info * i,ipfw_obj_tentry * tent)1854 table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent)
1855 {
1856 char *comma, tbuf[128], pval[128];
1857 void *paddr;
1858 struct tflow_entry *tfe;
1859
1860 table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask,
1861 co.do_value_as_ip);
1862
1863 switch (i->type) {
1864 case IPFW_TABLE_ADDR:
1865 /* IPv4 or IPv6 prefixes */
1866 inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf));
1867 printf("%s/%u %s\n", tbuf, tent->masklen, pval);
1868 break;
1869 case IPFW_TABLE_INTERFACE:
1870 /* Interface names */
1871 printf("%s %s\n", tent->k.iface, pval);
1872 break;
1873 case IPFW_TABLE_NUMBER:
1874 /* numbers */
1875 printf("%u %s\n", tent->k.key, pval);
1876 break;
1877 case IPFW_TABLE_FLOW:
1878 /* flows */
1879 tfe = &tent->k.flow;
1880 comma = "";
1881
1882 if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) {
1883 if (tfe->af == AF_INET)
1884 paddr = &tfe->a.a4.sip;
1885 else
1886 paddr = &tfe->a.a6.sip6;
1887
1888 inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1889 printf("%s%s", comma, tbuf);
1890 comma = ",";
1891 }
1892
1893 if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) {
1894 printf("%s%d", comma, tfe->proto);
1895 comma = ",";
1896 }
1897
1898 if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) {
1899 printf("%s%d", comma, ntohs(tfe->sport));
1900 comma = ",";
1901 }
1902 if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) {
1903 if (tfe->af == AF_INET)
1904 paddr = &tfe->a.a4.dip;
1905 else
1906 paddr = &tfe->a.a6.dip6;
1907
1908 inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf));
1909 printf("%s%s", comma, tbuf);
1910 comma = ",";
1911 }
1912
1913 if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) {
1914 printf("%s%d", comma, ntohs(tfe->dport));
1915 comma = ",";
1916 }
1917
1918 printf(" %s\n", pval);
1919 }
1920 }
1921
1922 static int
table_do_get_stdlist(uint16_t opcode,ipfw_obj_lheader ** polh)1923 table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh)
1924 {
1925 ipfw_obj_lheader req, *olh;
1926 size_t sz;
1927
1928 memset(&req, 0, sizeof(req));
1929 sz = sizeof(req);
1930
1931 if (do_get3(opcode, &req.opheader, &sz) != 0)
1932 if (errno != ENOMEM)
1933 return (errno);
1934
1935 sz = req.size;
1936 if ((olh = calloc(1, sz)) == NULL)
1937 return (ENOMEM);
1938
1939 olh->size = sz;
1940 if (do_get3(opcode, &olh->opheader, &sz) != 0) {
1941 free(olh);
1942 return (errno);
1943 }
1944
1945 *polh = olh;
1946 return (0);
1947 }
1948
1949 static int
table_do_get_algolist(ipfw_obj_lheader ** polh)1950 table_do_get_algolist(ipfw_obj_lheader **polh)
1951 {
1952
1953 return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh));
1954 }
1955
1956 static int
table_do_get_vlist(ipfw_obj_lheader ** polh)1957 table_do_get_vlist(ipfw_obj_lheader **polh)
1958 {
1959
1960 return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh));
1961 }
1962
1963 void
ipfw_list_ta(int ac,char * av[])1964 ipfw_list_ta(int ac, char *av[])
1965 {
1966 ipfw_obj_lheader *olh;
1967 ipfw_ta_info *info;
1968 int error, i;
1969 const char *atype;
1970
1971 error = table_do_get_algolist(&olh);
1972 if (error != 0)
1973 err(EX_OSERR, "Unable to request algorithm list");
1974
1975 info = (ipfw_ta_info *)(olh + 1);
1976 for (i = 0; i < olh->count; i++) {
1977 if ((atype = match_value(tabletypes, info->type)) == NULL)
1978 atype = "unknown";
1979 printf("--- %s ---\n", info->algoname);
1980 printf(" type: %s\n refcount: %u\n", atype, info->refcnt);
1981
1982 info = (ipfw_ta_info *)((caddr_t)info + olh->objsize);
1983 }
1984
1985 free(olh);
1986 }
1987
1988
1989 /* Copy of current kernel table_value structure */
1990 struct _table_value {
1991 uint32_t tag; /* O_TAG/O_TAGGED */
1992 uint32_t pipe; /* O_PIPE/O_QUEUE */
1993 uint16_t divert; /* O_DIVERT/O_TEE */
1994 uint16_t skipto; /* skipto, CALLRET */
1995 uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */
1996 uint32_t fib; /* O_SETFIB */
1997 uint32_t nat; /* O_NAT */
1998 uint32_t nh4;
1999 uint8_t dscp;
2000 uint8_t spare0;
2001 uint16_t spare1;
2002 /* -- 32 bytes -- */
2003 struct in6_addr nh6;
2004 uint32_t limit; /* O_LIMIT */
2005 uint32_t zoneid;
2006 uint64_t refcnt; /* Number of references */
2007 };
2008
2009 int
compare_values(const void * _a,const void * _b)2010 compare_values(const void *_a, const void *_b)
2011 {
2012 struct _table_value *a, *b;
2013
2014 a = (struct _table_value *)_a;
2015 b = (struct _table_value *)_b;
2016
2017 if (a->spare1 < b->spare1)
2018 return (-1);
2019 else if (a->spare1 > b->spare1)
2020 return (1);
2021
2022 return (0);
2023 }
2024
2025 void
ipfw_list_values(int ac,char * av[])2026 ipfw_list_values(int ac, char *av[])
2027 {
2028 ipfw_obj_lheader *olh;
2029 struct _table_value *v;
2030 int error, i;
2031 uint32_t vmask;
2032 char buf[128];
2033
2034 error = table_do_get_vlist(&olh);
2035 if (error != 0)
2036 err(EX_OSERR, "Unable to request value list");
2037
2038 vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */
2039
2040 table_print_valheader(buf, sizeof(buf), vmask);
2041 printf("HEADER: %s\n", buf);
2042 v = (struct _table_value *)(olh + 1);
2043 qsort(v, olh->count, olh->objsize, compare_values);
2044 for (i = 0; i < olh->count; i++) {
2045 table_show_value(buf, sizeof(buf), (ipfw_table_value *)v,
2046 vmask, 0);
2047 printf("[%u] refs=%lu %s\n", v->spare1, (u_long)v->refcnt, buf);
2048 v = (struct _table_value *)((caddr_t)v + olh->objsize);
2049 }
2050
2051 free(olh);
2052 }
2053
2054 int
table_check_name(const char * tablename)2055 table_check_name(const char *tablename)
2056 {
2057
2058 if (ipfw_check_object_name(tablename) != 0)
2059 return (EINVAL);
2060 /* Restrict some 'special' names */
2061 if (strcmp(tablename, "all") == 0)
2062 return (EINVAL);
2063 return (0);
2064 }
2065
2066