]> git.proxmox.com Git - mirror_frr.git/blob - lib/filter.c
lib: Add int encoder/decoder
[mirror_frr.git] / lib / filter.c
1 /* Route filtering function.
2 * Copyright (C) 1998, 1999 Kunihiro Ishiguro
3 *
4 * This file is part of GNU Zebra.
5 *
6 * GNU Zebra is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2, or (at your
9 * option) any later version.
10 *
11 * GNU Zebra is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include <zebra.h>
22
23 #include "prefix.h"
24 #include "filter.h"
25 #include "memory.h"
26 #include "command.h"
27 #include "sockunion.h"
28 #include "buffer.h"
29 #include "log.h"
30 #include "routemap.h"
31 #include "libfrr.h"
32 #include "northbound_cli.h"
33
34 DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST, "Access List");
35 DEFINE_MTYPE_STATIC(LIB, ACCESS_LIST_STR, "Access List Str");
36 DEFINE_MTYPE_STATIC(LIB, ACCESS_FILTER, "Access Filter");
37
38 /* Static structure for mac access_list's master. */
39 static struct access_master access_master_mac = {
40 {NULL, NULL},
41 NULL,
42 NULL,
43 };
44
45 /* Static structure for IPv4 access_list's master. */
46 static struct access_master access_master_ipv4 = {
47 {NULL, NULL},
48 NULL,
49 NULL,
50 };
51
52 /* Static structure for IPv6 access_list's master. */
53 static struct access_master access_master_ipv6 = {
54 {NULL, NULL},
55 NULL,
56 NULL,
57 };
58
59 static struct access_master *access_master_get(afi_t afi)
60 {
61 if (afi == AFI_IP)
62 return &access_master_ipv4;
63 else if (afi == AFI_IP6)
64 return &access_master_ipv6;
65 else if (afi == AFI_L2VPN)
66 return &access_master_mac;
67 return NULL;
68 }
69
70 /* Allocate new filter structure. */
71 struct filter *filter_new(void)
72 {
73 return XCALLOC(MTYPE_ACCESS_FILTER, sizeof(struct filter));
74 }
75
76 static void filter_free(struct filter *filter)
77 {
78 XFREE(MTYPE_ACCESS_FILTER, filter);
79 }
80
81 /* Return string of filter_type. */
82 static const char *filter_type_str(struct filter *filter)
83 {
84 switch (filter->type) {
85 case FILTER_PERMIT:
86 return "permit";
87 case FILTER_DENY:
88 return "deny";
89 case FILTER_DYNAMIC:
90 return "dynamic";
91 default:
92 return "";
93 }
94 }
95
96 /* If filter match to the prefix then return 1. */
97 static int filter_match_cisco(struct filter *mfilter, const struct prefix *p)
98 {
99 struct filter_cisco *filter;
100 struct in_addr mask;
101 uint32_t check_addr;
102 uint32_t check_mask;
103
104 filter = &mfilter->u.cfilter;
105 check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr;
106
107 if (filter->extended) {
108 masklen2ip(p->prefixlen, &mask);
109 check_mask = mask.s_addr & ~filter->mask_mask.s_addr;
110
111 if (memcmp(&check_addr, &filter->addr.s_addr, IPV4_MAX_BYTELEN)
112 == 0
113 && memcmp(&check_mask, &filter->mask.s_addr,
114 IPV4_MAX_BYTELEN)
115 == 0)
116 return 1;
117 } else if (memcmp(&check_addr, &filter->addr.s_addr, IPV4_MAX_BYTELEN)
118 == 0)
119 return 1;
120
121 return 0;
122 }
123
124 /* If filter match to the prefix then return 1. */
125 static int filter_match_zebra(struct filter *mfilter, const struct prefix *p)
126 {
127 struct filter_zebra *filter = NULL;
128
129 filter = &mfilter->u.zfilter;
130
131 if (filter->prefix.family == p->family) {
132 if (filter->exact) {
133 if (filter->prefix.prefixlen == p->prefixlen)
134 return prefix_match(&filter->prefix, p);
135 else
136 return 0;
137 } else
138 return prefix_match(&filter->prefix, p);
139 } else
140 return 0;
141 }
142
143 /* Allocate new access list structure. */
144 static struct access_list *access_list_new(void)
145 {
146 return XCALLOC(MTYPE_ACCESS_LIST, sizeof(struct access_list));
147 }
148
149 /* Free allocated access_list. */
150 static void access_list_free(struct access_list *access)
151 {
152 XFREE(MTYPE_ACCESS_LIST, access);
153 }
154
155 /* Delete access_list from access_master and free it. */
156 void access_list_delete(struct access_list *access)
157 {
158 struct filter *filter;
159 struct filter *next;
160 struct access_list_list *list;
161 struct access_master *master;
162
163 for (filter = access->head; filter; filter = next) {
164 next = filter->next;
165 filter_free(filter);
166 }
167
168 master = access->master;
169
170 list = &master->str;
171
172 if (access->next)
173 access->next->prev = access->prev;
174 else
175 list->tail = access->prev;
176
177 if (access->prev)
178 access->prev->next = access->next;
179 else
180 list->head = access->next;
181
182 route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
183
184 if (master->delete_hook)
185 master->delete_hook(access);
186
187 XFREE(MTYPE_ACCESS_LIST_STR, access->name);
188
189 XFREE(MTYPE_TMP, access->remark);
190
191 access_list_free(access);
192 }
193
194 /* Insert new access list to list of access_list. Each acceess_list
195 is sorted by the name. */
196 static struct access_list *access_list_insert(afi_t afi, const char *name)
197 {
198 struct access_list *access;
199 struct access_list *point;
200 struct access_list_list *alist;
201 struct access_master *master;
202
203 master = access_master_get(afi);
204 if (master == NULL)
205 return NULL;
206
207 /* Allocate new access_list and copy given name. */
208 access = access_list_new();
209 access->name = XSTRDUP(MTYPE_ACCESS_LIST_STR, name);
210 access->master = master;
211
212 /* Set access_list to string list. */
213 alist = &master->str;
214
215 /* Set point to insertion point. */
216 for (point = alist->head; point; point = point->next)
217 if (strcmp(point->name, name) >= 0)
218 break;
219
220 /* In case of this is the first element of master. */
221 if (alist->head == NULL) {
222 alist->head = alist->tail = access;
223 return access;
224 }
225
226 /* In case of insertion is made at the tail of access_list. */
227 if (point == NULL) {
228 access->prev = alist->tail;
229 alist->tail->next = access;
230 alist->tail = access;
231 return access;
232 }
233
234 /* In case of insertion is made at the head of access_list. */
235 if (point == alist->head) {
236 access->next = alist->head;
237 alist->head->prev = access;
238 alist->head = access;
239 return access;
240 }
241
242 /* Insertion is made at middle of the access_list. */
243 access->next = point;
244 access->prev = point->prev;
245
246 if (point->prev)
247 point->prev->next = access;
248 point->prev = access;
249
250 return access;
251 }
252
253 /* Lookup access_list from list of access_list by name. */
254 struct access_list *access_list_lookup(afi_t afi, const char *name)
255 {
256 struct access_list *access;
257 struct access_master *master;
258
259 if (name == NULL)
260 return NULL;
261
262 master = access_master_get(afi);
263 if (master == NULL)
264 return NULL;
265
266 for (access = master->str.head; access; access = access->next)
267 if (strcmp(access->name, name) == 0)
268 return access;
269
270 return NULL;
271 }
272
273 /* Get access list from list of access_list. If there isn't matched
274 access_list create new one and return it. */
275 struct access_list *access_list_get(afi_t afi, const char *name)
276 {
277 struct access_list *access;
278
279 access = access_list_lookup(afi, name);
280 if (access == NULL)
281 access = access_list_insert(afi, name);
282 return access;
283 }
284
285 /* Apply access list to object (which should be struct prefix *). */
286 enum filter_type access_list_apply(struct access_list *access,
287 const void *object)
288 {
289 struct filter *filter;
290 const struct prefix *p = (const struct prefix *)object;
291
292 if (access == NULL)
293 return FILTER_DENY;
294
295 for (filter = access->head; filter; filter = filter->next) {
296 if (filter->cisco) {
297 if (filter_match_cisco(filter, p))
298 return filter->type;
299 } else {
300 if (filter_match_zebra(filter, p))
301 return filter->type;
302 }
303 }
304
305 return FILTER_DENY;
306 }
307
308 /* Add hook function. */
309 void access_list_add_hook(void (*func)(struct access_list *access))
310 {
311 access_master_ipv4.add_hook = func;
312 access_master_ipv6.add_hook = func;
313 access_master_mac.add_hook = func;
314 }
315
316 /* Delete hook function. */
317 void access_list_delete_hook(void (*func)(struct access_list *access))
318 {
319 access_master_ipv4.delete_hook = func;
320 access_master_ipv6.delete_hook = func;
321 access_master_mac.delete_hook = func;
322 }
323
324 /* Calculate new sequential number. */
325 int64_t filter_new_seq_get(struct access_list *access)
326 {
327 int64_t maxseq;
328 int64_t newseq;
329 struct filter *filter;
330
331 maxseq = 0;
332
333 for (filter = access->head; filter; filter = filter->next) {
334 if (maxseq < filter->seq)
335 maxseq = filter->seq;
336 }
337
338 newseq = ((maxseq / 5) * 5) + 5;
339
340 return (newseq > UINT_MAX) ? UINT_MAX : newseq;
341 }
342
343 /* Return access list entry which has same seq number. */
344 static struct filter *filter_seq_check(struct access_list *access,
345 int64_t seq)
346 {
347 struct filter *filter;
348
349 for (filter = access->head; filter; filter = filter->next)
350 if (filter->seq == seq)
351 return filter;
352 return NULL;
353 }
354
355 /* Delete filter from specified access_list. If there is hook
356 function execute it. */
357 void access_list_filter_delete(struct access_list *access,
358 struct filter *filter)
359 {
360 struct access_master *master;
361
362 master = access->master;
363
364 if (filter->next)
365 filter->next->prev = filter->prev;
366 else
367 access->tail = filter->prev;
368
369 if (filter->prev)
370 filter->prev->next = filter->next;
371 else
372 access->head = filter->next;
373
374 filter_free(filter);
375
376 route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_DELETED);
377 /* Run hook function. */
378 if (master->delete_hook)
379 (*master->delete_hook)(access);
380 }
381
382 /* Add new filter to the end of specified access_list. */
383 void access_list_filter_add(struct access_list *access,
384 struct filter *filter)
385 {
386 struct filter *replace;
387 struct filter *point;
388
389 /* Automatic asignment of seq no. */
390 if (filter->seq == -1)
391 filter->seq = filter_new_seq_get(access);
392
393 if (access->tail && filter->seq > access->tail->seq)
394 point = NULL;
395 else {
396 /* Is there any same seq access list filter? */
397 replace = filter_seq_check(access, filter->seq);
398 if (replace)
399 access_list_filter_delete(access, replace);
400
401 /* Check insert point. */
402 for (point = access->head; point; point = point->next)
403 if (point->seq >= filter->seq)
404 break;
405 }
406
407 /* In case of this is the first element of the list. */
408 filter->next = point;
409
410 if (point) {
411 if (point->prev)
412 point->prev->next = filter;
413 else
414 access->head = filter;
415
416 filter->prev = point->prev;
417 point->prev = filter;
418 } else {
419 if (access->tail)
420 access->tail->next = filter;
421 else
422 access->head = filter;
423
424 filter->prev = access->tail;
425 access->tail = filter;
426 }
427
428 /* Run hook function. */
429 if (access->master->add_hook)
430 (*access->master->add_hook)(access);
431 route_map_notify_dependencies(access->name, RMAP_EVENT_FILTER_ADDED);
432 }
433
434 /*
435 deny Specify packets to reject
436 permit Specify packets to forward
437 dynamic ?
438 */
439
440 /*
441 Hostname or A.B.C.D Address to match
442 any Any source host
443 host A single host address
444 */
445
446 static void config_write_access_zebra(struct vty *, struct filter *);
447 static void config_write_access_cisco(struct vty *, struct filter *);
448
449 /* show access-list command. */
450 static int filter_show(struct vty *vty, const char *name, afi_t afi)
451 {
452 struct access_list *access;
453 struct access_master *master;
454 struct filter *mfilter;
455 struct filter_cisco *filter;
456 int write = 0;
457
458 master = access_master_get(afi);
459 if (master == NULL)
460 return 0;
461
462 /* Print the name of the protocol */
463 vty_out(vty, "%s:\n", frr_protoname);
464
465 for (access = master->str.head; access; access = access->next) {
466 if (name && strcmp(access->name, name) != 0)
467 continue;
468
469 write = 1;
470
471 for (mfilter = access->head; mfilter; mfilter = mfilter->next) {
472 filter = &mfilter->u.cfilter;
473
474 if (write) {
475 vty_out(vty, "%s %s access list %s\n",
476 mfilter->cisco ? (filter->extended
477 ? "Extended"
478 : "Standard")
479 : "Zebra",
480 (afi == AFI_IP)
481 ? ("IP")
482 : ((afi == AFI_IP6) ? ("IPv6 ")
483 : ("MAC ")),
484 access->name);
485 write = 0;
486 }
487
488 vty_out(vty, " seq %" PRId64, mfilter->seq);
489 vty_out(vty, " %s%s", filter_type_str(mfilter),
490 mfilter->type == FILTER_DENY ? " " : "");
491
492 if (!mfilter->cisco)
493 config_write_access_zebra(vty, mfilter);
494 else if (filter->extended)
495 config_write_access_cisco(vty, mfilter);
496 else {
497 if (filter->addr_mask.s_addr == 0xffffffff)
498 vty_out(vty, " any\n");
499 else {
500 vty_out(vty, " %pI4", &filter->addr);
501 if (filter->addr_mask.s_addr
502 != INADDR_ANY)
503 vty_out(vty,
504 ", wildcard bits %pI4",
505 &filter->addr_mask);
506 vty_out(vty, "\n");
507 }
508 }
509 }
510 }
511 return CMD_SUCCESS;
512 }
513
514 /* show MAC access list - this only has MAC filters for now*/
515 DEFUN (show_mac_access_list,
516 show_mac_access_list_cmd,
517 "show mac access-list",
518 SHOW_STR
519 "mac access lists\n"
520 "List mac access lists\n")
521 {
522 return filter_show(vty, NULL, AFI_L2VPN);
523 }
524
525 DEFUN (show_mac_access_list_name,
526 show_mac_access_list_name_cmd,
527 "show mac access-list WORD",
528 SHOW_STR
529 "mac access lists\n"
530 "List mac access lists\n"
531 "mac address\n")
532 {
533 return filter_show(vty, argv[3]->arg, AFI_L2VPN);
534 }
535
536 DEFUN (show_ip_access_list,
537 show_ip_access_list_cmd,
538 "show ip access-list",
539 SHOW_STR
540 IP_STR
541 "List IP access lists\n")
542 {
543 return filter_show(vty, NULL, AFI_IP);
544 }
545
546 DEFUN (show_ip_access_list_name,
547 show_ip_access_list_name_cmd,
548 "show ip access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD>",
549 SHOW_STR
550 IP_STR
551 "List IP access lists\n"
552 "IP standard access list\n"
553 "IP extended access list\n"
554 "IP standard access list (expanded range)\n"
555 "IP extended access list (expanded range)\n"
556 "IP zebra access-list\n")
557 {
558 int idx_acl = 3;
559 return filter_show(vty, argv[idx_acl]->arg, AFI_IP);
560 }
561
562 DEFUN (show_ipv6_access_list,
563 show_ipv6_access_list_cmd,
564 "show ipv6 access-list",
565 SHOW_STR
566 IPV6_STR
567 "List IPv6 access lists\n")
568 {
569 return filter_show(vty, NULL, AFI_IP6);
570 }
571
572 DEFUN (show_ipv6_access_list_name,
573 show_ipv6_access_list_name_cmd,
574 "show ipv6 access-list WORD",
575 SHOW_STR
576 IPV6_STR
577 "List IPv6 access lists\n"
578 "IPv6 zebra access-list\n")
579 {
580 int idx_word = 3;
581 return filter_show(vty, argv[idx_word]->arg, AFI_IP6);
582 }
583
584 static void config_write_access_cisco(struct vty *vty, struct filter *mfilter)
585 {
586 struct filter_cisco *filter;
587
588 filter = &mfilter->u.cfilter;
589
590 if (filter->extended) {
591 vty_out(vty, " ip");
592 if (filter->addr_mask.s_addr == 0xffffffff)
593 vty_out(vty, " any");
594 else if (filter->addr_mask.s_addr == INADDR_ANY)
595 vty_out(vty, " host %pI4", &filter->addr);
596 else {
597 vty_out(vty, " %pI4", &filter->addr);
598 vty_out(vty, " %pI4", &filter->addr_mask);
599 }
600
601 if (filter->mask_mask.s_addr == 0xffffffff)
602 vty_out(vty, " any");
603 else if (filter->mask_mask.s_addr == INADDR_ANY)
604 vty_out(vty, " host %pI4", &filter->mask);
605 else {
606 vty_out(vty, " %pI4", &filter->mask);
607 vty_out(vty, " %pI4", &filter->mask_mask);
608 }
609 vty_out(vty, "\n");
610 } else {
611 if (filter->addr_mask.s_addr == 0xffffffff)
612 vty_out(vty, " any\n");
613 else {
614 vty_out(vty, " %pI4", &filter->addr);
615 if (filter->addr_mask.s_addr != INADDR_ANY)
616 vty_out(vty, " %pI4", &filter->addr_mask);
617 vty_out(vty, "\n");
618 }
619 }
620 }
621
622 static void config_write_access_zebra(struct vty *vty, struct filter *mfilter)
623 {
624 struct filter_zebra *filter;
625 struct prefix *p;
626 char buf[BUFSIZ];
627
628 filter = &mfilter->u.zfilter;
629 p = &filter->prefix;
630
631 if (p->prefixlen == 0 && !filter->exact)
632 vty_out(vty, " any");
633 else if (p->family == AF_INET6 || p->family == AF_INET)
634 vty_out(vty, " %s/%d%s",
635 inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
636 p->prefixlen, filter->exact ? " exact-match" : "");
637 else if (p->family == AF_ETHERNET) {
638 if (p->prefixlen == 0)
639 vty_out(vty, " any");
640 else
641 vty_out(vty, " %s", prefix_mac2str(&(p->u.prefix_eth),
642 buf, sizeof(buf)));
643 }
644
645 vty_out(vty, "\n");
646 }
647
648 static struct cmd_node access_mac_node = {
649 .name = "MAC access list",
650 .node = ACCESS_MAC_NODE,
651 .prompt = "",
652 };
653
654 static void access_list_reset_mac(void)
655 {
656 struct access_list *access;
657 struct access_list *next;
658 struct access_master *master;
659
660 master = access_master_get(AFI_L2VPN);
661 if (master == NULL)
662 return;
663
664 for (access = master->str.head; access; access = next) {
665 next = access->next;
666 access_list_delete(access);
667 }
668
669 assert(master->str.head == NULL);
670 assert(master->str.tail == NULL);
671 }
672
673 /* Install vty related command. */
674 static void access_list_init_mac(void)
675 {
676 install_node(&access_mac_node);
677
678 install_element(ENABLE_NODE, &show_mac_access_list_cmd);
679 install_element(ENABLE_NODE, &show_mac_access_list_name_cmd);
680 }
681
682 /* Access-list node. */
683 static int config_write_access(struct vty *vty);
684 static struct cmd_node access_node = {
685 .name = "ipv4 access list",
686 .node = ACCESS_NODE,
687 .prompt = "",
688 .config_write = config_write_access,
689 };
690
691 static int config_write_access(struct vty *vty)
692 {
693 struct lyd_node *dnode;
694 int written = 0;
695
696 dnode = yang_dnode_get(running_config->dnode, "/frr-filter:lib");
697 if (dnode) {
698 nb_cli_show_dnode_cmds(vty, dnode, false);
699 written = 1;
700 }
701
702 return written;
703 }
704
705 static void access_list_reset_ipv4(void)
706 {
707 struct access_list *access;
708 struct access_list *next;
709 struct access_master *master;
710
711 master = access_master_get(AFI_IP);
712 if (master == NULL)
713 return;
714
715 for (access = master->str.head; access; access = next) {
716 next = access->next;
717 access_list_delete(access);
718 }
719
720 assert(master->str.head == NULL);
721 assert(master->str.tail == NULL);
722 }
723
724 /* Install vty related command. */
725 static void access_list_init_ipv4(void)
726 {
727 install_node(&access_node);
728
729 install_element(ENABLE_NODE, &show_ip_access_list_cmd);
730 install_element(ENABLE_NODE, &show_ip_access_list_name_cmd);
731 }
732
733 static struct cmd_node access_ipv6_node = {
734 .name = "ipv6 access list",
735 .node = ACCESS_IPV6_NODE,
736 .prompt = "",
737 };
738
739 static void access_list_reset_ipv6(void)
740 {
741 struct access_list *access;
742 struct access_list *next;
743 struct access_master *master;
744
745 master = access_master_get(AFI_IP6);
746 if (master == NULL)
747 return;
748
749 for (access = master->str.head; access; access = next) {
750 next = access->next;
751 access_list_delete(access);
752 }
753
754 assert(master->str.head == NULL);
755 assert(master->str.tail == NULL);
756 }
757
758 static void access_list_init_ipv6(void)
759 {
760 install_node(&access_ipv6_node);
761
762 install_element(ENABLE_NODE, &show_ipv6_access_list_cmd);
763 install_element(ENABLE_NODE, &show_ipv6_access_list_name_cmd);
764 }
765
766 void access_list_init(void)
767 {
768 access_list_init_ipv4();
769 access_list_init_ipv6();
770 access_list_init_mac();
771
772 filter_cli_init();
773 }
774
775 void access_list_reset(void)
776 {
777 access_list_reset_ipv4();
778 access_list_reset_ipv6();
779 access_list_reset_mac();
780 }