Changeset View
Changeset View
Standalone View
Standalone View
head/sbin/pfctl/pfctl_parser.c
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/in_systm.h> | #include <netinet/in_systm.h> | ||||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||||
#include <netinet/ip_icmp.h> | #include <netinet/ip_icmp.h> | ||||
#include <netinet/icmp6.h> | #include <netinet/icmp6.h> | ||||
#include <net/pfvar.h> | #include <net/pfvar.h> | ||||
#include <arpa/inet.h> | #include <arpa/inet.h> | ||||
#include <search.h> | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <netdb.h> | #include <netdb.h> | ||||
#include <stdarg.h> | #include <stdarg.h> | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <err.h> | #include <err.h> | ||||
#include <ifaddrs.h> | #include <ifaddrs.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include "pfctl_parser.h" | #include "pfctl_parser.h" | ||||
#include "pfctl.h" | #include "pfctl.h" | ||||
void print_op (u_int8_t, const char *, const char *); | void print_op (u_int8_t, const char *, const char *); | ||||
void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int); | void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int); | ||||
void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); | void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); | ||||
void print_flags (u_int8_t); | void print_flags (u_int8_t); | ||||
void print_fromto(struct pf_rule_addr *, pf_osfp_t, | void print_fromto(struct pf_rule_addr *, pf_osfp_t, | ||||
struct pf_rule_addr *, u_int8_t, u_int8_t, int, int); | struct pf_rule_addr *, u_int8_t, u_int8_t, int, int); | ||||
int ifa_skip_if(const char *filter, struct node_host *p); | int ifa_skip_if(const char *filter, struct node_host *p); | ||||
struct node_host *ifa_grouplookup(const char *, int); | |||||
struct node_host *host_if(const char *, int); | struct node_host *host_if(const char *, int); | ||||
struct node_host *host_v4(const char *, int); | struct node_host *host_v4(const char *, int); | ||||
struct node_host *host_v6(const char *, int); | struct node_host *host_v6(const char *, int); | ||||
struct node_host *host_dns(const char *, int, int); | struct node_host *host_dns(const char *, int, int); | ||||
const char * const tcpflags = "FSRPAUEW"; | const char * const tcpflags = "FSRPAUEW"; | ||||
static const struct icmptypeent icmp_type[] = { | static const struct icmptypeent icmp_type[] = { | ||||
▲ Show 20 Lines • Show All 120 Lines • ▼ Show 20 Lines | const struct pf_timeout pf_timeouts[] = { | ||||
{ "frag", PFTM_FRAG }, | { "frag", PFTM_FRAG }, | ||||
{ "interval", PFTM_INTERVAL }, | { "interval", PFTM_INTERVAL }, | ||||
{ "adaptive.start", PFTM_ADAPTIVE_START }, | { "adaptive.start", PFTM_ADAPTIVE_START }, | ||||
{ "adaptive.end", PFTM_ADAPTIVE_END }, | { "adaptive.end", PFTM_ADAPTIVE_END }, | ||||
{ "src.track", PFTM_SRC_NODE }, | { "src.track", PFTM_SRC_NODE }, | ||||
{ NULL, 0 } | { NULL, 0 } | ||||
}; | }; | ||||
static struct hsearch_data isgroup_map; | |||||
static __attribute__((constructor)) void | |||||
pfctl_parser_init(void) | |||||
{ | |||||
/* | |||||
* As hdestroy() will never be called on these tables, it will be | |||||
* safe to use references into the stored data as keys. | |||||
*/ | |||||
if (hcreate_r(0, &isgroup_map) == 0) | |||||
err(1, "Failed to create interface group query response map"); | |||||
} | |||||
const struct icmptypeent * | const struct icmptypeent * | ||||
geticmptypebynumber(u_int8_t type, sa_family_t af) | geticmptypebynumber(u_int8_t type, sa_family_t af) | ||||
{ | { | ||||
unsigned int i; | unsigned int i; | ||||
if (af != AF_INET6) { | if (af != AF_INET6) { | ||||
for (i=0; i < nitems(icmp_type); i++) { | for (i=0; i < nitems(icmp_type); i++) { | ||||
if (type == icmp_type[i].type) | if (type == icmp_type[i].type) | ||||
▲ Show 20 Lines • Show All 928 Lines • ▼ Show 20 Lines | check_netmask(struct node_host *h, sa_family_t af) | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
/* interface lookup routines */ | /* interface lookup routines */ | ||||
static struct node_host *iftab; | static struct node_host *iftab; | ||||
/* | |||||
* Retrieve the list of groups this interface is a member of and make sure | |||||
* each group is in the group map. | |||||
*/ | |||||
static void | |||||
ifa_add_groups_to_map(char *ifa_name) | |||||
{ | |||||
int s, len; | |||||
struct ifgroupreq ifgr; | |||||
struct ifg_req *ifg; | |||||
s = get_query_socket(); | |||||
/* Get size of group list for this interface */ | |||||
memset(&ifgr, 0, sizeof(ifgr)); | |||||
strlcpy(ifgr.ifgr_name, ifa_name, IFNAMSIZ); | |||||
if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) | |||||
err(1, "SIOCGIFGROUP"); | |||||
/* Retrieve group list for this interface */ | |||||
len = ifgr.ifgr_len; | |||||
ifgr.ifgr_groups = | |||||
(struct ifg_req *)calloc(len / sizeof(struct ifg_req), | |||||
sizeof(struct ifg_req)); | |||||
if (ifgr.ifgr_groups == NULL) | |||||
err(1, "calloc"); | |||||
if (ioctl(s, SIOCGIFGROUP, (caddr_t)&ifgr) == -1) | |||||
err(1, "SIOCGIFGROUP"); | |||||
ifg = ifgr.ifgr_groups; | |||||
for (; ifg && len >= sizeof(struct ifg_req); ifg++) { | |||||
len -= sizeof(struct ifg_req); | |||||
if (strcmp(ifg->ifgrq_group, "all")) { | |||||
ENTRY item; | |||||
ENTRY *ret_item; | |||||
int *answer; | |||||
item.key = ifg->ifgrq_group; | |||||
if (hsearch_r(item, FIND, &ret_item, &isgroup_map) == 0) { | |||||
struct ifgroupreq ifgr2; | |||||
/* Don't know the answer yet */ | |||||
if ((answer = malloc(sizeof(int))) == NULL) | |||||
err(1, "malloc"); | |||||
bzero(&ifgr2, sizeof(ifgr2)); | |||||
strlcpy(ifgr2.ifgr_name, ifg->ifgrq_group, | |||||
sizeof(ifgr2.ifgr_name)); | |||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr2) == 0) | |||||
*answer = ifgr2.ifgr_len; | |||||
else | |||||
*answer = 0; | |||||
item.key = strdup(ifg->ifgrq_group); | |||||
item.data = answer; | |||||
if (hsearch_r(item, ENTER, &ret_item, | |||||
&isgroup_map) == 0) | |||||
err(1, "interface group query response" | |||||
" map insert"); | |||||
} | |||||
} | |||||
} | |||||
free(ifgr.ifgr_groups); | |||||
} | |||||
void | void | ||||
ifa_load(void) | ifa_load(void) | ||||
{ | { | ||||
struct ifaddrs *ifap, *ifa; | struct ifaddrs *ifap, *ifa; | ||||
struct node_host *n = NULL, *h = NULL; | struct node_host *n = NULL, *h = NULL; | ||||
if (getifaddrs(&ifap) < 0) | if (getifaddrs(&ifap) < 0) | ||||
err(1, "getifaddrs"); | err(1, "getifaddrs"); | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | if (n->af == AF_INET) { | ||||
ifa->ifa_broadaddr)->sin6_addr.s6_addr, | ifa->ifa_broadaddr)->sin6_addr.s6_addr, | ||||
sizeof(struct in6_addr)); | sizeof(struct in6_addr)); | ||||
if (ifa->ifa_dstaddr != NULL) | if (ifa->ifa_dstaddr != NULL) | ||||
memcpy(&n->peer, &((struct sockaddr_in6 *) | memcpy(&n->peer, &((struct sockaddr_in6 *) | ||||
ifa->ifa_dstaddr)->sin6_addr.s6_addr, | ifa->ifa_dstaddr)->sin6_addr.s6_addr, | ||||
sizeof(struct in6_addr)); | sizeof(struct in6_addr)); | ||||
n->ifindex = ((struct sockaddr_in6 *) | n->ifindex = ((struct sockaddr_in6 *) | ||||
ifa->ifa_addr)->sin6_scope_id; | ifa->ifa_addr)->sin6_scope_id; | ||||
} else if (n->af == AF_LINK) { | |||||
ifa_add_groups_to_map(ifa->ifa_name); | |||||
} | } | ||||
if ((n->ifname = strdup(ifa->ifa_name)) == NULL) | if ((n->ifname = strdup(ifa->ifa_name)) == NULL) | ||||
err(1, "ifa_load: strdup"); | err(1, "ifa_load: strdup"); | ||||
n->next = NULL; | n->next = NULL; | ||||
n->tail = n; | n->tail = n; | ||||
if (h == NULL) | if (h == NULL) | ||||
h = n; | h = n; | ||||
else { | else { | ||||
h->tail->next = n; | h->tail->next = n; | ||||
h->tail = n; | h->tail = n; | ||||
} | } | ||||
} | } | ||||
iftab = h; | iftab = h; | ||||
freeifaddrs(ifap); | freeifaddrs(ifap); | ||||
} | } | ||||
int | static int | ||||
get_socket_domain(void) | get_socket_domain(void) | ||||
{ | { | ||||
int sdom; | int sdom; | ||||
sdom = AF_UNSPEC; | sdom = AF_UNSPEC; | ||||
#ifdef WITH_INET6 | #ifdef WITH_INET6 | ||||
if (sdom == AF_UNSPEC && feature_present("inet6")) | if (sdom == AF_UNSPEC && feature_present("inet6")) | ||||
sdom = AF_INET6; | sdom = AF_INET6; | ||||
#endif | #endif | ||||
#ifdef WITH_INET | #ifdef WITH_INET | ||||
if (sdom == AF_UNSPEC && feature_present("inet")) | if (sdom == AF_UNSPEC && feature_present("inet")) | ||||
sdom = AF_INET; | sdom = AF_INET; | ||||
#endif | #endif | ||||
if (sdom == AF_UNSPEC) | if (sdom == AF_UNSPEC) | ||||
sdom = AF_LINK; | sdom = AF_LINK; | ||||
return (sdom); | return (sdom); | ||||
} | } | ||||
int | |||||
get_query_socket(void) | |||||
{ | |||||
static int s = -1; | |||||
if (s == -1) { | |||||
if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1) | |||||
err(1, "socket"); | |||||
} | |||||
return (s); | |||||
} | |||||
/* | |||||
* Returns the response len if the name is a group, otherwise returns 0. | |||||
*/ | |||||
static int | |||||
is_a_group(char *name) | |||||
{ | |||||
ENTRY item; | |||||
ENTRY *ret_item; | |||||
item.key = name; | |||||
if (hsearch_r(item, FIND, &ret_item, &isgroup_map) == 0) | |||||
return (0); | |||||
return (*(int *)ret_item->data); | |||||
} | |||||
struct node_host * | struct node_host * | ||||
ifa_exists(const char *ifa_name) | ifa_exists(char *ifa_name) | ||||
{ | { | ||||
struct node_host *n; | struct node_host *n; | ||||
struct ifgroupreq ifgr; | |||||
int s; | int s; | ||||
if (iftab == NULL) | if (iftab == NULL) | ||||
ifa_load(); | ifa_load(); | ||||
/* check wether this is a group */ | /* check whether this is a group */ | ||||
if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1) | s = get_query_socket(); | ||||
err(1, "socket"); | if (is_a_group(ifa_name)) { | ||||
bzero(&ifgr, sizeof(ifgr)); | |||||
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); | |||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) { | |||||
/* fake a node_host */ | /* fake a node_host */ | ||||
if ((n = calloc(1, sizeof(*n))) == NULL) | if ((n = calloc(1, sizeof(*n))) == NULL) | ||||
err(1, "calloc"); | err(1, "calloc"); | ||||
if ((n->ifname = strdup(ifa_name)) == NULL) | if ((n->ifname = strdup(ifa_name)) == NULL) | ||||
err(1, "strdup"); | err(1, "strdup"); | ||||
close(s); | |||||
return (n); | return (n); | ||||
} | } | ||||
close(s); | |||||
for (n = iftab; n; n = n->next) { | for (n = iftab; n; n = n->next) { | ||||
if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) | if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) | ||||
return (n); | return (n); | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||
struct node_host * | struct node_host * | ||||
ifa_grouplookup(const char *ifa_name, int flags) | ifa_grouplookup(char *ifa_name, int flags) | ||||
{ | { | ||||
struct ifg_req *ifg; | struct ifg_req *ifg; | ||||
struct ifgroupreq ifgr; | struct ifgroupreq ifgr; | ||||
int s, len; | int s, len; | ||||
struct node_host *n, *h = NULL; | struct node_host *n, *h = NULL; | ||||
if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1) | s = get_query_socket(); | ||||
err(1, "socket"); | len = is_a_group(ifa_name); | ||||
if (len == 0) | |||||
return (NULL); | |||||
bzero(&ifgr, sizeof(ifgr)); | bzero(&ifgr, sizeof(ifgr)); | ||||
strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); | strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); | ||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) { | |||||
close(s); | |||||
return (NULL); | |||||
} | |||||
len = ifgr.ifgr_len; | |||||
if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) | if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) | ||||
err(1, "calloc"); | err(1, "calloc"); | ||||
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) | if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) | ||||
err(1, "SIOCGIFGMEMB"); | err(1, "SIOCGIFGMEMB"); | ||||
for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); | for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); | ||||
ifg++) { | ifg++) { | ||||
len -= sizeof(struct ifg_req); | len -= sizeof(struct ifg_req); | ||||
if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL) | if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL) | ||||
continue; | continue; | ||||
if (h == NULL) | if (h == NULL) | ||||
h = n; | h = n; | ||||
else { | else { | ||||
h->tail->next = n; | h->tail->next = n; | ||||
h->tail = n->tail; | h->tail = n->tail; | ||||
} | } | ||||
} | } | ||||
free(ifgr.ifgr_groups); | free(ifgr.ifgr_groups); | ||||
close(s); | |||||
return (h); | return (h); | ||||
} | } | ||||
struct node_host * | struct node_host * | ||||
ifa_lookup(const char *ifa_name, int flags) | ifa_lookup(char *ifa_name, int flags) | ||||
{ | { | ||||
struct node_host *p = NULL, *h = NULL, *n = NULL; | struct node_host *p = NULL, *h = NULL, *n = NULL; | ||||
int got4 = 0, got6 = 0; | int got4 = 0, got6 = 0; | ||||
const char *last_if = NULL; | const char *last_if = NULL; | ||||
if ((h = ifa_grouplookup(ifa_name, flags)) != NULL) | if ((h = ifa_grouplookup(ifa_name, flags)) != NULL) | ||||
return (h); | return (h); | ||||
▲ Show 20 Lines • Show All 432 Lines • Show Last 20 Lines |