📄 filter.c
字号:
/* Route filtering function. * Copyright (C) 1998, 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include <zebra.h>#include "prefix.h"#include "filter.h"#include "memory.h"#include "command.h"#include "sockunion.h"#include "buffer.h"struct filter_cisco{ /* Cisco access-list */ int extended; struct in_addr addr; struct in_addr addr_mask; struct in_addr mask; struct in_addr mask_mask;};struct filter_zebra{ /* If this filter is "exact" match then this flag is set. */ int exact; /* Prefix information. */ struct prefix prefix;};/* Filter element of access list */struct filter{ /* For doubly linked list. */ struct filter *next; struct filter *prev; /* Filter type information. */ enum filter_type type; /* Cisco access-list */ int cisco; union { struct filter_cisco cfilter; struct filter_zebra zfilter; } u;};/* List of access_list. */struct access_list_list{ struct access_list *head; struct access_list *tail;};/* Master structure of access_list. */struct access_master{ /* List of access_list which name is number. */ struct access_list_list num; /* List of access_list which name is string. */ struct access_list_list str; /* Hook function which is executed when new access_list is added. */ void (*add_hook) (); /* Hook function which is executed when access_list is deleted. */ void (*delete_hook) ();};/* Static structure for IPv4 access_list's master. */static struct access_master access_master_ipv4 = { {NULL, NULL}, {NULL, NULL}, NULL, NULL,};#ifdef HAVE_IPV6/* Static structure for IPv6 access_list's master. */static struct access_master access_master_ipv6 = { {NULL, NULL}, {NULL, NULL}, NULL, NULL,};#endif /* HAVE_IPV6 */struct access_master *access_master_get (afi_t afi){ if (afi == AFI_IP) return &access_master_ipv4;#ifdef HAVE_IPV6 else if (afi == AFI_IP6) return &access_master_ipv6;#endif /* HAVE_IPV6 */ return NULL;}/* Allocate new filter structure. */struct filter *filter_new (){ return (struct filter *) XCALLOC (MTYPE_ACCESS_FILTER, sizeof (struct filter));}voidfilter_free (struct filter *filter){ XFREE (MTYPE_ACCESS_FILTER, filter);}/* Return string of filter_type. */static char *filter_type_str (struct filter *filter){ switch (filter->type) { case FILTER_PERMIT: return "permit"; break; case FILTER_DENY: return "deny"; break; case FILTER_DYNAMIC: return "dynamic"; break; default: return ""; break; }}/* If filter match to the prefix then return 1. */static intfilter_match_cisco (struct filter *mfilter, struct prefix *p){ struct filter_cisco *filter; struct in_addr mask; u_int32_t check_addr; u_int32_t check_mask; filter = &mfilter->u.cfilter; check_addr = p->u.prefix4.s_addr & ~filter->addr_mask.s_addr; if (filter->extended) { masklen2ip (p->prefixlen, &mask); check_mask = mask.s_addr & ~filter->mask_mask.s_addr; if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0 && memcmp (&check_mask, &filter->mask.s_addr, 4) == 0) return 1; } else if (memcmp (&check_addr, &filter->addr.s_addr, 4) == 0) return 1; return 0;}/* If filter match to the prefix then return 1. */static intfilter_match_zebra (struct filter *mfilter, struct prefix *p){ struct filter_zebra *filter; filter = &mfilter->u.zfilter; if (filter->prefix.family == p->family) { if (filter->exact) { if (filter->prefix.prefixlen == p->prefixlen) return prefix_match (&filter->prefix, p); else return 0; } else return prefix_match (&filter->prefix, p); } else return 0;}/* Allocate new access list structure. */struct access_list *access_list_new (){ return (struct access_list *) XCALLOC (MTYPE_ACCESS_LIST, sizeof (struct access_list));}/* Free allocated access_list. */voidaccess_list_free (struct access_list *access){ XFREE (MTYPE_ACCESS_LIST, access);}/* Delete access_list from access_master and free it. */voidaccess_list_delete (struct access_list *access){ struct filter *filter; struct filter *next; struct access_list_list *list; struct access_master *master; for (filter = access->head; filter; filter = next) { next = filter->next; filter_free (filter); } master = access->master; if (access->type == ACCESS_TYPE_NUMBER) list = &master->num; else list = &master->str; if (access->next) access->next->prev = access->prev; else list->tail = access->prev; if (access->prev) access->prev->next = access->next; else list->head = access->next; if (access->name) XFREE (MTYPE_ACCESS_LIST_STR, access->name); if (access->remark) XFREE (MTYPE_TMP, access->remark); access_list_free (access);}/* Insert new access list to list of access_list. Each acceess_list is sorted by the name. */struct access_list *access_list_insert (afi_t afi, char *name){ int i; long number; struct access_list *access; struct access_list *point; struct access_list_list *alist; struct access_master *master; master = access_master_get (afi); if (master == NULL) return NULL; /* Allocate new access_list and copy given name. */ access = access_list_new (); access->name = XSTRDUP (MTYPE_ACCESS_LIST_STR, name); access->master = master; /* If name is made by all digit character. We treat it as number. */ for (number = 0, i = 0; i < strlen (name); i++) { if (isdigit ((int) name[i])) number = (number * 10) + (name[i] - '0'); else break; } /* In case of name is all digit character */ if (i == strlen (name)) { access->type = ACCESS_TYPE_NUMBER; /* Set access_list to number list. */ alist = &master->num; for (point = alist->head; point; point = point->next) if (atol (point->name) >= number) break; } else { access->type = ACCESS_TYPE_STRING; /* Set access_list to string list. */ alist = &master->str; /* Set point to insertion point. */ for (point = alist->head; point; point = point->next) if (strcmp (point->name, name) >= 0) break; } /* In case of this is the first element of master. */ if (alist->head == NULL) { alist->head = alist->tail = access; return access; } /* In case of insertion is made at the tail of access_list. */ if (point == NULL) { access->prev = alist->tail; alist->tail->next = access; alist->tail = access; return access; } /* In case of insertion is made at the head of access_list. */ if (point == alist->head) { access->next = alist->head; alist->head->prev = access; alist->head = access; return access; } /* Insertion is made at middle of the access_list. */ access->next = point; access->prev = point->prev; if (point->prev) point->prev->next = access; point->prev = access; return access;}/* Lookup access_list from list of access_list by name. */struct access_list *access_list_lookup (afi_t afi, char *name){ struct access_list *access; struct access_master *master; if (name == NULL) return NULL; master = access_master_get (afi); if (master == NULL) return NULL; for (access = master->num.head; access; access = access->next) if (strcmp (access->name, name) == 0) return access; for (access = master->str.head; access; access = access->next) if (strcmp (access->name, name) == 0) return access; return NULL;}/* Get access list from list of access_list. If there isn't matched access_list create new one and return it. */struct access_list *access_list_get (afi_t afi, char *name){ struct access_list *access; access = access_list_lookup (afi, name); if (access == NULL) access = access_list_insert (afi, name); return access;}/* Apply access list to object (which should be struct prefix *). */enum filter_typeaccess_list_apply (struct access_list *access, void *object){ struct filter *filter; struct prefix *p; p = (struct prefix *) object; if (access == NULL) return FILTER_DENY; for (filter = access->head; filter; filter = filter->next) { if (filter->cisco) { if (filter_match_cisco (filter, p)) return filter->type; } else { if (filter_match_zebra (filter, p)) return filter->type; } } return FILTER_DENY;}/* Add hook function. */voidaccess_list_add_hook (void (*func) (struct access_list *access)){ access_master_ipv4.add_hook = func;#ifdef HAVE_IPV6 access_master_ipv6.add_hook = func;#endif /* HAVE_IPV6 */}/* Delete hook function. */voidaccess_list_delete_hook (void (*func) (struct access_list *access)){ access_master_ipv4.delete_hook = func;#ifdef HAVE_IPV6 access_master_ipv6.delete_hook = func;#endif /* HAVE_IPV6 */}/* Add new filter to the end of specified access_list. */voidaccess_list_filter_add (struct access_list *access, struct filter *filter){ filter->next = NULL; filter->prev = access->tail; if (access->tail) access->tail->next = filter; else access->head = filter; access->tail = filter; /* Run hook function. */ if (access->master->add_hook) (*access->master->add_hook) (access);}/* If access_list has no filter then return 1. */static intaccess_list_empty (struct access_list *access){ if (access->head == NULL && access->tail == NULL) return 1; else return 0;}/* Delete filter from specified access_list. If there is hook function execute it. */voidaccess_list_filter_delete (struct access_list *access, struct filter *filter){ struct access_master *master; master = access->master; if (filter->next) filter->next->prev = filter->prev; else access->tail = filter->prev; if (filter->prev) filter->prev->next = filter->next; else access->head = filter->next; filter_free (filter); /* If access_list becomes empty delete it from access_master. */ if (access_list_empty (access)) access_list_delete (access); /* Run hook function. */ if (master->delete_hook) (*master->delete_hook) (access);}/* deny Specify packets to reject permit Specify packets to forward dynamic ?*//* Hostname or A.B.C.D Address to match any Any source host host A single host address*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -