diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-10-07 15:10:20 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-01-10 09:53:31 +0100 |
commit | c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch) | |
tree | ad4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sbin | |
parent | userspace-header-gen.py: Simplify program ports (diff) | |
download | rtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2 |
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sbin')
89 files changed, 32038 insertions, 2114 deletions
diff --git a/freebsd/sbin/dhclient/bpf.c b/freebsd/sbin/dhclient/bpf.c index 8ff451b2..4d3d2276 100644 --- a/freebsd/sbin/dhclient/bpf.c +++ b/freebsd/sbin/dhclient/bpf.c @@ -46,6 +46,8 @@ __FBSDID("$FreeBSD$"); #include "dhcpd.h" +#include "privsep.h" +#include <sys/capsicum.h> #include <sys/ioctl.h> #include <sys/uio.h> @@ -63,15 +65,15 @@ __FBSDID("$FreeBSD$"); * mask. */ int -if_register_bpf(struct interface_info *info) +if_register_bpf(struct interface_info *info, int flags) { char filename[50]; int sock, b; /* Open a BPF device */ - for (b = 0; 1; b++) { + for (b = 0;; b++) { snprintf(filename, sizeof(filename), BPF_FORMAT, b); - sock = open(filename, O_RDWR, 0); + sock = open(filename, flags); if (sock < 0) { if (errno == EBUSY) continue; @@ -89,16 +91,81 @@ if_register_bpf(struct interface_info *info) return (sock); } +/* + * Packet write filter program: + * 'ip and udp and src port bootps and dst port (bootps or bootpc)' + */ +struct bpf_insn dhcp_bpf_wfilter[] = { + BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12), + + /* Make sure this is an IP packet... */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10), + + /* Make sure it's a UDP packet... */ + BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8), + + /* Make sure this isn't a fragment... */ + BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), + BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */ + + /* Get the IP header length... */ + BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), + + /* Make sure it's from the right port... */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3), + + /* Make sure it is to the right ports ... */ + BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), + BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), + + /* If we passed all the tests, ask for the whole packet. */ + BPF_STMT(BPF_RET+BPF_K, (u_int)-1), + + /* Otherwise, drop it. */ + BPF_STMT(BPF_RET+BPF_K, 0), +}; + +int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn); + void if_register_send(struct interface_info *info) { + cap_rights_t rights; + struct bpf_version v; + struct bpf_program p; int sock, on = 1; - /* - * If we're using the bpf API for sending and receiving, we - * don't need to register this interface twice. - */ - info->wfdesc = info->rfdesc; + /* Open a BPF device and hang it on this interface... */ + info->wfdesc = if_register_bpf(info, O_WRONLY); + + /* Make sure the BPF version is in range... */ + if (ioctl(info->wfdesc, BIOCVERSION, &v) < 0) + error("Can't get BPF version: %m"); + + if (v.bv_major != BPF_MAJOR_VERSION || + v.bv_minor < BPF_MINOR_VERSION) + error("Kernel BPF version out of range - recompile dhcpd!"); + + /* Set up the bpf write filter program structure. */ + p.bf_len = dhcp_bpf_wfilter_len; + p.bf_insns = dhcp_bpf_wfilter; + + if (dhcp_bpf_wfilter[7].k == 0x1fff) + dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK); + + if (ioctl(info->wfdesc, BIOCSETWF, &p) < 0) + error("Can't install write filter program: %m"); + + if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0) + error("Cannot lock bpf"); + + cap_rights_init(&rights, CAP_WRITE); + if (cap_rights_limit(info->wfdesc, &rights) < 0 && errno != ENOSYS) + error("Can't limit bpf descriptor: %m"); /* * Use raw socket for unicast send. @@ -146,55 +213,17 @@ struct bpf_insn dhcp_bpf_filter[] = { int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn); -/* - * Packet write filter program: - * 'ip and udp and src port bootps and dst port (bootps or bootpc)' - */ -struct bpf_insn dhcp_bpf_wfilter[] = { - BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12), - - /* Make sure this is an IP packet... */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10), - - /* Make sure it's a UDP packet... */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8), - - /* Make sure this isn't a fragment... */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20), - BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */ - - /* Get the IP header length... */ - BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14), - - /* Make sure it's from the right port... */ - BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3), - - /* Make sure it is to the right ports ... */ - BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16), - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), - - /* If we passed all the tests, ask for the whole packet. */ - BPF_STMT(BPF_RET+BPF_K, (u_int)-1), - - /* Otherwise, drop it. */ - BPF_STMT(BPF_RET+BPF_K, 0), -}; - -int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn); - void if_register_receive(struct interface_info *info) { + static const unsigned long cmds[2] = { SIOCGIFFLAGS, SIOCGIFMEDIA }; + cap_rights_t rights; struct bpf_version v; struct bpf_program p; int flag = 1, sz; /* Open a BPF device and hang it on this interface... */ - info->rfdesc = if_register_bpf(info); + info->rfdesc = if_register_bpf(info, O_RDONLY); /* Make sure the BPF version is in range... */ if (ioctl(info->rfdesc, BIOCVERSION, &v) < 0) @@ -237,48 +266,94 @@ if_register_receive(struct interface_info *info) if (ioctl(info->rfdesc, BIOCSETF, &p) < 0) error("Can't install packet filter program: %m"); - /* Set up the bpf write filter program structure. */ - p.bf_len = dhcp_bpf_wfilter_len; - p.bf_insns = dhcp_bpf_wfilter; - - if (dhcp_bpf_wfilter[7].k == 0x1fff) - dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK); - - if (ioctl(info->rfdesc, BIOCSETWF, &p) < 0) - error("Can't install write filter program: %m"); - if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0) error("Cannot lock bpf"); + + cap_rights_init(&rights, CAP_IOCTL, CAP_EVENT, CAP_READ); + if (cap_rights_limit(info->rfdesc, &rights) < 0 && errno != ENOSYS) + error("Can't limit bpf descriptor: %m"); + if (cap_ioctls_limit(info->rfdesc, cmds, 2) < 0 && errno != ENOSYS) + error("Can't limit ioctls for bpf descriptor: %m"); } -ssize_t -send_packet(struct interface_info *interface, struct dhcp_packet *raw, - size_t len, struct in_addr from, struct sockaddr_in *to, - struct hardware *hto) +void +send_packet_unpriv(int privfd, struct dhcp_packet *raw, size_t len, + struct in_addr from, struct in_addr to) +{ + struct imsg_hdr hdr; + struct buf *buf; + int errs; + + hdr.code = IMSG_SEND_PACKET; + hdr.len = sizeof(hdr) + + sizeof(size_t) + len + + sizeof(from) + sizeof(to); + + if ((buf = buf_open(hdr.len)) == NULL) + error("buf_open: %m"); + + errs = 0; + errs += buf_add(buf, &hdr, sizeof(hdr)); + errs += buf_add(buf, &len, sizeof(len)); + errs += buf_add(buf, raw, len); + errs += buf_add(buf, &from, sizeof(from)); + errs += buf_add(buf, &to, sizeof(to)); + if (errs) + error("buf_add: %m"); + + if (buf_close(privfd, buf) == -1) + error("buf_close: %m"); +} + +void +send_packet_priv(struct interface_info *interface, struct imsg_hdr *hdr, int fd) { unsigned char buf[256]; struct iovec iov[2]; struct msghdr msg; + struct dhcp_packet raw; + size_t len; + struct in_addr from, to; int result, bufp = 0; + if (hdr->len < sizeof(*hdr) + sizeof(size_t)) + error("corrupted message received"); + buf_read(fd, &len, sizeof(len)); + if (hdr->len != sizeof(*hdr) + sizeof(size_t) + len + + sizeof(from) + sizeof(to)) { + error("corrupted message received"); + } + if (len > sizeof(raw)) + error("corrupted message received"); + buf_read(fd, &raw, len); + buf_read(fd, &from, sizeof(from)); + buf_read(fd, &to, sizeof(to)); + /* Assemble the headers... */ - if (to->sin_addr.s_addr == INADDR_BROADCAST) - assemble_hw_header(interface, buf, &bufp, hto); - assemble_udp_ip_header(buf, &bufp, from.s_addr, - to->sin_addr.s_addr, to->sin_port, (unsigned char *)raw, len); + if (to.s_addr == INADDR_BROADCAST) + assemble_hw_header(interface, buf, &bufp); + assemble_udp_ip_header(buf, &bufp, from.s_addr, to.s_addr, + htons(REMOTE_PORT), (unsigned char *)&raw, len); - iov[0].iov_base = (char *)buf; + iov[0].iov_base = buf; iov[0].iov_len = bufp; - iov[1].iov_base = (char *)raw; + iov[1].iov_base = &raw; iov[1].iov_len = len; /* Fire it off */ - if (to->sin_addr.s_addr == INADDR_BROADCAST) + if (to.s_addr == INADDR_BROADCAST) result = writev(interface->wfdesc, iov, 2); else { + struct sockaddr_in sato; + + sato.sin_addr = to; + sato.sin_port = htons(REMOTE_PORT); + sato.sin_family = AF_INET; + sato.sin_len = sizeof(sato); + memset(&msg, 0, sizeof(msg)); - msg.msg_name = (struct sockaddr *)to; - msg.msg_namelen = sizeof(*to); + msg.msg_name = (struct sockaddr *)&sato; + msg.msg_namelen = sizeof(sato); msg.msg_iov = iov; msg.msg_iovlen = 2; result = sendmsg(interface->ufdesc, &msg, 0); @@ -286,7 +361,6 @@ send_packet(struct interface_info *interface, struct dhcp_packet *raw, if (result < 0) warning("send_packet: %m"); - return (result); } ssize_t diff --git a/freebsd/sbin/dhclient/clparse.c b/freebsd/sbin/dhclient/clparse.c index b52bc473..a65236fc 100644 --- a/freebsd/sbin/dhclient/clparse.c +++ b/freebsd/sbin/dhclient/clparse.c @@ -644,6 +644,10 @@ parse_client_lease_declaration(FILE *cfile, struct client_lease *lease, case FILENAME: lease->filename = parse_string(cfile); return; + case NEXT_SERVER: + if (!parse_ip_addr(cfile, &lease->nextserver)) + return; + break; case SERVER_NAME: lease->server_name = parse_string(cfile); return; diff --git a/freebsd/sbin/dhclient/conflex.c b/freebsd/sbin/dhclient/conflex.c index 4990f45f..c4fd442c 100644 --- a/freebsd/sbin/dhclient/conflex.c +++ b/freebsd/sbin/dhclient/conflex.c @@ -99,8 +99,8 @@ get_char(FILE *cfile) cur_line = line2; prev_line = line1; } else { - cur_line = line2; - prev_line = line1; + cur_line = line1; + prev_line = line2; } line++; lpos = 1; diff --git a/freebsd/sbin/dhclient/dhclient.c b/freebsd/sbin/dhclient/dhclient.c index 97824985..c7b75c59 100644 --- a/freebsd/sbin/dhclient/dhclient.c +++ b/freebsd/sbin/dhclient/dhclient.c @@ -61,6 +61,8 @@ __FBSDID("$FreeBSD$"); #include "dhcpd.h" #include "privsep.h" +#include <sys/capsicum.h> + #include <net80211/ieee80211_freebsd.h> #ifndef _PATH_VAREMPTY @@ -93,9 +95,10 @@ int log_perror = 1; int privfd; int nullfd = -1; +char hostname[_POSIX_HOST_NAME_MAX + 1]; + struct iaddr iaddr_broadcast = { 4, { 255, 255, 255, 255 } }; -struct in_addr inaddr_any; -struct sockaddr_in sockaddr_broadcast; +struct in_addr inaddr_any, inaddr_broadcast; char *path_dhclient_pidfile; struct pidfh *pidfile; @@ -345,6 +348,7 @@ main(int argc, char *argv[]) int immediate_daemon = 0; struct passwd *pw; pid_t otherpid; + cap_rights_t rights; /* Initially, log errors to stderr as well as to syslogd. */ openlog(__progname, LOG_PID | LOG_NDELAY, DHCPD_LOG_FACILITY); @@ -389,7 +393,7 @@ main(int argc, char *argv[]) if (path_dhclient_pidfile == NULL) error("asprintf"); } - pidfile = pidfile_open(path_dhclient_pidfile, 0600, &otherpid); + pidfile = pidfile_open(path_dhclient_pidfile, 0644, &otherpid); if (pidfile == NULL) { if (errno == EEXIST) error("dhclient already running, pid: %d.", otherpid); @@ -412,11 +416,7 @@ main(int argc, char *argv[]) tzset(); time(&cur_time); - memset(&sockaddr_broadcast, 0, sizeof(sockaddr_broadcast)); - sockaddr_broadcast.sin_family = AF_INET; - sockaddr_broadcast.sin_port = htons(REMOTE_PORT); - sockaddr_broadcast.sin_addr.s_addr = INADDR_BROADCAST; - sockaddr_broadcast.sin_len = sizeof(sockaddr_broadcast); + inaddr_broadcast.s_addr = INADDR_BROADCAST; inaddr_any.s_addr = INADDR_ANY; read_client_conf(); @@ -453,13 +453,36 @@ main(int argc, char *argv[]) error("no such user: nobody"); } + /* + * Obtain hostname before entering capability mode - it won't be + * possible then, as reading kern.hostname is not permitted. + */ + if (gethostname(hostname, sizeof(hostname)) < 0) + hostname[0] = '\0'; + + priv_script_init("PREINIT", NULL); + if (ifi->client->alias) + priv_script_write_params("alias_", ifi->client->alias); + priv_script_go(); + + /* set up the interface */ + discover_interfaces(ifi); + if (pipe(pipe_fd) == -1) error("pipe"); fork_privchld(pipe_fd[0], pipe_fd[1]); + close(ifi->ufdesc); + ifi->ufdesc = -1; + close(ifi->wfdesc); + ifi->wfdesc = -1; + close(pipe_fd[0]); privfd = pipe_fd[1]; + cap_rights_init(&rights, CAP_READ, CAP_WRITE); + if (cap_rights_limit(privfd, &rights) < 0 && errno != ENOSYS) + error("can't limit private descriptor: %m"); if ((fd = open(path_dhclient_db, O_RDONLY|O_EXLOCK|O_CREAT, 0)) == -1) error("can't open and lock %s: %m", path_dhclient_db); @@ -467,16 +490,13 @@ main(int argc, char *argv[]) rewrite_client_leases(); close(fd); - priv_script_init("PREINIT", NULL); - if (ifi->client->alias) - priv_script_write_params("alias_", ifi->client->alias); - priv_script_go(); - if ((routefd = socket(PF_ROUTE, SOCK_RAW, 0)) != -1) add_protocol("AF_ROUTE", routefd, routehandler, ifi); - - /* set up the interface */ - discover_interfaces(ifi); + if (shutdown(routefd, SHUT_WR) < 0) + error("can't shutdown route socket: %m"); + cap_rights_init(&rights, CAP_EVENT, CAP_READ); + if (cap_rights_limit(routefd, &rights) < 0 && errno != ENOSYS) + error("can't limit route socket: %m"); if (chroot(_PATH_VAREMPTY) == -1) error("chroot"); @@ -492,6 +512,9 @@ main(int argc, char *argv[]) setproctitle("%s", ifi->name); + if (cap_enter() < 0 && errno != ENOSYS) + error("can't enter capability mode: %m"); + if (immediate_daemon) go_daemon(); @@ -1065,6 +1088,9 @@ packet_to_lease(struct packet *packet) lease->address.len = sizeof(packet->raw->yiaddr); memcpy(lease->address.iabuf, &packet->raw->yiaddr, lease->address.len); + lease->nextserver.len = sizeof(packet->raw->siaddr); + memcpy(lease->nextserver.iabuf, &packet->raw->siaddr, lease->nextserver.len); + /* If the server name was filled out, copy it. Do not attempt to validate the server name as a host name. RFC 2131 merely states that sname is NUL-terminated (which do @@ -1225,13 +1251,12 @@ again: ip->client->secs = ip->client->packet.secs; note("DHCPDISCOVER on %s to %s port %d interval %d", - ip->name, inet_ntoa(sockaddr_broadcast.sin_addr), - ntohs(sockaddr_broadcast.sin_port), + ip->name, inet_ntoa(inaddr_broadcast), REMOTE_PORT, (int)ip->client->interval); /* Send out a packet. */ - (void)send_packet(ip, &ip->client->packet, ip->client->packet_length, - inaddr_any, &sockaddr_broadcast, NULL); + send_packet_unpriv(privfd, &ip->client->packet, + ip->client->packet_length, inaddr_any, inaddr_broadcast); add_timeout(cur_time + ip->client->interval, send_discover, ip); } @@ -1339,8 +1364,7 @@ void send_request(void *ipp) { struct interface_info *ip = ipp; - struct sockaddr_in destination; - struct in_addr from; + struct in_addr from, to; int interval; /* Figure out how long it's been since we started transmitting. */ @@ -1428,18 +1452,13 @@ cancel: /* If the lease T2 time has elapsed, or if we're not yet bound, broadcast the DHCPREQUEST rather than unicasting. */ - memset(&destination, 0, sizeof(destination)); if (ip->client->state == S_REQUESTING || ip->client->state == S_REBOOTING || cur_time > ip->client->active->rebind) - destination.sin_addr.s_addr = INADDR_BROADCAST; + to.s_addr = INADDR_BROADCAST; else - memcpy(&destination.sin_addr.s_addr, - ip->client->destination.iabuf, - sizeof(destination.sin_addr.s_addr)); - destination.sin_port = htons(REMOTE_PORT); - destination.sin_family = AF_INET; - destination.sin_len = sizeof(destination); + memcpy(&to.s_addr, ip->client->destination.iabuf, + sizeof(to.s_addr)); if (ip->client->state != S_REQUESTING) memcpy(&from, ip->client->active->address.iabuf, @@ -1457,12 +1476,12 @@ cancel: ip->client->packet.secs = htons(65535); } - note("DHCPREQUEST on %s to %s port %d", ip->name, - inet_ntoa(destination.sin_addr), ntohs(destination.sin_port)); + note("DHCPREQUEST on %s to %s port %d", ip->name, inet_ntoa(to), + REMOTE_PORT); /* Send out a packet. */ - (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, - from, &destination, NULL); + send_packet_unpriv(privfd, &ip->client->packet, + ip->client->packet_length, from, to); add_timeout(cur_time + ip->client->interval, send_request, ip); } @@ -1473,12 +1492,11 @@ send_decline(void *ipp) struct interface_info *ip = ipp; note("DHCPDECLINE on %s to %s port %d", ip->name, - inet_ntoa(sockaddr_broadcast.sin_addr), - ntohs(sockaddr_broadcast.sin_port)); + inet_ntoa(inaddr_broadcast), REMOTE_PORT); /* Send out a packet. */ - (void) send_packet(ip, &ip->client->packet, ip->client->packet_length, - inaddr_any, &sockaddr_broadcast, NULL); + send_packet_unpriv(privfd, &ip->client->packet, + ip->client->packet_length, inaddr_any, inaddr_broadcast); } void @@ -1535,11 +1553,10 @@ make_discover(struct interface_info *ip, struct client_lease *lease) ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } - + /* send host name if not set via config file. */ - char hostname[_POSIX_HOST_NAME_MAX+1]; if (!options[DHO_HOST_NAME]) { - if (gethostname(hostname, sizeof(hostname)) == 0) { + if (hostname[0] != '\0') { size_t len; char* posDot = strchr(hostname, '.'); if (posDot != NULL) @@ -1555,12 +1572,12 @@ make_discover(struct interface_info *ip, struct client_lease *lease) } /* set unique client identifier */ - char client_ident[sizeof(struct hardware)]; + char client_ident[sizeof(ip->hw_address.haddr) + 1]; if (!options[DHO_DHCP_CLIENT_IDENTIFIER]) { int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? ip->hw_address.hlen : sizeof(client_ident)-1; client_ident[0] = ip->hw_address.htype; - memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); + memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; @@ -1659,11 +1676,10 @@ make_request(struct interface_info *ip, struct client_lease * lease) ip->client->config->send_options[i].len; options[i]->timeout = 0xFFFFFFFF; } - + /* send host name if not set via config file. */ - char hostname[_POSIX_HOST_NAME_MAX+1]; if (!options[DHO_HOST_NAME]) { - if (gethostname(hostname, sizeof(hostname)) == 0) { + if (hostname[0] != '\0') { size_t len; char* posDot = strchr(hostname, '.'); if (posDot != NULL) @@ -1684,7 +1700,7 @@ make_request(struct interface_info *ip, struct client_lease * lease) int hwlen = (ip->hw_address.hlen < sizeof(client_ident)-1) ? ip->hw_address.hlen : sizeof(client_ident)-1; client_ident[0] = ip->hw_address.htype; - memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); + memcpy(&client_ident[1], ip->hw_address.haddr, hwlen); options[DHO_DHCP_CLIENT_IDENTIFIER] = &option_elements[DHO_DHCP_CLIENT_IDENTIFIER]; options[DHO_DHCP_CLIENT_IDENTIFIER]->value = client_ident; options[DHO_DHCP_CLIENT_IDENTIFIER]->len = hwlen+1; @@ -1825,11 +1841,22 @@ void rewrite_client_leases(void) { struct client_lease *lp; + cap_rights_t rights; if (!leaseFile) { leaseFile = fopen(path_dhclient_db, "w"); if (!leaseFile) error("can't create %s: %m", path_dhclient_db); + cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_FSYNC, + CAP_FTRUNCATE, CAP_SEEK, CAP_WRITE); + if (cap_rights_limit(fileno(leaseFile), &rights) < 0 && + errno != ENOSYS) { + error("can't limit lease descriptor: %m"); + } + if (cap_fcntls_limit(fileno(leaseFile), CAP_FCNTL_GETFL) < 0 && + errno != ENOSYS) { + error("can't limit lease descriptor fcntls: %m"); + } } else { fflush(leaseFile); rewind(leaseFile); @@ -1876,6 +1903,11 @@ write_client_lease(struct interface_info *ip, struct client_lease *lease, fprintf(leaseFile, " bootp;\n"); fprintf(leaseFile, " interface \"%s\";\n", ip->name); fprintf(leaseFile, " fixed-address %s;\n", piaddr(lease->address)); + if (lease->nextserver.len == sizeof(inaddr_any) && + 0 != memcmp(lease->nextserver.iabuf, &inaddr_any, + sizeof(inaddr_any))) + fprintf(leaseFile, " next-server %s;\n", + piaddr(lease->nextserver)); if (lease->filename) fprintf(leaseFile, " filename \"%s\";\n", lease->filename); if (lease->server_name) @@ -2245,6 +2277,17 @@ script_set_env(struct client_state *client, const char *prefix, { int i, j, namelen; + /* No `` or $() command substitution allowed in environment values! */ + for (j=0; j < strlen(value); j++) + switch (value[j]) { + case '`': + case '$': + warning("illegal character (%c) in value '%s'", + value[j], value); + /* Ignore this option */ + return; + } + namelen = strlen(name); for (i = 0; client->scriptEnv[i]; i++) @@ -2281,16 +2324,6 @@ script_set_env(struct client_state *client, const char *prefix, strlen(value) + 1); if (client->scriptEnv[i] == NULL) error("script_set_env: no memory for variable assignment"); - - /* No `` or $() command substitution allowed in environment values! */ - for (j=0; j < strlen(value); j++) - switch (value[j]) { - case '`': - case '$': - error("illegal character (%c) in value '%s'", value[j], - value); - /* not reached */ - } snprintf(client->scriptEnv[i], strlen(prefix) + strlen(name) + 1 + strlen(value) + 1, "%s%s=%s", prefix, name, value); } @@ -2329,6 +2362,7 @@ void go_daemon(void) { static int state = 0; + cap_rights_t rights; if (no_daemon || state) return; @@ -2341,8 +2375,15 @@ go_daemon(void) if (daemon(1, 0) == -1) error("daemon"); - if (pidfile != NULL) + cap_rights_init(&rights); + + if (pidfile != NULL) { pidfile_write(pidfile); + if (cap_rights_limit(pidfile_fileno(pidfile), &rights) < 0 && + errno != ENOSYS) { + error("can't limit pidfile descriptor: %m"); + } + } /* we are chrooted, daemon(3) fails to open /dev/null */ if (nullfd != -1) { @@ -2352,6 +2393,14 @@ go_daemon(void) close(nullfd); nullfd = -1; } + + if (cap_rights_limit(STDIN_FILENO, &rights) < 0 && errno != ENOSYS) + error("can't limit stdin: %m"); + cap_rights_init(&rights, CAP_WRITE); + if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) + error("can't limit stdout: %m"); + if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) + error("can't limit stderr: %m"); } int @@ -2496,19 +2545,19 @@ check_classless_option(unsigned char *data, int len) i += 4; continue; } else if (width < 9) { - addr = (in_addr_t)(data[i] << 24); + addr = (in_addr_t)(data[i] << 24); i += 1; } else if (width < 17) { - addr = (in_addr_t)(data[i] << 24) + + addr = (in_addr_t)(data[i] << 24) + (in_addr_t)(data[i + 1] << 16); i += 2; } else if (width < 25) { - addr = (in_addr_t)(data[i] << 24) + + addr = (in_addr_t)(data[i] << 24) + (in_addr_t)(data[i + 1] << 16) + (in_addr_t)(data[i + 2] << 8); i += 3; } else if (width < 33) { - addr = (in_addr_t)(data[i] << 24) + + addr = (in_addr_t)(data[i] << 24) + (in_addr_t)(data[i + 1] << 16) + (in_addr_t)(data[i + 2] << 8) + data[i + 3]; @@ -2532,7 +2581,7 @@ check_classless_option(unsigned char *data, int len) addr &= mask; data[i - 1] = (unsigned char)( (addr >> (((32 - width)/8)*8)) & 0xFF); - } + } i += 4; } if (i > len) { @@ -2696,6 +2745,8 @@ fork_privchld(int fd, int fd2) dup2(nullfd, STDERR_FILENO); close(nullfd); close(fd2); + close(ifi->rfdesc); + ifi->rfdesc = -1; for (;;) { pfd[0].fd = fd; @@ -2707,6 +2758,6 @@ fork_privchld(int fd, int fd2) if (nfds == 0 || !(pfd[0].revents & POLLIN)) continue; - dispatch_imsg(fd); + dispatch_imsg(ifi, fd); } } diff --git a/freebsd/sbin/dhclient/dhcpd.h b/freebsd/sbin/dhclient/dhcpd.h index 030a96a0..852513a8 100644 --- a/freebsd/sbin/dhclient/dhcpd.h +++ b/freebsd/sbin/dhclient/dhcpd.h @@ -121,6 +121,7 @@ struct client_lease { struct client_lease *next; time_t expiry, renewal, rebind; struct iaddr address; + struct iaddr nextserver; char *server_name; char *filename; struct string_list *medium; @@ -296,11 +297,13 @@ struct hash_table *new_hash_table(int); struct hash_bucket *new_hash_bucket(void); /* bpf.c */ -int if_register_bpf(struct interface_info *); +int if_register_bpf(struct interface_info *, int); void if_register_send(struct interface_info *); void if_register_receive(struct interface_info *); -ssize_t send_packet(struct interface_info *, struct dhcp_packet *, size_t, - struct in_addr, struct sockaddr_in *, struct hardware *); +void send_packet_unpriv(int, struct dhcp_packet *, size_t, struct in_addr, + struct in_addr); +struct imsg_hdr; +void send_packet_priv(struct interface_info *, struct imsg_hdr *, int); ssize_t receive_packet(struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *); @@ -404,20 +407,13 @@ void bootp(struct packet *); void dhcp(struct packet *); /* packet.c */ -void assemble_hw_header(struct interface_info *, unsigned char *, - int *, struct hardware *); +void assemble_hw_header(struct interface_info *, unsigned char *, int *); void assemble_udp_ip_header(unsigned char *, int *, u_int32_t, u_int32_t, unsigned int, unsigned char *, int); ssize_t decode_hw_header(unsigned char *, int, struct hardware *); ssize_t decode_udp_ip_header(unsigned char *, int, struct sockaddr_in *, unsigned char *, int); -/* ethernet.c */ -void assemble_ethernet_header(struct interface_info *, unsigned char *, - int *, struct hardware *); -ssize_t decode_ethernet_header(struct interface_info *, unsigned char *, - int, struct hardware *); - /* clparse.c */ int read_client_conf(void); void read_client_leases(void); @@ -441,4 +437,4 @@ struct buf *buf_open(size_t); int buf_add(struct buf *, void *, size_t); int buf_close(int, struct buf *); ssize_t buf_read(int, void *, size_t); -void dispatch_imsg(int); +void dispatch_imsg(struct interface_info *, int); diff --git a/freebsd/sbin/dhclient/options.c b/freebsd/sbin/dhclient/options.c index c86b7e3b..5ea8de7c 100644 --- a/freebsd/sbin/dhclient/options.c +++ b/freebsd/sbin/dhclient/options.c @@ -286,8 +286,8 @@ find_search_domain_name_len(struct option_data *option, int *offset) option->data[i + 1]; if (pointer >= *offset) { /* - * The pointer must indicates a prior - * occurance. + * The pointer must indicate a prior + * occurrence. */ warning("Invalid forward pointer in DHCP " "Domain Search option compression."); diff --git a/freebsd/sbin/dhclient/packet.c b/freebsd/sbin/dhclient/packet.c index e4fa0e86..28a9ccec 100644 --- a/freebsd/sbin/dhclient/packet.c +++ b/freebsd/sbin/dhclient/packet.c @@ -57,11 +57,6 @@ __FBSDID("$FreeBSD$"); u_int32_t checksum(unsigned char *, unsigned, u_int32_t); u_int32_t wrapsum(u_int32_t); -void assemble_ethernet_header(struct interface_info *, unsigned char *, - int *, struct hardware *); -ssize_t decode_ethernet_header(struct interface_info *, unsigned char *, - int bufix, struct hardware *); - u_int32_t checksum(unsigned char *buf, unsigned nbytes, u_int32_t sum) { @@ -97,14 +92,11 @@ wrapsum(u_int32_t sum) void assemble_hw_header(struct interface_info *interface, unsigned char *buf, - int *bufix, struct hardware *to) + int *bufix) { struct ether_header eh; - if (to != NULL && to->hlen == 6) /* XXX */ - memcpy(eh.ether_dhost, to->haddr, sizeof(eh.ether_dhost)); - else - memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); + memset(eh.ether_dhost, 0xff, sizeof(eh.ether_dhost)); if (interface->hw_address.hlen == sizeof(eh.ether_shost)) memcpy(eh.ether_shost, interface->hw_address.haddr, sizeof(eh.ether_shost)); @@ -137,17 +129,6 @@ assemble_udp_ip_header(unsigned char *buf, int *bufix, u_int32_t from, ip.ip_dst.s_addr = to; ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0)); - - /* - * While the BPF -- used for broadcasts -- expects a "true" IP header - * with all the bytes in network byte order, the raw socket interface - * which is used for unicasts expects the ip_len field to be in host - * byte order. In both cases, the checksum has to be correct, so this - * is as good a place as any to turn the bytes around again. - */ - if (to != INADDR_BROADCAST) - ip.ip_len = ntohs(ip.ip_len); - memcpy(&buf[*bufix], &ip, sizeof(ip)); *bufix += sizeof(ip); diff --git a/freebsd/sbin/dhclient/privsep.c b/freebsd/sbin/dhclient/privsep.c index 7b68059a..aa1042fd 100644 --- a/freebsd/sbin/dhclient/privsep.c +++ b/freebsd/sbin/dhclient/privsep.c @@ -103,7 +103,7 @@ buf_read(int sock, void *buf, size_t nbytes) } void -dispatch_imsg(int fd) +dispatch_imsg(struct interface_info *ifi, int fd) { struct imsg_hdr hdr; char *medium, *reason, *filename, @@ -234,6 +234,9 @@ dispatch_imsg(int fd) if (buf_close(fd, buf) == -1) error("buf_close: %m"); break; + case IMSG_SEND_PACKET: + send_packet_priv(ifi, &hdr, fd); + break; default: error("received unknown message, code %d", hdr.code); } diff --git a/freebsd/sbin/dhclient/privsep.h b/freebsd/sbin/dhclient/privsep.h index f30284ee..d464da43 100644 --- a/freebsd/sbin/dhclient/privsep.h +++ b/freebsd/sbin/dhclient/privsep.h @@ -14,6 +14,8 @@ * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ */ #include <sys/types.h> @@ -33,7 +35,8 @@ enum imsg_code { IMSG_SCRIPT_INIT, IMSG_SCRIPT_WRITE_PARAMS, IMSG_SCRIPT_GO, - IMSG_SCRIPT_GO_RET + IMSG_SCRIPT_GO_RET, + IMSG_SEND_PACKET }; struct imsg_hdr { diff --git a/freebsd/sbin/ifconfig/af_inet.c b/freebsd/sbin/ifconfig/af_inet.c index 1d713eec..d464df52 100644 --- a/freebsd/sbin/ifconfig/af_inet.c +++ b/freebsd/sbin/ifconfig/af_inet.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. @@ -34,7 +38,10 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ -#include <sys/types.h> +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> @@ -48,20 +55,25 @@ static const char rcsid[] = #include <ifaddrs.h> #include <netinet/in.h> -#include <net/if_var.h> /* for struct ifaddr */ #include <netinet/in_var.h> #include <arpa/inet.h> #include <netdb.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-af_inet-data.h" +#endif /* __rtems__ */ static struct in_aliasreq in_addreq; static struct ifreq in_ridreq; +static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/ +extern char *f_inet, *f_addr; static void in_status(int s __unused, const struct ifaddrs *ifa) { struct sockaddr_in *sin, null_sin; + int error, n_flags; memset(&null_sin, 0, sizeof(null_sin)); @@ -69,25 +81,56 @@ in_status(int s __unused, const struct ifaddrs *ifa) if (sin == NULL) return; - printf("\tinet %s ", inet_ntoa(sin->sin_addr)); + if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0) + n_flags = 0; + else if (f_addr != NULL && strcmp(f_addr, "host") == 0) + n_flags = NI_NOFQDN; + else + n_flags = NI_NUMERICHOST; + + error = getnameinfo((struct sockaddr *)sin, sin->sin_len, addr_buf, + sizeof(addr_buf), NULL, 0, n_flags); + + if (error) + inet_ntop(AF_INET, &sin->sin_addr, addr_buf, sizeof(addr_buf)); + + printf("\tinet %s", addr_buf); if (ifa->ifa_flags & IFF_POINTOPOINT) { sin = (struct sockaddr_in *)ifa->ifa_dstaddr; if (sin == NULL) sin = &null_sin; - printf("--> %s ", inet_ntoa(sin->sin_addr)); + printf(" --> %s ", inet_ntoa(sin->sin_addr)); } sin = (struct sockaddr_in *)ifa->ifa_netmask; if (sin == NULL) sin = &null_sin; - printf("netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); + if (f_inet != NULL && strcmp(f_inet, "cidr") == 0) { + int cidr = 32; + unsigned long smask; + + smask = ntohl(sin->sin_addr.s_addr); + while ((smask & 1) == 0) { + smask = smask >> 1; + cidr--; + if (cidr == 0) + break; + } + printf("/%d ", cidr); + } else if (f_inet != NULL && strcmp(f_inet, "dotted") == 0) + printf(" netmask %s ", inet_ntoa(sin->sin_addr)); + else + printf(" netmask 0x%lx ", (unsigned long)ntohl(sin->sin_addr.s_addr)); if (ifa->ifa_flags & IFF_BROADCAST) { sin = (struct sockaddr_in *)ifa->ifa_broadaddr; if (sin != NULL && sin->sin_addr.s_addr != 0) - printf("broadcast %s", inet_ntoa(sin->sin_addr)); + printf("broadcast %s ", inet_ntoa(sin->sin_addr)); } + + print_vhid(ifa, " "); + putchar('\n'); } @@ -100,7 +143,6 @@ static struct sockaddr_in *sintab[] = { static void in_getaddr(const char *s, int which) { -#define MIN(a,b) ((a)<(b)?(a):(b)) struct sockaddr_in *sin = sintab[which]; struct hostent *hp; struct netent *np; @@ -117,7 +159,11 @@ in_getaddr(const char *s, int which) int masklen; struct sockaddr_in *min = sintab[MASK]; *p = '\0'; +#ifndef __rtems__ + if (!isdigit(*(p + 1))) +#else /* __rtems__ */ if (!isdigit((unsigned char)*(p + 1))) +#endif /* __rtems__ */ errstr = "invalid"; else masklen = (int)strtonum(p + 1, 0, 32, &errstr); @@ -134,14 +180,13 @@ in_getaddr(const char *s, int which) if (inet_aton(s, &sin->sin_addr)) return; - if ((hp = gethostbyname(s)) != 0) + if ((hp = gethostbyname(s)) != NULL) bcopy(hp->h_addr, (char *)&sin->sin_addr, MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); - else if ((np = getnetbyname(s)) != 0) + else if ((np = getnetbyname(s)) != NULL) sin->sin_addr = inet_makeaddr(np->n_net, INADDR_ANY); else errx(1, "%s: bad value", s); -#undef MIN } static void @@ -153,7 +198,7 @@ in_status_tunnel(int s) const struct sockaddr *sa = (const struct sockaddr *) &ifr.ifr_addr; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, name, IFNAMSIZ); + strlcpy(ifr.ifr_name, name, IFNAMSIZ); if (ioctl(s, SIOCGIFPSRCADDR, (caddr_t)&ifr) < 0) return; @@ -178,7 +223,7 @@ in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) struct in_aliasreq addreq; memset(&addreq, 0, sizeof(addreq)); - strncpy(addreq.ifra_name, name, IFNAMSIZ); + strlcpy(addreq.ifra_name, name, IFNAMSIZ); memcpy(&addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); memcpy(&addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len); @@ -211,11 +256,5 @@ inet_ctor(void) if (!feature_present("inet")) return; #endif - -#ifdef __rtems__ - memset(&in_addreq, 0, sizeof(in_addreq)); - memset(&in_ridreq, 0, sizeof(in_ridreq)); -#endif /* __rtems__ */ - af_register(&af_inet); } diff --git a/freebsd/sbin/ifconfig/af_inet6.c b/freebsd/sbin/ifconfig/af_inet6.c index 0e099ada..f743ee8f 100644 --- a/freebsd/sbin/ifconfig/af_inet6.c +++ b/freebsd/sbin/ifconfig/af_inet6.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. @@ -34,6 +38,9 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -45,12 +52,12 @@ static const char rcsid[] = #include <stdlib.h> #include <string.h> #include <unistd.h> +#include <time.h> #include <ifaddrs.h> #include <arpa/inet.h> #include <netinet/in.h> -#include <net/if_var.h> /* for struct ifaddr */ #include <netinet/in_var.h> #include <arpa/inet.h> #include <netdb.h> @@ -58,23 +65,26 @@ static const char rcsid[] = #include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */ #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-af_inet6-data.h" +#endif /* __rtems__ */ static struct in6_ifreq in6_ridreq; -static struct in6_aliasreq in6_addreq = - { .ifra_flags = 0, +static struct in6_aliasreq in6_addreq = + { .ifra_flags = 0, .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } }; static int ip6lifetime; -static void in6_fillscopeid(struct sockaddr_in6 *sin6); static int prefix(void *, int); static char *sec2str(time_t); static int explicit_prefix = 0; +extern char *f_inet6, *f_addr; extern void setnd6flags(const char *, int, int, const struct afswtch *); extern void setnd6defif(const char *, int, int, const struct afswtch *); extern void nd6_status(int); -static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ +static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/ static void setifprefixlen(const char *addr, int dummy __unused, int s, @@ -102,20 +112,21 @@ static void setip6lifetime(const char *cmd, const char *val, int s, const struct afswtch *afp) { - time_t newval, t; + struct timespec now; + time_t newval; char *ep; - t = time(NULL); + clock_gettime(CLOCK_MONOTONIC_FAST, &now); newval = (time_t)strtoul(val, &ep, 0); if (val == ep) errx(1, "invalid %s", cmd); if (afp->af_af != AF_INET6) errx(1, "%s not allowed for the AF", cmd); if (strcmp(cmd, "vltime") == 0) { - in6_addreq.ifra_lifetime.ia6t_expire = t + newval; + in6_addreq.ifra_lifetime.ia6t_expire = now.tv_sec + newval; in6_addreq.ifra_lifetime.ia6t_vltime = newval; } else if (strcmp(cmd, "pltime") == 0) { - in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; + in6_addreq.ifra_lifetime.ia6t_preferred = now.tv_sec + newval; in6_addreq.ifra_lifetime.ia6t_pltime = newval; } } @@ -169,18 +180,6 @@ setip6eui64(const char *cmd, int dummy __unused, int s, } static void -in6_fillscopeid(struct sockaddr_in6 *sin6) -{ -#if defined(__KAME__) && defined(KAME_SCOPEID) - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { - sin6->sin6_scope_id = - ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); - sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; - } -#endif -} - -static void in6_status(int s __unused, const struct ifaddrs *ifa) { struct sockaddr_in6 *sin, null_sin; @@ -188,9 +187,10 @@ in6_status(int s __unused, const struct ifaddrs *ifa) int s6; u_int32_t flags6; struct in6_addrlifetime lifetime; - time_t t = time(NULL); - int error; - u_int32_t scopeid; + struct timespec now; + int error, n_flags; + + clock_gettime(CLOCK_MONOTONIC_FAST, &now); memset(&null_sin, 0, sizeof(null_sin)); @@ -198,7 +198,7 @@ in6_status(int s __unused, const struct ifaddrs *ifa) if (sin == NULL) return; - strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); + strlcpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { warn("socket(AF_INET6,SOCK_DGRAM)"); return; @@ -220,24 +220,19 @@ in6_status(int s __unused, const struct ifaddrs *ifa) lifetime = ifr6.ifr_ifru.ifru_lifetime; close(s6); - /* XXX: embedded link local addr check */ - if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && - *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { - u_short index; - - index = *(u_short *)&sin->sin6_addr.s6_addr[2]; - *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; - if (sin->sin6_scope_id == 0) - sin->sin6_scope_id = ntohs(index); - } - scopeid = sin->sin6_scope_id; - - error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, - sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); + if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0) + n_flags = 0; + else if (f_addr != NULL && strcmp(f_addr, "host") == 0) + n_flags = NI_NOFQDN; + else + n_flags = NI_NUMERICHOST; + error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, + addr_buf, sizeof(addr_buf), NULL, 0, + n_flags); if (error != 0) inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, sizeof(addr_buf)); - printf("\tinet6 %s ", addr_buf); + printf("\tinet6 %s", addr_buf); if (ifa->ifa_flags & IFF_POINTOPOINT) { sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr; @@ -248,17 +243,6 @@ in6_status(int s __unused, const struct ifaddrs *ifa) if (sin != NULL && sin->sin6_family == AF_INET6) { int error; - /* XXX: embedded link local addr check */ - if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && - *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { - u_short index; - - index = *(u_short *)&sin->sin6_addr.s6_addr[2]; - *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; - if (sin->sin6_scope_id == 0) - sin->sin6_scope_id = ntohs(index); - } - error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, sizeof(addr_buf), NULL, 0, @@ -266,15 +250,19 @@ in6_status(int s __unused, const struct ifaddrs *ifa) if (error != 0) inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, sizeof(addr_buf)); - printf("--> %s ", addr_buf); + printf(" --> %s ", addr_buf); } } sin = (struct sockaddr_in6 *)ifa->ifa_netmask; if (sin == NULL) sin = &null_sin; - printf("prefixlen %d ", prefix(&sin->sin6_addr, - sizeof(struct in6_addr))); + if (f_inet6 != NULL && strcmp(f_inet6, "cidr") == 0) + printf("/%d ", prefix(&sin->sin6_addr, + sizeof(struct in6_addr))); + else + printf(" prefixlen %d ", prefix(&sin->sin6_addr, + sizeof(struct in6_addr))); if ((flags6 & IN6_IFF_ANYCAST) != 0) printf("anycast "); @@ -293,25 +281,30 @@ in6_status(int s __unused, const struct ifaddrs *ifa) if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0) printf("prefer_source "); - if (scopeid) - printf("scopeid 0x%x ", scopeid); + if (((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id) + printf("scopeid 0x%x ", + ((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id); if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) { printf("pltime "); if (lifetime.ia6t_preferred) { - printf("%s ", lifetime.ia6t_preferred < t - ? "0" : sec2str(lifetime.ia6t_preferred - t)); + printf("%s ", lifetime.ia6t_preferred < now.tv_sec + ? "0" : + sec2str(lifetime.ia6t_preferred - now.tv_sec)); } else printf("infty "); printf("vltime "); if (lifetime.ia6t_expire) { - printf("%s ", lifetime.ia6t_expire < t - ? "0" : sec2str(lifetime.ia6t_expire - t)); + printf("%s ", lifetime.ia6t_expire < now.tv_sec + ? "0" : + sec2str(lifetime.ia6t_expire - now.tv_sec)); } else printf("infty "); } + print_vhid(ifa, " "); + putchar('\n'); } @@ -389,25 +382,25 @@ done: static int prefix(void *val, int size) { - u_char *name = (u_char *)val; - int byte, bit, plen = 0; + u_char *name = (u_char *)val; + int byte, bit, plen = 0; - for (byte = 0; byte < size; byte++, plen += 8) - if (name[byte] != 0xff) - break; + for (byte = 0; byte < size; byte++, plen += 8) + if (name[byte] != 0xff) + break; if (byte == size) return (plen); for (bit = 7; bit != 0; bit--, plen++) - if (!(name[byte] & (1 << bit))) - break; - for (; bit != 0; bit--) - if (name[byte] & (1 << bit)) - return(0); - byte++; - for (; byte < size; byte++) - if (name[byte]) - return(0); - return (plen); + if (!(name[byte] & (1 << bit))) + break; + for (; bit != 0; bit--) + if (name[byte] & (1 << bit)) + return(0); + byte++; + for (; byte < size; byte++) + if (name[byte]) + return(0); + return (plen); } static char * @@ -464,13 +457,12 @@ in6_status_tunnel(int s) const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr; memset(&in6_ifr, 0, sizeof(in6_ifr)); - strncpy(in6_ifr.ifr_name, name, IFNAMSIZ); + strlcpy(in6_ifr.ifr_name, name, sizeof(in6_ifr.ifr_name)); if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0) return; if (sa->sa_family != AF_INET6) return; - in6_fillscopeid(&in6_ifr.ifr_addr); if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, NI_NUMERICHOST) != 0) src[0] = '\0'; @@ -479,7 +471,6 @@ in6_status_tunnel(int s) return; if (sa->sa_family != AF_INET6) return; - in6_fillscopeid(&in6_ifr.ifr_addr); if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, NI_NUMERICHOST) != 0) dst[0] = '\0'; @@ -493,7 +484,7 @@ in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) struct in6_aliasreq in6_addreq; memset(&in6_addreq, 0, sizeof(in6_addreq)); - strncpy(in6_addreq.ifra_name, name, IFNAMSIZ); + strlcpy(in6_addreq.ifra_name, name, sizeof(in6_addreq.ifra_name)); memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr, dstres->ai_addr->sa_len); @@ -527,6 +518,8 @@ static struct cmd inet6_cmds[] = { DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags), DEF_CMD("no_prefer_iface",ND6_IFF_NO_PREFER_IFACE,setnd6flags), DEF_CMD("-no_prefer_iface",-ND6_IFF_NO_PREFER_IFACE,setnd6flags), + DEF_CMD("no_dad", ND6_IFF_NO_DAD, setnd6flags), + DEF_CMD("-no_dad", -ND6_IFF_NO_DAD, setnd6flags), DEF_CMD_ARG("pltime", setip6pltime), DEF_CMD_ARG("vltime", setip6vltime), DEF_CMD("eui64", 0, setip6eui64), @@ -553,7 +546,11 @@ in6_Lopt_cb(const char *optarg __unused) { ip6lifetime++; /* print IPv6 address lifetime */ } -static struct option in6_Lopt = { .opt = "L", .opt_usage = "[-L]", .cb = in6_Lopt_cb }; +static struct option in6_Lopt = { + .opt = "L", + .opt_usage = "[-L]", + .cb = in6_Lopt_cb +}; #ifndef __rtems__ static __constructor void @@ -562,16 +559,6 @@ void #endif /* __rtems__ */ inet6_ctor(void) { -#ifdef __rtems__ - memset(&in6_ridreq, 0, sizeof(in6_ridreq)); - memset(&in6_addreq, 0, sizeof(in6_addreq)); - in6_addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; - in6_addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; - ip6lifetime = 0; - explicit_prefix = 0; - memset(&addr_buf, 0, sizeof(addr_buf)); -#endif /* __rtems__ */ -#define N(a) (sizeof(a) / sizeof(a[0])) size_t i; #ifndef RESCUE @@ -579,9 +566,8 @@ inet6_ctor(void) return; #endif - for (i = 0; i < N(inet6_cmds); i++) + for (i = 0; i < nitems(inet6_cmds); i++) cmd_register(&inet6_cmds[i]); af_register(&af_inet6); opt_register(&in6_Lopt); -#undef N } diff --git a/freebsd/sbin/ifconfig/af_link.c b/freebsd/sbin/ifconfig/af_link.c index ffd92e30..1c37496e 100644 --- a/freebsd/sbin/ifconfig/af_link.c +++ b/freebsd/sbin/ifconfig/af_link.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. @@ -34,6 +38,9 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -50,23 +57,35 @@ static const char rcsid[] = #include <net/ethernet.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-af_link-data.h" +#endif /* __rtems__ */ static struct ifreq link_ridreq; +extern char *f_ether; + static void link_status(int s __unused, const struct ifaddrs *ifa) { /* XXX no const 'cuz LLADDR is defined wrong */ struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr; + char *ether_format, *format_char; if (sdl != NULL && sdl->sdl_alen > 0) { if ((sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_L2VLAN || sdl->sdl_type == IFT_BRIDGE) && - sdl->sdl_alen == ETHER_ADDR_LEN) - printf("\tether %s\n", - ether_ntoa((struct ether_addr *)LLADDR(sdl))); - else { + sdl->sdl_alen == ETHER_ADDR_LEN) { + ether_format = ether_ntoa((struct ether_addr *)LLADDR(sdl)); + if (f_ether != NULL && strcmp(f_ether, "dash") == 0) { + for (format_char = strchr(ether_format, ':'); + format_char != NULL; + format_char = strchr(ether_format, ':')) + *format_char = '-'; + } + printf("\tether %s\n", ether_format); + } else { int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; printf("\tlladdr %s\n", link_ntoa(sdl) + n); @@ -129,9 +148,6 @@ void #endif /* __rtems__ */ link_ctor(void) { -#ifdef __rtems__ - memset(&link_ridreq, 0, sizeof(link_ridreq)); -#endif /* __rtems__ */ af_register(&af_link); af_register(&af_ether); af_register(&af_lladdr); diff --git a/freebsd/sbin/ifconfig/af_nd6.c b/freebsd/sbin/ifconfig/af_nd6.c index a1e930b0..ac302c65 100644 --- a/freebsd/sbin/ifconfig/af_nd6.c +++ b/freebsd/sbin/ifconfig/af_nd6.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 2009 Hiroki Sato. All rights reserved. * @@ -30,6 +34,9 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -48,7 +55,6 @@ static const char rcsid[] = #include <arpa/inet.h> #include <netinet/in.h> -#include <net/if_var.h> #include <netinet/in_var.h> #include <arpa/inet.h> #include <netdb.h> @@ -56,11 +62,15 @@ static const char rcsid[] = #include <netinet6/nd6.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-af_nd6-data.h" +#endif /* __rtems__ */ #define MAX_SYSCTL_TRY 5 #define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \ "\004IFDISABLED\005DONT_SET_IFROUTE\006AUTO_LINKLOCAL" \ - "\007NO_RADR\010NO_PREFER_IFACE\020DEFAULTIF" + "\007NO_RADR\010NO_PREFER_IFACE\011IGNORELOOP\012NO_DAD" \ + "\020DEFAULTIF" static int isnd6defif(int); void setnd6flags(const char *, int, int, const struct afswtch *); @@ -76,7 +86,7 @@ setnd6flags(const char *dummyaddr __unused, int error; memset(&nd, 0, sizeof(nd)); - strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); + strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); error = ioctl(s, SIOCGIFINFO_IN6, &nd); if (error) { warn("ioctl(SIOCGIFINFO_IN6)"); @@ -101,7 +111,7 @@ setnd6defif(const char *dummyaddr __unused, int error; memset(&ndifreq, 0, sizeof(ndifreq)); - strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname)); + strlcpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname)); if (d < 0) { if (isnd6defif(s)) { @@ -128,7 +138,7 @@ isnd6defif(int s) int error; memset(&ndifreq, 0, sizeof(ndifreq)); - strncpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname)); + strlcpy(ndifreq.ifname, ifr.ifr_name, sizeof(ndifreq.ifname)); ifindex = if_nametoindex(ndifreq.ifname); error = ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq); @@ -148,7 +158,7 @@ nd6_status(int s) int isdefif; memset(&nd, 0, sizeof(nd)); - strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); + strlcpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname)); if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { if (errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT) warn("socket(AF_INET6, SOCK_DGRAM)"); diff --git a/freebsd/sbin/ifconfig/ifbridge.c b/freebsd/sbin/ifconfig/ifbridge.c index 9a4d868d..26412a02 100644 --- a/freebsd/sbin/ifconfig/ifbridge.c +++ b/freebsd/sbin/ifconfig/ifbridge.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /*- * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. @@ -40,6 +44,9 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -62,6 +69,9 @@ static const char rcsid[] = #include <errno.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifbridge-data.h" +#endif /* __rtems__ */ #define PV2ID(pv, epri, eaddr) do { \ epri = pv >> 48; \ @@ -73,7 +83,7 @@ static const char rcsid[] = eaddr[5] = pv >> 0; \ } while (0) -static const char *const stpstates[] = { +static const char *stpstates[] = { "disabled", "listening", "learning", @@ -81,12 +91,12 @@ static const char *const stpstates[] = { "blocking", "discarding" }; -static const char *const stpproto[] = { +static const char *stpproto[] = { "stp", "-", "rstp" }; -static const char *const stproles[] = { +static const char *stproles[] = { "disabled", "root", "designated", @@ -157,7 +167,11 @@ bridge_interfaces(int s, const char *prefix) err(1, "strdup"); /* replace the prefix with whitespace */ for (p = pad; *p != '\0'; p++) { +#ifndef __rtems__ + if(isprint(*p)) +#else /* __rtems__ */ if(isprint((unsigned char)*p)) +#endif /* __rtems__ */ *p = ' '; } @@ -187,22 +201,19 @@ bridge_interfaces(int s, const char *prefix) printf(" path cost %u", req->ifbr_path_cost); if (req->ifbr_ifsflags & IFBIF_STP) { - if (req->ifbr_proto < - sizeof(stpproto) / sizeof(stpproto[0])) + if (req->ifbr_proto < nitems(stpproto)) printf(" proto %s", stpproto[req->ifbr_proto]); else printf(" <unknown proto %d>", req->ifbr_proto); printf("\n%s", pad); - if (req->ifbr_role < - sizeof(stproles) / sizeof(stproles[0])) + if (req->ifbr_role < nitems(stproles)) printf("role %s", stproles[req->ifbr_role]); else printf("<unknown role %d>", req->ifbr_role); - if (req->ifbr_state < - sizeof(stpstates) / sizeof(stpstates[0])) + if (req->ifbr_state < nitems(stpstates)) printf(" state %s", stpstates[req->ifbr_state]); else printf(" <unknown state %d>", @@ -755,11 +766,9 @@ void #endif /* __rtems__ */ bridge_ctor(void) { -#define N(a) (sizeof(a) / sizeof(a[0])) int i; - for (i = 0; i < N(bridge_cmds); i++) + for (i = 0; i < nitems(bridge_cmds); i++) cmd_register(&bridge_cmds[i]); af_register(&af_bridge); -#undef N } diff --git a/freebsd/sbin/ifconfig/ifcarp.c b/freebsd/sbin/ifconfig/ifcarp.c index d0f3616d..61e3fa36 100644 --- a/freebsd/sbin/ifconfig/ifcarp.c +++ b/freebsd/sbin/ifconfig/ifcarp.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* $FreeBSD$ */ /* from $OpenBSD: ifconfig.c,v 1.82 2003/10/19 05:43:35 mcbride Exp $ */ @@ -29,6 +33,9 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -51,6 +58,9 @@ #include <errno.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifcarp-data.h" +#endif /* __rtems__ */ static const char *const carp_states[] = { CARP_STATES }; diff --git a/freebsd/sbin/ifconfig/ifclone.c b/freebsd/sbin/ifconfig/ifclone.c index 8fb9d6c3..6dcd344c 100644 --- a/freebsd/sbin/ifconfig/ifclone.c +++ b/freebsd/sbin/ifconfig/ifclone.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. @@ -35,20 +39,11 @@ static const char rcsid[] = #endif /* not lint */ #ifdef __rtems__ -#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP -#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP #include <machine/rtems-bsd-program.h> #endif /* __rtems__ */ -#include <sys/queue.h> -#include <sys/types.h> +#include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> +#include <sys/queue.h> #include <sys/socket.h> #include <net/if.h> @@ -59,6 +54,9 @@ static const char rcsid[] = #include <unistd.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifclone-data.h" +#endif /* __rtems__ */ static void list_cloners(void) @@ -84,10 +82,8 @@ list_cloners(void) ifcr.ifcr_count = ifcr.ifcr_total; ifcr.ifcr_buffer = buf; - if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) { - free(buf); + if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) err(1, "SIOCIFGCLONERS for names"); - } /* * In case some disappeared in the mean time, clamp it down. @@ -111,7 +107,11 @@ struct clone_defcb { SLIST_ENTRY(clone_defcb) next; }; +#ifndef __rtems__ static SLIST_HEAD(, clone_defcb) clone_defcbh = +#else /* __rtems__ */ +static SLIST_HEAD(clone_defcb_list, clone_defcb) clone_defcbh = +#endif /* __rtems__ */ SLIST_HEAD_INITIALIZER(clone_defcbh); void @@ -165,11 +165,12 @@ ifclonecreate(int s, void *arg) } /* - * If we get a different name back than we put in, print it. + * If we get a different name back than we put in, update record and + * indicate it should be printed later. */ if (strncmp(name, ifr.ifr_name, sizeof(name)) != 0) { strlcpy(name, ifr.ifr_name, sizeof(name)); - printf("%s\n", name); + printifname = 1; } } @@ -182,7 +183,7 @@ DECL_CMD_FUNC(clone_create, arg, d) static DECL_CMD_FUNC(clone_destroy, arg, d) { - (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) err(1, "SIOCIFDESTROY"); } @@ -209,26 +210,9 @@ void #endif /* __rtems__ */ clone_ctor(void) { -#ifdef __rtems__ - SLIST_INIT(&clone_defcbh); -#endif /* __rtems__ */ -#define N(a) (sizeof(a) / sizeof(a[0])) size_t i; - for (i = 0; i < N(clone_cmds); i++) + for (i = 0; i < nitems(clone_cmds); i++) cmd_register(&clone_cmds[i]); opt_register(&clone_Copt); -#undef N } -#ifdef __rtems__ -void -clone_dtor(void) -{ - struct clone_defcb *dcp; - struct clone_defcb *dcp_tmp; - - SLIST_FOREACH_SAFE(dcp, &clone_defcbh, next, dcp_tmp) { - free(dcp); - } -} -#endif /* __rtems__ */ diff --git a/freebsd/sbin/ifconfig/ifconfig.c b/freebsd/sbin/ifconfig/ifconfig.c index 041e53d0..ad199be8 100644 --- a/freebsd/sbin/ifconfig/ifconfig.c +++ b/freebsd/sbin/ifconfig/ifconfig.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. @@ -48,28 +52,19 @@ static const char rcsid[] = #define option getopt_option #include <getopt.h> #undef option -#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP -#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP #include <machine/rtems-bsd-program.h> #include <machine/rtems-bsd-commands.h> #endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> -#include <sys/socket.h> -#include <sys/time.h> #include <sys/module.h> #include <sys/linker.h> +#include <sys/queue.h> +#include <sys/socket.h> +#include <sys/time.h> #include <net/ethernet.h> #include <net/if.h> -#include <net/if_var.h> #include <net/if_dl.h> #include <net/if_types.h> #include <net/route.h> @@ -85,13 +80,18 @@ static const char rcsid[] = #include <err.h> #include <errno.h> #include <fcntl.h> +#ifdef JAIL #include <jail.h> +#endif #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifconfig-data.h" +#endif /* __rtems__ */ /* * Since "struct ifreq" is composed of various union members, callers @@ -110,10 +110,14 @@ int clearaddr; int newaddr = 1; int verbose; int noload; +int printifname = 0; int supmedia = 0; int printkeys = 0; /* Print keying material for interfaces. */ +/* Formatter Strings */ +char *f_inet, *f_inet6, *f_ether, *f_addr; + static int ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *afp); static void status(const struct afswtch *afp, const struct sockaddr_dl *sdl, @@ -125,8 +129,19 @@ static struct afswtch *af_getbyname(const char *name); static struct afswtch *af_getbyfamily(int af); static void af_other_status(int); +void printifnamemaybe(void); + static struct option *opts = NULL; +struct ifa_order_elt { + int if_order; + int af_orders[255]; + struct ifaddrs *ifa; + TAILQ_ENTRY(ifa_order_elt) link; +}; + +TAILQ_HEAD(ifa_queue, ifa_order_elt); + void opt_register(struct option *p) { @@ -148,8 +163,8 @@ usage(void) } fprintf(stderr, - "usage: ifconfig %sinterface address_family [address [dest_address]]\n" - " [parameters]\n" + "usage: ifconfig [-f type:format] %sinterface address_family\n" + " [address [dest_address]] [parameters]\n" " ifconfig interface create\n" " ifconfig -a %s[-d] [-m] [-u] [-v] [address_family]\n" " ifconfig -l [-d] [-u] [address_family]\n" @@ -158,39 +173,241 @@ usage(void) exit(1); } +#define ORDERS_SIZE(x) sizeof(x) / sizeof(x[0]) + +static int +calcorders(struct ifaddrs *ifa, struct ifa_queue *q) +{ + struct ifaddrs *prev; + struct ifa_order_elt *cur; + unsigned int ord, af, ifa_ord; + + prev = NULL; + cur = NULL; + ord = 0; + ifa_ord = 0; + + while (ifa != NULL) { + if (prev == NULL || + strcmp(ifa->ifa_name, prev->ifa_name) != 0) { + cur = calloc(1, sizeof(*cur)); + + if (cur == NULL) + return (-1); + + TAILQ_INSERT_TAIL(q, cur, link); + cur->if_order = ifa_ord ++; + cur->ifa = ifa; + ord = 0; + } + + if (ifa->ifa_addr) { + af = ifa->ifa_addr->sa_family; + + if (af < ORDERS_SIZE(cur->af_orders) && + cur->af_orders[af] == 0) + cur->af_orders[af] = ++ord; + } + prev = ifa; + ifa = ifa->ifa_next; + } + + return (0); +} + +static int +cmpifaddrs(struct ifaddrs *a, struct ifaddrs *b, struct ifa_queue *q) +{ + struct ifa_order_elt *cur, *e1, *e2; + unsigned int af1, af2; + int ret; + + e1 = e2 = NULL; + + ret = strcmp(a->ifa_name, b->ifa_name); + if (ret != 0) { + TAILQ_FOREACH(cur, q, link) { + if (e1 && e2) + break; + + if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) + e1 = cur; + else if (strcmp(cur->ifa->ifa_name, b->ifa_name) == 0) + e2 = cur; + } + + if (!e1 || !e2) + return (0); + else + return (e1->if_order - e2->if_order); + + } else if (a->ifa_addr != NULL && b->ifa_addr != NULL) { + TAILQ_FOREACH(cur, q, link) { + if (strcmp(cur->ifa->ifa_name, a->ifa_name) == 0) { + e1 = cur; + break; + } + } + + if (!e1) + return (0); + + af1 = a->ifa_addr->sa_family; + af2 = b->ifa_addr->sa_family; + + if (af1 < ORDERS_SIZE(e1->af_orders) && + af2 < ORDERS_SIZE(e1->af_orders)) + return (e1->af_orders[af1] - e1->af_orders[af2]); + } + + return (0); +} + +static void freeformat(void) +{ + + if (f_inet != NULL) + free(f_inet); + if (f_inet6 != NULL) + free(f_inet6); + if (f_ether != NULL) + free(f_ether); + if (f_addr != NULL) + free(f_addr); +} + +static void setformat(char *input) +{ + char *formatstr, *category, *modifier; + + formatstr = strdup(input); + while ((category = strsep(&formatstr, ",")) != NULL) { + modifier = strchr(category, ':'); + if (modifier == NULL || modifier[1] == '\0') { + warnx("Skipping invalid format specification: %s\n", + category); + continue; + } + + /* Split the string on the separator, then seek past it */ + modifier[0] = '\0'; + modifier++; + + if (strcmp(category, "addr") == 0) + f_addr = strdup(modifier); + else if (strcmp(category, "ether") == 0) + f_ether = strdup(modifier); + else if (strcmp(category, "inet") == 0) + f_inet = strdup(modifier); + else if (strcmp(category, "inet6") == 0) + f_inet6 = strdup(modifier); + } + free(formatstr); +} + +#undef ORDERS_SIZE + +static struct ifaddrs * +sortifaddrs(struct ifaddrs *list, + int (*compare)(struct ifaddrs *, struct ifaddrs *, struct ifa_queue *), + struct ifa_queue *q) +{ + struct ifaddrs *right, *temp, *last, *result, *next, *tail; + + right = list; + temp = list; + last = list; + result = NULL; + next = NULL; + tail = NULL; + + if (!list || !list->ifa_next) + return (list); + + while (temp && temp->ifa_next) { + last = right; + right = right->ifa_next; + temp = temp->ifa_next->ifa_next; + } + + last->ifa_next = NULL; + + list = sortifaddrs(list, compare, q); + right = sortifaddrs(right, compare, q); + + while (list || right) { + + if (!right) { + next = list; + list = list->ifa_next; + } else if (!list) { + next = right; + right = right->ifa_next; + } else if (compare(list, right, q) <= 0) { + next = list; + list = list->ifa_next; + } else { + next = right; + right = right->ifa_next; + } + + if (!result) + result = next; + else + tail->ifa_next = next; + + tail = next; + } + + return (result); +} + +void printifnamemaybe() +{ + if (printifname) + printf("%s\n", name); +} + #ifdef __rtems__ static void ifconfig_ctor(void); -static void ifconfig_dtor(void); static int main(int argc, char *argv[]); -int rtems_bsd_command_ifconfig(int argc, char *argv[]) +static int +mainwrapper(int argc, char *argv[]) { - int exit_code; - - rtems_bsd_program_lock(); - ifconfig_ctor(); - bridge_ctor(); - carp_ctor(); clone_ctor(); gif_ctor(); gre_ctor(); group_ctor(); ifmedia_ctor(); - inet_ctor(); inet6_ctor(); + inet_ctor(); lagg_ctor(); link_ctor(); mac_ctor(); pfsync_ctor(); vlan_ctor(); - exit_code = rtems_bsd_program_call_main("ifconfig", main, argc, argv); + return main(argc, argv); +} + +RTEMS_LINKER_RWSET(bsd_prog_ifconfig, char); + +int +rtems_bsd_command_ifconfig(int argc, char *argv[]) +{ + int exit_code; + const void *data_begin; + size_t data_size; - clone_dtor(); - ifconfig_dtor(); + data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_ifconfig); + data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_ifconfig); + rtems_bsd_program_lock(); + exit_code = rtems_bsd_program_call_main_with_data_restore("ifconfig", + mainwrapper, argc, argv, data_begin, data_size); rtems_bsd_program_unlock(); return exit_code; @@ -202,10 +419,12 @@ main(int argc, char *argv[]) int c, all, namesonly, downonly, uponly; const struct afswtch *afp = NULL; int ifindex; - struct ifaddrs *ifap, *ifa; + struct ifaddrs *ifap, *sifap, *ifa; struct ifreq paifr; const struct sockaddr_dl *sdl; - char options[1024], *cp, *namecp = NULL; + char options[1024], *cp, *envformat, *namecp = NULL; + struct ifa_queue q = TAILQ_HEAD_INITIALIZER(q); + struct ifa_order_elt *cur, *tmp; const char *ifname; struct option *p; size_t iflen; @@ -220,12 +439,23 @@ main(int argc, char *argv[]) #endif /* __rtems__ */ all = downonly = uponly = namesonly = noload = verbose = 0; + f_inet = f_inet6 = f_ether = f_addr = NULL; + + envformat = getenv("IFCONFIG_FORMAT"); + if (envformat != NULL) + setformat(envformat); + + /* + * Ensure we print interface name when expected to, + * even if we terminate early due to error. + */ + atexit(printifnamemaybe); /* Parse leading line options */ #ifndef __rtems__ - strlcpy(options, "adklmnuv", sizeof(options)); + strlcpy(options, "f:adklmnuv", sizeof(options)); #else /* __rtems__ */ - strlcpy(options, "+adklmnuv", sizeof(options)); + strlcpy(options, "+f:adklmnuv", sizeof(options)); #endif /* __rtems__ */ for (p = opts; p != NULL; p = p->next) strlcat(options, p->opt, sizeof(options)); @@ -237,6 +467,11 @@ main(int argc, char *argv[]) case 'd': /* restrict scan to "down" interfaces */ downonly++; break; + case 'f': + if (optarg == NULL) + usage(); + setformat(optarg); + break; case 'k': printkeys++; break; @@ -325,6 +560,7 @@ main(int argc, char *argv[]) ifconfig(argc, argv, 1, NULL); exit(0); } +#ifdef JAIL /* * NOTE: We have to special-case the `-vnet' command * right here as we would otherwise fail when trying @@ -338,6 +574,7 @@ main(int argc, char *argv[]) ifconfig(argc, argv, 0, NULL); exit(0); } +#endif errx(1, "interface %s does not exist", ifname); } } @@ -351,11 +588,21 @@ main(int argc, char *argv[]) if (getifaddrs(&ifap) != 0) err(EXIT_FAILURE, "getifaddrs"); + cp = NULL; + + if (calcorders(ifap, &q) != 0) + err(EXIT_FAILURE, "calcorders"); + + sifap = sortifaddrs(ifap, cmpifaddrs, &q); + + TAILQ_FOREACH_SAFE(cur, &q, link, tmp) + free(cur); + ifindex = 0; - for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + for (ifa = sifap; ifa; ifa = ifa->ifa_next) { memset(&paifr, 0, sizeof(paifr)); - strncpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name)); + strlcpy(paifr.ifr_name, ifa->ifa_name, sizeof(paifr.ifr_name)); if (sizeof(paifr.ifr_addr) >= ifa->ifa_addr->sa_len) { memcpy(&paifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len); @@ -399,7 +646,8 @@ main(int argc, char *argv[]) sdl->sdl_alen != ETHER_ADDR_LEN) continue; } else { - if (ifa->ifa_addr->sa_family != afp->af_af) + if (ifa->ifa_addr->sa_family + != afp->af_af) continue; } } @@ -421,6 +669,7 @@ main(int argc, char *argv[]) printf("\n"); freeifaddrs(ifap); + freeformat(); exit(0); } @@ -501,7 +750,6 @@ cmd_register(struct cmd *p) static const struct cmd * cmd_lookup(const char *name, int iscreate) { -#define N(a) (sizeof(a)/sizeof(a[0])) const struct cmd *p; for (p = cmds; p != NULL; p = p->c_next) @@ -515,7 +763,6 @@ cmd_lookup(const char *name, int iscreate) } } return NULL; -#undef N } struct callback { @@ -555,7 +802,7 @@ ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp) struct callback *cb; int s; - strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name); + strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name); afp = NULL; if (uafp != NULL) afp = uafp; @@ -586,7 +833,7 @@ top: AF_LOCAL : afp->af_af; if ((s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0)) < 0 && - (uafp != NULL || errno != EPROTONOSUPPORT || + (uafp != NULL || errno != EAFNOSUPPORT || (s = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0)) err(1, "socket(family %u,SOCK_DGRAM", ifr.ifr_addr.sa_family); @@ -676,7 +923,8 @@ top: } if (clearaddr) { int ret; - strncpy(afp->af_ridreq, name, sizeof ifr.ifr_name); + strlcpy(((struct ifreq *)afp->af_ridreq)->ifr_name, name, + sizeof ifr.ifr_name); ret = ioctl(s, afp->af_difaddr, afp->af_ridreq); if (ret < 0) { if (errno == EADDRNOTAVAIL && (doalias >= 0)) { @@ -693,7 +941,8 @@ top: } } if (newaddr && (setaddr || setmask)) { - strncpy(afp->af_addreq, name, sizeof ifr.ifr_name); + strlcpy(((struct ifreq *)afp->af_addreq)->ifr_name, name, + sizeof ifr.ifr_name); if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0) Perror("ioctl (SIOCAIFADDR)"); } @@ -735,7 +984,7 @@ settunnel(const char *src, const char *dst, int s, const struct afswtch *afp) errx(1, "error in parsing address string: %s", gai_strerror(ecode)); - if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) + if ((ecode = getaddrinfo(dst, NULL, NULL, &dstres)) != 0) errx(1, "error in parsing address string: %s", gai_strerror(ecode)); @@ -758,7 +1007,7 @@ deletetunnel(const char *vname, int param, int s, const struct afswtch *afp) err(1, "SIOCDIFPHYADDR"); } -#ifndef __rtems__ +#ifdef JAIL static void setifvnet(const char *jname, int dummy __unused, int s, const struct afswtch *afp) @@ -786,7 +1035,7 @@ setifrvnet(const char *jname, int dummy __unused, int s, if (ioctl(s, SIOCSIFRVNET, &my_ifr) < 0) err(1, "SIOCSIFRVNET(%d, %s)", my_ifr.ifr_jid, my_ifr.ifr_name); } -#endif /* __rtems__ */ +#endif static void setifnetmask(const char *addr, int dummy __unused, int s, @@ -807,20 +1056,6 @@ setifbroadaddr(const char *addr, int dummy __unused, int s, } static void -setifipdst(const char *addr, int dummy __unused, int s, - const struct afswtch *afp) -{ - const struct afswtch *inet; - - inet = af_getbyname("inet"); - if (inet == NULL) - return; - inet->af_getaddr(addr, DSTADDR); - clearaddr = 0; - newaddr = 0; -} - -static void notealias(const char *addr, int param, int s, const struct afswtch *afp) { #define rqtosa(x) (&(((struct ifreq *)(afp->x))->ifr_addr)) @@ -903,20 +1138,20 @@ static void setifmetric(const char *val, int dummy __unused, int s, const struct afswtch *afp) { - strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_metric = atoi(val); if (ioctl(s, SIOCSIFMETRIC, (caddr_t)&ifr) < 0) - warn("ioctl (set metric)"); + err(1, "ioctl SIOCSIFMETRIC (set metric)"); } static void setifmtu(const char *val, int dummy __unused, int s, const struct afswtch *afp) { - strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_mtu = atoi(val); if (ioctl(s, SIOCSIFMTU, (caddr_t)&ifr) < 0) - warn("ioctl (set mtu)"); + err(1, "ioctl SIOCSIFMTU (set mtu)"); } static void @@ -924,18 +1159,18 @@ setifname(const char *val, int dummy __unused, int s, const struct afswtch *afp) { char *newname; + + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); newname = strdup(val); - if (newname == NULL) { - warn("no memory to set ifname"); - return; - } + if (newname == NULL) + err(1, "no memory to set ifname"); ifr.ifr_data = newname; if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) { - warn("ioctl (set name)"); free(newname); - return; + err(1, "ioctl SIOCSIFNAME (set name)"); } + printifname = 1; strlcpy(name, newname, sizeof(name)); free(newname); } @@ -947,6 +1182,8 @@ setifdescr(const char *val, int dummy __unused, int s, { char *newdescr; + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_buffer.length = strlen(val) + 1; if (ifr.ifr_buffer.length == 1) { ifr.ifr_buffer.buffer = newdescr = NULL; @@ -961,7 +1198,7 @@ setifdescr(const char *val, int dummy __unused, int s, } if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) - warn("ioctl (set descr)"); + err(1, "ioctl SIOCSIFDESCR (set descr)"); free(newdescr); } @@ -975,7 +1212,7 @@ unsetifdescr(const char *val, int value, int s, const struct afswtch *afp) } #define IFFBITS \ -"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6SMART\7RUNNING" \ +"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \ "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \ "\20MULTICAST\22PPROMISC\23MONITOR\24STATICARP" @@ -1009,7 +1246,7 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, ifr.ifr_addr.sa_family = afp->af_af == AF_LINK ? AF_LOCAL : afp->af_af; } - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0); if (s < 0) @@ -1091,10 +1328,13 @@ status(const struct afswtch *afp, const struct sockaddr_dl *sdl, else if (afp->af_other_status != NULL) afp->af_other_status(s); - strncpy(ifs.ifs_name, name, sizeof ifs.ifs_name); + strlcpy(ifs.ifs_name, name, sizeof ifs.ifs_name); if (ioctl(s, SIOCGIFSTATUS, &ifs) == 0) printf("%s", ifs.ascii); + if (verbose > 0) + sfp_status(s, &ifr, verbose); + close(s); return; } @@ -1155,6 +1395,21 @@ printb(const char *s, unsigned v, const char *bits) } void +print_vhid(const struct ifaddrs *ifa, const char *s) +{ + struct if_data *ifd; + + if (ifa->ifa_data == NULL) + return; + + ifd = ifa->ifa_data; + if (ifd->ifi_vhid == 0) + return; + + printf("vhid %d ", ifd->ifi_vhid); +} + +void ifmaybeload(const char *name) { #ifndef __rtems__ @@ -1177,9 +1432,8 @@ ifmaybeload(const char *name) } /* turn interface and unit into module name */ - strcpy(ifkind, "if_"); - strlcpy(ifkind + MOD_PREFIX_LEN, ifname, - sizeof(ifkind) - MOD_PREFIX_LEN); + strlcpy(ifkind, "if_", sizeof(ifkind)); + strlcat(ifkind, ifname, sizeof(ifkind)); /* scan files in kernel */ mstat.version = sizeof(struct module_stat); @@ -1196,8 +1450,8 @@ ifmaybeload(const char *name) cp = mstat.name; } /* already loaded? */ - if (strncmp(ifname, cp, strlen(ifname) + 1) == 0 || - strncmp(ifkind, cp, strlen(ifkind) + 1) == 0) + if (strcmp(ifname, cp) == 0 || + strcmp(ifkind, cp) == 0) return; } } @@ -1233,14 +1487,13 @@ static struct cmd basic_cmds[] = { DEF_CMD_ARG("netmask", setifnetmask), DEF_CMD_ARG("metric", setifmetric), DEF_CMD_ARG("broadcast", setifbroadaddr), - DEF_CMD_ARG("ipdst", setifipdst), DEF_CMD_ARG2("tunnel", settunnel), DEF_CMD("-tunnel", 0, deletetunnel), DEF_CMD("deletetunnel", 0, deletetunnel), -#ifndef __rtems__ +#ifdef JAIL DEF_CMD_ARG("vnet", setifvnet), DEF_CMD_ARG("-vnet", setifrvnet), -#endif /* __rtems__ */ +#endif DEF_CMD("link0", IFF_LINK0, setifflags), DEF_CMD("-link0", -IFF_LINK0, setifflags), DEF_CMD("link1", IFF_LINK1, setifflags), @@ -1288,48 +1541,15 @@ static struct cmd basic_cmds[] = { DEF_CMD_ARG("name", setifname), }; +#ifndef __rtems__ static __constructor void +#else /* __rtems__ */ +static void +#endif /* __rtems__ */ ifconfig_ctor(void) { -#ifdef __rtems__ - memset(&ifr, 0, sizeof(ifr)); - memset(&name, 0, sizeof(name)); - descr = NULL; - descrlen = 64; - setaddr = 0; - setmask = 0; - doalias = 0; - clearaddr = 0; - newaddr = 1; - verbose = 0; - noload = 0; - supmedia = 0; - printkeys = 0; - opts = NULL; - afs = NULL; - callbacks = NULL; - cmds = NULL; -#endif /* __rtems__ */ -#define N(a) (sizeof(a) / sizeof(a[0])) size_t i; - for (i = 0; i < N(basic_cmds); i++) + for (i = 0; i < nitems(basic_cmds); i++) cmd_register(&basic_cmds[i]); -#undef N -} -#ifdef __rtems__ -static void -ifconfig_dtor(void) -{ - struct callback *cb = callbacks; - - while (cb != NULL) { - struct callback *to_free = cb; - - cb = to_free->cb_next; - free(to_free); - } - - free(descr); } -#endif /* __rtems__ */ diff --git a/freebsd/sbin/ifconfig/ifconfig.h b/freebsd/sbin/ifconfig/ifconfig.h index 074e810e..d9be9c7b 100644 --- a/freebsd/sbin/ifconfig/ifconfig.h +++ b/freebsd/sbin/ifconfig/ifconfig.h @@ -34,11 +34,7 @@ * $FreeBSD$ */ -#ifndef __rtems__ #define __constructor __attribute__((constructor)) -#else /* __rtems__ */ -#define __constructor -#endif /* __rtems__ */ struct afswtch; struct cmd; @@ -78,6 +74,7 @@ void callback_register(callback_func *, void *); #define DEF_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func }, 0, NULL } #define DEF_CLONE_CMD(name, param, func) { name, param, { .c_func = func }, 1, NULL } #define DEF_CLONE_CMD_ARG(name, func) { name, NEXTARG, { .c_func = func }, 1, NULL } +#define DEF_CLONE_CMD_ARG2(name, func) { name, NEXTARG2, { .c_func2 = func }, 1, NULL } struct ifaddrs; struct addrinfo; @@ -136,6 +133,7 @@ extern int supmedia; extern int printkeys; extern int newaddr; extern int verbose; +extern int printifname; void setifcap(const char *, int value, int s, const struct afswtch *); @@ -147,19 +145,23 @@ void ifmaybeload(const char *name); typedef void clone_callback_func(int, struct ifreq *); void clone_setdefcallback(const char *, clone_callback_func *); +void sfp_status(int s, struct ifreq *ifr, int verbose); + /* * XXX expose this so modules that neeed to know of any pending * operations on ifmedia can avoid cmd line ordering confusion. */ struct ifmediareq *ifmedia_getstate(int s); + +void print_vhid(const struct ifaddrs *, const char *); #ifdef __rtems__ -void atalk_ctor(void); void bridge_ctor(void); void carp_ctor(void); void clone_ctor(void); void gif_ctor(void); void gre_ctor(void); void group_ctor(void); +void ieee80211_ctor(void); void ifmedia_ctor(void); void inet6_ctor(void); void inet_ctor(void); @@ -169,5 +171,6 @@ void mac_ctor(void); void pfsync_ctor(void); void vlan_ctor(void); -void clone_dtor(void); +/* Necessary for struct ifmedia_description */ +#include <if_media.h> #endif /* __rtems__ */ diff --git a/freebsd/sbin/ifconfig/ifgif.c b/freebsd/sbin/ifconfig/ifgif.c index e55933a5..c13a0506 100644 --- a/freebsd/sbin/ifconfig/ifgif.c +++ b/freebsd/sbin/ifconfig/ifgif.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /*- * Copyright (c) 2009 Hiroki Sato. All rights reserved. * @@ -30,6 +34,9 @@ static const char rcsid[] = "$FreeBSD$"; #endif +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -52,8 +59,11 @@ static const char rcsid[] = #include <errno.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifgif-data.h" +#endif /* __rtems__ */ -#define GIFBITS "\020\1ACCEPT_REV_ETHIP_VER\5SEND_REV_ETHIP_VER" +#define GIFBITS "\020\2IGNORE_SOURCE" static void gif_status(int); @@ -72,8 +82,7 @@ gif_status(int s) } static void -setgifopts(const char *val, - int d, int s, const struct afswtch *afp) +setgifopts(const char *val, int d, int s, const struct afswtch *afp) { int opts; @@ -95,10 +104,8 @@ setgifopts(const char *val, } static struct cmd gif_cmds[] = { - DEF_CMD("accept_rev_ethip_ver", GIF_ACCEPT_REVETHIP, setgifopts), - DEF_CMD("-accept_rev_ethip_ver",-GIF_ACCEPT_REVETHIP, setgifopts), - DEF_CMD("send_rev_ethip_ver", GIF_SEND_REVETHIP, setgifopts), - DEF_CMD("-send_rev_ethip_ver", -GIF_SEND_REVETHIP, setgifopts), + DEF_CMD("ignore_source", GIF_IGNORE_SOURCE, setgifopts), + DEF_CMD("-ignore_source", -GIF_IGNORE_SOURCE, setgifopts), }; static struct afswtch af_gif = { @@ -114,11 +121,9 @@ void #endif /* __rtems__ */ gif_ctor(void) { -#define N(a) (sizeof(a) / sizeof(a[0])) size_t i; - for (i = 0; i < N(gif_cmds); i++) + for (i = 0; i < nitems(gif_cmds); i++) cmd_register(&gif_cmds[i]); af_register(&af_gif); -#undef N } diff --git a/freebsd/sbin/ifconfig/ifgre.c b/freebsd/sbin/ifconfig/ifgre.c index 221371f6..6f72a89e 100644 --- a/freebsd/sbin/ifconfig/ifgre.c +++ b/freebsd/sbin/ifconfig/ifgre.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /*- * Copyright (c) 2008 Andrew Thompson. All rights reserved. * @@ -25,61 +29,92 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <sys/sockio.h> - -#include <stdlib.h> -#include <unistd.h> - -#include <net/ethernet.h> #include <net/if.h> #include <net/if_gre.h> -#include <net/route.h> #include <ctype.h> +#include <limits.h> #include <stdio.h> -#include <string.h> #include <stdlib.h> -#include <unistd.h> +#include <string.h> #include <err.h> -#include <errno.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifgre-data.h" +#endif /* __rtems__ */ + +#define GREBITS "\020\01ENABLE_CSUM\02ENABLE_SEQ" static void gre_status(int s); static void gre_status(int s) { - int grekey = 0; + uint32_t opts = 0; - ifr.ifr_data = (caddr_t)&grekey; + ifr.ifr_data = (caddr_t)&opts; if (ioctl(s, GREGKEY, &ifr) == 0) - if (grekey != 0) - printf("\tgrekey: %d\n", grekey); + if (opts != 0) + printf("\tgrekey: 0x%x (%u)\n", opts, opts); + opts = 0; + if (ioctl(s, GREGOPTS, &ifr) != 0 || opts == 0) + return; + printb("\toptions", opts, GREBITS); + putchar('\n'); } static void setifgrekey(const char *val, int dummy __unused, int s, const struct afswtch *afp) { - uint32_t grekey = atol(val); + uint32_t grekey = strtol(val, NULL, 0); - strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof (ifr.ifr_name)); ifr.ifr_data = (caddr_t)&grekey; if (ioctl(s, GRESKEY, (caddr_t)&ifr) < 0) warn("ioctl (set grekey)"); } +static void +setifgreopts(const char *val, int d, int s, const struct afswtch *afp) +{ + uint32_t opts; + + ifr.ifr_data = (caddr_t)&opts; + if (ioctl(s, GREGOPTS, &ifr) == -1) { + warn("ioctl(GREGOPTS)"); + return; + } + + if (d < 0) + opts &= ~(-d); + else + opts |= d; + + if (ioctl(s, GRESOPTS, &ifr) == -1) { + warn("ioctl(GIFSOPTS)"); + return; + } +} + + static struct cmd gre_cmds[] = { DEF_CMD_ARG("grekey", setifgrekey), + DEF_CMD("enable_csum", GRE_ENABLE_CSUM, setifgreopts), + DEF_CMD("-enable_csum",-GRE_ENABLE_CSUM,setifgreopts), + DEF_CMD("enable_seq", GRE_ENABLE_SEQ, setifgreopts), + DEF_CMD("-enable_seq",-GRE_ENABLE_SEQ, setifgreopts), }; static struct afswtch af_gre = { .af_name = "af_gre", @@ -94,11 +129,9 @@ void #endif /* __rtems__ */ gre_ctor(void) { -#define N(a) (sizeof(a) / sizeof(a[0])) size_t i; - for (i = 0; i < N(gre_cmds); i++) + for (i = 0; i < nitems(gre_cmds); i++) cmd_register(&gre_cmds[i]); af_register(&af_gre); -#undef N } diff --git a/freebsd/sbin/ifconfig/ifgroup.c b/freebsd/sbin/ifconfig/ifgroup.c index 444a1c22..0e19d4ae 100644 --- a/freebsd/sbin/ifconfig/ifgroup.c +++ b/freebsd/sbin/ifconfig/ifgroup.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /*- * Copyright (c) 2006 Max Laier. All rights reserved. * @@ -31,18 +35,9 @@ static const char rcsid[] = #endif /* not lint */ #ifdef __rtems__ -#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP -#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP #include <machine/rtems-bsd-program.h> #endif /* __rtems__ */ -#include <sys/types.h> +#include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> @@ -56,6 +51,9 @@ static const char rcsid[] = #include <unistd.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifgroup-data.h" +#endif /* __rtems__ */ /* ARGSUSED */ static void @@ -66,7 +64,12 @@ setifgroup(const char *group_name, int d, int s, const struct afswtch *rafp) memset(&ifgr, 0, sizeof(ifgr)); strlcpy(ifgr.ifgr_name, name, IFNAMSIZ); - if (group_name[0] && isdigit((unsigned char)group_name[strlen(group_name) - 1])) +#ifndef __rtems__ + if (group_name[0] && isdigit(group_name[strlen(group_name) - 1])) +#else /* __rtems__ */ + if (group_name[0] && isdigit( + (unsigned char)group_name[strlen(group_name) - 1])) +#endif /* __rtems__ */ errx(1, "setifgroup: group names may not end in a digit"); if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ) @@ -84,7 +87,12 @@ unsetifgroup(const char *group_name, int d, int s, const struct afswtch *rafp) memset(&ifgr, 0, sizeof(ifgr)); strlcpy(ifgr.ifgr_name, name, IFNAMSIZ); - if (group_name[0] && isdigit((unsigned char)group_name[strlen(group_name) - 1])) +#ifndef __rtems__ + if (group_name[0] && isdigit(group_name[strlen(group_name) - 1])) +#else /* __rtems__ */ + if (group_name[0] && isdigit( + (unsigned char)group_name[strlen(group_name) - 1])) +#endif /* __rtems__ */ errx(1, "unsetifgroup: group names may not end in a digit"); if (strlcpy(ifgr.ifgr_group, group_name, IFNAMSIZ) >= IFNAMSIZ) @@ -100,9 +108,6 @@ getifgroups(int s) struct ifgroupreq ifgr; struct ifg_req *ifg; - if (!verbose) - return; - memset(&ifgr, 0, sizeof(ifgr)); strlcpy(ifgr.ifgr_name, name, IFNAMSIZ); @@ -135,6 +140,8 @@ getifgroups(int s) } if (cnt) printf("\n"); + + free(ifgr.ifgr_groups); } static void @@ -151,7 +158,6 @@ printgroup(const char *groupname) bzero(&ifgr, sizeof(ifgr)); strlcpy(ifgr.ifgr_name, groupname, sizeof(ifgr.ifgr_name)); if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) { - close(s); if (errno == EINVAL || errno == ENOTTY || errno == ENOENT) exit(0); @@ -160,15 +166,10 @@ printgroup(const char *groupname) } len = ifgr.ifgr_len; - if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) { - close(s); + if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) err(1, "printgroup"); - } - if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) { - free(ifgr.ifgr_groups); - close(s); + if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) err(1, "SIOCGIFGMEMB"); - } for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); ifg++) { @@ -177,7 +178,6 @@ printgroup(const char *groupname) cnt++; } free(ifgr.ifgr_groups); - close(s); exit(0); } @@ -200,12 +200,10 @@ void #endif /* __rtems__ */ group_ctor(void) { -#define N(a) (sizeof(a) / sizeof(a[0])) int i; - for (i = 0; i < N(group_cmds); i++) + for (i = 0; i < nitems(group_cmds); i++) cmd_register(&group_cmds[i]); af_register(&af_group); opt_register(&group_gopt); -#undef N } diff --git a/freebsd/sbin/ifconfig/ifieee80211.c b/freebsd/sbin/ifconfig/ifieee80211.c index 29b49a5b..ead27e2b 100644 --- a/freebsd/sbin/ifconfig/ifieee80211.c +++ b/freebsd/sbin/ifconfig/ifieee80211.c @@ -1,3 +1,9 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* * Copyright 2001 The Aerospace Corporation. All rights reserved. * @@ -64,6 +70,9 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -98,6 +107,9 @@ #include "ifconfig.h" #include "regdomain.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifieee80211-data.h" +#endif /* __rtems__ */ #ifndef IEEE80211_FIXED_RATE_NONE #define IEEE80211_FIXED_RATE_NONE 0xff @@ -207,12 +219,22 @@ getchaninfo(int s) gethtconf(s); } +#ifdef __rtems__ +static struct regdata *getregdata_rdp = NULL; +#endif /* __rtems__ */ static struct regdata * getregdata(void) { +#ifndef __rtems__ static struct regdata *rdp = NULL; +#else /* __rtems__ */ + struct regdata *rdp = getregdata_rdp; +#endif /* __rtems__ */ if (rdp == NULL) { rdp = lib80211_alloc_regdata(); +#ifdef __rtems__ + getregdata_rdp = rdp; +#endif /* __rtems__ */ if (rdp == NULL) errx(-1, "missing or corrupted regdomain database"); } @@ -5269,7 +5291,11 @@ static struct afswtch af_ieee80211 = { .af_other_status = ieee80211_status, }; +#ifndef __rtems__ static __constructor void +#else /* __rtems__ */ +void +#endif /* __rtems__ */ ieee80211_ctor(void) { #define N(a) (sizeof(a) / sizeof(a[0])) diff --git a/freebsd/sbin/ifconfig/iflagg.c b/freebsd/sbin/ifconfig/iflagg.c index 56970e57..78f81fdb 100644 --- a/freebsd/sbin/ifconfig/iflagg.c +++ b/freebsd/sbin/ifconfig/iflagg.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /*- */ @@ -8,6 +12,9 @@ static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -19,6 +26,7 @@ static const char rcsid[] = #include <net/ethernet.h> #include <net/if.h> #include <net/if_lagg.h> +#include <net/ieee8023ad_lacp.h> #include <net/route.h> #include <ctype.h> @@ -30,6 +38,9 @@ static const char rcsid[] = #include <errno.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-iflagg-data.h" +#endif /* __rtems__ */ char lacpbuf[120]; /* LACP peer '[(a,a,a),(p,p,p)]' */ @@ -70,7 +81,7 @@ setlaggproto(const char *val, int d, int s, const struct afswtch *afp) bzero(&ra, sizeof(ra)); ra.ra_proto = LAGG_PROTO_MAX; - for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) { + for (i = 0; i < nitems(lpr); i++) { if (strcmp(val, lpr[i].lpr_name) == 0) { ra.ra_proto = lpr[i].lpr_proto; break; @@ -85,6 +96,63 @@ setlaggproto(const char *val, int d, int s, const struct afswtch *afp) } static void +setlaggflowidshift(const char *val, int d, int s, const struct afswtch *afp) +{ + struct lagg_reqopts ro; + + bzero(&ro, sizeof(ro)); + ro.ro_opts = LAGG_OPT_FLOWIDSHIFT; + strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname)); + ro.ro_flowid_shift = (int)strtol(val, NULL, 10); + if (ro.ro_flowid_shift & ~LAGG_OPT_FLOWIDSHIFT_MASK) + errx(1, "Invalid flowid_shift option: %s", val); + + if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0) + err(1, "SIOCSLAGGOPTS"); +} + +static void +setlaggrr_limit(const char *val, int d, int s, const struct afswtch *afp) +{ + struct lagg_reqopts ro; + + bzero(&ro, sizeof(ro)); + strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname)); + ro.ro_bkt = (int)strtol(val, NULL, 10); + + if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0) + err(1, "SIOCSLAGG"); +} + +static void +setlaggsetopt(const char *val, int d, int s, const struct afswtch *afp) +{ + struct lagg_reqopts ro; + + bzero(&ro, sizeof(ro)); + ro.ro_opts = d; + switch (ro.ro_opts) { + case LAGG_OPT_USE_FLOWID: + case -LAGG_OPT_USE_FLOWID: + case LAGG_OPT_LACP_STRICT: + case -LAGG_OPT_LACP_STRICT: + case LAGG_OPT_LACP_TXTEST: + case -LAGG_OPT_LACP_TXTEST: + case LAGG_OPT_LACP_RXTEST: + case -LAGG_OPT_LACP_RXTEST: + case LAGG_OPT_LACP_TIMEOUT: + case -LAGG_OPT_LACP_TIMEOUT: + break; + default: + err(1, "Invalid lagg option"); + } + strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname)); + + if (ioctl(s, SIOCSLAGGOPTS, &ro) != 0) + err(1, "SIOCSLAGGOPTS"); +} + +static void setlagghash(const char *val, int d, int s, const struct afswtch *afp) { struct lagg_reqflags rf; @@ -146,6 +214,7 @@ lagg_status(int s) struct lagg_protos lpr[] = LAGG_PROTOS; struct lagg_reqport rp, rpbuf[LAGG_MAX_PORTS]; struct lagg_reqall ra; + struct lagg_reqopts ro; struct lagg_reqflags rf; struct lacp_opreq *lp; const char *proto = "<unknown>"; @@ -153,6 +222,7 @@ lagg_status(int s) bzero(&rp, sizeof(rp)); bzero(&ra, sizeof(ra)); + bzero(&ro, sizeof(ro)); strlcpy(rp.rp_ifname, name, sizeof(rp.rp_ifname)); strlcpy(rp.rp_portname, name, sizeof(rp.rp_portname)); @@ -164,6 +234,9 @@ lagg_status(int s) ra.ra_size = sizeof(rpbuf); ra.ra_port = rpbuf; + strlcpy(ro.ro_ifname, name, sizeof(ro.ro_ifname)); + ioctl(s, SIOCGLAGGOPTS, &ro); + strlcpy(rf.rf_ifname, name, sizeof(rf.rf_ifname)); if (ioctl(s, SIOCGLAGGFLAGS, &rf) != 0) rf.rf_flags = 0; @@ -171,7 +244,7 @@ lagg_status(int s) if (ioctl(s, SIOCGLAGG, &ra) == 0) { lp = (struct lacp_opreq *)&ra.ra_lacpreq; - for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) { + for (i = 0; i < nitems(lpr); i++) { if (ra.ra_proto == lpr[i].lpr_proto) { proto = lpr[i].lpr_name; break; @@ -199,16 +272,29 @@ lagg_status(int s) if (isport) printf(" laggdev %s", rp.rp_ifname); putchar('\n'); - if (verbose && ra.ra_proto == LAGG_PROTO_LACP) - printf("\tlag id: %s\n", - lacp_format_peer(lp, "\n\t\t ")); + if (verbose) { + printf("\tlagg options:\n"); + printb("\t\tflags", ro.ro_opts, LAGG_OPT_BITS); + putchar('\n'); + printf("\t\tflowid_shift: %d\n", ro.ro_flowid_shift); + if (ra.ra_proto == LAGG_PROTO_ROUNDROBIN) + printf("\t\trr_limit: %d\n", ro.ro_bkt); + printf("\tlagg statistics:\n"); + printf("\t\tactive ports: %d\n", ro.ro_active); + printf("\t\tflapping: %u\n", ro.ro_flapping); + if (ra.ra_proto == LAGG_PROTO_LACP) { + printf("\tlag id: %s\n", + lacp_format_peer(lp, "\n\t\t ")); + } + } for (i = 0; i < ra.ra_ports; i++) { lp = (struct lacp_opreq *)&rpbuf[i].rp_lacpreq; printf("\tlaggport: %s ", rpbuf[i].rp_portname); printb("flags", rpbuf[i].rp_flags, LAGG_PORT_BITS); if (verbose && ra.ra_proto == LAGG_PROTO_LACP) - printf(" state=%X", lp->actor_state); + printb(" state", lp->actor_state, + LACP_STATE_BITS); putchar('\n'); if (verbose && ra.ra_proto == LAGG_PROTO_LACP) printf("\t\t%s\n", @@ -217,7 +303,7 @@ lagg_status(int s) if (0 /* XXX */) { printf("\tsupported aggregation protocols:\n"); - for (i = 0; i < (sizeof(lpr) / sizeof(lpr[0])); i++) + for (i = 0; i < nitems(lpr); i++) printf("\t\tlaggproto %s\n", lpr[i].lpr_name); } } @@ -228,6 +314,18 @@ static struct cmd lagg_cmds[] = { DEF_CMD_ARG("-laggport", unsetlaggport), DEF_CMD_ARG("laggproto", setlaggproto), DEF_CMD_ARG("lagghash", setlagghash), + DEF_CMD("use_flowid", LAGG_OPT_USE_FLOWID, setlaggsetopt), + DEF_CMD("-use_flowid", -LAGG_OPT_USE_FLOWID, setlaggsetopt), + DEF_CMD("lacp_strict", LAGG_OPT_LACP_STRICT, setlaggsetopt), + DEF_CMD("-lacp_strict", -LAGG_OPT_LACP_STRICT, setlaggsetopt), + DEF_CMD("lacp_txtest", LAGG_OPT_LACP_TXTEST, setlaggsetopt), + DEF_CMD("-lacp_txtest", -LAGG_OPT_LACP_TXTEST, setlaggsetopt), + DEF_CMD("lacp_rxtest", LAGG_OPT_LACP_RXTEST, setlaggsetopt), + DEF_CMD("-lacp_rxtest", -LAGG_OPT_LACP_RXTEST, setlaggsetopt), + DEF_CMD("lacp_fast_timeout", LAGG_OPT_LACP_TIMEOUT, setlaggsetopt), + DEF_CMD("-lacp_fast_timeout", -LAGG_OPT_LACP_TIMEOUT, setlaggsetopt), + DEF_CMD_ARG("flowid_shift", setlaggflowidshift), + DEF_CMD_ARG("rr_limit", setlaggrr_limit), }; static struct afswtch af_lagg = { .af_name = "af_lagg", @@ -242,14 +340,9 @@ void #endif /* __rtems__ */ lagg_ctor(void) { -#ifdef __rtems__ - memset(&lacpbuf, 0, sizeof(lacpbuf)); -#endif /* __rtems__ */ -#define N(a) (sizeof(a) / sizeof(a[0])) int i; - for (i = 0; i < N(lagg_cmds); i++) + for (i = 0; i < nitems(lagg_cmds); i++) cmd_register(&lagg_cmds[i]); af_register(&af_lagg); -#undef N } diff --git a/freebsd/sbin/ifconfig/ifmac.c b/freebsd/sbin/ifconfig/ifmac.c index a64a0cbf..b9aa5eed 100644 --- a/freebsd/sbin/ifconfig/ifmac.c +++ b/freebsd/sbin/ifconfig/ifmac.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /*- * Copyright (c) 2001 Networks Associates Technology, Inc. * All rights reserved. @@ -36,6 +40,9 @@ * $FreeBSD$ */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/mac.h> @@ -50,6 +57,9 @@ #include <string.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifmac-data.h" +#endif /* __rtems__ */ static void maclabel_status(int s) @@ -59,7 +69,7 @@ maclabel_status(int s) char *label_text; memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (mac_prepare_ifnet_label(&label) == -1) return; @@ -92,7 +102,7 @@ setifmaclabel(const char *val, int d, int s, const struct afswtch *rafp) } memset(&ifr, 0, sizeof(ifr)); - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_ifru.ifru_data = (void *)label; error = ioctl(s, SIOCSIFMAC, &ifr); @@ -117,11 +127,9 @@ void #endif /* __rtems__ */ mac_ctor(void) { -#define N(a) (sizeof(a) / sizeof(a[0])) size_t i; - for (i = 0; i < N(mac_cmds); i++) + for (i = 0; i < nitems(mac_cmds); i++) cmd_register(&mac_cmds[i]); af_register(&af_mac); -#undef N } diff --git a/freebsd/sbin/ifconfig/ifmedia.c b/freebsd/sbin/ifconfig/ifmedia.c index ba029cb4..890ca8e3 100644 --- a/freebsd/sbin/ifconfig/ifmedia.c +++ b/freebsd/sbin/ifconfig/ifmedia.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* $NetBSD: ifconfig.c,v 1.34 1997/04/21 01:17:58 lukem Exp $ */ /* $FreeBSD$ */ @@ -64,6 +68,9 @@ * SUCH DAMAGE. */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -86,19 +93,37 @@ #include <unistd.h> #include "ifconfig.h" +#ifdef __rtems__ +struct ifmedia_type_to_subtype { + struct { + struct ifmedia_description *desc; + int alias; + } subtypes[5]; + struct { + struct ifmedia_description *desc; + int alias; + } options[4]; + struct { + struct ifmedia_description *desc; + int alias; + } modes[3]; +}; + +#include "rtems-bsd-ifconfig-ifmedia-data.h" +#endif /* __rtems__ */ static void domediaopt(const char *, int, int); static int get_media_subtype(int, const char *); static int get_media_mode(int, const char *); static int get_media_options(int, const char *); -static int lookup_media_word(const struct ifmedia_description *, const char *); +static int lookup_media_word(struct ifmedia_description *, const char *); static void print_media_word(int, int); static void print_media_word_ifconfig(int); -static const struct ifmedia_description *get_toptype_desc(int); -static const struct ifmedia_type_to_subtype *get_toptype_ttos(int); -static const struct ifmedia_description *get_subtype_desc(int, - const struct ifmedia_type_to_subtype *ttos); +static struct ifmedia_description *get_toptype_desc(int); +static struct ifmedia_type_to_subtype *get_toptype_ttos(int); +static struct ifmedia_description *get_subtype_desc(int, + struct ifmedia_type_to_subtype *ttos); #define IFM_OPMODE(x) \ ((x) & (IFM_IEEE80211_ADHOC | IFM_IEEE80211_HOSTAP | \ @@ -111,11 +136,17 @@ media_status(int s) { struct ifmediareq ifmr; int *media_list, i; + int xmedia = 1; (void) memset(&ifmr, 0, sizeof(ifmr)); - (void) strncpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); + (void) strlcpy(ifmr.ifm_name, name, sizeof(ifmr.ifm_name)); - if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { + /* + * Check if interface supports extended media types. + */ + if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) + xmedia = 0; + if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { /* * Interface doesn't support SIOC{G,S}IFMEDIA. */ @@ -132,9 +163,12 @@ media_status(int s) err(1, "malloc"); ifmr.ifm_ulist = media_list; - if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) { - free(media_list); - err(1, "SIOCGIFMEDIA"); + if (xmedia) { + if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)&ifmr) < 0) + err(1, "SIOCGIFXMEDIA"); + } else { + if (ioctl(s, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0) + err(1, "SIOCGIFMEDIA"); } printf("\tmedia: "); @@ -194,23 +228,29 @@ media_status(int s) } #ifdef __rtems__ -static struct ifmediareq *ifmr = NULL; +static struct ifmediareq *ifmedia_getstate_ifmr = NULL; #endif /* __rtems__ */ struct ifmediareq * ifmedia_getstate(int s) { #ifndef __rtems__ static struct ifmediareq *ifmr = NULL; +#else /* __rtems__ */ + struct ifmediareq *ifmr = ifmedia_getstate_ifmr; #endif /* __rtems__ */ int *mwords; + int xmedia = 1; if (ifmr == NULL) { ifmr = (struct ifmediareq *)malloc(sizeof(struct ifmediareq)); +#ifdef __rtems__ + ifmedia_getstate_ifmr = ifmr; +#endif /* __rtems__ */ if (ifmr == NULL) err(1, "malloc"); (void) memset(ifmr, 0, sizeof(struct ifmediareq)); - (void) strncpy(ifmr->ifm_name, name, + (void) strlcpy(ifmr->ifm_name, name, sizeof(ifmr->ifm_name)); ifmr->ifm_count = 0; @@ -222,7 +262,10 @@ ifmedia_getstate(int s) * the current media type and the top-level type. */ - if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) { + if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) { + xmedia = 0; + } + if (xmedia == 0 && ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) { err(1, "SIOCGIFMEDIA"); } @@ -234,8 +277,13 @@ ifmedia_getstate(int s) err(1, "malloc"); ifmr->ifm_ulist = mwords; - if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) - err(1, "SIOCGIFMEDIA"); + if (xmedia) { + if (ioctl(s, SIOCGIFXMEDIA, (caddr_t)ifmr) < 0) + err(1, "SIOCGIFXMEDIA"); + } else { + if (ioctl(s, SIOCGIFMEDIA, (caddr_t)ifmr) < 0) + err(1, "SIOCGIFMEDIA"); + } } return ifmr; @@ -281,7 +329,7 @@ setmedia(const char *val, int d, int s, const struct afswtch *afp) */ subtype = get_media_subtype(IFM_TYPE(ifmr->ifm_ulist[0]), val); - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_media = (ifmr->ifm_current & IFM_IMASK) | IFM_TYPE(ifmr->ifm_ulist[0]) | subtype; @@ -313,7 +361,7 @@ domediaopt(const char *val, int clear, int s) options = get_media_options(IFM_TYPE(ifmr->ifm_ulist[0]), val); - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_media = ifmr->ifm_current; if (clear) ifr.ifr_media &= ~options; @@ -340,7 +388,7 @@ setmediainst(const char *val, int d, int s, const struct afswtch *afp) if (inst < 0 || inst > (int)IFM_INST_MAX) errx(1, "invalid media instance: %s", val); - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_media = (ifmr->ifm_current & ~IFM_IMASK) | inst << IFM_ISHIFT; ifmr->ifm_current = ifr.ifr_media; @@ -357,7 +405,7 @@ setmediamode(const char *val, int d, int s, const struct afswtch *afp) mode = get_media_mode(IFM_TYPE(ifmr->ifm_ulist[0]), val); - strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); ifr.ifr_media = (ifmr->ifm_current & ~IFM_MMASK) | mode; ifmr->ifm_current = ifr.ifr_media; @@ -368,89 +416,91 @@ setmediamode(const char *val, int d, int s, const struct afswtch *afp) * A good chunk of this is duplicated from sys/net/ifmedia.c **********************************************************************/ -static const struct ifmedia_description ifm_type_descriptions[] = +static struct ifmedia_description ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_ethernet_descriptions[] = +static struct ifmedia_description ifm_subtype_ethernet_descriptions[] = IFM_SUBTYPE_ETHERNET_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_ethernet_aliases[] = +static struct ifmedia_description ifm_subtype_ethernet_aliases[] = IFM_SUBTYPE_ETHERNET_ALIASES; -static const struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = +static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[] = IFM_SUBTYPE_ETHERNET_OPTION_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_tokenring_descriptions[] = +static struct ifmedia_description ifm_subtype_tokenring_descriptions[] = IFM_SUBTYPE_TOKENRING_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_tokenring_aliases[] = +static struct ifmedia_description ifm_subtype_tokenring_aliases[] = IFM_SUBTYPE_TOKENRING_ALIASES; -static const struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = +static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[] = IFM_SUBTYPE_TOKENRING_OPTION_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_fddi_descriptions[] = +static struct ifmedia_description ifm_subtype_fddi_descriptions[] = IFM_SUBTYPE_FDDI_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_fddi_aliases[] = +static struct ifmedia_description ifm_subtype_fddi_aliases[] = IFM_SUBTYPE_FDDI_ALIASES; -static const struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = +static struct ifmedia_description ifm_subtype_fddi_option_descriptions[] = IFM_SUBTYPE_FDDI_OPTION_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = +static struct ifmedia_description ifm_subtype_ieee80211_descriptions[] = IFM_SUBTYPE_IEEE80211_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_ieee80211_aliases[] = +static struct ifmedia_description ifm_subtype_ieee80211_aliases[] = IFM_SUBTYPE_IEEE80211_ALIASES; -static const struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = +static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[] = IFM_SUBTYPE_IEEE80211_OPTION_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] = +struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[] = IFM_SUBTYPE_IEEE80211_MODE_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] = +struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[] = IFM_SUBTYPE_IEEE80211_MODE_ALIASES; -static const struct ifmedia_description ifm_subtype_atm_descriptions[] = +static struct ifmedia_description ifm_subtype_atm_descriptions[] = IFM_SUBTYPE_ATM_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_atm_aliases[] = +static struct ifmedia_description ifm_subtype_atm_aliases[] = IFM_SUBTYPE_ATM_ALIASES; -static const struct ifmedia_description ifm_subtype_atm_option_descriptions[] = +static struct ifmedia_description ifm_subtype_atm_option_descriptions[] = IFM_SUBTYPE_ATM_OPTION_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_shared_descriptions[] = +static struct ifmedia_description ifm_subtype_shared_descriptions[] = IFM_SUBTYPE_SHARED_DESCRIPTIONS; -static const struct ifmedia_description ifm_subtype_shared_aliases[] = +static struct ifmedia_description ifm_subtype_shared_aliases[] = IFM_SUBTYPE_SHARED_ALIASES; -static const struct ifmedia_description ifm_shared_option_descriptions[] = +static struct ifmedia_description ifm_shared_option_descriptions[] = IFM_SHARED_OPTION_DESCRIPTIONS; static struct ifmedia_description ifm_shared_option_aliases[] = IFM_SHARED_OPTION_ALIASES; +#ifndef __rtems__ struct ifmedia_type_to_subtype { struct { - const struct ifmedia_description *desc; + struct ifmedia_description *desc; int alias; } subtypes[5]; struct { - const struct ifmedia_description *desc; + struct ifmedia_description *desc; int alias; } options[4]; struct { - const struct ifmedia_description *desc; + struct ifmedia_description *desc; int alias; } modes[3]; }; +#endif /* __rtems__ */ /* must be in the same order as IFM_TYPE_DESCRIPTIONS */ -static const struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { +static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { { { { &ifm_subtype_shared_descriptions[0], 0 }, @@ -548,8 +598,8 @@ static const struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[] = { static int get_media_subtype(int type, const char *val) { - const struct ifmedia_description *desc; - const struct ifmedia_type_to_subtype *ttos; + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; int rval, i; /* Find the top-level interface type. */ @@ -572,8 +622,8 @@ get_media_subtype(int type, const char *val) static int get_media_mode(int type, const char *val) { - const struct ifmedia_description *desc; - const struct ifmedia_type_to_subtype *ttos; + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; int rval, i; /* Find the top-level interface type. */ @@ -595,8 +645,8 @@ get_media_mode(int type, const char *val) static int get_media_options(int type, const char *val) { - const struct ifmedia_description *desc; - const struct ifmedia_type_to_subtype *ttos; + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; char *optlist, *optptr; int option = 0, i, rval = 0; @@ -634,7 +684,7 @@ get_media_options(int type, const char *val) } static int -lookup_media_word(const struct ifmedia_description *desc, const char *val) +lookup_media_word(struct ifmedia_description *desc, const char *val) { for (; desc->ifmt_string != NULL; desc++) @@ -644,9 +694,9 @@ lookup_media_word(const struct ifmedia_description *desc, const char *val) return (-1); } -static const struct ifmedia_description *get_toptype_desc(int ifmw) +static struct ifmedia_description *get_toptype_desc(int ifmw) { - const struct ifmedia_description *desc; + struct ifmedia_description *desc; for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) if (IFM_TYPE(ifmw) == desc->ifmt_word) @@ -655,10 +705,10 @@ static const struct ifmedia_description *get_toptype_desc(int ifmw) return desc; } -static const struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw) +static struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw) { - const struct ifmedia_description *desc; - const struct ifmedia_type_to_subtype *ttos; + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; for (desc = ifm_type_descriptions, ttos = ifmedia_types_to_subtypes; desc->ifmt_string != NULL; desc++, ttos++) @@ -668,11 +718,11 @@ static const struct ifmedia_type_to_subtype *get_toptype_ttos(int ifmw) return ttos; } -static const struct ifmedia_description *get_subtype_desc(int ifmw, - const struct ifmedia_type_to_subtype *ttos) +static struct ifmedia_description *get_subtype_desc(int ifmw, + struct ifmedia_type_to_subtype *ttos) { int i; - const struct ifmedia_description *desc; + struct ifmedia_description *desc; for (i = 0; ttos->subtypes[i].desc != NULL; i++) { if (ttos->subtypes[i].alias) @@ -687,11 +737,11 @@ static const struct ifmedia_description *get_subtype_desc(int ifmw, return NULL; } -static const struct ifmedia_description *get_mode_desc(int ifmw, - const struct ifmedia_type_to_subtype *ttos) +static struct ifmedia_description *get_mode_desc(int ifmw, + struct ifmedia_type_to_subtype *ttos) { int i; - const struct ifmedia_description *desc; + struct ifmedia_description *desc; for (i = 0; ttos->modes[i].desc != NULL; i++) { if (ttos->modes[i].alias) @@ -709,8 +759,8 @@ static const struct ifmedia_description *get_mode_desc(int ifmw, static void print_media_word(int ifmw, int print_toptype) { - const struct ifmedia_description *desc; - const struct ifmedia_type_to_subtype *ttos; + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; int seen_option = 0, i; /* Find the top-level interface type. */ @@ -769,8 +819,8 @@ print_media_word(int ifmw, int print_toptype) static void print_media_word_ifconfig(int ifmw) { - const struct ifmedia_description *desc; - const struct ifmedia_type_to_subtype *ttos; + struct ifmedia_description *desc; + struct ifmedia_type_to_subtype *ttos; int seen_option = 0, i; /* Find the top-level interface type. */ @@ -843,15 +893,9 @@ void #endif /* __rtems__ */ ifmedia_ctor(void) { -#ifdef __rtems__ - did_it = 0; - ifmr = NULL; -#endif /* __rtems__ */ -#define N(a) (sizeof(a) / sizeof(a[0])) size_t i; - for (i = 0; i < N(media_cmds); i++) + for (i = 0; i < nitems(media_cmds); i++) cmd_register(&media_cmds[i]); af_register(&af_media); -#undef N } diff --git a/freebsd/sbin/ifconfig/ifpfsync.c b/freebsd/sbin/ifconfig/ifpfsync.c index ad65e659..162219c8 100644 --- a/freebsd/sbin/ifconfig/ifpfsync.c +++ b/freebsd/sbin/ifconfig/ifpfsync.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 2003 Ryan McBride. All rights reserved. * Copyright (c) 2004 Max Laier. All rights reserved. @@ -28,7 +32,10 @@ * $FreeBSD$ */ -#include <sys/types.h> +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -47,6 +54,9 @@ #include <unistd.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifpfsync-data.h" +#endif /* __rtems__ */ void setpfsync_syncdev(const char *, int, int, const struct afswtch *); void unsetpfsync_syncdev(const char *, int, int, const struct afswtch *); @@ -54,6 +64,7 @@ void setpfsync_syncpeer(const char *, int, int, const struct afswtch *); void unsetpfsync_syncpeer(const char *, int, int, const struct afswtch *); void setpfsync_syncpeer(const char *, int, int, const struct afswtch *); void setpfsync_maxupd(const char *, int, int, const struct afswtch *); +void setpfsync_defer(const char *, int, int, const struct afswtch *); void pfsync_status(int); void @@ -164,6 +175,23 @@ setpfsync_maxupd(const char *val, int d, int s, const struct afswtch *rafp) err(1, "SIOCSETPFSYNC"); } +/* ARGSUSED */ +void +setpfsync_defer(const char *val, int d, int s, const struct afswtch *rafp) +{ + struct pfsyncreq preq; + + memset((char *)&preq, 0, sizeof(struct pfsyncreq)); + ifr.ifr_data = (caddr_t)&preq; + + if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1) + err(1, "SIOCGETPFSYNC"); + + preq.pfsyncr_defer = d; + if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1) + err(1, "SIOCSETPFSYNC"); +} + void pfsync_status(int s) { @@ -185,8 +213,10 @@ pfsync_status(int s) printf("syncpeer: %s ", inet_ntoa(preq.pfsyncr_syncpeer)); if (preq.pfsyncr_syncdev[0] != '\0' || - preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP) - printf("maxupd: %d\n", preq.pfsyncr_maxupdates); + preq.pfsyncr_syncpeer.s_addr != INADDR_PFSYNC_GROUP) { + printf("maxupd: %d ", preq.pfsyncr_maxupdates); + printf("defer: %s\n", preq.pfsyncr_defer ? "on" : "off"); + } } static struct cmd pfsync_cmds[] = { @@ -196,7 +226,9 @@ static struct cmd pfsync_cmds[] = { DEF_CMD("-syncif", 1, unsetpfsync_syncdev), DEF_CMD_ARG("syncpeer", setpfsync_syncpeer), DEF_CMD("-syncpeer", 1, unsetpfsync_syncpeer), - DEF_CMD_ARG("maxupd", setpfsync_maxupd) + DEF_CMD_ARG("maxupd", setpfsync_maxupd), + DEF_CMD("defer", 1, setpfsync_defer), + DEF_CMD("-defer", 0, setpfsync_defer), }; static struct afswtch af_pfsync = { .af_name = "af_pfsync", @@ -211,11 +243,9 @@ void #endif /* __rtems__ */ pfsync_ctor(void) { -#define N(a) (sizeof(a) / sizeof(a[0])) int i; - for (i = 0; i < N(pfsync_cmds); i++) + for (i = 0; i < nitems(pfsync_cmds); i++) cmd_register(&pfsync_cmds[i]); af_register(&af_pfsync); -#undef N } diff --git a/freebsd/sbin/ifconfig/ifvlan.c b/freebsd/sbin/ifconfig/ifvlan.c index 9fc2971d..14350baf 100644 --- a/freebsd/sbin/ifconfig/ifvlan.c +++ b/freebsd/sbin/ifconfig/ifvlan.c @@ -1,8 +1,16 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + /* - * Copyright (c) 1999 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. + * Copyright (c) 1999 Bill Paul <wpaul@ctr.columbia.edu> + * Copyright (c) 2012 ADARA Networks, Inc. + * All rights reserved. + * + * Portions of this software were developed by Robert N. M. Watson under + * contract to ADARA Networks, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,6 +40,9 @@ * THE POSSIBILITY OF SUCH DAMAGE. */ +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/ioctl.h> #include <sys/socket.h> @@ -42,7 +53,6 @@ #include <net/ethernet.h> #include <net/if.h> -#include <net/if_var.h> #include <net/if_vlan_var.h> #include <net/route.h> @@ -55,6 +65,9 @@ #include <errno.h> #include "ifconfig.h" +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-ifvlan-data.h" +#endif /* __rtems__ */ #ifndef lint static const char rcsid[] = @@ -81,10 +94,14 @@ vlan_status(int s) { struct vlanreq vreq; - if (getvlan(s, &ifr, &vreq) != -1) - printf("\tvlan: %d parent interface: %s\n", - vreq.vlr_tag, vreq.vlr_parent[0] == '\0' ? - "<none>" : vreq.vlr_parent); + if (getvlan(s, &ifr, &vreq) == -1) + return; + printf("\tvlan: %d", vreq.vlr_tag); + if (ioctl(s, SIOCGVLANPCP, (caddr_t)&ifr) != -1) + printf(" vlanpcp: %u", ifr.ifr_vlan_pcp); + printf(" parent interface: %s", vreq.vlr_parent[0] == '\0' ? + "<none>" : vreq.vlr_parent); + printf("\n"); } static void @@ -152,6 +169,22 @@ DECL_CMD_FUNC(setvlandev, val, d) } static +DECL_CMD_FUNC(setvlanpcp, val, d) +{ + u_long ul; + char *endp; + + ul = strtoul(val, &endp, 0); + if (*endp != '\0') + errx(1, "invalid value for vlanpcp"); + if (ul > 7) + errx(1, "value for vlanpcp out of range"); + ifr.ifr_vlan_pcp = ul; + if (ioctl(s, SIOCSVLANPCP, (caddr_t)&ifr) == -1) + err(1, "SIOCSVLANPCP"); +} + +static DECL_CMD_FUNC(unsetvlandev, val, d) { struct vlanreq vreq; @@ -172,6 +205,7 @@ DECL_CMD_FUNC(unsetvlandev, val, d) static struct cmd vlan_cmds[] = { DEF_CLONE_CMD_ARG("vlan", setvlantag), DEF_CLONE_CMD_ARG("vlandev", setvlandev), + DEF_CMD_ARG("vlanpcp", setvlanpcp), /* NB: non-clone cmds */ DEF_CMD_ARG("vlan", setvlantag), DEF_CMD_ARG("vlandev", setvlandev), @@ -201,17 +235,11 @@ void #endif /* __rtems__ */ vlan_ctor(void) { -#ifdef __rtems__ - memset(¶ms, 0, sizeof(params)); - params.vlr_tag = NOTAG; -#endif /* __rtems__ */ -#define N(a) (sizeof(a) / sizeof(a[0])) size_t i; - for (i = 0; i < N(vlan_cmds); i++) + for (i = 0; i < nitems(vlan_cmds); i++) cmd_register(&vlan_cmds[i]); af_register(&af_vlan); callback_register(vlan_cb, NULL); clone_setdefcallback("vlan", vlan_create); -#undef N } diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet-data.h new file mode 100644 index 00000000..962974a0 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet-data.h @@ -0,0 +1,9 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* af_inet.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct in_aliasreq in_addreq); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifreq in_ridreq); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_inet); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char addr_buf[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct sockaddr_in *sintab[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet6-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet6-data.h new file mode 100644 index 00000000..6038db41 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_inet6-data.h @@ -0,0 +1,13 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* af_inet6.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct in6_ifreq in6_ridreq); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct in6_aliasreq in6_addreq); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static int ip6lifetime); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static int explicit_prefix); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_inet6); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct option in6_Lopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char addr_buf[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct sockaddr_in6 *sin6tab[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd inet6_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_link-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_link-data.h new file mode 100644 index 00000000..b5f77c05 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_link-data.h @@ -0,0 +1,8 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* af_link.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifreq link_ridreq); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_link); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_ether); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_lladdr); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_nd6-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_nd6-data.h new file mode 100644 index 00000000..5ad9960a --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-af_nd6-data.h @@ -0,0 +1,4 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* af_nd6.c */ diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-data.h new file mode 100644 index 00000000..d5d6f294 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-data.h @@ -0,0 +1,39 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +/* af_inet6.c */ +/* af_inet.c */ +/* af_link.c */ +/* af_nd6.c */ +/* ifbridge.c */ +/* ifclone.c */ +/* ifconfig.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int setaddr); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern struct ifreq ifr); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char name[16]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *descr); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern size_t descrlen); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int setmask); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int doalias); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int clearaddr); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int newaddr); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int verbose); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int noload); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int printifname); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int supmedia); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern int printkeys); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *f_inet); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *f_inet6); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *f_ether); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char *f_addr); +/* ifgif.c */ +/* ifgre.c */ +/* ifgroup.c */ +/* iflagg.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern char lacpbuf[120]); +/* ifmac.c */ +/* ifmedia.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern struct ifmedia_description ifm_subtype_ieee80211_mode_descriptions[8]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, extern struct ifmedia_description ifm_subtype_ieee80211_mode_aliases[2]); +/* ifpfsync.c */ +/* ifvlan.c */ +/* sfp.c */ diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifbridge-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifbridge-data.h new file mode 100644 index 00000000..ba3ee5c6 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifbridge-data.h @@ -0,0 +1,9 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifbridge.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_bridge); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char const *stpstates[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char const *stpproto[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char const *stproles[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd bridge_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifclone-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifclone-data.h new file mode 100644 index 00000000..746e12c5 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifclone-data.h @@ -0,0 +1,7 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifclone.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct clone_defcb_list clone_defcbh); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct option clone_Copt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd clone_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifconfig-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifconfig-data.h new file mode 100644 index 00000000..4ce74977 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifconfig-data.h @@ -0,0 +1,9 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifconfig.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct option *opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch *afs); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd *cmds); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct callback *callbacks); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd basic_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgif-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgif-data.h new file mode 100644 index 00000000..2364de3e --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgif-data.h @@ -0,0 +1,6 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifgif.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_gif); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd gif_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgre-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgre-data.h new file mode 100644 index 00000000..af37782d --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgre-data.h @@ -0,0 +1,6 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifgre.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_gre); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd gre_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgroup-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgroup-data.h new file mode 100644 index 00000000..3b306f50 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifgroup-data.h @@ -0,0 +1,7 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifgroup.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_group); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct option group_gopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd group_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-iflagg-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-iflagg-data.h new file mode 100644 index 00000000..64f05f94 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-iflagg-data.h @@ -0,0 +1,6 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* iflagg.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_lagg); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd lagg_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmac-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmac-data.h new file mode 100644 index 00000000..c7bc23f2 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmac-data.h @@ -0,0 +1,6 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifmac.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_mac); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd mac_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmedia-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmedia-data.h new file mode 100644 index 00000000..a14edd2b --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifmedia-data.h @@ -0,0 +1,29 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifmedia.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmediareq *ifmedia_getstate_ifmr); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static int did_it); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_media); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_type_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ethernet_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ethernet_aliases[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ethernet_option_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_tokenring_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_tokenring_aliases[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_tokenring_option_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_fddi_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_fddi_aliases[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_fddi_option_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ieee80211_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ieee80211_aliases[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_ieee80211_option_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_atm_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_atm_aliases[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_atm_option_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_shared_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_subtype_shared_aliases[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_shared_option_descriptions[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_description ifm_shared_option_aliases[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct ifmedia_type_to_subtype ifmedia_types_to_subtypes[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd media_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifpfsync-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifpfsync-data.h new file mode 100644 index 00000000..ad28104a --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifpfsync-data.h @@ -0,0 +1,6 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifpfsync.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_pfsync); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd pfsync_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifvlan-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifvlan-data.h new file mode 100644 index 00000000..0d8ffe8a --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-ifvlan-data.h @@ -0,0 +1,7 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* ifvlan.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct vlanreq params); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct afswtch af_vlan); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct cmd vlan_cmds[]); diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-namespace.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-namespace.h new file mode 100644 index 00000000..5bf653b8 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-namespace.h @@ -0,0 +1,76 @@ +/* generated by userspace-header-gen.py */ +/* af_inet6.c */ +#define inet6_ctor _bsd_ifconfig_inet6_ctor +/* af_inet.c */ +#define inet_ctor _bsd_ifconfig_inet_ctor +/* af_link.c */ +#define link_ctor _bsd_ifconfig_link_ctor +/* af_nd6.c */ +#define nd6_status _bsd_ifconfig_nd6_status +#define setnd6defif _bsd_ifconfig_setnd6defif +#define setnd6flags _bsd_ifconfig_setnd6flags +/* ifbridge.c */ +#define bridge_ctor _bsd_ifconfig_bridge_ctor +/* ifclone.c */ +#define clone_ctor _bsd_ifconfig_clone_ctor +#define clone_setdefcallback _bsd_ifconfig_clone_setdefcallback +/* ifconfig.c */ +#define setaddr _bsd_ifconfig_setaddr +#define ifr _bsd_ifconfig_ifr +#define name _bsd_ifconfig_name +#define descr _bsd_ifconfig_descr +#define descrlen _bsd_ifconfig_descrlen +#define setmask _bsd_ifconfig_setmask +#define doalias _bsd_ifconfig_doalias +#define clearaddr _bsd_ifconfig_clearaddr +#define newaddr _bsd_ifconfig_newaddr +#define verbose _bsd_ifconfig_verbose +#define noload _bsd_ifconfig_noload +#define printifname _bsd_ifconfig_printifname +#define supmedia _bsd_ifconfig_supmedia +#define printkeys _bsd_ifconfig_printkeys +#define f_inet _bsd_ifconfig_f_inet +#define f_inet6 _bsd_ifconfig_f_inet6 +#define f_ether _bsd_ifconfig_f_ether +#define f_addr _bsd_ifconfig_f_addr +#define ifmaybeload _bsd_ifconfig_ifmaybeload +#define print_vhid _bsd_ifconfig_print_vhid +#define printb _bsd_ifconfig_printb +#define Perror _bsd_ifconfig_Perror +#define setifcap _bsd_ifconfig_setifcap +#define callback_register _bsd_ifconfig_callback_register +#define cmd_register _bsd_ifconfig_cmd_register +#define af_register _bsd_ifconfig_af_register +#define printifnamemaybe _bsd_ifconfig_printifnamemaybe +#define opt_register _bsd_ifconfig_opt_register +/* ifgif.c */ +#define gif_ctor _bsd_ifconfig_gif_ctor +/* ifgre.c */ +#define gre_ctor _bsd_ifconfig_gre_ctor +/* ifgroup.c */ +#define group_ctor _bsd_ifconfig_group_ctor +/* iflagg.c */ +#define lacpbuf _bsd_ifconfig_lacpbuf +#define lagg_ctor _bsd_ifconfig_lagg_ctor +/* ifmac.c */ +#define mac_ctor _bsd_ifconfig_mac_ctor +/* ifmedia.c */ +#define ifm_subtype_ieee80211_mode_descriptions _bsd_ifconfig_ifm_subtype_ieee80211_mode_descriptions +#define ifm_subtype_ieee80211_mode_aliases _bsd_ifconfig_ifm_subtype_ieee80211_mode_aliases +#define ifmedia_ctor _bsd_ifconfig_ifmedia_ctor +#define ifmedia_getstate _bsd_ifconfig_ifmedia_getstate +/* ifpfsync.c */ +#define pfsync_ctor _bsd_ifconfig_pfsync_ctor +#define pfsync_status _bsd_ifconfig_pfsync_status +#define setpfsync_defer _bsd_ifconfig_setpfsync_defer +#define setpfsync_maxupd _bsd_ifconfig_setpfsync_maxupd +#define unsetpfsync_syncpeer _bsd_ifconfig_unsetpfsync_syncpeer +#define setpfsync_syncpeer _bsd_ifconfig_setpfsync_syncpeer +#define unsetpfsync_syncdev _bsd_ifconfig_unsetpfsync_syncdev +#define setpfsync_syncdev _bsd_ifconfig_setpfsync_syncdev +/* ifvlan.c */ +#define vlan_ctor _bsd_ifconfig_vlan_ctor +/* sfp.c */ +#define sfp_status _bsd_ifconfig_sfp_status +#define find_zero_bit _bsd_ifconfig_find_zero_bit +#define find_value _bsd_ifconfig_find_value diff --git a/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-sfp-data.h b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-sfp-data.h new file mode 100644 index 00000000..994d2279 --- /dev/null +++ b/freebsd/sbin/ifconfig/rtems-bsd-ifconfig-sfp-data.h @@ -0,0 +1,15 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ifconfig-data.h" +/* sfp.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static char const *sff_8024_id[23]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv conn[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv eth_10g[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv eth_compat[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv fc_len[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv cab_tech[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv fc_media[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv fc_speed[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv eth_1040g[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv eth_extended_comp[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ifconfig, static struct _nv rev_compl[]); diff --git a/freebsd/sbin/ifconfig/sfp.c b/freebsd/sbin/ifconfig/sfp.c new file mode 100644 index 00000000..55fb7c7e --- /dev/null +++ b/freebsd/sbin/ifconfig/sfp.c @@ -0,0 +1,935 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-ifconfig-namespace.h" +#endif /* __rtems__ */ + +/*- + * Copyright (c) 2014 Alexander V. Chernikov. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static const char rcsid[] = + "$FreeBSD$"; +#endif /* not lint */ + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <sys/types.h> +#include <rtems/bsd/sys/param.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/sff8436.h> +#include <net/sff8472.h> + +#include <math.h> +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "ifconfig.h" +#ifdef __rtems__ +struct _nv { + int v; + const char *n; +}; + +#include "rtems-bsd-ifconfig-sfp-data.h" +#endif /* __rtems__ */ + +struct i2c_info { + int fd; /* fd to issue SIOCGI2C */ + int error; /* Store first error */ + int qsfp; /* True if transceiver is QSFP */ + int do_diag; /* True if we need to request DDM */ + struct ifreq *ifr; /* Pointer to pre-filled ifreq */ +}; + +static int read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, + uint8_t len, uint8_t *buf); +static void dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, + uint8_t len); + +#ifndef __rtems__ +struct _nv { + int v; + const char *n; +}; +#endif /* __rtems__ */ + +const char *find_value(struct _nv *x, int value); +const char *find_zero_bit(struct _nv *x, int value, int sz); + +/* SFF-8472 Rev. 11.4 table 3.4: Connector values */ +static struct _nv conn[] = { + { 0x00, "Unknown" }, + { 0x01, "SC" }, + { 0x02, "Fibre Channel Style 1 copper" }, + { 0x03, "Fibre Channel Style 2 copper" }, + { 0x04, "BNC/TNC" }, + { 0x05, "Fibre Channel coaxial" }, + { 0x06, "FiberJack" }, + { 0x07, "LC" }, + { 0x08, "MT-RJ" }, + { 0x09, "MU" }, + { 0x0A, "SG" }, + { 0x0B, "Optical pigtail" }, + { 0x0C, "MPO Parallel Optic" }, + { 0x20, "HSSDC II" }, + { 0x21, "Copper pigtail" }, + { 0x22, "RJ45" }, + { 0x23, "No separate connector" }, /* SFF-8436 */ + { 0, NULL } +}; + +/* SFF-8472 Rev. 11.4 table 3.5: Transceiver codes */ +/* 10G Ethernet/IB compliance codes, byte 3 */ +static struct _nv eth_10g[] = { + { 0x80, "10G Base-ER" }, + { 0x40, "10G Base-LRM" }, + { 0x20, "10G Base-LR" }, + { 0x10, "10G Base-SR" }, + { 0x08, "1X SX" }, + { 0x04, "1X LX" }, + { 0x02, "1X Copper Active" }, + { 0x01, "1X Copper Passive" }, + { 0, NULL } +}; + +/* Ethernet compliance codes, byte 6 */ +static struct _nv eth_compat[] = { + { 0x80, "BASE-PX" }, + { 0x40, "BASE-BX10" }, + { 0x20, "100BASE-FX" }, + { 0x10, "100BASE-LX/LX10" }, + { 0x08, "1000BASE-T" }, + { 0x04, "1000BASE-CX" }, + { 0x02, "1000BASE-LX" }, + { 0x01, "1000BASE-SX" }, + { 0, NULL } +}; + +/* FC link length, byte 7 */ +static struct _nv fc_len[] = { + { 0x80, "very long distance" }, + { 0x40, "short distance" }, + { 0x20, "intermediate distance" }, + { 0x10, "long distance" }, + { 0x08, "medium distance" }, + { 0, NULL } +}; + +/* Channel/Cable technology, byte 7-8 */ +static struct _nv cab_tech[] = { + { 0x0400, "Shortwave laser (SA)" }, + { 0x0200, "Longwave laser (LC)" }, + { 0x0100, "Electrical inter-enclosure (EL)" }, + { 0x80, "Electrical intra-enclosure (EL)" }, + { 0x40, "Shortwave laser (SN)" }, + { 0x20, "Shortwave laser (SL)" }, + { 0x10, "Longwave laser (LL)" }, + { 0x08, "Active Cable" }, + { 0x04, "Passive Cable" }, + { 0, NULL } +}; + +/* FC Transmission media, byte 9 */ +static struct _nv fc_media[] = { + { 0x80, "Twin Axial Pair" }, + { 0x40, "Twisted Pair" }, + { 0x20, "Miniature Coax" }, + { 0x10, "Viao Coax" }, + { 0x08, "Miltimode, 62.5um" }, + { 0x04, "Multimode, 50um" }, + { 0x02, "" }, + { 0x01, "Single Mode" }, + { 0, NULL } +}; + +/* FC Speed, byte 10 */ +static struct _nv fc_speed[] = { + { 0x80, "1200 MBytes/sec" }, + { 0x40, "800 MBytes/sec" }, + { 0x20, "1600 MBytes/sec" }, + { 0x10, "400 MBytes/sec" }, + { 0x08, "3200 MBytes/sec" }, + { 0x04, "200 MBytes/sec" }, + { 0x01, "100 MBytes/sec" }, + { 0, NULL } +}; + +/* SFF-8436 Rev. 4.8 table 33: Specification compliance */ + +/* 10/40G Ethernet compliance codes, byte 128 + 3 */ +static struct _nv eth_1040g[] = { + { 0x80, "Extended" }, + { 0x40, "10GBASE-LRM" }, + { 0x20, "10GBASE-LR" }, + { 0x10, "10GBASE-SR" }, + { 0x08, "40GBASE-CR4" }, + { 0x04, "40GBASE-SR4" }, + { 0x02, "40GBASE-LR4" }, + { 0x01, "40G Active Cable" }, + { 0, NULL } +}; +#define SFF_8636_EXT_COMPLIANCE 0x80 + +/* SFF-8024 Rev. 3.4 table 4.4: Extended Specification Compliance */ +static struct _nv eth_extended_comp[] = { + { 0xFF, "Reserved" }, + { 0x1A, "2 lambda DWDM 100G" }, + { 0x19, "100G ACC or 25GAUI C2M ACC" }, + { 0x18, "100G AOC or 25GAUI C2M AOC" }, + { 0x17, "100G CLR4" }, + { 0x16, "10GBASE-T with SFI electrical interface" }, + { 0x15, "G959.1 profile P1L1-2D2" }, + { 0x14, "G959.1 profile P1S1-2D2" }, + { 0x13, "G959.1 profile P1I1-2D1" }, + { 0x12, "40G PSM4 Parallel SMF" }, + { 0x11, "4 x 10GBASE-SR" }, + { 0x10, "40GBASE-ER4" }, + { 0x0F, "Reserved" }, + { 0x0D, "25GBASE-CR CA-N" }, + { 0x0C, "25GBASE-CR CA-S" }, + { 0x0B, "100GBASE-CR4 or 25GBASE-CR CA-L" }, + { 0x0A, "Reserved" }, + { 0x09, "100G CWDM4 MSA without FEC" }, + { 0x08, "100G ACC (Active Copper Cable)" }, + { 0x07, "100G PSM4 Parallel SMF" }, + { 0x06, "100G CWDM4 MSA with FEC" }, + { 0x05, "100GBASE-SR10" }, + { 0x04, "100GBASE-ER4" }, + { 0x03, "100GBASE-LR4" }, + { 0x02, "100GBASE-SR4" }, + { 0x01, "100G AOC (Active Optical Cable) or 25GAUI C2M ACC" }, + { 0x00, "Unspecified" } +}; + +/* SFF-8636 Rev. 2.5 table 6.3: Revision compliance */ +static struct _nv rev_compl[] = { + { 0x1, "SFF-8436 rev <=4.8" }, + { 0x2, "SFF-8436 rev <=4.8" }, + { 0x3, "SFF-8636 rev <=1.3" }, + { 0x4, "SFF-8636 rev <=1.4" }, + { 0x5, "SFF-8636 rev <=1.5" }, + { 0x6, "SFF-8636 rev <=2.0" }, + { 0x7, "SFF-8636 rev <=2.5" }, + { 0x0, "Unspecified" } +}; + +const char * +find_value(struct _nv *x, int value) +{ + for (; x->n != NULL; x++) + if (x->v == value) + return (x->n); + return (NULL); +} + +const char * +find_zero_bit(struct _nv *x, int value, int sz) +{ + int v, m; + const char *s; + + v = 1; + for (v = 1, m = 1 << (8 * sz); v < m; v *= 2) { + if ((value & v) == 0) + continue; + if ((s = find_value(x, value & v)) != NULL) { + value &= ~v; + return (s); + } + } + + return (NULL); +} + +static void +convert_sff_identifier(char *buf, size_t size, uint8_t value) +{ + const char *x; + + x = NULL; + if (value <= SFF_8024_ID_LAST) + x = sff_8024_id[value]; + else { + if (value > 0x80) + x = "Vendor specific"; + else + x = "Reserved"; + } + + snprintf(buf, size, "%s", x); +} + +static void +convert_sff_connector(char *buf, size_t size, uint8_t value) +{ + const char *x; + + if ((x = find_value(conn, value)) == NULL) { + if (value >= 0x0D && value <= 0x1F) + x = "Unallocated"; + else if (value >= 0x24 && value <= 0x7F) + x = "Unallocated"; + else + x = "Vendor specific"; + } + + snprintf(buf, size, "%s", x); +} + +static void +convert_sff_rev_compliance(char *buf, size_t size, uint8_t value) +{ + const char *x; + + if (value > 0x07) + x = "Unallocated"; + else + x = find_value(rev_compl, value); + + snprintf(buf, size, "%s", x); +} + +static void +get_sfp_identifier(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t data; + + read_i2c(ii, SFF_8472_BASE, SFF_8472_ID, 1, &data); + convert_sff_identifier(buf, size, data); +} + +static void +get_sfp_connector(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t data; + + read_i2c(ii, SFF_8472_BASE, SFF_8472_CONNECTOR, 1, &data); + convert_sff_connector(buf, size, data); +} + +static void +get_qsfp_identifier(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t data; + + read_i2c(ii, SFF_8436_BASE, SFF_8436_ID, 1, &data); + convert_sff_identifier(buf, size, data); +} + +static void +get_qsfp_connector(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t data; + + read_i2c(ii, SFF_8436_BASE, SFF_8436_CONNECTOR, 1, &data); + convert_sff_connector(buf, size, data); +} + +static void +printf_sfp_transceiver_descr(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[12]; + const char *tech_class, *tech_len, *tech_tech, *tech_media, *tech_speed; + + tech_class = NULL; + tech_len = NULL; + tech_tech = NULL; + tech_media = NULL; + tech_speed = NULL; + + /* Read bytes 3-10 at once */ + read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, &xbuf[3]); + + /* Check 10G ethernet first */ + tech_class = find_zero_bit(eth_10g, xbuf[3], 1); + if (tech_class == NULL) { + /* No match. Try 1G */ + tech_class = find_zero_bit(eth_compat, xbuf[6], 1); + } + + tech_len = find_zero_bit(fc_len, xbuf[7], 1); + tech_tech = find_zero_bit(cab_tech, xbuf[7] << 8 | xbuf[8], 2); + tech_media = find_zero_bit(fc_media, xbuf[9], 1); + tech_speed = find_zero_bit(fc_speed, xbuf[10], 1); + + printf("Class: %s\n", tech_class); + printf("Length: %s\n", tech_len); + printf("Tech: %s\n", tech_tech); + printf("Media: %s\n", tech_media); + printf("Speed: %s\n", tech_speed); +} + +static void +get_sfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size) +{ + const char *tech_class; + uint8_t code; + + unsigned char qbuf[8]; + read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 8, (uint8_t *)qbuf); + + /* Check 10G Ethernet/IB first */ + read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START, 1, &code); + tech_class = find_zero_bit(eth_10g, code, 1); + if (tech_class == NULL) { + /* No match. Try Ethernet 1G */ + read_i2c(ii, SFF_8472_BASE, SFF_8472_TRANS_START + 3, + 1, (caddr_t)&code); + tech_class = find_zero_bit(eth_compat, code, 1); + } + + if (tech_class == NULL) + tech_class = "Unknown"; + + snprintf(buf, size, "%s", tech_class); +} + +static void +get_qsfp_transceiver_class(struct i2c_info *ii, char *buf, size_t size) +{ + const char *tech_class; + uint8_t code; + + read_i2c(ii, SFF_8436_BASE, SFF_8436_CODE_E1040100G, 1, &code); + + /* Check for extended specification compliance */ + if (code & SFF_8636_EXT_COMPLIANCE) { + read_i2c(ii, SFF_8436_BASE, SFF_8436_OPTIONS_START, 1, &code); + tech_class = find_value(eth_extended_comp, code); + } else + /* Check 10/40G Ethernet class only */ + tech_class = find_zero_bit(eth_1040g, code, 1); + + if (tech_class == NULL) + tech_class = "Unknown"; + + snprintf(buf, size, "%s", tech_class); +} + +/* + * Print SFF-8472/SFF-8436 string to supplied buffer. + * All (vendor-specific) strings are padded right with '0x20'. + */ +static void +convert_sff_name(char *buf, size_t size, char *xbuf) +{ + char *p; + + for (p = &xbuf[16]; *(p - 1) == 0x20; p--) + ; + *p = '\0'; + snprintf(buf, size, "%s", xbuf); +} + +static void +convert_sff_date(char *buf, size_t size, char *xbuf) +{ + + snprintf(buf, size, "20%c%c-%c%c-%c%c", xbuf[0], xbuf[1], + xbuf[2], xbuf[3], xbuf[4], xbuf[5]); +} + +static void +get_sfp_vendor_name(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[17]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8472_BASE, SFF_8472_VENDOR_START, 16, (uint8_t *)xbuf); + convert_sff_name(buf, size, xbuf); +} + +static void +get_sfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[17]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8472_BASE, SFF_8472_PN_START, 16, (uint8_t *)xbuf); + convert_sff_name(buf, size, xbuf); +} + +static void +get_sfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[17]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8472_BASE, SFF_8472_SN_START, 16, (uint8_t *)xbuf); + convert_sff_name(buf, size, xbuf); +} + +static void +get_sfp_vendor_date(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[6]; + + memset(xbuf, 0, sizeof(xbuf)); + /* Date code, see Table 3.8 for description */ + read_i2c(ii, SFF_8472_BASE, SFF_8472_DATE_START, 6, (uint8_t *)xbuf); + convert_sff_date(buf, size, xbuf); +} + +static void +get_qsfp_vendor_name(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[17]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8436_BASE, SFF_8436_VENDOR_START, 16, (uint8_t *)xbuf); + convert_sff_name(buf, size, xbuf); +} + +static void +get_qsfp_vendor_pn(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[17]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8436_BASE, SFF_8436_PN_START, 16, (uint8_t *)xbuf); + convert_sff_name(buf, size, xbuf); +} + +static void +get_qsfp_vendor_sn(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[17]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8436_BASE, SFF_8436_SN_START, 16, (uint8_t *)xbuf); + convert_sff_name(buf, size, xbuf); +} + +static void +get_qsfp_vendor_date(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[6]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8436_BASE, SFF_8436_DATE_START, 6, (uint8_t *)xbuf); + convert_sff_date(buf, size, xbuf); +} + +static void +print_sfp_vendor(struct i2c_info *ii, char *buf, size_t size) +{ + char xbuf[80]; + + memset(xbuf, 0, sizeof(xbuf)); + if (ii->qsfp != 0) { + get_qsfp_vendor_name(ii, xbuf, 20); + get_qsfp_vendor_pn(ii, &xbuf[20], 20); + get_qsfp_vendor_sn(ii, &xbuf[40], 20); + get_qsfp_vendor_date(ii, &xbuf[60], 20); + } else { + get_sfp_vendor_name(ii, xbuf, 20); + get_sfp_vendor_pn(ii, &xbuf[20], 20); + get_sfp_vendor_sn(ii, &xbuf[40], 20); + get_sfp_vendor_date(ii, &xbuf[60], 20); + } + + snprintf(buf, size, "vendor: %s PN: %s SN: %s DATE: %s", + xbuf, &xbuf[20], &xbuf[40], &xbuf[60]); +} + +/* + * Converts internal templerature (SFF-8472, SFF-8436) + * 16-bit unsigned value to human-readable representation: + * + * Internally measured Module temperature are represented + * as a 16-bit signed twos complement value in increments of + * 1/256 degrees Celsius, yielding a total range of –128C to +128C + * that is considered valid between –40 and +125C. + * + */ +static void +convert_sff_temp(char *buf, size_t size, uint8_t *xbuf) +{ + double d; + + d = (double)xbuf[0]; + d += (double)xbuf[1] / 256; + + snprintf(buf, size, "%.2f C", d); +} + +/* + * Retrieves supplied voltage (SFF-8472, SFF-8436). + * 16-bit usigned value, treated as range 0..+6.55 Volts + */ +static void +convert_sff_voltage(char *buf, size_t size, uint8_t *xbuf) +{ + double d; + + d = (double)((xbuf[0] << 8) | xbuf[1]); + snprintf(buf, size, "%.2f Volts", d / 10000); +} + +/* + * Converts value in @xbuf to both milliwats and dBm + * human representation. + */ +static void +convert_sff_power(struct i2c_info *ii, char *buf, size_t size, uint8_t *xbuf) +{ + uint16_t mW; + double dbm; + + mW = (xbuf[0] << 8) + xbuf[1]; + + /* Convert mw to dbm */ + dbm = 10.0 * log10(1.0 * mW / 10000); + + /* + * Assume internally-calibrated data. + * This is always true for SFF-8346, and explicitly + * checked for SFF-8472. + */ + + /* Table 3.9, bit 5 is set, internally calibrated */ + snprintf(buf, size, "%d.%02d mW (%.2f dBm)", + mW / 10000, (mW % 10000) / 100, dbm); +} + +static void +get_sfp_temp(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t xbuf[2]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8472_DIAG, SFF_8472_TEMP, 2, xbuf); + convert_sff_temp(buf, size, xbuf); +} + +static void +get_sfp_voltage(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t xbuf[2]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8472_DIAG, SFF_8472_VCC, 2, xbuf); + convert_sff_voltage(buf, size, xbuf); +} + +static int +get_qsfp_temp(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t xbuf[2]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8436_BASE, SFF_8436_TEMP, 2, xbuf); + if ((xbuf[0] == 0xFF && xbuf[1] == 0xFF) || (xbuf[0] == 0 && xbuf[1] == 0)) + return (-1); + convert_sff_temp(buf, size, xbuf); + return (0); +} + +static void +get_qsfp_voltage(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t xbuf[2]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8436_BASE, SFF_8436_VCC, 2, xbuf); + convert_sff_voltage(buf, size, xbuf); +} + +static void +get_sfp_rx_power(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t xbuf[2]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8472_DIAG, SFF_8472_RX_POWER, 2, xbuf); + convert_sff_power(ii, buf, size, xbuf); +} + +static void +get_sfp_tx_power(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t xbuf[2]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8472_DIAG, SFF_8472_TX_POWER, 2, xbuf); + convert_sff_power(ii, buf, size, xbuf); +} + +static void +get_qsfp_rx_power(struct i2c_info *ii, char *buf, size_t size, int chan) +{ + uint8_t xbuf[2]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8436_BASE, SFF_8436_RX_CH1_MSB + (chan-1)*2, 2, xbuf); + convert_sff_power(ii, buf, size, xbuf); +} + +static void +get_qsfp_tx_power(struct i2c_info *ii, char *buf, size_t size, int chan) +{ + uint8_t xbuf[2]; + + memset(xbuf, 0, sizeof(xbuf)); + read_i2c(ii, SFF_8436_BASE, SFF_8436_TX_CH1_MSB + (chan-1)*2, 2, xbuf); + convert_sff_power(ii, buf, size, xbuf); +} + +static void +get_qsfp_rev_compliance(struct i2c_info *ii, char *buf, size_t size) +{ + uint8_t xbuf; + + xbuf = 0; + read_i2c(ii, SFF_8436_BASE, SFF_8436_STATUS, 1, &xbuf); + convert_sff_rev_compliance(buf, size, xbuf); +} + +static uint32_t +get_qsfp_br(struct i2c_info *ii) +{ + uint8_t xbuf; + uint32_t rate; + + xbuf = 0; + read_i2c(ii, SFF_8436_BASE, SFF_8436_BITRATE, 1, &xbuf); + rate = xbuf * 100; + if (xbuf == 0xFF) { + read_i2c(ii, SFF_8436_BASE, SFF_8636_BITRATE, 1, &xbuf); + rate = xbuf * 250; + } + + return (rate); +} + +/* + * Reads i2c data from opened kernel socket. + */ +static int +read_i2c(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len, + uint8_t *buf) +{ + struct ifi2creq req; + int i, l; + + if (ii->error != 0) + return (ii->error); + + ii->ifr->ifr_data = (caddr_t)&req; + + i = 0; + l = 0; + memset(&req, 0, sizeof(req)); + req.dev_addr = addr; + req.offset = off; + req.len = len; + + while (len > 0) { + l = MIN(sizeof(req.data), len); + req.len = l; + if (ioctl(ii->fd, SIOCGI2C, ii->ifr) != 0) { + ii->error = errno; + return (errno); + } + + memcpy(&buf[i], req.data, l); + len -= l; + i += l; + req.offset += l; + } + + return (0); +} + +static void +dump_i2c_data(struct i2c_info *ii, uint8_t addr, uint8_t off, uint8_t len) +{ + unsigned char buf[16]; + int i, read; + + while (len > 0) { + memset(buf, 0, sizeof(buf)); + read = MIN(sizeof(buf), len); + read_i2c(ii, addr, off, read, buf); + if (ii->error != 0) { + fprintf(stderr, "Error reading i2c info\n"); + return; + } + + printf("\t"); + for (i = 0; i < read; i++) + printf("%02X ", buf[i]); + printf("\n"); + len -= read; + off += read; + } +} + +static void +print_qsfp_status(struct i2c_info *ii, int verbose) +{ + char buf[80], buf2[40], buf3[40]; + uint32_t bitrate; + int i; + + ii->qsfp = 1; + + /* Transceiver type */ + get_qsfp_identifier(ii, buf, sizeof(buf)); + get_qsfp_transceiver_class(ii, buf2, sizeof(buf2)); + get_qsfp_connector(ii, buf3, sizeof(buf3)); + if (ii->error == 0) + printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3); + print_sfp_vendor(ii, buf, sizeof(buf)); + if (ii->error == 0) + printf("\t%s\n", buf); + + if (verbose > 1) { + get_qsfp_rev_compliance(ii, buf, sizeof(buf)); + if (ii->error == 0) + printf("\tcompliance level: %s\n", buf); + + bitrate = get_qsfp_br(ii); + if (ii->error == 0 && bitrate > 0) + printf("\tnominal bitrate: %u Mbps\n", bitrate); + } + + /* + * The standards in this area are not clear when the + * additional measurements are present or not. Use a valid + * temperature reading as an indicator for the presence of + * voltage and TX/RX power measurements. + */ + if (get_qsfp_temp(ii, buf, sizeof(buf)) == 0) { + get_qsfp_voltage(ii, buf2, sizeof(buf2)); + printf("\tmodule temperature: %s voltage: %s\n", buf, buf2); + for (i = 1; i <= 4; i++) { + get_qsfp_rx_power(ii, buf, sizeof(buf), i); + get_qsfp_tx_power(ii, buf2, sizeof(buf2), i); + printf("\tlane %d: RX: %s TX: %s\n", i, buf, buf2); + } + } + + if (verbose > 2) { + printf("\n\tSFF8436 DUMP (0xA0 128..255 range):\n"); + dump_i2c_data(ii, SFF_8436_BASE, 128, 128); + printf("\n\tSFF8436 DUMP (0xA0 0..81 range):\n"); + dump_i2c_data(ii, SFF_8436_BASE, 0, 82); + } +} + +static void +print_sfp_status(struct i2c_info *ii, int verbose) +{ + char buf[80], buf2[40], buf3[40]; + uint8_t diag_type, flags; + + /* Read diagnostic monitoring type */ + read_i2c(ii, SFF_8472_BASE, SFF_8472_DIAG_TYPE, 1, (caddr_t)&diag_type); + if (ii->error != 0) + return; + + /* + * Read monitoring data IFF it is supplied AND is + * internally calibrated + */ + flags = SFF_8472_DDM_DONE | SFF_8472_DDM_INTERNAL; + if ((diag_type & flags) == flags) + ii->do_diag = 1; + + /* Transceiver type */ + get_sfp_identifier(ii, buf, sizeof(buf)); + get_sfp_transceiver_class(ii, buf2, sizeof(buf2)); + get_sfp_connector(ii, buf3, sizeof(buf3)); + if (ii->error == 0) + printf("\tplugged: %s %s (%s)\n", buf, buf2, buf3); + print_sfp_vendor(ii, buf, sizeof(buf)); + if (ii->error == 0) + printf("\t%s\n", buf); + + if (verbose > 5) + printf_sfp_transceiver_descr(ii, buf, sizeof(buf)); + /* + * Request current measurements iff they are provided: + */ + if (ii->do_diag != 0) { + get_sfp_temp(ii, buf, sizeof(buf)); + get_sfp_voltage(ii, buf2, sizeof(buf2)); + printf("\tmodule temperature: %s Voltage: %s\n", buf, buf2); + get_sfp_rx_power(ii, buf, sizeof(buf)); + get_sfp_tx_power(ii, buf2, sizeof(buf2)); + printf("\tRX: %s TX: %s\n", buf, buf2); + } + + if (verbose > 2) { + printf("\n\tSFF8472 DUMP (0xA0 0..127 range):\n"); + dump_i2c_data(ii, SFF_8472_BASE, 0, 128); + } +} + +void +sfp_status(int s, struct ifreq *ifr, int verbose) +{ + struct i2c_info ii; + uint8_t id_byte; + + /* Prepare necessary into pass to i2c reader */ + memset(&ii, 0, sizeof(ii)); + ii.fd = s; + ii.ifr = ifr; + + /* + * Try to read byte 0 from i2c: + * Both SFF-8472 and SFF-8436 use it as + * 'identification byte'. + * Stop reading status on zero as value - + * this might happen in case of empty transceiver slot. + */ + id_byte = 0; + read_i2c(&ii, SFF_8472_BASE, SFF_8472_ID, 1, (caddr_t)&id_byte); + if (ii.error != 0 || id_byte == 0) + return; + + switch (id_byte) { + case SFF_8024_ID_QSFP: + case SFF_8024_ID_QSFPPLUS: + case SFF_8024_ID_QSFP28: + print_qsfp_status(&ii, verbose); + break; + default: + print_sfp_status(&ii, verbose); + } +} + diff --git a/freebsd/sbin/pfctl/parse.c b/freebsd/sbin/pfctl/parse.c new file mode 100644 index 00000000..1ae5fc95 --- /dev/null +++ b/freebsd/sbin/pfctl/parse.c @@ -0,0 +1,9315 @@ +/* original parser id follows */ +/* yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93" */ +/* (use YYMAJOR/YYMINOR for ifdefs dependent on parser version) */ + +#define YYBYACC 1 +#define YYMAJOR 1 +#define YYMINOR 9 +#define YYPATCH 20160324 + +#define YYEMPTY (-1) +#define yyclearin (yychar = YYEMPTY) +#define yyerrok (yyerrflag = 0) +#define YYRECOVERING() (yyerrflag != 0) +#define YYENOMEM (-2) +#define YYEOF 0 + +#ifndef yyparse +#define yyparse pfctlyparse +#endif /* yyparse */ + +#ifndef yylex +#define yylex pfctlylex +#endif /* yylex */ + +#ifndef yyerror +#define yyerror pfctlyerror +#endif /* yyerror */ + +#ifndef yychar +#define yychar pfctlychar +#endif /* yychar */ + +#ifndef yyval +#define yyval pfctlyval +#endif /* yyval */ + +#ifndef yylval +#define yylval pfctlylval +#endif /* yylval */ + +#ifndef yydebug +#define yydebug pfctlydebug +#endif /* yydebug */ + +#ifndef yynerrs +#define yynerrs pfctlynerrs +#endif /* yynerrs */ + +#ifndef yyerrflag +#define yyerrflag pfctlyerrflag +#endif /* yyerrflag */ + +#ifndef yylhs +#define yylhs pfctlylhs +#endif /* yylhs */ + +#ifndef yylen +#define yylen pfctlylen +#endif /* yylen */ + +#ifndef yydefred +#define yydefred pfctlydefred +#endif /* yydefred */ + +#ifndef yydgoto +#define yydgoto pfctlydgoto +#endif /* yydgoto */ + +#ifndef yysindex +#define yysindex pfctlysindex +#endif /* yysindex */ + +#ifndef yyrindex +#define yyrindex pfctlyrindex +#endif /* yyrindex */ + +#ifndef yygindex +#define yygindex pfctlygindex +#endif /* yygindex */ + +#ifndef yytable +#define yytable pfctlytable +#endif /* yytable */ + +#ifndef yycheck +#define yycheck pfctlycheck +#endif /* yycheck */ + +#ifndef yyname +#define yyname pfctlyname +#endif /* yyname */ + +#ifndef yyrule +#define yyrule pfctlyrule +#endif /* yyrule */ +#define YYPREFIX "pfctly" + +#define YYPURE 0 + +#line 30 "../../freebsd/sbin/pfctl/parse.y" +#ifdef __rtems__ +#include <machine/rtems-bsd-user-space.h> +#endif /* __rtems__ */ + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset +#define pf_anchor_setup _bsd_pf_anchor_setup +#define pf_remove_if_empty_ruleset _bsd_pf_remove_if_empty_ruleset +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#endif +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp6.h> +#include <net/pfvar.h> +#include <arpa/inet.h> +#include <net/altq/altq.h> +#include <net/altq/altq_cbq.h> +#include <net/altq/altq_codel.h> +#include <net/altq/altq_priq.h> +#include <net/altq/altq_hfsc.h> +#include <net/altq/altq_fairq.h> + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <netdb.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <math.h> +#include <err.h> +#include <limits.h> +#include <pwd.h> +#include <grp.h> +#include <md5.h> + +#include "pfctl_parser.h" +#include "pfctl.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-parse-data.h" +#endif /* __rtems__ */ + +static struct pfctl *pf = NULL; +static int debug = 0; +static int rulestate = 0; +static u_int16_t returnicmpdefault = + (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; +static u_int16_t returnicmp6default = + (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; +static int blockpolicy = PFRULE_DROP; +static int require_order = 1; +static int default_statelock; + +static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); +static struct file { + TAILQ_ENTRY(file) entry; + FILE *stream; + char *name; + int lineno; + int errors; +} *file; +struct file *pushfile(const char *, int); +int popfile(void); +int check_file_secrecy(int, const char *); +int yyparse(void); +int yylex(void); +int yyerror(const char *, ...); +int kw_cmp(const void *, const void *); +int lookup(char *); +int lgetc(int); +int lungetc(int); +int findeol(void); + +static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); +struct sym { + TAILQ_ENTRY(sym) entry; + int used; + int persist; + char *nam; + char *val; +}; +int symset(const char *, const char *, int); +char *symget(const char *); + +int atoul(char *, u_long *); + +enum { + PFCTL_STATE_NONE, + PFCTL_STATE_OPTION, + PFCTL_STATE_SCRUB, + PFCTL_STATE_QUEUE, + PFCTL_STATE_NAT, + PFCTL_STATE_FILTER +}; + +struct node_proto { + u_int8_t proto; + struct node_proto *next; + struct node_proto *tail; +}; + +struct node_port { + u_int16_t port[2]; + u_int8_t op; + struct node_port *next; + struct node_port *tail; +}; + +struct node_uid { + uid_t uid[2]; + u_int8_t op; + struct node_uid *next; + struct node_uid *tail; +}; + +struct node_gid { + gid_t gid[2]; + u_int8_t op; + struct node_gid *next; + struct node_gid *tail; +}; + +struct node_icmp { + u_int8_t code; + u_int8_t type; + u_int8_t proto; + struct node_icmp *next; + struct node_icmp *tail; +}; + +enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, + PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, + PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, + PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, + PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, }; + +enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; + +struct node_state_opt { + int type; + union { + u_int32_t max_states; + u_int32_t max_src_states; + u_int32_t max_src_conn; + struct { + u_int32_t limit; + u_int32_t seconds; + } max_src_conn_rate; + struct { + u_int8_t flush; + char tblname[PF_TABLE_NAME_SIZE]; + } overload; + u_int32_t max_src_nodes; + u_int8_t src_track; + u_int32_t statelock; + struct { + int number; + u_int32_t seconds; + } timeout; + } data; + struct node_state_opt *next; + struct node_state_opt *tail; +}; + +struct peer { + struct node_host *host; + struct node_port *port; +}; + +static struct node_queue { + char queue[PF_QNAME_SIZE]; + char parent[PF_QNAME_SIZE]; + char ifname[IFNAMSIZ]; + int scheduler; + struct node_queue *next; + struct node_queue *tail; +} *queues = NULL; + +struct node_qassign { + char *qname; + char *pqname; +}; + +static struct filter_opts { + int marker; +#define FOM_FLAGS 0x01 +#define FOM_ICMP 0x02 +#define FOM_TOS 0x04 +#define FOM_KEEP 0x08 +#define FOM_SRCTRACK 0x10 +#define FOM_SETPRIO 0x0400 +#define FOM_PRIO 0x2000 + struct node_uid *uid; + struct node_gid *gid; + struct { + u_int8_t b1; + u_int8_t b2; + u_int16_t w; + u_int16_t w2; + } flags; + struct node_icmp *icmpspec; + u_int32_t tos; + u_int32_t prob; + struct { + int action; + struct node_state_opt *options; + } keep; + int fragment; + int allowopts; + char *label; + struct node_qassign queues; + char *tag; + char *match_tag; + u_int8_t match_tag_not; + u_int rtableid; + u_int8_t prio; + u_int8_t set_prio[2]; + struct { + struct node_host *addr; + u_int16_t port; + } divert; +} filter_opts; + +static struct antispoof_opts { + char *label; + u_int rtableid; +} antispoof_opts; + +static struct scrub_opts { + int marker; +#define SOM_MINTTL 0x01 +#define SOM_MAXMSS 0x02 +#define SOM_FRAGCACHE 0x04 +#define SOM_SETTOS 0x08 + int nodf; + int minttl; + int maxmss; + int settos; + int fragcache; + int randomid; + int reassemble_tcp; + char *match_tag; + u_int8_t match_tag_not; + u_int rtableid; +} scrub_opts; + +static struct queue_opts { + int marker; +#define QOM_BWSPEC 0x01 +#define QOM_SCHEDULER 0x02 +#define QOM_PRIORITY 0x04 +#define QOM_TBRSIZE 0x08 +#define QOM_QLIMIT 0x10 + struct node_queue_bw queue_bwspec; + struct node_queue_opt scheduler; + int priority; + int tbrsize; + int qlimit; +} queue_opts; + +static struct table_opts { + int flags; + int init_addr; + struct node_tinithead init_nodes; +} table_opts; + +static struct pool_opts { + int marker; +#define POM_TYPE 0x01 +#define POM_STICKYADDRESS 0x02 + u_int8_t opts; + int type; + int staticport; + struct pf_poolhashkey *key; + +} pool_opts; + +static struct codel_opts codel_opts; +static struct node_hfsc_opts hfsc_opts; +static struct node_fairq_opts fairq_opts; +static struct node_state_opt *keep_state_defaults = NULL; + +int disallow_table(struct node_host *, const char *); +int disallow_urpf_failed(struct node_host *, const char *); +int disallow_alias(struct node_host *, const char *); +int rule_consistent(struct pf_rule *, int); +int filter_consistent(struct pf_rule *, int); +int nat_consistent(struct pf_rule *); +int rdr_consistent(struct pf_rule *); +int process_tabledef(char *, struct table_opts *); +void expand_label_str(char *, size_t, const char *, const char *); +void expand_label_if(const char *, char *, size_t, const char *); +void expand_label_addr(const char *, char *, size_t, u_int8_t, + struct node_host *); +void expand_label_port(const char *, char *, size_t, + struct node_port *); +void expand_label_proto(const char *, char *, size_t, u_int8_t); +void expand_label_nr(const char *, char *, size_t); +void expand_label(char *, size_t, const char *, u_int8_t, + struct node_host *, struct node_port *, struct node_host *, + struct node_port *, u_int8_t); +void expand_rule(struct pf_rule *, struct node_if *, + struct node_host *, struct node_proto *, struct node_os *, + struct node_host *, struct node_port *, struct node_host *, + struct node_port *, struct node_uid *, struct node_gid *, + struct node_icmp *, const char *); +int expand_altq(struct pf_altq *, struct node_if *, + struct node_queue *, struct node_queue_bw bwspec, + struct node_queue_opt *); +int expand_queue(struct pf_altq *, struct node_if *, + struct node_queue *, struct node_queue_bw, + struct node_queue_opt *); +int expand_skip_interface(struct node_if *); + +int check_rulestate(int); +int getservice(char *); +int rule_label(struct pf_rule *, char *); +int rt_tableid_max(void); + +void mv_rules(struct pf_ruleset *, struct pf_ruleset *); +void decide_address_family(struct node_host *, sa_family_t *); +void remove_invalid_hosts(struct node_host **, sa_family_t *); +int invalid_redirect(struct node_host *, sa_family_t); +u_int16_t parseicmpspec(char *, sa_family_t); + +static TAILQ_HEAD(loadanchorshead, loadanchors) + loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); + +struct loadanchors { + TAILQ_ENTRY(loadanchors) entries; + char *anchorname; + char *filename; +}; + +typedef struct { + union { + int64_t number; + double probability; + int i; + char *string; + u_int rtableid; + struct { + u_int8_t b1; + u_int8_t b2; + u_int16_t w; + u_int16_t w2; + } b; + struct range { + int a; + int b; + int t; + } range; + struct node_if *interface; + struct node_proto *proto; + struct node_icmp *icmp; + struct node_host *host; + struct node_os *os; + struct node_port *port; + struct node_uid *uid; + struct node_gid *gid; + struct node_state_opt *state_opt; + struct peer peer; + struct { + struct peer src, dst; + struct node_os *src_os; + } fromto; + struct { + struct node_host *host; + u_int8_t rt; + u_int8_t pool_opts; + sa_family_t af; + struct pf_poolhashkey *key; + } route; + struct redirection { + struct node_host *host; + struct range rport; + } *redirection; + struct { + int action; + struct node_state_opt *options; + } keep_state; + struct { + u_int8_t log; + u_int8_t logif; + u_int8_t quick; + } logquick; + struct { + int neg; + char *name; + } tagged; + struct pf_poolhashkey *hashkey; + struct node_queue *queue; + struct node_queue_opt queue_options; + struct node_queue_bw queue_bwspec; + struct node_qassign qassign; + struct filter_opts filter_opts; + struct antispoof_opts antispoof_opts; + struct queue_opts queue_opts; + struct scrub_opts scrub_opts; + struct table_opts table_opts; + struct pool_opts pool_opts; + struct node_hfsc_opts hfsc_opts; + struct node_fairq_opts fairq_opts; + struct codel_opts codel_opts; + } v; + int lineno; +} YYSTYPE; + +#define PPORT_RANGE 1 +#define PPORT_STAR 2 +int parseport(char *, struct range *r, int); + +#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ + (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ + !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) + +#line 534 "pfctly.tab.c" + +/* compatibility with bison */ +#ifdef YYPARSE_PARAM +/* compatibility with FreeBSD */ +# ifdef YYPARSE_PARAM_TYPE +# define YYPARSE_DECL() yyparse(YYPARSE_PARAM_TYPE YYPARSE_PARAM) +# else +# define YYPARSE_DECL() yyparse(void *YYPARSE_PARAM) +# endif +#else +# define YYPARSE_DECL() yyparse(void) +#endif + +/* Parameters sent to lex. */ +#ifdef YYLEX_PARAM +# define YYLEX_DECL() yylex(void *YYLEX_PARAM) +# define YYLEX yylex(YYLEX_PARAM) +#else +# define YYLEX_DECL() yylex(void) +# define YYLEX yylex() +#endif + +/* Parameters sent to yyerror. */ +#ifndef YYERROR_DECL +#define YYERROR_DECL() yyerror(const char *s) +#endif +#ifndef YYERROR_CALL +#define YYERROR_CALL(msg) yyerror(msg) +#endif + +extern int YYPARSE_DECL(); + +#define PASS 257 +#define BLOCK 258 +#define SCRUB 259 +#define RETURN 260 +#define IN 261 +#define OS 262 +#define OUT 263 +#define LOG 264 +#define QUICK 265 +#define ON 266 +#define FROM 267 +#define TO 268 +#define FLAGS 269 +#define RETURNRST 270 +#define RETURNICMP 271 +#define RETURNICMP6 272 +#define PROTO 273 +#define INET 274 +#define INET6 275 +#define ALL 276 +#define ANY 277 +#define ICMPTYPE 278 +#define ICMP6TYPE 279 +#define CODE 280 +#define KEEP 281 +#define MODULATE 282 +#define STATE 283 +#define PORT 284 +#define RDR 285 +#define NAT 286 +#define BINAT 287 +#define ARROW 288 +#define NODF 289 +#define MINTTL 290 +#define ERROR 291 +#define ALLOWOPTS 292 +#define FASTROUTE 293 +#define FILENAME 294 +#define ROUTETO 295 +#define DUPTO 296 +#define REPLYTO 297 +#define NO 298 +#define LABEL 299 +#define NOROUTE 300 +#define URPFFAILED 301 +#define FRAGMENT 302 +#define USER 303 +#define GROUP 304 +#define MAXMSS 305 +#define MAXIMUM 306 +#define TTL 307 +#define TOS 308 +#define DROP 309 +#define TABLE 310 +#define REASSEMBLE 311 +#define FRAGDROP 312 +#define FRAGCROP 313 +#define ANCHOR 314 +#define NATANCHOR 315 +#define RDRANCHOR 316 +#define BINATANCHOR 317 +#define SET 318 +#define OPTIMIZATION 319 +#define TIMEOUT 320 +#define LIMIT 321 +#define LOGINTERFACE 322 +#define BLOCKPOLICY 323 +#define RANDOMID 324 +#define REQUIREORDER 325 +#define SYNPROXY 326 +#define FINGERPRINTS 327 +#define NOSYNC 328 +#define DEBUG 329 +#define SKIP 330 +#define HOSTID 331 +#define ANTISPOOF 332 +#define FOR 333 +#define INCLUDE 334 +#define BITMASK 335 +#define RANDOM 336 +#define SOURCEHASH 337 +#define ROUNDROBIN 338 +#define STATICPORT 339 +#define PROBABILITY 340 +#define ALTQ 341 +#define CBQ 342 +#define CODEL 343 +#define PRIQ 344 +#define HFSC 345 +#define FAIRQ 346 +#define BANDWIDTH 347 +#define TBRSIZE 348 +#define LINKSHARE 349 +#define REALTIME 350 +#define UPPERLIMIT 351 +#define QUEUE 352 +#define PRIORITY 353 +#define QLIMIT 354 +#define HOGS 355 +#define BUCKETS 356 +#define RTABLE 357 +#define TARGET 358 +#define INTERVAL 359 +#define LOAD 360 +#define RULESET_OPTIMIZATION 361 +#define PRIO 362 +#define STICKYADDRESS 363 +#define MAXSRCSTATES 364 +#define MAXSRCNODES 365 +#define SOURCETRACK 366 +#define GLOBAL 367 +#define RULE 368 +#define MAXSRCCONN 369 +#define MAXSRCCONNRATE 370 +#define OVERLOAD 371 +#define FLUSH 372 +#define SLOPPY 373 +#define TAGGED 374 +#define TAG 375 +#define IFBOUND 376 +#define FLOATING 377 +#define STATEPOLICY 378 +#define STATEDEFAULTS 379 +#define ROUTE 380 +#define SETTOS 381 +#define DIVERTTO 382 +#define DIVERTREPLY 383 +#define STRING 384 +#define NUMBER 385 +#define PORTBINARY 386 +#define YYERRCODE 256 +typedef int YYINT; +static const YYINT pfctlylhs[] = { -1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 137, 150, 150, + 150, 150, 150, 150, 18, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, + 138, 77, 77, 80, 80, 81, 81, 82, 82, 147, + 79, 79, 156, 156, 156, 156, 158, 157, 157, 143, + 143, 143, 143, 144, 26, 139, 159, 126, 126, 128, + 128, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 17, 17, 17, 148, 92, 92, 93, 93, 94, 94, + 161, 120, 120, 122, 122, 121, 121, 11, 11, 149, + 162, 129, 129, 131, 131, 130, 130, 130, 130, 145, + 146, 163, 123, 123, 125, 125, 124, 124, 124, 124, + 124, 113, 113, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 100, 100, 101, 102, 102, 103, 164, + 106, 104, 104, 105, 105, 105, 105, 105, 105, 105, + 165, 109, 107, 107, 108, 108, 108, 108, 108, 166, + 112, 110, 110, 111, 111, 111, 96, 96, 96, 97, + 97, 98, 142, 167, 114, 114, 116, 116, 115, 115, + 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, + 115, 115, 115, 115, 115, 115, 115, 117, 117, 119, + 119, 118, 30, 30, 13, 13, 23, 23, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 44, 44, + 45, 45, 15, 15, 15, 88, 88, 87, 87, 87, + 87, 87, 89, 89, 90, 90, 91, 91, 91, 91, + 1, 1, 1, 2, 2, 3, 4, 16, 16, 16, + 35, 35, 35, 36, 36, 37, 38, 38, 46, 46, + 61, 61, 61, 62, 63, 63, 48, 48, 49, 49, + 47, 47, 47, 152, 152, 50, 50, 50, 51, 51, + 55, 55, 52, 52, 52, 53, 53, 53, 53, 53, + 53, 53, 5, 5, 54, 64, 64, 65, 65, 66, + 66, 66, 31, 33, 67, 67, 68, 68, 69, 69, + 69, 8, 8, 70, 70, 71, 71, 72, 72, 72, + 9, 9, 28, 27, 27, 27, 39, 39, 39, 39, + 40, 40, 42, 42, 41, 41, 41, 43, 43, 43, + 6, 6, 7, 7, 10, 10, 19, 19, 19, 22, + 22, 83, 83, 83, 83, 20, 20, 20, 84, 84, + 85, 85, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 76, 95, 95, 95, 14, 14, 32, + 57, 57, 56, 56, 75, 75, 75, 34, 34, 168, + 132, 132, 134, 134, 133, 133, 133, 133, 133, 133, + 74, 74, 74, 25, 25, 25, 25, 24, 24, 140, + 141, 78, 78, 135, 135, 136, 136, 58, 58, 59, + 59, 60, 60, 73, 73, 73, 73, 73, 151, 151, + 153, 153, 154, 155, 155, 160, 160, 12, 12, 21, + 21, 21, 21, 21, 21, +}; +static const YYINT pfctlylen[] = { 2, + 0, 3, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 4, 3, 2, 2, 3, + 3, 3, 3, 3, 1, 3, 3, 3, 6, 3, + 6, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 2, 1, 2, 1, 1, 1, 3, + 1, 0, 0, 2, 3, 3, 0, 5, 0, 10, + 7, 7, 7, 5, 2, 8, 0, 2, 0, 2, + 1, 1, 2, 2, 2, 1, 2, 1, 2, 3, + 2, 2, 2, 5, 2, 5, 2, 4, 1, 3, + 0, 2, 0, 2, 1, 1, 2, 1, 0, 5, + 0, 2, 0, 2, 1, 1, 3, 4, 2, 5, + 5, 0, 2, 0, 2, 1, 2, 2, 2, 1, + 2, 1, 1, 1, 4, 1, 4, 1, 4, 1, + 4, 1, 4, 1, 3, 1, 1, 3, 1, 0, + 2, 1, 3, 2, 8, 2, 8, 2, 8, 1, + 0, 2, 1, 3, 2, 6, 2, 2, 1, 0, + 2, 1, 3, 2, 2, 1, 0, 1, 4, 2, + 4, 1, 9, 0, 2, 0, 2, 1, 2, 2, + 1, 1, 2, 2, 1, 1, 1, 1, 1, 2, + 3, 2, 2, 2, 4, 1, 1, 4, 2, 3, + 1, 1, 2, 6, 1, 1, 1, 2, 0, 1, + 1, 5, 1, 1, 4, 4, 6, 1, 1, 1, + 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, + 2, 2, 1, 4, 1, 3, 1, 1, 1, 2, + 0, 2, 5, 2, 4, 2, 1, 0, 1, 1, + 0, 2, 5, 2, 4, 1, 1, 1, 1, 3, + 0, 2, 5, 1, 2, 4, 0, 2, 0, 2, + 1, 3, 2, 2, 0, 1, 1, 4, 2, 0, + 2, 4, 2, 2, 2, 1, 3, 3, 3, 1, + 3, 3, 1, 1, 3, 1, 4, 2, 4, 1, + 2, 3, 1, 1, 1, 4, 2, 4, 1, 2, + 3, 1, 1, 1, 4, 2, 4, 1, 2, 3, + 1, 1, 1, 4, 3, 2, 2, 5, 2, 5, + 2, 4, 2, 4, 1, 3, 3, 1, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, + 1, 2, 3, 3, 3, 0, 1, 2, 3, 0, + 1, 3, 2, 1, 2, 2, 4, 5, 2, 1, + 1, 1, 2, 2, 2, 4, 6, 0, 1, 1, + 1, 4, 2, 4, 0, 2, 4, 0, 1, 0, + 2, 0, 2, 1, 1, 1, 2, 1, 1, 1, + 0, 2, 4, 0, 1, 2, 1, 3, 3, 10, + 13, 0, 2, 0, 3, 0, 2, 1, 4, 2, + 4, 1, 4, 0, 1, 3, 3, 3, 2, 2, + 4, 2, 2, 4, 2, 1, 0, 1, 1, 1, + 2, 2, 1, 2, 1, +}; +static const YYINT pfctlydefred[] = { 0, + 0, 0, 0, 0, 207, 0, 379, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, + 0, 0, 0, 0, 0, 17, 218, 0, 0, 0, + 210, 208, 0, 51, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 18, 0, 0, 0, + 0, 0, 65, 0, 0, 0, 224, 225, 0, 0, + 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 24, 16, 22, 21, 23, 20, + 0, 0, 0, 0, 0, 44, 0, 0, 0, 26, + 0, 0, 0, 28, 0, 0, 30, 43, 42, 32, + 35, 34, 438, 439, 36, 37, 39, 40, 294, 293, + 33, 27, 25, 350, 351, 38, 0, 364, 0, 0, + 0, 0, 0, 0, 372, 0, 370, 371, 0, 361, + 0, 232, 0, 0, 231, 0, 98, 242, 0, 0, + 0, 0, 0, 49, 48, 50, 0, 0, 409, 407, + 408, 0, 0, 249, 250, 0, 0, 0, 219, 220, + 0, 221, 222, 0, 0, 227, 0, 0, 0, 0, + 430, 429, 0, 0, 433, 0, 363, 365, 369, 348, + 349, 366, 0, 0, 373, 436, 0, 0, 237, 238, + 239, 0, 235, 247, 0, 0, 89, 85, 0, 0, + 246, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 120, 116, 0, 0, 0, 46, 406, 0, 0, + 0, 0, 0, 0, 215, 0, 216, 100, 0, 0, + 0, 0, 0, 274, 0, 0, 0, 0, 0, 0, + 362, 240, 234, 0, 0, 0, 84, 0, 0, 0, + 172, 0, 110, 168, 0, 160, 0, 140, 151, 122, + 123, 117, 121, 118, 119, 115, 111, 64, 0, 425, + 0, 0, 0, 0, 257, 258, 0, 252, 256, 0, + 259, 0, 0, 0, 212, 0, 0, 106, 0, 105, + 0, 0, 0, 0, 0, 432, 29, 0, 435, 31, + 0, 367, 0, 236, 0, 0, 90, 0, 0, 96, + 95, 0, 243, 0, 244, 0, 136, 0, 134, 0, + 0, 139, 0, 137, 0, 0, 0, 0, 0, 418, + 0, 0, 422, 0, 0, 0, 0, 0, 276, 0, + 0, 0, 268, 0, 277, 0, 0, 0, 0, 0, + 217, 109, 0, 104, 0, 0, 61, 62, 63, 0, + 0, 0, 368, 86, 0, 87, 374, 97, 94, 0, + 0, 0, 125, 0, 133, 0, 0, 166, 0, 162, + 127, 0, 129, 0, 0, 0, 150, 0, 142, 131, + 0, 0, 0, 159, 0, 153, 0, 0, 0, 426, + 0, 428, 427, 0, 0, 0, 0, 440, 0, 0, + 0, 0, 0, 273, 296, 304, 0, 284, 285, 0, + 0, 0, 0, 283, 0, 0, 413, 0, 0, 264, + 0, 262, 0, 260, 0, 107, 0, 0, 0, 417, + 431, 434, 358, 0, 245, 169, 0, 170, 135, 165, + 164, 0, 138, 0, 144, 0, 146, 0, 148, 0, + 0, 155, 157, 158, 0, 0, 0, 0, 0, 395, + 396, 0, 398, 399, 400, 394, 0, 0, 253, 0, + 254, 0, 441, 442, 444, 301, 0, 0, 0, 0, + 0, 0, 0, 0, 272, 0, 0, 0, 270, 66, + 0, 281, 108, 0, 0, 0, 88, 0, 163, 0, + 0, 0, 143, 0, 154, 0, 0, 420, 423, 0, + 419, 397, 389, 393, 173, 0, 0, 0, 302, 278, + 287, 288, 289, 295, 292, 291, 415, 0, 0, 0, + 0, 72, 0, 0, 0, 0, 78, 0, 0, 0, + 76, 71, 0, 0, 57, 60, 0, 0, 0, 0, + 0, 187, 0, 186, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 196, 0, 181, 182, 188, + 185, 189, 178, 0, 197, 171, 0, 0, 0, 0, + 279, 0, 0, 255, 297, 0, 298, 0, 381, 0, + 410, 265, 263, 0, 73, 81, 83, 82, 74, 77, + 79, 345, 346, 75, 0, 70, 282, 0, 326, 323, + 0, 0, 341, 342, 0, 0, 327, 343, 344, 0, + 0, 329, 0, 0, 352, 312, 313, 0, 0, 0, + 179, 305, 321, 322, 0, 0, 0, 180, 314, 184, + 0, 0, 202, 199, 0, 205, 206, 192, 375, 0, + 193, 183, 190, 0, 194, 303, 0, 177, 0, 0, + 0, 0, 0, 421, 0, 0, 0, 0, 80, 53, + 325, 0, 0, 0, 0, 0, 0, 353, 354, 0, + 0, 310, 0, 0, 319, 203, 0, 201, 0, 355, + 0, 0, 191, 0, 0, 0, 156, 0, 299, 0, + 0, 387, 380, 266, 0, 324, 0, 0, 336, 337, + 0, 0, 339, 340, 0, 0, 0, 311, 0, 0, + 320, 0, 198, 0, 376, 0, 195, 0, 0, 0, + 0, 411, 383, 382, 0, 54, 58, 0, 0, 328, + 0, 331, 330, 0, 333, 359, 306, 0, 307, 315, + 0, 316, 0, 200, 0, 145, 147, 149, 0, 0, + 55, 56, 0, 0, 0, 0, 0, 377, 0, 384, + 332, 334, 308, 317, 204, 403, +}; +static const YYINT pfctlydgoto[] = { 2, + 79, 279, 168, 227, 141, 656, 661, 669, 676, 644, + 372, 135, 688, 21, 89, 186, 581, 142, 157, 393, + 442, 158, 22, 23, 179, 24, 608, 652, 52, 683, + 695, 742, 443, 552, 252, 435, 308, 309, 609, 747, + 657, 751, 662, 191, 194, 312, 373, 313, 464, 374, + 547, 375, 454, 455, 468, 741, 630, 363, 498, 364, + 379, 462, 571, 444, 557, 445, 671, 756, 672, 678, + 759, 679, 304, 772, 569, 340, 130, 377, 55, 57, + 176, 446, 611, 718, 159, 160, 75, 197, 76, 222, + 223, 164, 335, 228, 612, 283, 401, 284, 242, 348, + 349, 353, 354, 418, 419, 355, 425, 426, 357, 409, + 410, 350, 292, 535, 613, 614, 615, 684, 729, 277, + 341, 342, 170, 243, 244, 530, 582, 583, 258, 320, + 321, 430, 506, 507, 459, 387, 25, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 3, + 124, 204, 266, 127, 268, 745, 586, 648, 531, 217, + 278, 259, 171, 356, 358, 351, 536, 431, +}; +static const YYINT pfctlysindex[] = { -28, + 0, 118, 1618, 94, 0, 604, 0, 57, -163, -158, + -158, -158, 1728, 392, -129, 213, -35, -49, 463, 0, + 680, -20, 213, -20, 519, 525, 538, 552, 569, 622, + 651, 664, 670, 678, 684, 691, 711, 714, 0, 716, + 424, 720, 726, 731, 749, 0, 0, 545, 650, 657, + 0, 0, 230, 0, -20, -158, 213, 213, 213, 386, + -93, -72, -226, -58, -230, 390, 403, 213, -107, -158, + 371, 1487, 754, 540, 486, 556, 0, 27, 0, 213, + -158, 428, 0, 326, 326, 326, 0, 0, 392, 579, + 392, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 516, 475, 532, 768, 601, 0, 579, 579, 579, 0, + 492, 496, 883, 0, 518, 883, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 529, 0, 555, 559, + 489, 567, 577, 841, 0, 587, 0, 0, 931, 0, + 347, 0, 19, 579, 0, 883, 0, 0, 611, 655, + 1926, 0, 744, 0, 0, 0, 428, 540, 0, 0, + 0, 213, 213, 0, 0, 747, 213, 632, 0, 0, + 599, 0, 0, 997, 0, 0, 213, 747, 747, 747, + 0, 0, 883, -156, 0, 669, 0, 0, 0, 0, + 0, 0, 994, 689, 0, 0, 1487, -158, 0, 0, + 0, 603, 0, 0, 883, 611, 0, 0, 0, 1006, + 0, -57, 1022, 1024, 1028, 1035, 1050, 535, 707, 713, + 739, 0, 0, 1926, -57, -158, 0, 0, 579, 382, + -47, -187, 579, 1067, 0, 532, 0, 0, -81, 579, + -187, -187, -187, 0, 883, 13, 883, 49, 770, 1034, + 0, 0, 0, 347, 34, 1082, 0, -101, 67, 883, + 0, 883, 0, 0, 745, 0, 750, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 747, 0, + 39, 39, 39, 579, 0, 0, 883, 0, 0, 192, + 0, 758, 894, 747, 0, 1119, 777, 0, 883, 0, + -81, 747, 810, 810, 810, 0, 0, -156, 0, 0, + 669, 0, 801, 0, 82, 883, 0, 790, 791, 0, + 0, -101, 0, 1006, 0, 797, 0, 679, 0, 1134, + 349, 0, 724, 0, 1141, 483, 1142, -274, 922, 0, + 883, 807, 0, 0, 0, 0, 747, 541, 0, 83, + 883, 246, 0, 908, 0, 813, 1006, -45, 926, -187, + 0, 0, 28, 0, -187, 815, 0, 0, 0, 883, + 883, 834, 0, 0, 34, 0, 0, 0, 0, 883, + 86, 883, 0, 745, 0, -107, -107, 0, 931, 0, + 0, 750, 0, 24, 187, 214, 0, 931, 0, 0, + 224, 535, -107, 0, 931, 0, 190, 56, 190, 0, + 765, 0, 0, -187, 97, 883, 883, 0, 1143, 1144, + 1146, 428, 822, 0, 0, 0, 32, 0, 0, 575, + 1167, 838, 839, 0, 1171, 83, 0, 852, 810, 0, + 883, 0, 192, 0, 0, 0, 883, 108, 0, 0, + 0, 0, 0, 883, 0, 0, 797, 0, 0, 0, + 0, 349, 0, 535, 0, 535, 0, 535, 0, 483, + 535, 0, 0, 0, -274, 959, 883, 136, 1188, 0, + 0, -158, 0, 0, 0, 0, 765, 0, 0, 541, + 0, 61, 0, 0, 0, 0, 428, 137, 846, 847, + 848, 1193, 1176, 855, 0, -158, 953, 858, 0, 0, + 1405, 0, 0, 32, 1122, 4400, 0, 883, 0, 931, + 931, 931, 0, -107, 0, 32, 758, 0, 0, 56, + 0, 0, 0, 0, 0, 883, 155, 883, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 417, 0, 883, + 200, 0, 863, 595, 866, 868, 0, 869, 550, 879, + 0, 0, 1405, 883, 0, 0, 235, 361, 376, 972, + 975, 0, 976, 0, 135, 283, 550, 37, 978, 562, + 69, 877, 880, -158, 570, 0, 890, 0, 0, 0, + 0, 0, 0, 4400, 0, 0, 888, 892, 893, 535, + 0, 1006, 883, 0, 0, 61, 0, 883, 0, 984, + 0, 0, 0, 858, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, -158, 0, 0, 1265, 0, 0, + 896, 1234, 0, 0, 883, 1007, 0, 0, 0, 883, + 1008, 0, 1249, 1249, 0, 0, 0, 883, 904, 630, + 0, 0, 0, 0, 883, 909, 642, 0, 0, 0, + -16, 934, 0, 0, 1249, 0, 0, 0, 0, 913, + 0, 0, 0, 1014, 0, 0, -158, 0, 931, 931, + 931, 1262, 810, 0, 883, 190, 428, 883, 0, 0, + 0, 896, 644, 659, 661, 665, 1487, 0, 0, 116, + 630, 0, 158, 642, 0, 0, 919, 0, 728, 0, + 734, 428, 0, 535, 535, 535, 0, 1017, 0, 883, + 363, 0, 0, 0, 654, 0, 385, 883, 0, 0, + 429, 883, 0, 0, 773, 452, 883, 0, 472, 883, + 0, 931, 0, 934, 0, 927, 0, 1269, 1271, 1272, + 190, 0, 0, 0, 190, 0, 0, 1296, 1304, 0, + 644, 0, 0, 661, 0, 0, 0, 116, 0, 0, + 158, 0, 930, 0, 1276, 0, 0, 0, 1037, 883, + 0, 0, 883, 883, 883, 883, 1277, 0, 428, 0, + 0, 0, 0, 0, 0, 0, +}; +static const YYINT pfctlyrindex[] = { 36, + 0, 723, 738, 0, 0, 1644, 0, 0, 2743, 0, + 0, 0, 0, 986, 0, 1156, 0, 0, 0, 0, + 0, 2290, 2701, 4182, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1712, 1836, 1959, + 0, 0, 0, 0, 3033, 1283, 1115, 1115, 1115, 0, + 0, 0, 0, 0, 0, 0, 0, 1312, 0, 0, + 0, 0, 1155, 1394, 0, 1521, 0, 939, 1813, 1027, + 0, 0, 0, 4235, 4235, 878, 0, 0, 2811, 4313, + 4202, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3144, 0, 629, 629, 629, 0, + 0, 0, -99, 0, 0, 942, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 289, 0, 0, 0, 0, 0, 0, 0, 793, 0, + 0, 0, 0, 15, 0, -23, 0, 0, 0, 0, + 0, 1055, 0, 0, 0, 0, 1318, 4267, 0, 0, + 0, 533, 2922, 0, 0, 4320, 3576, 0, 0, 0, + 687, 0, 0, 0, 2, 0, 3255, 219, 219, 219, + 0, 0, 1481, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 459, 0, 0, 78, 0, 0, 0, 30, 939, + 0, 1321, 258, 438, 795, 992, 1012, 0, 0, 0, + 0, 0, 0, 6, 1321, 0, 0, 0, -204, 3323, + 0, 505, 2139, 0, 0, 0, 0, 0, 0, 3459, + 73, 73, 73, 0, 574, -96, -27, 948, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -13, -18, + 0, 942, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1066, 0, + 0, 0, 0, 3528, 0, 0, 697, 0, 0, 510, + 0, 154, 2167, 8, 0, 0, 0, 0, 1352, 0, + 684, 3645, 1331, 1331, 1331, 0, 0, 0, 0, 0, + 0, 0, 572, 0, 80, -17, 0, 0, 0, 0, + 0, 519, 0, 939, 0, 0, 0, 948, 0, 0, + 0, 0, 948, 0, 0, 0, 0, 0, 0, 0, + 78, 0, 0, 2499, 2499, 2499, 3697, 0, 0, 0, + 59, 0, 0, 2057, 0, 0, 748, 0, 2388, 2543, + 0, 0, 510, 0, 3795, 0, 0, 0, 0, 574, + -27, 690, 0, 0, 0, 0, 0, 0, 0, -18, + 948, -27, 0, 0, 0, 0, 0, 0, 287, 0, + 0, 0, 0, 0, 0, 0, 0, 285, 0, 0, + 0, 0, 0, 0, 514, 0, 0, 0, 0, 0, + 0, 0, 0, 3846, 687, 142, 175, 0, 0, 710, + 733, 0, 695, 0, 0, 0, 510, 0, 0, 414, + 0, 0, 0, 0, 547, 0, 0, 0, 195, 0, + 942, 0, 510, 0, 882, 0, 1184, 704, 3935, 0, + 0, 0, 0, -17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 23, -17, 80, 0, 0, + 0, 2610, 0, 0, 0, 0, 3391, 4079, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 704, 0, 0, + 0, 0, 0, 0, 0, 0, 75, 0, 0, 0, + 973, 0, 0, 510, 1338, 973, 0, -27, 0, 964, + 964, 964, 0, 0, 0, 510, -1, 0, 0, 0, + 0, 0, 0, 0, 0, 142, 240, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 229, -27, + 948, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 1184, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, + 0, 43, -17, 0, 0, 0, 0, 209, 0, 653, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 697, 917, 0, 0, 0, 697, + 968, 0, 3981, 3981, 0, 0, 0, 175, 123, 0, + 0, 0, 0, 0, 175, 828, 0, 0, 0, 0, + 0, 0, 0, 0, 3981, 0, 0, 0, 0, 0, + 0, 0, 0, 4033, 0, 0, 0, 0, 687, 687, + 687, 0, 1, 0, 10, 0, 0, -27, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 999, 0, + 948, 0, 0, 0, 0, 0, 0, 1353, 0, 87, + 264, 0, 0, 0, 0, 0, 687, 142, 0, 0, + 687, 142, 0, 0, 1707, 240, 10, 0, 240, 10, + 0, 964, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1357, 87, + 0, 0, 142, 142, 10, 10, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +}; +static const YYINT pfctlygindex[] = { 0, + 1557, 0, -208, -102, -320, 0, 0, -476, -619, 771, + -70, 0, 0, 1359, 490, 1165, 0, 0, 0, 0, + 328, 1307, 0, 0, 874, 0, 0, -612, 0, 0, + 647, 578, -308, 0, 1650, 0, -331, 0, 0, 0, + -668, 0, -525, 0, 1128, 851, 923, 0, 0, -345, + 0, 0, -315, 0, 946, 0, 0, -379, 0, 677, + 0, -497, 0, 938, 0, -457, 0, 0, -554, 0, + 0, -444, 0, 0, 0, -421, 0, 860, 0, -8, + 1218, -80, 0, -182, 688, 1196, 537, 0, 130, 0, + 1136, 0, 0, -223, 0, 1170, 0, -312, 0, 0, + 1015, 0, 1004, 0, 936, 0, 0, 937, 0, 0, + 958, 0, 1472, 933, 821, 0, 0, -591, 0, 0, + 1100, 0, 1274, 1205, 0, 0, 872, 0, 0, 1135, + 0, -337, 955, 0, 842, -319, 0, 0, 0, 1462, + 1464, -3, -2, 0, 0, 0, 0, 0, 0, 0, + -169, -119, 0, -192, 0, 0, 0, 0, 0, -178, + 0, 0, 0, 0, 0, 0, 0, 0, +}; +#define YYTABLESIZE 4783 +static const YYINT pfctlytable[] = { 44, + 45, 177, 58, 59, 388, 389, 206, 169, 412, 275, + 416, 103, 256, 267, 275, 113, 275, 251, 175, 437, + 68, 280, 275, 727, 248, 275, 275, 432, 433, 123, + 570, 412, 280, 402, 265, 1, 436, 467, 711, 93, + 251, 319, 275, 274, 748, 1, 230, 116, 497, 128, + 126, 336, 414, 275, 558, 280, 216, 725, 226, 167, + 167, 143, 248, 484, 167, 282, 231, 133, 248, 275, + 275, 275, 173, 226, 421, 307, 682, 461, 362, 310, + 422, 423, 267, 264, 385, 480, 481, 328, 311, 331, + 728, 275, 216, 439, 1, 362, 177, 275, 275, 746, + 344, 467, 494, 46, 761, 275, 275, 275, 690, 424, + 216, 496, 803, 499, 610, 439, 53, 275, 275, 437, + 440, 438, 441, 276, 101, 216, 275, 20, 113, 216, + 275, 175, 309, 516, 275, 400, 708, 327, 391, 527, + 216, 225, 440, 438, 441, 326, 275, 329, 439, 166, + 371, 216, 466, 134, 371, 309, 395, 129, 390, 169, + 345, 361, 346, 412, 538, 757, 309, 439, 705, 404, + 623, 474, 794, 330, 412, 440, 438, 441, 556, 216, + 216, 275, 309, 309, 309, 275, 412, 368, 584, 752, + 439, 343, 610, 722, 440, 438, 441, 338, 216, 383, + 621, 131, 121, 162, 416, 437, 394, 275, 559, 272, + 476, 275, 317, 180, 180, 180, 396, 440, 438, 441, + 54, 509, 477, 620, 167, 56, 486, 122, 251, 452, + 482, 631, 533, 805, 275, 275, 275, 298, 392, 490, + 87, 428, 88, 216, 758, 309, 495, 309, 275, 453, + 132, 447, 629, 488, 77, 339, 510, 668, 804, 275, + 549, 560, 437, 491, 81, 121, 275, 124, 275, 251, + 471, 472, 437, 169, 251, 251, 139, 140, 760, 625, + 475, 651, 478, 251, 275, 452, 412, 437, 416, 534, + 122, 1, 1, 1, 1, 101, 251, 251, 347, 437, + 437, 437, 318, 437, 369, 453, 458, 248, 369, 251, + 280, 125, 251, 248, 371, 439, 511, 512, 251, 550, + 1, 1, 1, 437, 633, 141, 281, 161, 91, 347, + 414, 251, 347, 1, 267, 275, 305, 306, 460, 534, + 267, 528, 440, 438, 441, 1, 806, 532, 80, 1, + 1, 1, 1, 1, 537, 412, 275, 113, 275, 275, + 275, 617, 618, 619, 251, 275, 275, 1, 726, 1, + 437, 248, 412, 4, 5, 6, 1, 548, 626, 280, + 124, 251, 99, 738, 99, 101, 91, 1, 251, 113, + 740, 309, 634, 275, 275, 1, 280, 280, 681, 414, + 309, 309, 224, 309, 309, 675, 216, 290, 291, 385, + 385, 385, 385, 385, 309, 7, 99, 224, 616, 1, + 309, 309, 360, 286, 309, 309, 309, 8, 216, 267, + 309, 9, 10, 11, 12, 13, 624, 385, 627, 360, + 309, 412, 275, 275, 174, 175, 286, 132, 309, 14, + 632, 15, 689, 286, 286, 799, 452, 286, 16, 800, + 580, 275, 309, 437, 647, 607, 174, 175, 369, 17, + 275, 275, 216, 286, 309, 370, 453, 18, 78, 309, + 251, 719, 416, 655, 309, 251, 251, 774, 412, 412, + 412, 412, 412, 553, 251, 216, 309, 309, 660, 666, + 667, 19, 730, 704, 309, 309, 309, 309, 706, 780, + 412, 649, 580, 91, 267, 216, 412, 567, 666, 667, + 734, 735, 736, 82, 696, 275, 275, 412, 92, 416, + 416, 416, 416, 416, 93, 713, 286, 267, 286, 628, + 715, 673, 674, 607, 115, 448, 449, 94, 720, 99, + 764, 458, 766, 783, 152, 723, 290, 416, 275, 275, + 132, 95, 775, 390, 390, 390, 390, 390, 781, 99, + 290, 291, 784, 450, 451, 251, 787, 788, 96, 290, + 791, 356, 178, 793, 111, 739, 290, 290, 744, 73, + 290, 390, 275, 275, 347, 693, 790, 290, 291, 124, + 124, 124, 124, 124, 124, 124, 290, 290, 291, 124, + 124, 124, 356, 114, 218, 356, 347, 275, 650, 519, + 773, 520, 219, 437, 437, 183, 743, 187, 782, 450, + 451, 97, 785, 437, 437, 437, 709, 789, 248, 255, + 792, 124, 216, 273, 437, 437, 216, 437, 437, 220, + 221, 696, 347, 347, 347, 73, 74, 347, 347, 347, + 98, 347, 386, 776, 347, 347, 673, 674, 437, 290, + 437, 290, 347, 99, 300, 286, 301, 302, 303, 100, + 810, 286, 286, 811, 812, 813, 814, 101, 733, 112, + 286, 286, 286, 102, 286, 286, 113, 286, 275, 357, + 103, 286, 286, 286, 300, 286, 406, 407, 84, 85, + 86, 286, 286, 286, 286, 286, 286, 286, 286, 403, + 104, 286, 216, 105, 286, 106, 437, 300, 743, 107, + 357, 286, 408, 357, 437, 108, 437, 286, 300, 286, + 109, 778, 779, 437, 653, 654, 144, 145, 286, 286, + 286, 286, 286, 286, 300, 300, 300, 414, 110, 658, + 659, 437, 437, 437, 411, 286, 267, 216, 763, 120, + 286, 216, 267, 136, 765, 286, 286, 216, 777, 132, + 132, 132, 132, 132, 132, 132, 137, 286, 286, 132, + 132, 132, 267, 161, 286, 286, 286, 286, 286, 241, + 450, 451, 41, 73, 126, 241, 241, 241, 290, 99, + 99, 174, 175, 786, 290, 290, 216, 300, 163, 300, + 165, 132, 188, 290, 290, 290, 437, 290, 290, 195, + 290, 414, 415, 416, 290, 290, 290, 318, 290, 267, + 267, 267, 267, 267, 290, 290, 290, 290, 290, 290, + 290, 290, 184, 185, 290, 210, 211, 290, 189, 190, + 318, 267, 437, 47, 290, 196, 417, 267, 437, 437, + 290, 318, 290, 48, 49, 50, 201, 356, 267, 267, + 202, 290, 290, 290, 290, 290, 290, 318, 318, 318, + 248, 69, 203, 99, 99, 248, 248, 437, 290, 356, + 214, 248, 205, 290, 248, 636, 637, 638, 290, 290, + 5, 6, 51, 207, 67, 192, 193, 126, 290, 291, + 290, 290, 670, 677, 305, 306, 335, 290, 290, 290, + 290, 290, 275, 642, 643, 356, 356, 356, 83, 208, + 356, 356, 356, 209, 356, 686, 687, 356, 356, 335, + 318, 212, 318, 694, 175, 356, 300, 275, 181, 182, + 335, 213, 300, 300, 84, 85, 86, 9, 10, 11, + 12, 215, 300, 300, 216, 300, 300, 338, 365, 366, + 437, 378, 300, 300, 300, 248, 300, 386, 386, 386, + 386, 386, 300, 300, 224, 357, 300, 300, 300, 300, + 338, 128, 300, 437, 437, 300, 232, 378, 378, 378, + 246, 338, 300, 666, 667, 386, 254, 357, 300, 251, + 300, 130, 378, 378, 378, 673, 674, 653, 654, 300, + 300, 300, 300, 300, 300, 414, 241, 257, 167, 335, + 269, 335, 749, 750, 658, 659, 300, 670, 753, 754, + 677, 300, 125, 357, 357, 357, 300, 300, 357, 357, + 357, 285, 357, 286, 114, 357, 357, 287, 300, 300, + 437, 437, 270, 357, 288, 300, 300, 300, 300, 300, + 275, 275, 414, 414, 414, 414, 414, 437, 437, 289, + 338, 293, 338, 443, 443, 333, 318, 294, 437, 500, + 501, 502, 503, 504, 414, 318, 318, 315, 318, 318, + 414, 323, 324, 325, 128, 670, 445, 445, 677, 318, + 437, 99, 337, 295, 241, 318, 318, 505, 347, 318, + 318, 318, 376, 352, 130, 318, 126, 126, 126, 126, + 126, 126, 126, 404, 404, 318, 126, 126, 126, 241, + 404, 404, 404, 318, 332, 378, 437, 437, 437, 381, + 382, 437, 437, 437, 233, 437, 386, 318, 437, 437, + 67, 67, 392, 397, 405, 398, 437, 114, 126, 318, + 281, 413, 420, 67, 318, 335, 67, 233, 427, 318, + 429, 456, 67, 463, 335, 335, 457, 335, 335, 470, + 473, 318, 318, 513, 514, 67, 515, 517, 335, 318, + 318, 318, 318, 521, 335, 335, 275, 524, 335, 335, + 335, 522, 523, 275, 335, 526, 546, 275, 551, 561, + 465, 562, 563, 564, 335, 469, 338, 565, 67, 566, + 568, 460, 335, 275, 585, 338, 338, 635, 338, 338, + 639, 640, 645, 641, 663, 67, 335, 664, 665, 338, + 685, 691, 67, 697, 692, 338, 338, 707, 335, 338, + 338, 338, 699, 335, 710, 338, 700, 701, 335, 650, + 712, 198, 199, 200, 508, 338, 714, 716, 717, 721, + 335, 335, 45, 338, 724, 681, 731, 732, 335, 335, + 335, 335, 737, 762, 771, 801, 275, 338, 275, 796, + 795, 797, 798, 802, 807, 45, 808, 815, 228, 338, + 809, 241, 99, 45, 338, 275, 45, 47, 229, 338, + 167, 437, 251, 128, 128, 128, 128, 128, 128, 128, + 416, 338, 338, 128, 128, 128, 99, 59, 437, 338, + 338, 338, 338, 130, 130, 130, 130, 130, 130, 130, + 437, 41, 401, 130, 130, 130, 402, 680, 241, 241, + 241, 241, 241, 241, 241, 128, 241, 146, 767, 241, + 241, 241, 241, 316, 275, 529, 816, 241, 241, 241, + 241, 275, 518, 525, 247, 130, 112, 112, 112, 112, + 112, 112, 112, 230, 755, 45, 622, 112, 112, 334, + 241, 275, 271, 299, 297, 483, 233, 314, 479, 233, + 233, 233, 233, 233, 322, 543, 230, 233, 233, 233, + 233, 545, 233, 233, 698, 233, 233, 167, 114, 539, + 555, 399, 233, 233, 233, 245, 233, 233, 296, 233, + 233, 233, 233, 233, 646, 384, 233, 233, 233, 233, + 275, 554, 233, 703, 42, 233, 43, 0, 367, 0, + 0, 241, 233, 0, 275, 0, 275, 0, 233, 0, + 233, 0, 0, 275, 275, 0, 0, 233, 0, 233, + 233, 233, 233, 233, 233, 0, 0, 241, 241, 241, + 241, 241, 241, 241, 0, 0, 233, 241, 241, 241, + 0, 233, 0, 275, 0, 0, 233, 233, 0, 0, + 275, 0, 0, 0, 275, 0, 0, 0, 233, 233, + 229, 0, 0, 0, 0, 233, 233, 233, 0, 0, + 275, 275, 275, 0, 45, 0, 0, 0, 45, 45, + 45, 45, 0, 229, 0, 45, 45, 45, 45, 0, + 45, 45, 0, 45, 45, 0, 0, 275, 275, 0, + 45, 45, 45, 0, 45, 0, 0, 0, 0, 90, + 45, 45, 0, 0, 45, 45, 45, 45, 0, 0, + 45, 0, 0, 45, 0, 0, 0, 0, 0, 0, + 45, 0, 0, 275, 0, 275, 45, 0, 45, 0, + 0, 0, 0, 117, 118, 119, 0, 45, 45, 45, + 45, 45, 45, 0, 138, 0, 0, 39, 275, 0, + 0, 0, 0, 0, 45, 0, 172, 0, 0, 45, + 0, 0, 0, 0, 45, 45, 0, 0, 0, 0, + 0, 275, 275, 209, 0, 230, 45, 45, 0, 230, + 230, 230, 230, 45, 45, 45, 230, 230, 230, 230, + 0, 230, 230, 0, 230, 230, 209, 0, 0, 0, + 0, 0, 230, 230, 0, 230, 230, 0, 230, 230, + 230, 230, 230, 572, 573, 230, 230, 230, 230, 0, + 0, 230, 0, 0, 230, 0, 574, 0, 0, 575, + 0, 230, 0, 0, 0, 576, 0, 230, 0, 230, + 0, 211, 0, 0, 0, 0, 230, 0, 577, 0, + 0, 0, 0, 230, 0, 275, 275, 0, 249, 250, + 0, 0, 40, 253, 211, 230, 0, 0, 0, 0, + 230, 0, 0, 260, 0, 230, 0, 275, 0, 0, + 0, 578, 0, 0, 0, 0, 0, 230, 230, 0, + 0, 0, 0, 0, 230, 230, 230, 0, 0, 0, + 275, 275, 229, 0, 0, 579, 229, 229, 229, 229, + 0, 0, 147, 229, 229, 229, 229, 0, 229, 229, + 0, 229, 229, 0, 0, 0, 0, 0, 0, 229, + 229, 0, 229, 229, 148, 229, 229, 229, 229, 229, + 0, 0, 229, 229, 229, 229, 0, 0, 229, 0, + 0, 229, 0, 0, 0, 0, 0, 0, 229, 275, + 0, 0, 0, 0, 229, 213, 229, 261, 262, 263, + 149, 150, 151, 229, 0, 152, 153, 154, 0, 155, + 229, 0, 144, 145, 275, 275, 0, 0, 213, 0, + 156, 0, 229, 38, 5, 6, 0, 229, 0, 0, + 0, 0, 229, 0, 0, 485, 487, 489, 0, 0, + 0, 0, 492, 493, 229, 229, 0, 0, 0, 0, + 0, 229, 229, 229, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 0, 0, 7, 209, 209, 209, 209, + 0, 209, 209, 0, 209, 209, 0, 0, 0, 0, + 0, 9, 10, 11, 12, 209, 209, 0, 209, 209, + 209, 209, 209, 0, 0, 209, 209, 209, 359, 0, + 0, 209, 0, 0, 0, 540, 0, 541, 0, 542, + 0, 209, 544, 380, 0, 0, 0, 0, 214, 209, + 0, 385, 211, 211, 211, 211, 211, 211, 211, 211, + 211, 0, 0, 209, 211, 211, 211, 211, 0, 211, + 211, 214, 211, 211, 0, 209, 0, 0, 0, 0, + 209, 0, 0, 211, 211, 209, 211, 211, 211, 211, + 211, 0, 437, 211, 211, 211, 434, 209, 209, 211, + 0, 0, 0, 0, 0, 209, 209, 0, 0, 211, + 0, 0, 0, 0, 437, 0, 0, 211, 0, 0, + 0, 0, 0, 0, 0, 0, 60, 61, 62, 63, + 64, 211, 65, 0, 66, 0, 67, 68, 69, 0, + 0, 0, 0, 211, 0, 0, 271, 0, 211, 0, + 437, 437, 437, 211, 0, 437, 437, 437, 0, 437, + 0, 0, 437, 437, 0, 211, 211, 0, 70, 271, + 437, 702, 0, 211, 211, 0, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 71, 72, 0, 213, 213, + 213, 213, 0, 213, 213, 0, 213, 213, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 213, 213, 0, + 213, 213, 213, 213, 213, 0, 0, 213, 213, 213, + 0, 0, 0, 213, 0, 0, 0, 0, 248, 0, + 0, 0, 0, 213, 112, 112, 112, 112, 112, 112, + 112, 213, 0, 0, 114, 112, 112, 0, 0, 0, + 0, 248, 0, 0, 0, 213, 261, 0, 0, 271, + 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, + 0, 0, 213, 0, 0, 0, 0, 213, 0, 261, + 0, 0, 0, 0, 0, 768, 769, 770, 0, 213, + 213, 0, 0, 0, 0, 0, 0, 213, 213, 214, + 214, 214, 214, 214, 214, 214, 214, 214, 0, 0, + 0, 214, 214, 214, 214, 0, 214, 214, 0, 214, + 214, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 214, 214, 0, 214, 214, 214, 214, 214, 0, 0, + 214, 214, 214, 0, 0, 0, 214, 233, 234, 235, + 236, 237, 238, 239, 0, 0, 214, 0, 240, 241, + 0, 0, 0, 0, 214, 0, 0, 0, 0, 261, + 0, 0, 0, 0, 0, 0, 0, 0, 214, 223, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 214, 0, 0, 0, 0, 214, 0, 0, 271, 0, + 214, 0, 223, 0, 271, 271, 0, 0, 0, 0, + 0, 0, 214, 214, 271, 271, 0, 271, 271, 0, + 214, 214, 0, 0, 271, 271, 271, 0, 271, 0, + 0, 0, 0, 0, 271, 271, 0, 0, 271, 271, + 271, 271, 0, 0, 271, 0, 0, 271, 0, 0, + 0, 0, 0, 0, 271, 0, 0, 0, 0, 0, + 271, 0, 271, 0, 0, 0, 0, 0, 0, 0, + 0, 271, 271, 271, 271, 271, 271, 269, 0, 0, + 248, 0, 0, 0, 0, 248, 248, 0, 271, 0, + 0, 248, 0, 271, 248, 0, 0, 0, 271, 271, + 269, 0, 0, 0, 0, 0, 0, 248, 248, 0, + 271, 271, 0, 0, 261, 261, 0, 271, 271, 271, + 248, 0, 0, 248, 261, 261, 0, 261, 261, 248, + 0, 0, 0, 0, 261, 261, 261, 0, 261, 0, + 0, 0, 248, 0, 261, 261, 0, 0, 261, 261, + 261, 261, 0, 0, 261, 0, 0, 261, 0, 0, + 0, 0, 0, 0, 261, 0, 0, 0, 0, 0, + 261, 0, 261, 0, 0, 248, 0, 0, 0, 0, + 0, 261, 261, 261, 261, 261, 261, 0, 392, 0, + 269, 0, 248, 0, 0, 0, 0, 0, 261, 248, + 0, 0, 0, 261, 0, 0, 0, 0, 261, 261, + 0, 392, 0, 0, 0, 0, 0, 0, 0, 0, + 261, 261, 0, 0, 0, 0, 0, 261, 261, 261, + 0, 223, 267, 223, 223, 223, 223, 223, 223, 0, + 0, 0, 223, 223, 223, 223, 0, 223, 223, 0, + 223, 223, 0, 0, 0, 267, 0, 0, 0, 0, + 0, 223, 223, 0, 223, 223, 223, 223, 223, 0, + 0, 223, 223, 223, 0, 0, 0, 223, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 223, 0, 0, + 0, 0, 0, 0, 0, 223, 0, 0, 0, 388, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 223, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 223, 388, 0, 0, 0, 223, 0, 0, 0, + 0, 223, 0, 0, 0, 0, 269, 0, 0, 0, + 0, 0, 0, 223, 223, 269, 269, 0, 269, 269, + 0, 223, 223, 0, 0, 269, 269, 269, 0, 269, + 0, 0, 0, 0, 0, 269, 269, 0, 0, 269, + 269, 269, 269, 0, 0, 269, 0, 0, 269, 0, + 0, 0, 0, 0, 0, 269, 0, 0, 0, 0, + 241, 269, 0, 269, 0, 0, 0, 0, 0, 0, + 0, 0, 269, 269, 269, 269, 269, 269, 0, 0, + 0, 0, 0, 241, 0, 0, 0, 0, 0, 269, + 0, 0, 0, 0, 269, 0, 0, 0, 0, 269, + 269, 0, 52, 0, 0, 0, 0, 0, 0, 0, + 392, 269, 269, 0, 0, 392, 392, 392, 269, 269, + 269, 392, 392, 392, 392, 52, 392, 392, 0, 392, + 392, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 392, 0, 0, 0, 0, 0, 392, 392, 0, 0, + 392, 392, 392, 0, 267, 0, 392, 0, 0, 0, + 267, 0, 0, 0, 0, 0, 392, 0, 0, 0, + 228, 0, 0, 0, 392, 0, 0, 0, 0, 0, + 0, 267, 267, 390, 390, 390, 390, 390, 392, 0, + 0, 0, 0, 228, 267, 0, 0, 267, 0, 0, + 392, 0, 0, 267, 0, 392, 0, 0, 0, 0, + 392, 390, 0, 0, 0, 52, 267, 0, 0, 0, + 0, 388, 392, 392, 0, 0, 388, 388, 388, 0, + 392, 392, 388, 388, 388, 388, 0, 388, 388, 0, + 388, 388, 0, 0, 0, 0, 0, 0, 0, 267, + 0, 388, 0, 0, 0, 0, 0, 388, 388, 0, + 0, 388, 388, 388, 0, 0, 267, 388, 0, 0, + 0, 0, 0, 267, 0, 0, 0, 388, 0, 0, + 0, 241, 0, 0, 0, 388, 0, 0, 0, 0, + 0, 0, 0, 0, 388, 388, 388, 388, 388, 388, + 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, + 0, 388, 241, 0, 0, 0, 388, 241, 241, 0, + 0, 388, 388, 241, 241, 241, 241, 0, 0, 0, + 0, 0, 0, 388, 388, 0, 0, 0, 241, 0, + 0, 388, 388, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 52, 52, 52, 0, 52, 52, 52, + 52, 52, 0, 0, 0, 52, 52, 52, 52, 0, + 52, 52, 0, 52, 52, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 52, 241, 241, 241, 241, 241, + 52, 52, 223, 0, 52, 52, 52, 0, 0, 0, + 52, 0, 0, 0, 0, 0, 0, 241, 0, 0, + 52, 0, 0, 241, 0, 223, 0, 0, 52, 0, + 0, 0, 228, 0, 241, 241, 228, 228, 228, 228, + 0, 0, 52, 228, 228, 228, 228, 0, 228, 228, + 0, 228, 228, 0, 52, 0, 0, 0, 0, 52, + 0, 0, 228, 228, 52, 228, 228, 228, 228, 228, + 0, 0, 228, 228, 228, 0, 52, 52, 228, 0, + 0, 0, 0, 0, 52, 52, 0, 0, 228, 0, + 0, 0, 0, 0, 0, 0, 228, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 228, 0, 0, 226, 0, 223, 0, 0, 0, 0, + 0, 0, 228, 0, 0, 0, 0, 228, 0, 0, + 0, 0, 228, 0, 0, 0, 226, 0, 0, 0, + 0, 0, 0, 241, 228, 228, 0, 0, 241, 241, + 241, 0, 228, 228, 241, 241, 241, 241, 0, 241, + 241, 0, 241, 241, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 241, 241, 0, 241, 241, 241, 241, + 241, 0, 0, 241, 241, 241, 0, 0, 0, 241, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, + 0, 0, 0, 0, 0, 0, 0, 241, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 241, 0, 0, 241, 0, 226, 0, 0, 0, + 0, 0, 0, 241, 0, 0, 0, 0, 241, 0, + 0, 0, 0, 241, 0, 0, 0, 241, 0, 0, + 0, 0, 0, 0, 223, 241, 241, 223, 223, 223, + 223, 223, 0, 241, 241, 223, 223, 223, 223, 0, + 223, 223, 0, 223, 223, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 223, 0, 0, 0, 0, 0, + 223, 223, 424, 0, 223, 223, 223, 0, 0, 0, + 223, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 223, 0, 0, 0, 0, 424, 0, 0, 223, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 223, 0, 0, 0, 0, 241, 0, 0, + 0, 0, 0, 0, 223, 0, 0, 0, 0, 223, + 0, 0, 0, 0, 223, 0, 0, 0, 0, 0, + 391, 0, 0, 0, 0, 226, 223, 223, 0, 226, + 226, 226, 226, 0, 223, 223, 226, 226, 226, 226, + 0, 226, 226, 391, 226, 226, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 226, 0, 0, 0, 0, + 0, 226, 226, 0, 0, 226, 226, 226, 0, 0, + 0, 226, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 226, 0, 0, 0, 0, 0, 0, 248, 226, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 226, 0, 0, 0, 0, 0, 0, + 0, 248, 0, 0, 0, 226, 0, 0, 0, 0, + 226, 0, 0, 0, 0, 226, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 241, 226, 226, 0, + 0, 241, 241, 241, 0, 226, 226, 241, 241, 241, + 241, 0, 241, 241, 0, 241, 241, 248, 0, 0, + 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, + 0, 0, 241, 241, 0, 0, 241, 241, 241, 0, + 248, 0, 241, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, + 241, 248, 0, 0, 424, 241, 0, 0, 0, 424, + 424, 424, 0, 0, 241, 424, 424, 424, 424, 0, + 424, 424, 0, 424, 424, 0, 241, 0, 241, 0, + 0, 241, 0, 0, 424, 0, 241, 0, 0, 0, + 424, 424, 0, 0, 424, 424, 424, 0, 241, 241, + 424, 0, 0, 0, 0, 0, 241, 241, 0, 0, + 424, 0, 0, 0, 0, 0, 0, 0, 424, 0, + 0, 0, 391, 0, 251, 0, 0, 391, 391, 391, + 0, 0, 424, 391, 391, 391, 391, 0, 391, 391, + 0, 391, 391, 0, 424, 0, 0, 251, 0, 424, + 0, 0, 391, 0, 424, 0, 0, 0, 391, 391, + 0, 0, 391, 391, 391, 0, 424, 424, 391, 0, + 0, 0, 0, 0, 424, 424, 251, 0, 391, 0, + 0, 0, 0, 0, 0, 0, 391, 0, 0, 0, + 248, 0, 0, 0, 0, 248, 248, 248, 0, 251, + 391, 248, 0, 0, 248, 0, 248, 248, 0, 248, + 248, 0, 391, 0, 0, 0, 0, 391, 0, 0, + 248, 0, 391, 0, 0, 0, 248, 248, 0, 0, + 248, 248, 248, 0, 391, 391, 248, 251, 0, 0, + 0, 0, 391, 391, 0, 0, 248, 0, 0, 0, + 0, 0, 0, 0, 248, 0, 0, 0, 0, 248, + 0, 0, 0, 0, 248, 248, 248, 0, 248, 0, + 248, 0, 0, 248, 267, 248, 248, 0, 248, 248, + 248, 0, 0, 0, 0, 248, 0, 0, 0, 248, + 248, 0, 0, 0, 0, 248, 248, 267, 0, 248, + 248, 248, 248, 248, 0, 248, 0, 241, 0, 0, + 248, 248, 241, 241, 0, 248, 0, 0, 241, 241, + 241, 241, 0, 248, 0, 267, 0, 0, 0, 0, + 0, 0, 0, 0, 241, 241, 0, 248, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 241, 267, 248, + 241, 0, 0, 0, 248, 0, 241, 0, 0, 248, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, + 0, 248, 248, 0, 0, 0, 251, 0, 0, 248, + 248, 251, 251, 251, 0, 0, 0, 267, 0, 0, + 251, 0, 251, 251, 0, 251, 251, 0, 0, 0, + 0, 0, 241, 0, 0, 0, 251, 0, 0, 0, + 0, 0, 251, 251, 176, 0, 251, 251, 251, 241, + 0, 0, 251, 0, 0, 0, 241, 0, 251, 0, + 0, 0, 251, 251, 251, 251, 0, 174, 0, 0, + 251, 0, 251, 0, 251, 251, 0, 251, 251, 0, + 0, 0, 0, 0, 251, 0, 0, 0, 251, 0, + 360, 0, 0, 0, 251, 251, 251, 0, 251, 251, + 251, 251, 0, 0, 251, 0, 251, 0, 0, 0, + 0, 0, 0, 360, 251, 0, 0, 0, 251, 251, + 0, 0, 251, 0, 0, 0, 251, 251, 0, 0, + 0, 0, 0, 0, 0, 0, 251, 0, 0, 0, + 0, 0, 49, 0, 0, 0, 0, 0, 251, 0, + 0, 0, 0, 251, 0, 0, 267, 176, 251, 0, + 0, 0, 267, 267, 0, 49, 0, 0, 0, 0, + 251, 251, 267, 267, 0, 267, 267, 0, 251, 251, + 0, 0, 0, 0, 0, 0, 267, 0, 176, 0, + 0, 0, 267, 267, 0, 0, 267, 267, 267, 0, + 0, 0, 267, 360, 0, 0, 0, 267, 0, 0, + 0, 174, 267, 267, 267, 0, 0, 0, 0, 0, + 267, 0, 0, 267, 267, 0, 267, 267, 0, 0, + 0, 0, 0, 0, 267, 0, 0, 267, 0, 0, + 0, 0, 0, 267, 267, 0, 267, 267, 267, 267, + 0, 267, 0, 267, 0, 49, 267, 0, 0, 0, + 0, 0, 0, 267, 0, 0, 0, 0, 267, 267, + 0, 267, 0, 0, 0, 0, 267, 267, 0, 0, + 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, + 0, 223, 0, 0, 0, 0, 0, 267, 0, 0, + 0, 0, 267, 174, 0, 0, 0, 267, 0, 0, + 0, 228, 174, 174, 223, 174, 174, 0, 0, 267, + 267, 0, 0, 0, 0, 0, 174, 267, 267, 0, + 0, 0, 174, 174, 228, 0, 174, 174, 174, 0, + 0, 0, 174, 0, 404, 0, 0, 0, 0, 360, + 0, 0, 174, 0, 0, 0, 0, 0, 360, 360, + 174, 360, 360, 0, 0, 0, 0, 404, 0, 0, + 0, 0, 360, 0, 174, 0, 405, 0, 360, 360, + 0, 0, 360, 360, 360, 0, 174, 0, 360, 0, + 0, 174, 0, 0, 0, 0, 174, 0, 360, 405, + 0, 49, 0, 0, 0, 0, 360, 0, 174, 174, + 49, 49, 0, 49, 49, 0, 174, 174, 0, 0, + 360, 0, 248, 0, 49, 0, 0, 0, 0, 251, + 49, 49, 360, 0, 49, 49, 49, 360, 0, 0, + 49, 0, 360, 0, 0, 248, 0, 174, 0, 0, + 49, 0, 251, 0, 360, 360, 174, 174, 49, 174, + 174, 0, 360, 360, 0, 0, 0, 0, 0, 0, + 174, 0, 49, 0, 0, 0, 174, 174, 0, 0, + 174, 174, 174, 0, 49, 0, 174, 0, 0, 49, + 0, 0, 0, 0, 49, 0, 174, 0, 0, 0, + 0, 0, 0, 0, 174, 0, 49, 49, 0, 0, + 0, 0, 0, 0, 49, 49, 0, 0, 174, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 174, 0, 167, 0, 0, 174, 0, 0, 0, 0, + 174, 0, 0, 223, 0, 223, 223, 223, 223, 223, + 0, 0, 174, 174, 223, 223, 223, 223, 0, 0, + 174, 174, 0, 228, 0, 0, 0, 228, 228, 228, + 223, 223, 0, 0, 228, 228, 228, 228, 0, 0, + 0, 0, 0, 223, 0, 0, 223, 0, 0, 0, + 228, 228, 223, 0, 0, 0, 404, 0, 0, 0, + 404, 404, 404, 228, 0, 223, 228, 404, 404, 404, + 404, 0, 228, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 404, 0, 0, 228, 0, 0, 405, 0, + 0, 0, 405, 405, 405, 0, 0, 0, 223, 405, + 405, 405, 405, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 405, 223, 0, 0, 228, 0, + 0, 0, 223, 0, 0, 0, 0, 0, 0, 404, + 404, 404, 404, 404, 248, 228, 0, 0, 0, 248, + 248, 251, 228, 0, 0, 248, 251, 251, 248, 0, + 0, 404, 0, 0, 0, 251, 0, 404, 0, 0, + 248, 405, 405, 405, 405, 405, 0, 251, 404, 404, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 405, 0, 0, 0, 0, 0, 405, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 405, 405, 0, 0, 0, 0, 0, 248, 248, 248, + 248, 248, 0, 0, 251, 251, 251, 251, 251, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 587, 248, + 0, 0, 0, 0, 0, 248, 251, 588, 589, 0, + 590, 591, 251, 0, 0, 0, 248, 248, 0, 0, + 0, 592, 0, 251, 251, 0, 0, 593, 338, 0, + 0, 594, 595, 596, 0, 0, 0, 597, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 598, 0, 0, + 0, 0, 0, 0, 0, 599, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 600, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 601, 0, 0, 0, 0, 602, 0, 0, 0, + 0, 603, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 604, 0, 0, 0, 0, 0, + 0, 605, 606, +}; +static const YYINT pfctlycheck[] = { 3, + 3, 82, 11, 12, 324, 325, 126, 78, 10, 33, + 10, 10, 191, 206, 33, 10, 44, 10, 10, 33, + 10, 230, 40, 40, 10, 44, 44, 365, 366, 123, + 528, 33, 10, 346, 204, 0, 368, 383, 651, 10, + 33, 123, 33, 222, 713, 10, 166, 56, 428, 276, + 123, 275, 10, 44, 512, 33, 44, 677, 40, 33, + 33, 70, 267, 40, 33, 123, 169, 298, 273, 60, + 61, 62, 81, 40, 349, 123, 40, 123, 40, 267, + 355, 356, 10, 203, 10, 406, 407, 266, 276, 268, + 682, 33, 44, 33, 123, 40, 177, 125, 40, 712, + 279, 447, 423, 10, 724, 225, 125, 125, 40, 384, + 44, 427, 781, 429, 536, 33, 60, 40, 60, 40, + 60, 61, 62, 226, 123, 44, 40, 10, 123, 44, + 44, 123, 10, 442, 125, 344, 634, 125, 331, 459, + 44, 123, 60, 61, 62, 265, 60, 267, 33, 123, + 123, 44, 125, 384, 123, 33, 335, 384, 328, 230, + 280, 123, 282, 10, 477, 720, 44, 33, 626, 348, + 550, 395, 764, 125, 353, 60, 61, 62, 510, 44, + 44, 123, 60, 61, 62, 44, 33, 307, 534, 715, + 33, 125, 614, 670, 60, 61, 62, 299, 44, 319, + 546, 260, 359, 74, 10, 123, 125, 33, 517, 218, + 125, 125, 294, 84, 85, 86, 336, 60, 61, 62, + 384, 125, 401, 544, 33, 384, 40, 384, 10, 40, + 409, 569, 125, 788, 60, 61, 62, 246, 10, 418, + 261, 361, 263, 44, 721, 123, 425, 125, 40, 60, + 309, 371, 568, 40, 384, 357, 435, 123, 784, 359, + 125, 125, 359, 40, 314, 359, 125, 10, 60, 262, + 390, 391, 33, 344, 267, 268, 384, 385, 723, 125, + 400, 47, 402, 276, 384, 40, 288, 384, 288, 468, + 384, 256, 257, 258, 259, 294, 289, 290, 10, 60, + 61, 62, 384, 40, 277, 60, 377, 178, 277, 302, + 288, 384, 305, 299, 123, 33, 436, 437, 311, 498, + 285, 286, 287, 60, 125, 41, 384, 41, 299, 41, + 288, 324, 44, 298, 262, 277, 384, 385, 384, 518, + 268, 461, 60, 61, 62, 310, 791, 467, 384, 314, + 315, 316, 317, 318, 474, 357, 384, 352, 300, 301, + 384, 540, 541, 542, 357, 384, 384, 332, 385, 334, + 384, 357, 374, 256, 257, 258, 341, 497, 557, 357, + 123, 374, 374, 703, 374, 384, 357, 352, 381, 384, + 706, 269, 571, 384, 385, 360, 374, 375, 362, 357, + 278, 279, 384, 281, 282, 123, 44, 384, 385, 335, + 336, 337, 338, 339, 292, 298, 374, 384, 538, 384, + 298, 299, 384, 10, 302, 303, 304, 310, 44, 357, + 308, 314, 315, 316, 317, 318, 556, 363, 558, 384, + 318, 288, 384, 385, 384, 385, 33, 10, 326, 332, + 570, 334, 384, 40, 41, 771, 40, 44, 341, 775, + 531, 384, 340, 384, 584, 536, 384, 385, 277, 352, + 384, 385, 44, 60, 352, 284, 60, 360, 266, 357, + 262, 664, 288, 123, 362, 267, 268, 125, 335, 336, + 337, 338, 339, 502, 276, 44, 374, 375, 123, 384, + 385, 384, 685, 623, 382, 383, 384, 385, 628, 125, + 357, 277, 583, 24, 10, 44, 363, 526, 384, 385, + 699, 700, 701, 61, 605, 384, 385, 374, 10, 335, + 336, 337, 338, 339, 10, 655, 123, 33, 125, 123, + 660, 384, 385, 614, 55, 300, 301, 10, 668, 40, + 729, 622, 731, 125, 41, 675, 10, 363, 384, 385, + 123, 10, 741, 335, 336, 337, 338, 339, 747, 60, + 384, 385, 751, 384, 385, 357, 125, 756, 10, 33, + 759, 10, 257, 762, 40, 705, 40, 41, 708, 264, + 44, 363, 384, 385, 306, 604, 125, 384, 385, 342, + 343, 344, 345, 346, 347, 348, 60, 384, 385, 352, + 353, 354, 41, 384, 268, 44, 328, 44, 384, 45, + 740, 47, 276, 384, 385, 89, 707, 91, 748, 384, + 385, 10, 752, 349, 350, 351, 645, 757, 10, 41, + 760, 384, 44, 41, 358, 359, 44, 384, 385, 303, + 304, 732, 364, 365, 366, 264, 265, 369, 370, 371, + 10, 373, 10, 10, 376, 377, 384, 385, 384, 123, + 384, 125, 384, 10, 293, 262, 295, 296, 297, 10, + 800, 268, 269, 803, 804, 805, 806, 10, 697, 40, + 277, 278, 279, 10, 281, 282, 40, 284, 125, 10, + 10, 288, 289, 290, 10, 292, 358, 359, 285, 286, + 287, 298, 299, 300, 301, 302, 303, 304, 305, 41, + 10, 308, 44, 10, 311, 10, 268, 33, 809, 10, + 41, 318, 384, 44, 276, 10, 33, 324, 44, 326, + 10, 745, 745, 40, 384, 385, 376, 377, 335, 336, + 337, 338, 339, 340, 60, 61, 62, 10, 10, 384, + 385, 303, 304, 60, 41, 352, 262, 44, 41, 384, + 357, 44, 268, 384, 41, 362, 363, 44, 125, 342, + 343, 344, 345, 346, 347, 348, 384, 374, 375, 352, + 353, 354, 288, 40, 381, 382, 383, 384, 385, 267, + 384, 385, 10, 264, 10, 273, 274, 275, 262, 300, + 301, 384, 385, 41, 268, 269, 44, 123, 333, 125, + 265, 384, 307, 277, 278, 279, 123, 281, 282, 62, + 284, 349, 350, 351, 288, 289, 290, 10, 292, 335, + 336, 337, 338, 339, 298, 299, 300, 301, 302, 303, + 304, 305, 274, 275, 308, 367, 368, 311, 384, 385, + 33, 357, 349, 260, 318, 265, 384, 363, 355, 356, + 324, 44, 326, 270, 271, 272, 385, 306, 374, 375, + 385, 335, 336, 337, 338, 339, 340, 60, 61, 62, + 262, 10, 10, 384, 385, 267, 268, 384, 352, 328, + 60, 273, 385, 357, 276, 311, 312, 313, 362, 363, + 257, 258, 309, 385, 33, 384, 385, 123, 384, 385, + 374, 375, 595, 596, 384, 385, 10, 381, 382, 383, + 384, 385, 359, 384, 385, 364, 365, 366, 259, 385, + 369, 370, 371, 385, 373, 384, 385, 376, 377, 33, + 123, 385, 125, 384, 385, 384, 262, 384, 85, 86, + 44, 385, 268, 269, 285, 286, 287, 314, 315, 316, + 317, 385, 278, 279, 44, 281, 282, 10, 302, 303, + 277, 259, 288, 289, 290, 357, 292, 335, 336, 337, + 338, 339, 298, 299, 384, 306, 302, 303, 304, 305, + 33, 10, 308, 300, 301, 311, 352, 285, 286, 287, + 267, 44, 318, 384, 385, 363, 385, 328, 324, 273, + 326, 10, 285, 286, 287, 384, 385, 384, 385, 335, + 336, 337, 338, 339, 340, 288, 10, 41, 33, 123, + 47, 125, 384, 385, 384, 385, 352, 720, 384, 385, + 723, 357, 384, 364, 365, 366, 362, 363, 369, 370, + 371, 40, 373, 40, 10, 376, 377, 40, 374, 375, + 384, 385, 384, 384, 40, 381, 382, 383, 384, 385, + 384, 385, 335, 336, 337, 338, 339, 384, 385, 40, + 123, 385, 125, 384, 385, 62, 269, 385, 306, 335, + 336, 337, 338, 339, 357, 278, 279, 41, 281, 282, + 363, 261, 262, 263, 123, 788, 384, 385, 791, 292, + 328, 374, 41, 385, 10, 298, 299, 363, 384, 302, + 303, 304, 375, 384, 123, 308, 342, 343, 344, 345, + 346, 347, 348, 266, 267, 318, 352, 353, 354, 123, + 273, 274, 275, 326, 385, 262, 364, 365, 366, 41, + 384, 369, 370, 371, 10, 373, 357, 340, 376, 377, + 289, 290, 372, 384, 41, 385, 384, 123, 384, 352, + 384, 41, 41, 302, 357, 269, 305, 33, 267, 362, + 384, 284, 311, 268, 278, 279, 384, 281, 282, 385, + 367, 374, 375, 61, 61, 324, 61, 386, 292, 382, + 383, 384, 385, 47, 298, 299, 33, 47, 302, 303, + 304, 384, 384, 40, 308, 374, 268, 44, 41, 384, + 380, 385, 385, 41, 318, 385, 269, 62, 357, 385, + 288, 384, 326, 60, 123, 278, 279, 385, 281, 282, + 385, 384, 374, 385, 283, 374, 340, 283, 283, 292, + 283, 385, 381, 374, 385, 298, 299, 284, 352, 302, + 303, 304, 385, 357, 10, 308, 385, 385, 362, 384, + 47, 117, 118, 119, 434, 318, 280, 280, 40, 386, + 374, 375, 10, 326, 386, 362, 384, 284, 382, 383, + 384, 385, 41, 385, 288, 10, 123, 340, 125, 41, + 384, 41, 41, 10, 385, 33, 41, 41, 333, 352, + 284, 10, 384, 41, 357, 384, 44, 10, 164, 362, + 10, 384, 267, 342, 343, 344, 345, 346, 347, 348, + 10, 374, 375, 352, 353, 354, 374, 10, 385, 382, + 383, 384, 385, 342, 343, 344, 345, 346, 347, 348, + 362, 3, 10, 352, 353, 354, 10, 597, 342, 343, + 344, 345, 346, 347, 348, 384, 262, 71, 732, 353, + 354, 267, 268, 256, 33, 463, 809, 273, 274, 275, + 276, 40, 447, 456, 177, 384, 342, 343, 344, 345, + 346, 347, 348, 10, 717, 123, 547, 353, 354, 274, + 384, 60, 217, 249, 245, 412, 262, 253, 404, 265, + 266, 267, 268, 269, 260, 490, 33, 273, 274, 275, + 276, 495, 278, 279, 614, 281, 282, 33, 384, 482, + 508, 342, 288, 289, 290, 172, 292, 293, 244, 295, + 296, 297, 298, 299, 583, 321, 302, 303, 304, 305, + 277, 507, 308, 622, 3, 311, 3, -1, 304, -1, + -1, 357, 318, -1, 123, -1, 125, -1, 324, -1, + 326, -1, -1, 300, 301, -1, -1, 333, -1, 335, + 336, 337, 338, 339, 340, -1, -1, 342, 343, 344, + 345, 346, 347, 348, -1, -1, 352, 352, 353, 354, + -1, 357, -1, 33, -1, -1, 362, 363, -1, -1, + 40, -1, -1, -1, 44, -1, -1, -1, 374, 375, + 10, -1, -1, -1, -1, 381, 382, 383, -1, -1, + 60, 61, 62, -1, 262, -1, -1, -1, 266, 267, + 268, 269, -1, 33, -1, 273, 274, 275, 276, -1, + 278, 279, -1, 281, 282, -1, -1, 384, 385, -1, + 288, 289, 290, -1, 292, -1, -1, -1, -1, 23, + 298, 299, -1, -1, 302, 303, 304, 305, -1, -1, + 308, -1, -1, 311, -1, -1, -1, -1, -1, -1, + 318, -1, -1, 123, -1, 125, 324, -1, 326, -1, + -1, -1, -1, 57, 58, 59, -1, 335, 336, 337, + 338, 339, 340, -1, 68, -1, -1, 10, 277, -1, + -1, -1, -1, -1, 352, -1, 80, -1, -1, 357, + -1, -1, -1, -1, 362, 363, -1, -1, -1, -1, + -1, 300, 301, 10, -1, 262, 374, 375, -1, 266, + 267, 268, 269, 381, 382, 383, 273, 274, 275, 276, + -1, 278, 279, -1, 281, 282, 33, -1, -1, -1, + -1, -1, 289, 290, -1, 292, 293, -1, 295, 296, + 297, 298, 299, 289, 290, 302, 303, 304, 305, -1, + -1, 308, -1, -1, 311, -1, 302, -1, -1, 305, + -1, 318, -1, -1, -1, 311, -1, 324, -1, 326, + -1, 10, -1, -1, -1, -1, 333, -1, 324, -1, + -1, -1, -1, 340, -1, 384, 385, -1, 182, 183, + -1, -1, 125, 187, 33, 352, -1, -1, -1, -1, + 357, -1, -1, 197, -1, 362, -1, 277, -1, -1, + -1, 357, -1, -1, -1, -1, -1, 374, 375, -1, + -1, -1, -1, -1, 381, 382, 383, -1, -1, -1, + 300, 301, 262, -1, -1, 381, 266, 267, 268, 269, + -1, -1, 306, 273, 274, 275, 276, -1, 278, 279, + -1, 281, 282, -1, -1, -1, -1, -1, -1, 289, + 290, -1, 292, 293, 328, 295, 296, 297, 298, 299, + -1, -1, 302, 303, 304, 305, -1, -1, 308, -1, + -1, 311, -1, -1, -1, -1, -1, -1, 318, 359, + -1, -1, -1, -1, 324, 10, 326, 198, 199, 200, + 364, 365, 366, 333, -1, 369, 370, 371, -1, 373, + 340, -1, 376, 377, 384, 385, -1, -1, 33, -1, + 384, -1, 352, 256, 257, 258, -1, 357, -1, -1, + -1, -1, 362, -1, -1, 414, 415, 416, -1, -1, + -1, -1, 421, 422, 374, 375, -1, -1, -1, -1, + -1, 381, 382, 383, 261, 262, 263, 264, 265, 266, + 267, 268, 269, -1, -1, 298, 273, 274, 275, 276, + -1, 278, 279, -1, 281, 282, -1, -1, -1, -1, + -1, 314, 315, 316, 317, 292, 293, -1, 295, 296, + 297, 298, 299, -1, -1, 302, 303, 304, 299, -1, + -1, 308, -1, -1, -1, 484, -1, 486, -1, 488, + -1, 318, 491, 314, -1, -1, -1, -1, 10, 326, + -1, 322, 261, 262, 263, 264, 265, 266, 267, 268, + 269, -1, -1, 340, 273, 274, 275, 276, -1, 278, + 279, 33, 281, 282, -1, 352, -1, -1, -1, -1, + 357, -1, -1, 292, 293, 362, 295, 296, 297, 298, + 299, -1, 306, 302, 303, 304, 367, 374, 375, 308, + -1, -1, -1, -1, -1, 382, 383, -1, -1, 318, + -1, -1, -1, -1, 328, -1, -1, 326, -1, -1, + -1, -1, -1, -1, -1, -1, 319, 320, 321, 322, + 323, 340, 325, -1, 327, -1, 329, 330, 331, -1, + -1, -1, -1, 352, -1, -1, 10, -1, 357, -1, + 364, 365, 366, 362, -1, 369, 370, 371, -1, 373, + -1, -1, 376, 377, -1, 374, 375, -1, 361, 33, + 384, 620, -1, 382, 383, -1, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 378, 379, -1, 273, 274, + 275, 276, -1, 278, 279, -1, 281, 282, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 292, 293, -1, + 295, 296, 297, 298, 299, -1, -1, 302, 303, 304, + -1, -1, -1, 308, -1, -1, -1, -1, 10, -1, + -1, -1, -1, 318, 342, 343, 344, 345, 346, 347, + 348, 326, -1, -1, 352, 353, 354, -1, -1, -1, + -1, 33, -1, -1, -1, 340, 10, -1, -1, 123, + -1, -1, -1, -1, -1, -1, -1, 352, -1, -1, + -1, -1, 357, -1, -1, -1, -1, 362, -1, 33, + -1, -1, -1, -1, -1, 734, 735, 736, -1, 374, + 375, -1, -1, -1, -1, -1, -1, 382, 383, 261, + 262, 263, 264, 265, 266, 267, 268, 269, -1, -1, + -1, 273, 274, 275, 276, -1, 278, 279, -1, 281, + 282, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 292, 293, -1, 295, 296, 297, 298, 299, -1, -1, + 302, 303, 304, -1, -1, -1, 308, 342, 343, 344, + 345, 346, 347, 348, -1, -1, 318, -1, 353, 354, + -1, -1, -1, -1, 326, -1, -1, -1, -1, 123, + -1, -1, -1, -1, -1, -1, -1, -1, 340, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 352, -1, -1, -1, -1, 357, -1, -1, 262, -1, + 362, -1, 33, -1, 268, 269, -1, -1, -1, -1, + -1, -1, 374, 375, 278, 279, -1, 281, 282, -1, + 382, 383, -1, -1, 288, 289, 290, -1, 292, -1, + -1, -1, -1, -1, 298, 299, -1, -1, 302, 303, + 304, 305, -1, -1, 308, -1, -1, 311, -1, -1, + -1, -1, -1, -1, 318, -1, -1, -1, -1, -1, + 324, -1, 326, -1, -1, -1, -1, -1, -1, -1, + -1, 335, 336, 337, 338, 339, 340, 10, -1, -1, + 262, -1, -1, -1, -1, 267, 268, -1, 352, -1, + -1, 273, -1, 357, 276, -1, -1, -1, 362, 363, + 33, -1, -1, -1, -1, -1, -1, 289, 290, -1, + 374, 375, -1, -1, 268, 269, -1, 381, 382, 383, + 302, -1, -1, 305, 278, 279, -1, 281, 282, 311, + -1, -1, -1, -1, 288, 289, 290, -1, 292, -1, + -1, -1, 324, -1, 298, 299, -1, -1, 302, 303, + 304, 305, -1, -1, 308, -1, -1, 311, -1, -1, + -1, -1, -1, -1, 318, -1, -1, -1, -1, -1, + 324, -1, 326, -1, -1, 357, -1, -1, -1, -1, + -1, 335, 336, 337, 338, 339, 340, -1, 10, -1, + 123, -1, 374, -1, -1, -1, -1, -1, 352, 381, + -1, -1, -1, 357, -1, -1, -1, -1, 362, 363, + -1, 33, -1, -1, -1, -1, -1, -1, -1, -1, + 374, 375, -1, -1, -1, -1, -1, 381, 382, 383, + -1, 262, 10, 264, 265, 266, 267, 268, 269, -1, + -1, -1, 273, 274, 275, 276, -1, 278, 279, -1, + 281, 282, -1, -1, -1, 33, -1, -1, -1, -1, + -1, 292, 293, -1, 295, 296, 297, 298, 299, -1, + -1, 302, 303, 304, -1, -1, -1, 308, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 318, -1, -1, + -1, -1, -1, -1, -1, 326, -1, -1, -1, 10, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 340, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 352, 33, -1, -1, -1, 357, -1, -1, -1, + -1, 362, -1, -1, -1, -1, 269, -1, -1, -1, + -1, -1, -1, 374, 375, 278, 279, -1, 281, 282, + -1, 382, 383, -1, -1, 288, 289, 290, -1, 292, + -1, -1, -1, -1, -1, 298, 299, -1, -1, 302, + 303, 304, 305, -1, -1, 308, -1, -1, 311, -1, + -1, -1, -1, -1, -1, 318, -1, -1, -1, -1, + 10, 324, -1, 326, -1, -1, -1, -1, -1, -1, + -1, -1, 335, 336, 337, 338, 339, 340, -1, -1, + -1, -1, -1, 33, -1, -1, -1, -1, -1, 352, + -1, -1, -1, -1, 357, -1, -1, -1, -1, 362, + 363, -1, 10, -1, -1, -1, -1, -1, -1, -1, + 262, 374, 375, -1, -1, 267, 268, 269, 381, 382, + 383, 273, 274, 275, 276, 33, 278, 279, -1, 281, + 282, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 292, -1, -1, -1, -1, -1, 298, 299, -1, -1, + 302, 303, 304, -1, 262, -1, 308, -1, -1, -1, + 268, -1, -1, -1, -1, -1, 318, -1, -1, -1, + 10, -1, -1, -1, 326, -1, -1, -1, -1, -1, + -1, 289, 290, 335, 336, 337, 338, 339, 340, -1, + -1, -1, -1, 33, 302, -1, -1, 305, -1, -1, + 352, -1, -1, 311, -1, 357, -1, -1, -1, -1, + 362, 363, -1, -1, -1, 123, 324, -1, -1, -1, + -1, 262, 374, 375, -1, -1, 267, 268, 269, -1, + 382, 383, 273, 274, 275, 276, -1, 278, 279, -1, + 281, 282, -1, -1, -1, -1, -1, -1, -1, 357, + -1, 292, -1, -1, -1, -1, -1, 298, 299, -1, + -1, 302, 303, 304, -1, -1, 374, 308, -1, -1, + -1, -1, -1, 381, -1, -1, -1, 318, -1, -1, + -1, 10, -1, -1, -1, 326, -1, -1, -1, -1, + -1, -1, -1, -1, 335, 336, 337, 338, 339, 340, + -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, + -1, 352, 262, -1, -1, -1, 357, 267, 268, -1, + -1, 362, 363, 273, 274, 275, 276, -1, -1, -1, + -1, -1, -1, 374, 375, -1, -1, -1, 288, -1, + -1, 382, 383, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 261, 262, 263, -1, 265, 266, 267, + 268, 269, -1, -1, -1, 273, 274, 275, 276, -1, + 278, 279, -1, 281, 282, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 292, 335, 336, 337, 338, 339, + 298, 299, 10, -1, 302, 303, 304, -1, -1, -1, + 308, -1, -1, -1, -1, -1, -1, 357, -1, -1, + 318, -1, -1, 363, -1, 33, -1, -1, 326, -1, + -1, -1, 262, -1, 374, 375, 266, 267, 268, 269, + -1, -1, 340, 273, 274, 275, 276, -1, 278, 279, + -1, 281, 282, -1, 352, -1, -1, -1, -1, 357, + -1, -1, 292, 293, 362, 295, 296, 297, 298, 299, + -1, -1, 302, 303, 304, -1, 374, 375, 308, -1, + -1, -1, -1, -1, 382, 383, -1, -1, 318, -1, + -1, -1, -1, -1, -1, -1, 326, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 340, -1, -1, 10, -1, 123, -1, -1, -1, -1, + -1, -1, 352, -1, -1, -1, -1, 357, -1, -1, + -1, -1, 362, -1, -1, -1, 33, -1, -1, -1, + -1, -1, -1, 262, 374, 375, -1, -1, 267, 268, + 269, -1, 382, 383, 273, 274, 275, 276, -1, 278, + 279, -1, 281, 282, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 292, 293, -1, 295, 296, 297, 298, + 299, -1, -1, 302, 303, 304, -1, -1, -1, 308, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 318, + -1, -1, -1, -1, -1, -1, -1, 326, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 340, -1, -1, 10, -1, 123, -1, -1, -1, + -1, -1, -1, 352, -1, -1, -1, -1, 357, -1, + -1, -1, -1, 362, -1, -1, -1, 33, -1, -1, + -1, -1, -1, -1, 262, 374, 375, 265, 266, 267, + 268, 269, -1, 382, 383, 273, 274, 275, 276, -1, + 278, 279, -1, 281, 282, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 292, -1, -1, -1, -1, -1, + 298, 299, 10, -1, 302, 303, 304, -1, -1, -1, + 308, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 318, -1, -1, -1, -1, 33, -1, -1, 326, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 340, -1, -1, -1, -1, 123, -1, -1, + -1, -1, -1, -1, 352, -1, -1, -1, -1, 357, + -1, -1, -1, -1, 362, -1, -1, -1, -1, -1, + 10, -1, -1, -1, -1, 262, 374, 375, -1, 266, + 267, 268, 269, -1, 382, 383, 273, 274, 275, 276, + -1, 278, 279, 33, 281, 282, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 292, -1, -1, -1, -1, + -1, 298, 299, -1, -1, 302, 303, 304, -1, -1, + -1, 308, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 318, -1, -1, -1, -1, -1, -1, 10, 326, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 340, -1, -1, -1, -1, -1, -1, + -1, 33, -1, -1, -1, 352, -1, -1, -1, -1, + 357, -1, -1, -1, -1, 362, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 262, 374, 375, -1, + -1, 267, 268, 269, -1, 382, 383, 273, 274, 275, + 276, -1, 278, 279, -1, 281, 282, 10, -1, -1, + -1, -1, -1, -1, -1, -1, 292, -1, -1, -1, + -1, -1, 298, 299, -1, -1, 302, 303, 304, -1, + 33, -1, 308, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 318, -1, -1, -1, -1, -1, -1, -1, + 326, 123, -1, -1, 262, 10, -1, -1, -1, 267, + 268, 269, -1, -1, 340, 273, 274, 275, 276, -1, + 278, 279, -1, 281, 282, -1, 352, -1, 33, -1, + -1, 357, -1, -1, 292, -1, 362, -1, -1, -1, + 298, 299, -1, -1, 302, 303, 304, -1, 374, 375, + 308, -1, -1, -1, -1, -1, 382, 383, -1, -1, + 318, -1, -1, -1, -1, -1, -1, -1, 326, -1, + -1, -1, 262, -1, 10, -1, -1, 267, 268, 269, + -1, -1, 340, 273, 274, 275, 276, -1, 278, 279, + -1, 281, 282, -1, 352, -1, -1, 33, -1, 357, + -1, -1, 292, -1, 362, -1, -1, -1, 298, 299, + -1, -1, 302, 303, 304, -1, 374, 375, 308, -1, + -1, -1, -1, -1, 382, 383, 10, -1, 318, -1, + -1, -1, -1, -1, -1, -1, 326, -1, -1, -1, + 262, -1, -1, -1, -1, 267, 268, 269, -1, 33, + 340, 273, -1, -1, 276, -1, 278, 279, -1, 281, + 282, -1, 352, -1, -1, -1, -1, 357, -1, -1, + 292, -1, 362, -1, -1, -1, 298, 299, -1, -1, + 302, 303, 304, -1, 374, 375, 308, 123, -1, -1, + -1, -1, 382, 383, -1, -1, 318, -1, -1, -1, + -1, -1, -1, -1, 326, -1, -1, -1, -1, 262, + -1, -1, -1, -1, 267, 268, 269, -1, 340, -1, + 273, -1, -1, 276, 10, 278, 279, -1, 281, 282, + 352, -1, -1, -1, -1, 357, -1, -1, -1, 292, + 362, -1, -1, -1, -1, 298, 299, 33, -1, 302, + 303, 304, 374, 375, -1, 308, -1, 262, -1, -1, + 382, 383, 267, 268, -1, 318, -1, -1, 273, 274, + 275, 276, -1, 326, -1, 10, -1, -1, -1, -1, + -1, -1, -1, -1, 289, 290, -1, 340, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 302, 33, 352, + 305, -1, -1, -1, 357, -1, 311, -1, -1, 362, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 324, + -1, 374, 375, -1, -1, -1, 262, -1, -1, 382, + 383, 267, 268, 269, -1, -1, -1, 123, -1, -1, + 276, -1, 278, 279, -1, 281, 282, -1, -1, -1, + -1, -1, 357, -1, -1, -1, 292, -1, -1, -1, + -1, -1, 298, 299, 10, -1, 302, 303, 304, 374, + -1, -1, 308, -1, -1, -1, 381, -1, 262, -1, + -1, -1, 318, 267, 268, 269, -1, 33, -1, -1, + 326, -1, 276, -1, 278, 279, -1, 281, 282, -1, + -1, -1, -1, -1, 340, -1, -1, -1, 292, -1, + 10, -1, -1, -1, 298, 299, 352, -1, 302, 303, + 304, 357, -1, -1, 308, -1, 362, -1, -1, -1, + -1, -1, -1, 33, 318, -1, -1, -1, 374, 375, + -1, -1, 326, -1, -1, -1, 382, 383, -1, -1, + -1, -1, -1, -1, -1, -1, 340, -1, -1, -1, + -1, -1, 10, -1, -1, -1, -1, -1, 352, -1, + -1, -1, -1, 357, -1, -1, 262, 123, 362, -1, + -1, -1, 268, 269, -1, 33, -1, -1, -1, -1, + 374, 375, 278, 279, -1, 281, 282, -1, 382, 383, + -1, -1, -1, -1, -1, -1, 292, -1, 10, -1, + -1, -1, 298, 299, -1, -1, 302, 303, 304, -1, + -1, -1, 308, 123, -1, -1, -1, 262, -1, -1, + -1, 33, 318, 268, 269, -1, -1, -1, -1, -1, + 326, -1, -1, 278, 279, -1, 281, 282, -1, -1, + -1, -1, -1, -1, 340, -1, -1, 292, -1, -1, + -1, -1, -1, 298, 299, -1, 352, 302, 303, 304, + -1, 357, -1, 308, -1, 123, 362, -1, -1, -1, + -1, -1, -1, 318, -1, -1, -1, -1, 374, 375, + -1, 326, -1, -1, -1, -1, 382, 383, -1, -1, + -1, -1, -1, -1, -1, 340, -1, -1, -1, -1, + -1, 10, -1, -1, -1, -1, -1, 352, -1, -1, + -1, -1, 357, 269, -1, -1, -1, 362, -1, -1, + -1, 10, 278, 279, 33, 281, 282, -1, -1, 374, + 375, -1, -1, -1, -1, -1, 292, 382, 383, -1, + -1, -1, 298, 299, 33, -1, 302, 303, 304, -1, + -1, -1, 308, -1, 10, -1, -1, -1, -1, 269, + -1, -1, 318, -1, -1, -1, -1, -1, 278, 279, + 326, 281, 282, -1, -1, -1, -1, 33, -1, -1, + -1, -1, 292, -1, 340, -1, 10, -1, 298, 299, + -1, -1, 302, 303, 304, -1, 352, -1, 308, -1, + -1, 357, -1, -1, -1, -1, 362, -1, 318, 33, + -1, 269, -1, -1, -1, -1, 326, -1, 374, 375, + 278, 279, -1, 281, 282, -1, 382, 383, -1, -1, + 340, -1, 10, -1, 292, -1, -1, -1, -1, 10, + 298, 299, 352, -1, 302, 303, 304, 357, -1, -1, + 308, -1, 362, -1, -1, 33, -1, 269, -1, -1, + 318, -1, 33, -1, 374, 375, 278, 279, 326, 281, + 282, -1, 382, 383, -1, -1, -1, -1, -1, -1, + 292, -1, 340, -1, -1, -1, 298, 299, -1, -1, + 302, 303, 304, -1, 352, -1, 308, -1, -1, 357, + -1, -1, -1, -1, 362, -1, 318, -1, -1, -1, + -1, -1, -1, -1, 326, -1, 374, 375, -1, -1, + -1, -1, -1, -1, 382, 383, -1, -1, 340, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 352, -1, 33, -1, -1, 357, -1, -1, -1, -1, + 362, -1, -1, 262, -1, 264, 265, 266, 267, 268, + -1, -1, 374, 375, 273, 274, 275, 276, -1, -1, + 382, 383, -1, 262, -1, -1, -1, 266, 267, 268, + 289, 290, -1, -1, 273, 274, 275, 276, -1, -1, + -1, -1, -1, 302, -1, -1, 305, -1, -1, -1, + 289, 290, 311, -1, -1, -1, 262, -1, -1, -1, + 266, 267, 268, 302, -1, 324, 305, 273, 274, 275, + 276, -1, 311, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 288, -1, -1, 324, -1, -1, 262, -1, + -1, -1, 266, 267, 268, -1, -1, -1, 357, 273, + 274, 275, 276, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 288, 374, -1, -1, 357, -1, + -1, -1, 381, -1, -1, -1, -1, -1, -1, 335, + 336, 337, 338, 339, 262, 374, -1, -1, -1, 267, + 268, 262, 381, -1, -1, 273, 267, 268, 276, -1, + -1, 357, -1, -1, -1, 276, -1, 363, -1, -1, + 288, 335, 336, 337, 338, 339, -1, 288, 374, 375, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 357, -1, -1, -1, -1, -1, 363, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 374, 375, -1, -1, -1, -1, -1, 335, 336, 337, + 338, 339, -1, -1, 335, 336, 337, 338, 339, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 269, 357, + -1, -1, -1, -1, -1, 363, 357, 278, 279, -1, + 281, 282, 363, -1, -1, -1, 374, 375, -1, -1, + -1, 292, -1, 374, 375, -1, -1, 298, 299, -1, + -1, 302, 303, 304, -1, -1, -1, 308, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 318, -1, -1, + -1, -1, -1, -1, -1, 326, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 340, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 352, -1, -1, -1, -1, 357, -1, -1, -1, + -1, 362, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 375, -1, -1, -1, -1, -1, + -1, 382, 383, +}; +#define YYFINAL 2 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 386 +#define YYUNDFTOKEN 557 +#define YYTRANSLATE(a) ((a) > YYMAXTOKEN ? YYUNDFTOKEN : (a)) +#if YYDEBUG +static const char *const pfctlyname[] = { + +"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,"'!'",0,0,0,0,0,0,"'('","')'",0,0,"','","'-'",0,"'/'",0,0,0,0,0,0,0,0,0,0,0, +0,"'<'","'='","'>'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,"PASS","BLOCK","SCRUB","RETURN","IN","OS","OUT","LOG","QUICK", +"ON","FROM","TO","FLAGS","RETURNRST","RETURNICMP","RETURNICMP6","PROTO","INET", +"INET6","ALL","ANY","ICMPTYPE","ICMP6TYPE","CODE","KEEP","MODULATE","STATE", +"PORT","RDR","NAT","BINAT","ARROW","NODF","MINTTL","ERROR","ALLOWOPTS", +"FASTROUTE","FILENAME","ROUTETO","DUPTO","REPLYTO","NO","LABEL","NOROUTE", +"URPFFAILED","FRAGMENT","USER","GROUP","MAXMSS","MAXIMUM","TTL","TOS","DROP", +"TABLE","REASSEMBLE","FRAGDROP","FRAGCROP","ANCHOR","NATANCHOR","RDRANCHOR", +"BINATANCHOR","SET","OPTIMIZATION","TIMEOUT","LIMIT","LOGINTERFACE", +"BLOCKPOLICY","RANDOMID","REQUIREORDER","SYNPROXY","FINGERPRINTS","NOSYNC", +"DEBUG","SKIP","HOSTID","ANTISPOOF","FOR","INCLUDE","BITMASK","RANDOM", +"SOURCEHASH","ROUNDROBIN","STATICPORT","PROBABILITY","ALTQ","CBQ","CODEL", +"PRIQ","HFSC","FAIRQ","BANDWIDTH","TBRSIZE","LINKSHARE","REALTIME","UPPERLIMIT", +"QUEUE","PRIORITY","QLIMIT","HOGS","BUCKETS","RTABLE","TARGET","INTERVAL", +"LOAD","RULESET_OPTIMIZATION","PRIO","STICKYADDRESS","MAXSRCSTATES", +"MAXSRCNODES","SOURCETRACK","GLOBAL","RULE","MAXSRCCONN","MAXSRCCONNRATE", +"OVERLOAD","FLUSH","SLOPPY","TAGGED","TAG","IFBOUND","FLOATING","STATEPOLICY", +"STATEDEFAULTS","ROUTE","SETTOS","DIVERTTO","DIVERTREPLY","STRING","NUMBER", +"PORTBINARY",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"illegal-symbol", +}; +static const char *const pfctlyrule[] = { +"$accept : ruleset", +"ruleset :", +"ruleset : ruleset include '\\n'", +"ruleset : ruleset '\\n'", +"ruleset : ruleset option '\\n'", +"ruleset : ruleset scrubrule '\\n'", +"ruleset : ruleset natrule '\\n'", +"ruleset : ruleset binatrule '\\n'", +"ruleset : ruleset pfrule '\\n'", +"ruleset : ruleset anchorrule '\\n'", +"ruleset : ruleset loadrule '\\n'", +"ruleset : ruleset altqif '\\n'", +"ruleset : ruleset queuespec '\\n'", +"ruleset : ruleset varset '\\n'", +"ruleset : ruleset antispoof '\\n'", +"ruleset : ruleset tabledef '\\n'", +"ruleset : '{' fakeanchor '}' '\\n'", +"ruleset : ruleset error '\\n'", +"include : INCLUDE STRING", +"fakeanchor : fakeanchor '\\n'", +"fakeanchor : fakeanchor anchorrule '\\n'", +"fakeanchor : fakeanchor binatrule '\\n'", +"fakeanchor : fakeanchor natrule '\\n'", +"fakeanchor : fakeanchor pfrule '\\n'", +"fakeanchor : fakeanchor error '\\n'", +"optimizer : string", +"option : SET OPTIMIZATION STRING", +"option : SET RULESET_OPTIMIZATION optimizer", +"option : SET TIMEOUT timeout_spec", +"option : SET TIMEOUT '{' optnl timeout_list '}'", +"option : SET LIMIT limit_spec", +"option : SET LIMIT '{' optnl limit_list '}'", +"option : SET LOGINTERFACE stringall", +"option : SET HOSTID number", +"option : SET BLOCKPOLICY DROP", +"option : SET BLOCKPOLICY RETURN", +"option : SET REQUIREORDER yesno", +"option : SET FINGERPRINTS STRING", +"option : SET STATEPOLICY statelock", +"option : SET DEBUG STRING", +"option : SET SKIP interface", +"option : SET STATEDEFAULTS state_opt_list", +"stringall : STRING", +"stringall : ALL", +"string : STRING string", +"string : STRING", +"varstring : numberstring varstring", +"varstring : numberstring", +"numberstring : NUMBER", +"numberstring : STRING", +"varset : STRING '=' varstring", +"anchorname : STRING", +"anchorname :", +"pfa_anchorlist :", +"pfa_anchorlist : pfa_anchorlist '\\n'", +"pfa_anchorlist : pfa_anchorlist pfrule '\\n'", +"pfa_anchorlist : pfa_anchorlist anchorrule '\\n'", +"$$1 :", +"pfa_anchor : '{' $$1 '\\n' pfa_anchorlist '}'", +"pfa_anchor :", +"anchorrule : ANCHOR anchorname dir quick interface af proto fromto filter_opts pfa_anchor", +"anchorrule : NATANCHOR string interface af proto fromto rtable", +"anchorrule : RDRANCHOR string interface af proto fromto rtable", +"anchorrule : BINATANCHOR string interface af proto fromto rtable", +"loadrule : LOAD ANCHOR string FROM string", +"scrubaction : no SCRUB", +"scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts", +"$$2 :", +"scrub_opts : $$2 scrub_opts_l", +"scrub_opts :", +"scrub_opts_l : scrub_opts_l scrub_opt", +"scrub_opts_l : scrub_opt", +"scrub_opt : NODF", +"scrub_opt : MINTTL NUMBER", +"scrub_opt : MAXMSS NUMBER", +"scrub_opt : SETTOS tos", +"scrub_opt : fragcache", +"scrub_opt : REASSEMBLE STRING", +"scrub_opt : RANDOMID", +"scrub_opt : RTABLE NUMBER", +"scrub_opt : not TAGGED string", +"fragcache : FRAGMENT REASSEMBLE", +"fragcache : FRAGMENT FRAGCROP", +"fragcache : FRAGMENT FRAGDROP", +"antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts", +"antispoof_ifspc : FOR antispoof_if", +"antispoof_ifspc : FOR '{' optnl antispoof_iflst '}'", +"antispoof_iflst : antispoof_if optnl", +"antispoof_iflst : antispoof_iflst comma antispoof_if optnl", +"antispoof_if : if_item", +"antispoof_if : '(' if_item ')'", +"$$3 :", +"antispoof_opts : $$3 antispoof_opts_l", +"antispoof_opts :", +"antispoof_opts_l : antispoof_opts_l antispoof_opt", +"antispoof_opts_l : antispoof_opt", +"antispoof_opt : label", +"antispoof_opt : RTABLE NUMBER", +"not : '!'", +"not :", +"tabledef : TABLE '<' STRING '>' table_opts", +"$$4 :", +"table_opts : $$4 table_opts_l", +"table_opts :", +"table_opts_l : table_opts_l table_opt", +"table_opts_l : table_opt", +"table_opt : STRING", +"table_opt : '{' optnl '}'", +"table_opt : '{' optnl host_list '}'", +"table_opt : FILENAME STRING", +"altqif : ALTQ interface queue_opts QUEUE qassign", +"queuespec : QUEUE STRING interface queue_opts qassign", +"$$5 :", +"queue_opts : $$5 queue_opts_l", +"queue_opts :", +"queue_opts_l : queue_opts_l queue_opt", +"queue_opts_l : queue_opt", +"queue_opt : BANDWIDTH bandwidth", +"queue_opt : PRIORITY NUMBER", +"queue_opt : QLIMIT NUMBER", +"queue_opt : scheduler", +"queue_opt : TBRSIZE NUMBER", +"bandwidth : STRING", +"bandwidth : NUMBER", +"scheduler : CBQ", +"scheduler : CBQ '(' cbqflags_list ')'", +"scheduler : PRIQ", +"scheduler : PRIQ '(' priqflags_list ')'", +"scheduler : HFSC", +"scheduler : HFSC '(' hfsc_opts ')'", +"scheduler : FAIRQ", +"scheduler : FAIRQ '(' fairq_opts ')'", +"scheduler : CODEL", +"scheduler : CODEL '(' codel_opts ')'", +"cbqflags_list : cbqflags_item", +"cbqflags_list : cbqflags_list comma cbqflags_item", +"cbqflags_item : STRING", +"priqflags_list : priqflags_item", +"priqflags_list : priqflags_list comma priqflags_item", +"priqflags_item : STRING", +"$$6 :", +"hfsc_opts : $$6 hfscopts_list", +"hfscopts_list : hfscopts_item", +"hfscopts_list : hfscopts_list comma hfscopts_item", +"hfscopts_item : LINKSHARE bandwidth", +"hfscopts_item : LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')'", +"hfscopts_item : REALTIME bandwidth", +"hfscopts_item : REALTIME '(' bandwidth comma NUMBER comma bandwidth ')'", +"hfscopts_item : UPPERLIMIT bandwidth", +"hfscopts_item : UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')'", +"hfscopts_item : STRING", +"$$7 :", +"fairq_opts : $$7 fairqopts_list", +"fairqopts_list : fairqopts_item", +"fairqopts_list : fairqopts_list comma fairqopts_item", +"fairqopts_item : LINKSHARE bandwidth", +"fairqopts_item : LINKSHARE '(' bandwidth number bandwidth ')'", +"fairqopts_item : HOGS bandwidth", +"fairqopts_item : BUCKETS number", +"fairqopts_item : STRING", +"$$8 :", +"codel_opts : $$8 codelopts_list", +"codelopts_list : codelopts_item", +"codelopts_list : codelopts_list comma codelopts_item", +"codelopts_item : INTERVAL number", +"codelopts_item : TARGET number", +"codelopts_item : STRING", +"qassign :", +"qassign : qassign_item", +"qassign : '{' optnl qassign_list '}'", +"qassign_list : qassign_item optnl", +"qassign_list : qassign_list comma qassign_item optnl", +"qassign_item : STRING", +"pfrule : action dir logquick interface route af proto fromto filter_opts", +"$$9 :", +"filter_opts : $$9 filter_opts_l", +"filter_opts :", +"filter_opts_l : filter_opts_l filter_opt", +"filter_opts_l : filter_opt", +"filter_opt : USER uids", +"filter_opt : GROUP gids", +"filter_opt : flags", +"filter_opt : icmpspec", +"filter_opt : PRIO NUMBER", +"filter_opt : TOS tos", +"filter_opt : keep", +"filter_opt : FRAGMENT", +"filter_opt : ALLOWOPTS", +"filter_opt : label", +"filter_opt : qname", +"filter_opt : TAG string", +"filter_opt : not TAGGED string", +"filter_opt : PROBABILITY probability", +"filter_opt : RTABLE NUMBER", +"filter_opt : DIVERTTO portplain", +"filter_opt : DIVERTTO STRING PORT portplain", +"filter_opt : DIVERTREPLY", +"filter_opt : filter_sets", +"filter_sets : SET '(' filter_sets_l ')'", +"filter_sets : SET filter_set", +"filter_sets_l : filter_sets_l comma filter_set", +"filter_sets_l : filter_set", +"filter_set : prio", +"prio : PRIO NUMBER", +"prio : PRIO '(' NUMBER comma NUMBER ')'", +"probability : STRING", +"probability : NUMBER", +"action : PASS", +"action : BLOCK blockspec", +"blockspec :", +"blockspec : DROP", +"blockspec : RETURNRST", +"blockspec : RETURNRST '(' TTL NUMBER ')'", +"blockspec : RETURNICMP", +"blockspec : RETURNICMP6", +"blockspec : RETURNICMP '(' reticmpspec ')'", +"blockspec : RETURNICMP6 '(' reticmp6spec ')'", +"blockspec : RETURNICMP '(' reticmpspec comma reticmp6spec ')'", +"blockspec : RETURN", +"reticmpspec : STRING", +"reticmpspec : NUMBER", +"reticmp6spec : STRING", +"reticmp6spec : NUMBER", +"dir :", +"dir : IN", +"dir : OUT", +"quick :", +"quick : QUICK", +"logquick :", +"logquick : log", +"logquick : QUICK", +"logquick : log QUICK", +"logquick : QUICK log", +"log : LOG", +"log : LOG '(' logopts ')'", +"logopts : logopt", +"logopts : logopts comma logopt", +"logopt : ALL", +"logopt : USER", +"logopt : GROUP", +"logopt : TO string", +"interface :", +"interface : ON if_item_not", +"interface : ON '{' optnl if_list '}'", +"if_list : if_item_not optnl", +"if_list : if_list comma if_item_not optnl", +"if_item_not : not if_item", +"if_item : STRING", +"af :", +"af : INET", +"af : INET6", +"proto :", +"proto : PROTO proto_item", +"proto : PROTO '{' optnl proto_list '}'", +"proto_list : proto_item optnl", +"proto_list : proto_list comma proto_item optnl", +"proto_item : protoval", +"protoval : STRING", +"protoval : NUMBER", +"fromto : ALL", +"fromto : from os to", +"os :", +"os : OS xos", +"os : OS '{' optnl os_list '}'", +"xos : STRING", +"os_list : xos optnl", +"os_list : os_list comma xos optnl", +"from :", +"from : FROM ipportspec", +"to :", +"to : TO ipportspec", +"ipportspec : ipspec", +"ipportspec : ipspec PORT portspec", +"ipportspec : PORT portspec", +"optnl : '\\n' optnl", +"optnl :", +"ipspec : ANY", +"ipspec : xhost", +"ipspec : '{' optnl host_list '}'", +"toipspec : TO ipspec", +"toipspec :", +"host_list : ipspec optnl", +"host_list : host_list comma ipspec optnl", +"xhost : not host", +"xhost : not NOROUTE", +"xhost : not URPFFAILED", +"host : STRING", +"host : STRING '-' STRING", +"host : STRING '/' NUMBER", +"host : NUMBER '/' NUMBER", +"host : dynaddr", +"host : dynaddr '/' NUMBER", +"host : '<' STRING '>'", +"number : NUMBER", +"number : STRING", +"dynaddr : '(' STRING ')'", +"portspec : port_item", +"portspec : '{' optnl port_list '}'", +"port_list : port_item optnl", +"port_list : port_list comma port_item optnl", +"port_item : portrange", +"port_item : unaryop portrange", +"port_item : portrange PORTBINARY portrange", +"portplain : numberstring", +"portrange : numberstring", +"uids : uid_item", +"uids : '{' optnl uid_list '}'", +"uid_list : uid_item optnl", +"uid_list : uid_list comma uid_item optnl", +"uid_item : uid", +"uid_item : unaryop uid", +"uid_item : uid PORTBINARY uid", +"uid : STRING", +"uid : NUMBER", +"gids : gid_item", +"gids : '{' optnl gid_list '}'", +"gid_list : gid_item optnl", +"gid_list : gid_list comma gid_item optnl", +"gid_item : gid", +"gid_item : unaryop gid", +"gid_item : gid PORTBINARY gid", +"gid : STRING", +"gid : NUMBER", +"flag : STRING", +"flags : FLAGS flag '/' flag", +"flags : FLAGS '/' flag", +"flags : FLAGS ANY", +"icmpspec : ICMPTYPE icmp_item", +"icmpspec : ICMPTYPE '{' optnl icmp_list '}'", +"icmpspec : ICMP6TYPE icmp6_item", +"icmpspec : ICMP6TYPE '{' optnl icmp6_list '}'", +"icmp_list : icmp_item optnl", +"icmp_list : icmp_list comma icmp_item optnl", +"icmp6_list : icmp6_item optnl", +"icmp6_list : icmp6_list comma icmp6_item optnl", +"icmp_item : icmptype", +"icmp_item : icmptype CODE STRING", +"icmp_item : icmptype CODE NUMBER", +"icmp6_item : icmp6type", +"icmp6_item : icmp6type CODE STRING", +"icmp6_item : icmp6type CODE NUMBER", +"icmptype : STRING", +"icmptype : NUMBER", +"icmp6type : STRING", +"icmp6type : NUMBER", +"tos : STRING", +"tos : NUMBER", +"sourcetrack : SOURCETRACK", +"sourcetrack : SOURCETRACK GLOBAL", +"sourcetrack : SOURCETRACK RULE", +"statelock : IFBOUND", +"statelock : FLOATING", +"keep : NO STATE", +"keep : KEEP STATE state_opt_spec", +"keep : MODULATE STATE state_opt_spec", +"keep : SYNPROXY STATE state_opt_spec", +"flush :", +"flush : FLUSH", +"flush : FLUSH GLOBAL", +"state_opt_spec : '(' state_opt_list ')'", +"state_opt_spec :", +"state_opt_list : state_opt_item", +"state_opt_list : state_opt_list comma state_opt_item", +"state_opt_item : MAXIMUM NUMBER", +"state_opt_item : NOSYNC", +"state_opt_item : MAXSRCSTATES NUMBER", +"state_opt_item : MAXSRCCONN NUMBER", +"state_opt_item : MAXSRCCONNRATE NUMBER '/' NUMBER", +"state_opt_item : OVERLOAD '<' STRING '>' flush", +"state_opt_item : MAXSRCNODES NUMBER", +"state_opt_item : sourcetrack", +"state_opt_item : statelock", +"state_opt_item : SLOPPY", +"state_opt_item : STRING NUMBER", +"label : LABEL STRING", +"qname : QUEUE STRING", +"qname : QUEUE '(' STRING ')'", +"qname : QUEUE '(' STRING comma STRING ')'", +"no :", +"no : NO", +"portstar : numberstring", +"redirspec : host", +"redirspec : '{' optnl redir_host_list '}'", +"redir_host_list : host optnl", +"redir_host_list : redir_host_list comma host optnl", +"redirpool :", +"redirpool : ARROW redirspec", +"redirpool : ARROW redirspec PORT portstar", +"hashkey :", +"hashkey : string", +"$$10 :", +"pool_opts : $$10 pool_opts_l", +"pool_opts :", +"pool_opts_l : pool_opts_l pool_opt", +"pool_opts_l : pool_opt", +"pool_opt : BITMASK", +"pool_opt : RANDOM", +"pool_opt : SOURCEHASH hashkey", +"pool_opt : ROUNDROBIN", +"pool_opt : STATICPORT", +"pool_opt : STICKYADDRESS", +"redirection :", +"redirection : ARROW host", +"redirection : ARROW host PORT portstar", +"natpasslog :", +"natpasslog : PASS", +"natpasslog : PASS log", +"natpasslog : log", +"nataction : no NAT natpasslog", +"nataction : no RDR natpasslog", +"natrule : nataction interface af proto fromto tag tagged rtable redirpool pool_opts", +"binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag tagged rtable redirection", +"tag :", +"tag : TAG STRING", +"tagged :", +"tagged : not TAGGED string", +"rtable :", +"rtable : RTABLE NUMBER", +"route_host : STRING", +"route_host : '(' STRING host ')'", +"route_host_list : route_host optnl", +"route_host_list : route_host_list comma route_host optnl", +"routespec : route_host", +"routespec : '{' optnl route_host_list '}'", +"route :", +"route : FASTROUTE", +"route : ROUTETO routespec pool_opts", +"route : REPLYTO routespec pool_opts", +"route : DUPTO routespec pool_opts", +"timeout_spec : STRING NUMBER", +"timeout_spec : INTERVAL NUMBER", +"timeout_list : timeout_list comma timeout_spec optnl", +"timeout_list : timeout_spec optnl", +"limit_spec : STRING NUMBER", +"limit_list : limit_list comma limit_spec optnl", +"limit_list : limit_spec optnl", +"comma : ','", +"comma :", +"yesno : NO", +"yesno : STRING", +"unaryop : '='", +"unaryop : '!' '='", +"unaryop : '<' '='", +"unaryop : '<'", +"unaryop : '>' '='", +"unaryop : '>'", + +}; +#endif + +int yydebug; +int yynerrs; + +int yyerrflag; +int yychar; +YYSTYPE yyval; +YYSTYPE yylval; + +/* define the initial stack-sizes */ +#ifdef YYSTACKSIZE +#undef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 10000 +#define YYMAXDEPTH 10000 +#endif +#endif + +#define YYINITSTACKSIZE 200 + +typedef struct { + unsigned stacksize; + YYINT *s_base; + YYINT *s_mark; + YYINT *s_last; + YYSTYPE *l_base; + YYSTYPE *l_mark; +} YYSTACKDATA; +/* variables for the parser stack */ +static YYSTACKDATA yystack; +#line 4545 "../../freebsd/sbin/pfctl/parse.y" +#ifdef __rtems__ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlyval); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlylval); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack); +#endif /* __rtems__ */ + +int +yyerror(const char *fmt, ...) +{ + va_list ap; + + file->errors++; + va_start(ap, fmt); + fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + return (0); +} + +int +disallow_table(struct node_host *h, const char *fmt) +{ + for (; h != NULL; h = h->next) + if (h->addr.type == PF_ADDR_TABLE) { + yyerror(fmt, h->addr.v.tblname); + return (1); + } + return (0); +} + +int +disallow_urpf_failed(struct node_host *h, const char *fmt) +{ + for (; h != NULL; h = h->next) + if (h->addr.type == PF_ADDR_URPFFAILED) { + yyerror(fmt); + return (1); + } + return (0); +} + +int +disallow_alias(struct node_host *h, const char *fmt) +{ + for (; h != NULL; h = h->next) + if (DYNIF_MULTIADDR(h->addr)) { + yyerror(fmt, h->addr.v.tblname); + return (1); + } + return (0); +} + +int +rule_consistent(struct pf_rule *r, int anchor_call) +{ + int problems = 0; + + switch (r->action) { + case PF_PASS: + case PF_DROP: + case PF_SCRUB: + case PF_NOSCRUB: + problems = filter_consistent(r, anchor_call); + break; + case PF_NAT: + case PF_NONAT: + problems = nat_consistent(r); + break; + case PF_RDR: + case PF_NORDR: + problems = rdr_consistent(r); + break; + case PF_BINAT: + case PF_NOBINAT: + default: + break; + } + return (problems); +} + +int +filter_consistent(struct pf_rule *r, int anchor_call) +{ + int problems = 0; + + if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && + (r->src.port_op || r->dst.port_op)) { + yyerror("port only applies to tcp/udp"); + problems++; + } + if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && + (r->type || r->code)) { + yyerror("icmp-type/code only applies to icmp"); + problems++; + } + if (!r->af && (r->type || r->code)) { + yyerror("must indicate address family with icmp-type/code"); + problems++; + } + if (r->overload_tblname[0] && + r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) { + yyerror("'overload' requires 'max-src-conn' " + "or 'max-src-conn-rate'"); + problems++; + } + if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || + (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { + yyerror("proto %s doesn't match address family %s", + r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", + r->af == AF_INET ? "inet" : "inet6"); + problems++; + } + if (r->allow_opts && r->action != PF_PASS) { + yyerror("allow-opts can only be specified for pass rules"); + problems++; + } + if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || + r->dst.port_op || r->flagset || r->type || r->code)) { + yyerror("fragments can be filtered only on IP header fields"); + problems++; + } + if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { + yyerror("return-rst can only be applied to TCP rules"); + problems++; + } + if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { + yyerror("max-src-nodes requires 'source-track rule'"); + problems++; + } + if (r->action == PF_DROP && r->keep_state) { + yyerror("keep state on block rules doesn't make sense"); + problems++; + } + if (r->rule_flag & PFRULE_STATESLOPPY && + (r->keep_state == PF_STATE_MODULATE || + r->keep_state == PF_STATE_SYNPROXY)) { + yyerror("sloppy state matching cannot be used with " + "synproxy state or modulate state"); + problems++; + } + return (-problems); +} + +int +nat_consistent(struct pf_rule *r) +{ + return (0); /* yeah! */ +} + +int +rdr_consistent(struct pf_rule *r) +{ + int problems = 0; + + if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { + if (r->src.port_op) { + yyerror("src port only applies to tcp/udp"); + problems++; + } + if (r->dst.port_op) { + yyerror("dst port only applies to tcp/udp"); + problems++; + } + if (r->rpool.proxy_port[0]) { + yyerror("rpool port only applies to tcp/udp"); + problems++; + } + } + if (r->dst.port_op && + r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { + yyerror("invalid port operator for rdr destination port"); + problems++; + } + return (-problems); +} + +int +process_tabledef(char *name, struct table_opts *opts) +{ + struct pfr_buffer ab; + struct node_tinit *ti; + + bzero(&ab, sizeof(ab)); + ab.pfrb_type = PFRB_ADDRS; + SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { + if (ti->file) + if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { + if (errno) + yyerror("cannot load \"%s\": %s", + ti->file, strerror(errno)); + else + yyerror("file \"%s\" contains bad data", + ti->file); + goto _error; + } + if (ti->host) + if (append_addr_host(&ab, ti->host, 0, 0)) { + yyerror("cannot create address buffer: %s", + strerror(errno)); + goto _error; + } + } + if (pf->opts & PF_OPT_VERBOSE) + print_tabledef(name, opts->flags, opts->init_addr, + &opts->init_nodes); + if (!(pf->opts & PF_OPT_NOACTION) && + pfctl_define_table(name, opts->flags, opts->init_addr, + pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { + yyerror("cannot define table %s: %s", name, + pfr_strerror(errno)); + goto _error; + } + pf->tdirty = 1; + pfr_buf_clear(&ab); + return (0); +_error: + pfr_buf_clear(&ab); + return (-1); +} + +struct keywords { + const char *k_name; + int k_val; +}; + +/* macro gore, but you should've seen the prior indentation nightmare... */ + +#define FREE_LIST(T,r) \ + do { \ + T *p, *node = r; \ + while (node != NULL) { \ + p = node; \ + node = node->next; \ + free(p); \ + } \ + } while (0) + +#define LOOP_THROUGH(T,n,r,C) \ + do { \ + T *n; \ + if (r == NULL) { \ + r = calloc(1, sizeof(T)); \ + if (r == NULL) \ + err(1, "LOOP: calloc"); \ + r->next = NULL; \ + } \ + n = r; \ + while (n != NULL) { \ + do { \ + C; \ + } while (0); \ + n = n->next; \ + } \ + } while (0) + +void +expand_label_str(char *label, size_t len, const char *srch, const char *repl) +{ + char *tmp; + char *p, *q; + + if ((tmp = calloc(1, len)) == NULL) + err(1, "expand_label_str: calloc"); + p = q = label; + while ((q = strstr(p, srch)) != NULL) { + *q = '\0'; + if ((strlcat(tmp, p, len) >= len) || + (strlcat(tmp, repl, len) >= len)) + errx(1, "expand_label: label too long"); + q += strlen(srch); + p = q; + } + if (strlcat(tmp, p, len) >= len) + errx(1, "expand_label: label too long"); + strlcpy(label, tmp, len); /* always fits */ + free(tmp); +} + +void +expand_label_if(const char *name, char *label, size_t len, const char *ifname) +{ + if (strstr(label, name) != NULL) { + if (!*ifname) + expand_label_str(label, len, name, "any"); + else + expand_label_str(label, len, name, ifname); + } +} + +void +expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, + struct node_host *h) +{ + char tmp[64], tmp_not[66]; + + if (strstr(label, name) != NULL) { + switch (h->addr.type) { + case PF_ADDR_DYNIFTL: + snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname); + break; + case PF_ADDR_TABLE: + snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname); + break; + case PF_ADDR_NOROUTE: + snprintf(tmp, sizeof(tmp), "no-route"); + break; + case PF_ADDR_URPFFAILED: + snprintf(tmp, sizeof(tmp), "urpf-failed"); + break; + case PF_ADDR_ADDRMASK: + if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && + PF_AZERO(&h->addr.v.a.mask, af))) + snprintf(tmp, sizeof(tmp), "any"); + else { + char a[48]; + int bits; + + if (inet_ntop(af, &h->addr.v.a.addr, a, + sizeof(a)) == NULL) + snprintf(tmp, sizeof(tmp), "?"); + else { + bits = unmask(&h->addr.v.a.mask, af); + if ((af == AF_INET && bits < 32) || + (af == AF_INET6 && bits < 128)) + snprintf(tmp, sizeof(tmp), + "%s/%d", a, bits); + else + snprintf(tmp, sizeof(tmp), + "%s", a); + } + } + break; + default: + snprintf(tmp, sizeof(tmp), "?"); + break; + } + + if (h->not) { + snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); + expand_label_str(label, len, name, tmp_not); + } else + expand_label_str(label, len, name, tmp); + } +} + +void +expand_label_port(const char *name, char *label, size_t len, + struct node_port *port) +{ + char a1[6], a2[6], op[13] = ""; + + if (strstr(label, name) != NULL) { + snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); + snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); + if (!port->op) + ; + else if (port->op == PF_OP_IRG) + snprintf(op, sizeof(op), "%s><%s", a1, a2); + else if (port->op == PF_OP_XRG) + snprintf(op, sizeof(op), "%s<>%s", a1, a2); + else if (port->op == PF_OP_EQ) + snprintf(op, sizeof(op), "%s", a1); + else if (port->op == PF_OP_NE) + snprintf(op, sizeof(op), "!=%s", a1); + else if (port->op == PF_OP_LT) + snprintf(op, sizeof(op), "<%s", a1); + else if (port->op == PF_OP_LE) + snprintf(op, sizeof(op), "<=%s", a1); + else if (port->op == PF_OP_GT) + snprintf(op, sizeof(op), ">%s", a1); + else if (port->op == PF_OP_GE) + snprintf(op, sizeof(op), ">=%s", a1); + expand_label_str(label, len, name, op); + } +} + +void +expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) +{ + struct protoent *pe; + char n[4]; + + if (strstr(label, name) != NULL) { + pe = getprotobynumber(proto); + if (pe != NULL) + expand_label_str(label, len, name, pe->p_name); + else { + snprintf(n, sizeof(n), "%u", proto); + expand_label_str(label, len, name, n); + } + } +} + +void +expand_label_nr(const char *name, char *label, size_t len) +{ + char n[11]; + + if (strstr(label, name) != NULL) { + snprintf(n, sizeof(n), "%u", pf->anchor->match); + expand_label_str(label, len, name, n); + } +} + +void +expand_label(char *label, size_t len, const char *ifname, sa_family_t af, + struct node_host *src_host, struct node_port *src_port, + struct node_host *dst_host, struct node_port *dst_port, + u_int8_t proto) +{ + expand_label_if("$if", label, len, ifname); + expand_label_addr("$srcaddr", label, len, af, src_host); + expand_label_addr("$dstaddr", label, len, af, dst_host); + expand_label_port("$srcport", label, len, src_port); + expand_label_port("$dstport", label, len, dst_port); + expand_label_proto("$proto", label, len, proto); + expand_label_nr("$nr", label, len); +} + +int +expand_altq(struct pf_altq *a, struct node_if *interfaces, + struct node_queue *nqueues, struct node_queue_bw bwspec, + struct node_queue_opt *opts) +{ + struct pf_altq pa, pb; + char qname[PF_QNAME_SIZE]; + struct node_queue *n; + struct node_queue_bw bw; + int errs = 0; + + if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { + FREE_LIST(struct node_if, interfaces); + if (nqueues) + FREE_LIST(struct node_queue, nqueues); + return (0); + } + + LOOP_THROUGH(struct node_if, interface, interfaces, + memcpy(&pa, a, sizeof(struct pf_altq)); + if (strlcpy(pa.ifname, interface->ifname, + sizeof(pa.ifname)) >= sizeof(pa.ifname)) + errx(1, "expand_altq: strlcpy"); + + if (interface->not) { + yyerror("altq on ! <interface> is not supported"); + errs++; + } else { + if (eval_pfaltq(pf, &pa, &bwspec, opts)) + errs++; + else + if (pfctl_add_altq(pf, &pa)) + errs++; + + if (pf->opts & PF_OPT_VERBOSE) { + print_altq(&pf->paltq->altq, 0, + &bwspec, opts); + if (nqueues && nqueues->tail) { + printf("queue { "); + LOOP_THROUGH(struct node_queue, queue, + nqueues, + printf("%s ", + queue->queue); + ); + printf("}"); + } + printf("\n"); + } + + if (pa.scheduler == ALTQT_CBQ || + pa.scheduler == ALTQT_HFSC) { + /* now create a root queue */ + memset(&pb, 0, sizeof(struct pf_altq)); + if (strlcpy(qname, "root_", sizeof(qname)) >= + sizeof(qname)) + errx(1, "expand_altq: strlcpy"); + if (strlcat(qname, interface->ifname, + sizeof(qname)) >= sizeof(qname)) + errx(1, "expand_altq: strlcat"); + if (strlcpy(pb.qname, qname, + sizeof(pb.qname)) >= sizeof(pb.qname)) + errx(1, "expand_altq: strlcpy"); + if (strlcpy(pb.ifname, interface->ifname, + sizeof(pb.ifname)) >= sizeof(pb.ifname)) + errx(1, "expand_altq: strlcpy"); + pb.qlimit = pa.qlimit; + pb.scheduler = pa.scheduler; + bw.bw_absolute = pa.ifbandwidth; + bw.bw_percent = 0; + if (eval_pfqueue(pf, &pb, &bw, opts)) + errs++; + else + if (pfctl_add_altq(pf, &pb)) + errs++; + } + + LOOP_THROUGH(struct node_queue, queue, nqueues, + n = calloc(1, sizeof(struct node_queue)); + if (n == NULL) + err(1, "expand_altq: calloc"); + if (pa.scheduler == ALTQT_CBQ || + pa.scheduler == ALTQT_HFSC) + if (strlcpy(n->parent, qname, + sizeof(n->parent)) >= + sizeof(n->parent)) + errx(1, "expand_altq: strlcpy"); + if (strlcpy(n->queue, queue->queue, + sizeof(n->queue)) >= sizeof(n->queue)) + errx(1, "expand_altq: strlcpy"); + if (strlcpy(n->ifname, interface->ifname, + sizeof(n->ifname)) >= sizeof(n->ifname)) + errx(1, "expand_altq: strlcpy"); + n->scheduler = pa.scheduler; + n->next = NULL; + n->tail = n; + if (queues == NULL) + queues = n; + else { + queues->tail->next = n; + queues->tail = n; + } + ); + } + ); + FREE_LIST(struct node_if, interfaces); + if (nqueues) + FREE_LIST(struct node_queue, nqueues); + + return (errs); +} + +int +expand_queue(struct pf_altq *a, struct node_if *interfaces, + struct node_queue *nqueues, struct node_queue_bw bwspec, + struct node_queue_opt *opts) +{ + struct node_queue *n, *nq; + struct pf_altq pa; + u_int8_t found = 0; + u_int8_t errs = 0; + + if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { + FREE_LIST(struct node_queue, nqueues); + return (0); + } + + if (queues == NULL) { + yyerror("queue %s has no parent", a->qname); + FREE_LIST(struct node_queue, nqueues); + return (1); + } + + LOOP_THROUGH(struct node_if, interface, interfaces, + LOOP_THROUGH(struct node_queue, tqueue, queues, + if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && + (interface->ifname[0] == 0 || + (!interface->not && !strncmp(interface->ifname, + tqueue->ifname, IFNAMSIZ)) || + (interface->not && strncmp(interface->ifname, + tqueue->ifname, IFNAMSIZ)))) { + /* found ourself in queues */ + found++; + + memcpy(&pa, a, sizeof(struct pf_altq)); + + if (pa.scheduler != ALTQT_NONE && + pa.scheduler != tqueue->scheduler) { + yyerror("exactly one scheduler type " + "per interface allowed"); + return (1); + } + pa.scheduler = tqueue->scheduler; + + /* scheduler dependent error checking */ + switch (pa.scheduler) { + case ALTQT_PRIQ: + if (nqueues != NULL) { + yyerror("priq queues cannot " + "have child queues"); + return (1); + } + if (bwspec.bw_absolute > 0 || + bwspec.bw_percent < 100) { + yyerror("priq doesn't take " + "bandwidth"); + return (1); + } + break; + default: + break; + } + + if (strlcpy(pa.ifname, tqueue->ifname, + sizeof(pa.ifname)) >= sizeof(pa.ifname)) + errx(1, "expand_queue: strlcpy"); + if (strlcpy(pa.parent, tqueue->parent, + sizeof(pa.parent)) >= sizeof(pa.parent)) + errx(1, "expand_queue: strlcpy"); + + if (eval_pfqueue(pf, &pa, &bwspec, opts)) + errs++; + else + if (pfctl_add_altq(pf, &pa)) + errs++; + + for (nq = nqueues; nq != NULL; nq = nq->next) { + if (!strcmp(a->qname, nq->queue)) { + yyerror("queue cannot have " + "itself as child"); + errs++; + continue; + } + n = calloc(1, + sizeof(struct node_queue)); + if (n == NULL) + err(1, "expand_queue: calloc"); + if (strlcpy(n->parent, a->qname, + sizeof(n->parent)) >= + sizeof(n->parent)) + errx(1, "expand_queue strlcpy"); + if (strlcpy(n->queue, nq->queue, + sizeof(n->queue)) >= + sizeof(n->queue)) + errx(1, "expand_queue strlcpy"); + if (strlcpy(n->ifname, tqueue->ifname, + sizeof(n->ifname)) >= + sizeof(n->ifname)) + errx(1, "expand_queue strlcpy"); + n->scheduler = tqueue->scheduler; + n->next = NULL; + n->tail = n; + if (queues == NULL) + queues = n; + else { + queues->tail->next = n; + queues->tail = n; + } + } + if ((pf->opts & PF_OPT_VERBOSE) && ( + (found == 1 && interface->ifname[0] == 0) || + (found > 0 && interface->ifname[0] != 0))) { + print_queue(&pf->paltq->altq, 0, + &bwspec, interface->ifname[0] != 0, + opts); + if (nqueues && nqueues->tail) { + printf("{ "); + LOOP_THROUGH(struct node_queue, + queue, nqueues, + printf("%s ", + queue->queue); + ); + printf("}"); + } + printf("\n"); + } + } + ); + ); + + FREE_LIST(struct node_queue, nqueues); + FREE_LIST(struct node_if, interfaces); + + if (!found) { + yyerror("queue %s has no parent", a->qname); + errs++; + } + + if (errs) + return (1); + else + return (0); +} + +void +expand_rule(struct pf_rule *r, + struct node_if *interfaces, struct node_host *rpool_hosts, + struct node_proto *protos, struct node_os *src_oses, + struct node_host *src_hosts, struct node_port *src_ports, + struct node_host *dst_hosts, struct node_port *dst_ports, + struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types, + const char *anchor_call) +{ + sa_family_t af = r->af; + int added = 0, error = 0; + char ifname[IF_NAMESIZE]; + char label[PF_RULE_LABEL_SIZE]; + char tagname[PF_TAG_NAME_SIZE]; + char match_tagname[PF_TAG_NAME_SIZE]; + struct pf_pooladdr *pa; + struct node_host *h; + u_int8_t flags, flagset, keep_state; + + if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= + sizeof(match_tagname)) + errx(1, "expand_rule: strlcpy"); + flags = r->flags; + flagset = r->flagset; + keep_state = r->keep_state; + + LOOP_THROUGH(struct node_if, interface, interfaces, + LOOP_THROUGH(struct node_proto, proto, protos, + LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, + LOOP_THROUGH(struct node_host, src_host, src_hosts, + LOOP_THROUGH(struct node_port, src_port, src_ports, + LOOP_THROUGH(struct node_os, src_os, src_oses, + LOOP_THROUGH(struct node_host, dst_host, dst_hosts, + LOOP_THROUGH(struct node_port, dst_port, dst_ports, + LOOP_THROUGH(struct node_uid, uid, uids, + LOOP_THROUGH(struct node_gid, gid, gids, + + r->af = af; + /* for link-local IPv6 address, interface must match up */ + if ((r->af && src_host->af && r->af != src_host->af) || + (r->af && dst_host->af && r->af != dst_host->af) || + (src_host->af && dst_host->af && + src_host->af != dst_host->af) || + (src_host->ifindex && dst_host->ifindex && + src_host->ifindex != dst_host->ifindex) || + (src_host->ifindex && *interface->ifname && + src_host->ifindex != if_nametoindex(interface->ifname)) || + (dst_host->ifindex && *interface->ifname && + dst_host->ifindex != if_nametoindex(interface->ifname))) + continue; + if (!r->af && src_host->af) + r->af = src_host->af; + else if (!r->af && dst_host->af) + r->af = dst_host->af; + + if (*interface->ifname) + strlcpy(r->ifname, interface->ifname, + sizeof(r->ifname)); + else if (if_indextoname(src_host->ifindex, ifname)) + strlcpy(r->ifname, ifname, sizeof(r->ifname)); + else if (if_indextoname(dst_host->ifindex, ifname)) + strlcpy(r->ifname, ifname, sizeof(r->ifname)); + else + memset(r->ifname, '\0', sizeof(r->ifname)); + + if (strlcpy(r->label, label, sizeof(r->label)) >= + sizeof(r->label)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= + sizeof(r->tagname)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(r->match_tagname, match_tagname, + sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) + errx(1, "expand_rule: strlcpy"); + expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af, + src_host, src_port, dst_host, dst_port, proto->proto); + expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af, + src_host, src_port, dst_host, dst_port, proto->proto); + expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname, + r->af, src_host, src_port, dst_host, dst_port, + proto->proto); + + error += check_netmask(src_host, r->af); + error += check_netmask(dst_host, r->af); + + r->ifnot = interface->not; + r->proto = proto->proto; + r->src.addr = src_host->addr; + r->src.neg = src_host->not; + r->src.port[0] = src_port->port[0]; + r->src.port[1] = src_port->port[1]; + r->src.port_op = src_port->op; + r->dst.addr = dst_host->addr; + r->dst.neg = dst_host->not; + r->dst.port[0] = dst_port->port[0]; + r->dst.port[1] = dst_port->port[1]; + r->dst.port_op = dst_port->op; + r->uid.op = uid->op; + r->uid.uid[0] = uid->uid[0]; + r->uid.uid[1] = uid->uid[1]; + r->gid.op = gid->op; + r->gid.gid[0] = gid->gid[0]; + r->gid.gid[1] = gid->gid[1]; + r->type = icmp_type->type; + r->code = icmp_type->code; + + if ((keep_state == PF_STATE_MODULATE || + keep_state == PF_STATE_SYNPROXY) && + r->proto && r->proto != IPPROTO_TCP) + r->keep_state = PF_STATE_NORMAL; + else + r->keep_state = keep_state; + + if (r->proto && r->proto != IPPROTO_TCP) { + r->flags = 0; + r->flagset = 0; + } else { + r->flags = flags; + r->flagset = flagset; + } + if (icmp_type->proto && r->proto != icmp_type->proto) { + yyerror("icmp-type mismatch"); + error++; + } + + if (src_os && src_os->os) { + r->os_fingerprint = pfctl_get_fingerprint(src_os->os); + if ((pf->opts & PF_OPT_VERBOSE2) && + r->os_fingerprint == PF_OSFP_NOMATCH) + fprintf(stderr, + "warning: unknown '%s' OS fingerprint\n", + src_os->os); + } else { + r->os_fingerprint = PF_OSFP_ANY; + } + + TAILQ_INIT(&r->rpool.list); + for (h = rpool_hosts; h != NULL; h = h->next) { + pa = calloc(1, sizeof(struct pf_pooladdr)); + if (pa == NULL) + err(1, "expand_rule: calloc"); + pa->addr = h->addr; + if (h->ifname != NULL) { + if (strlcpy(pa->ifname, h->ifname, + sizeof(pa->ifname)) >= + sizeof(pa->ifname)) + errx(1, "expand_rule: strlcpy"); + } else + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); + } + + if (rule_consistent(r, anchor_call[0]) < 0 || error) + yyerror("skipping rule due to errors"); + else { + r->nr = pf->astack[pf->asd]->match++; + pfctl_add_rule(pf, r, anchor_call); + added++; + } + + )))))))))); + + FREE_LIST(struct node_if, interfaces); + FREE_LIST(struct node_proto, protos); + FREE_LIST(struct node_host, src_hosts); + FREE_LIST(struct node_port, src_ports); + FREE_LIST(struct node_os, src_oses); + FREE_LIST(struct node_host, dst_hosts); + FREE_LIST(struct node_port, dst_ports); + FREE_LIST(struct node_uid, uids); + FREE_LIST(struct node_gid, gids); + FREE_LIST(struct node_icmp, icmp_types); + FREE_LIST(struct node_host, rpool_hosts); + + if (!added) + yyerror("rule expands to no valid combination"); +} + +int +expand_skip_interface(struct node_if *interfaces) +{ + int errs = 0; + + if (!interfaces || (!interfaces->next && !interfaces->not && + !strcmp(interfaces->ifname, "none"))) { + if (pf->opts & PF_OPT_VERBOSE) + printf("set skip on none\n"); + errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0); + return (errs); + } + + if (pf->opts & PF_OPT_VERBOSE) + printf("set skip on {"); + LOOP_THROUGH(struct node_if, interface, interfaces, + if (pf->opts & PF_OPT_VERBOSE) + printf(" %s", interface->ifname); + if (interface->not) { + yyerror("skip on ! <interface> is not supported"); + errs++; + } else + errs += pfctl_set_interface_flags(pf, + interface->ifname, PFI_IFLAG_SKIP, 1); + ); + if (pf->opts & PF_OPT_VERBOSE) + printf(" }\n"); + + FREE_LIST(struct node_if, interfaces); + + if (errs) + return (1); + else + return (0); +} + +#undef FREE_LIST +#undef LOOP_THROUGH + +int +check_rulestate(int desired_state) +{ + if (require_order && (rulestate > desired_state)) { + yyerror("Rules must be in order: options, normalization, " + "queueing, translation, filtering"); + return (1); + } + rulestate = desired_state; + return (0); +} + +int +kw_cmp(const void *k, const void *e) +{ + return (strcmp(k, ((const struct keywords *)e)->k_name)); +} + +int +lookup(char *s) +{ + /* this has to be sorted always */ + static const struct keywords keywords[] = { + { "all", ALL}, + { "allow-opts", ALLOWOPTS}, + { "altq", ALTQ}, + { "anchor", ANCHOR}, + { "antispoof", ANTISPOOF}, + { "any", ANY}, + { "bandwidth", BANDWIDTH}, + { "binat", BINAT}, + { "binat-anchor", BINATANCHOR}, + { "bitmask", BITMASK}, + { "block", BLOCK}, + { "block-policy", BLOCKPOLICY}, + { "buckets", BUCKETS}, + { "cbq", CBQ}, + { "code", CODE}, + { "codelq", CODEL}, + { "crop", FRAGCROP}, + { "debug", DEBUG}, + { "divert-reply", DIVERTREPLY}, + { "divert-to", DIVERTTO}, + { "drop", DROP}, + { "drop-ovl", FRAGDROP}, + { "dup-to", DUPTO}, + { "fairq", FAIRQ}, + { "fastroute", FASTROUTE}, + { "file", FILENAME}, + { "fingerprints", FINGERPRINTS}, + { "flags", FLAGS}, + { "floating", FLOATING}, + { "flush", FLUSH}, + { "for", FOR}, + { "fragment", FRAGMENT}, + { "from", FROM}, + { "global", GLOBAL}, + { "group", GROUP}, + { "hfsc", HFSC}, + { "hogs", HOGS}, + { "hostid", HOSTID}, + { "icmp-type", ICMPTYPE}, + { "icmp6-type", ICMP6TYPE}, + { "if-bound", IFBOUND}, + { "in", IN}, + { "include", INCLUDE}, + { "inet", INET}, + { "inet6", INET6}, + { "interval", INTERVAL}, + { "keep", KEEP}, + { "label", LABEL}, + { "limit", LIMIT}, + { "linkshare", LINKSHARE}, + { "load", LOAD}, + { "log", LOG}, + { "loginterface", LOGINTERFACE}, + { "max", MAXIMUM}, + { "max-mss", MAXMSS}, + { "max-src-conn", MAXSRCCONN}, + { "max-src-conn-rate", MAXSRCCONNRATE}, + { "max-src-nodes", MAXSRCNODES}, + { "max-src-states", MAXSRCSTATES}, + { "min-ttl", MINTTL}, + { "modulate", MODULATE}, + { "nat", NAT}, + { "nat-anchor", NATANCHOR}, + { "no", NO}, + { "no-df", NODF}, + { "no-route", NOROUTE}, + { "no-sync", NOSYNC}, + { "on", ON}, + { "optimization", OPTIMIZATION}, + { "os", OS}, + { "out", OUT}, + { "overload", OVERLOAD}, + { "pass", PASS}, + { "port", PORT}, + { "prio", PRIO}, + { "priority", PRIORITY}, + { "priq", PRIQ}, + { "probability", PROBABILITY}, + { "proto", PROTO}, + { "qlimit", QLIMIT}, + { "queue", QUEUE}, + { "quick", QUICK}, + { "random", RANDOM}, + { "random-id", RANDOMID}, + { "rdr", RDR}, + { "rdr-anchor", RDRANCHOR}, + { "realtime", REALTIME}, + { "reassemble", REASSEMBLE}, + { "reply-to", REPLYTO}, + { "require-order", REQUIREORDER}, + { "return", RETURN}, + { "return-icmp", RETURNICMP}, + { "return-icmp6", RETURNICMP6}, + { "return-rst", RETURNRST}, + { "round-robin", ROUNDROBIN}, + { "route", ROUTE}, + { "route-to", ROUTETO}, + { "rtable", RTABLE}, + { "rule", RULE}, + { "ruleset-optimization", RULESET_OPTIMIZATION}, + { "scrub", SCRUB}, + { "set", SET}, + { "set-tos", SETTOS}, + { "skip", SKIP}, + { "sloppy", SLOPPY}, + { "source-hash", SOURCEHASH}, + { "source-track", SOURCETRACK}, + { "state", STATE}, + { "state-defaults", STATEDEFAULTS}, + { "state-policy", STATEPOLICY}, + { "static-port", STATICPORT}, + { "sticky-address", STICKYADDRESS}, + { "synproxy", SYNPROXY}, + { "table", TABLE}, + { "tag", TAG}, + { "tagged", TAGGED}, + { "target", TARGET}, + { "tbrsize", TBRSIZE}, + { "timeout", TIMEOUT}, + { "to", TO}, + { "tos", TOS}, + { "ttl", TTL}, + { "upperlimit", UPPERLIMIT}, + { "urpf-failed", URPFFAILED}, + { "user", USER}, + }; + const struct keywords *p; + + p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), + sizeof(keywords[0]), kw_cmp); + + if (p) { + if (debug > 1) + fprintf(stderr, "%s: %d\n", s, p->k_val); + return (p->k_val); + } else { + if (debug > 1) + fprintf(stderr, "string: %s\n", s); + return (STRING); + } +} + +#define MAXPUSHBACK 128 + +static char *parsebuf; +static int parseindex; +static char pushback_buffer[MAXPUSHBACK]; +static int pushback_index = 0; + +int +lgetc(int quotec) +{ + int c, next; + + if (parsebuf) { + /* Read character from the parsebuffer instead of input. */ + if (parseindex >= 0) { + c = parsebuf[parseindex++]; + if (c != '\0') + return (c); + parsebuf = NULL; + } else + parseindex++; + } + + if (pushback_index) + return (pushback_buffer[--pushback_index]); + + if (quotec) { + if ((c = getc(file->stream)) == EOF) { + yyerror("reached end of file while parsing quoted string"); + if (popfile() == EOF) + return (EOF); + return (quotec); + } + return (c); + } + + while ((c = getc(file->stream)) == '\\') { + next = getc(file->stream); + if (next != '\n') { + c = next; + break; + } + yylval.lineno = file->lineno; + file->lineno++; + } + + while (c == EOF) { + if (popfile() == EOF) + return (EOF); + c = getc(file->stream); + } + return (c); +} + +int +lungetc(int c) +{ + if (c == EOF) + return (EOF); + if (parsebuf) { + parseindex--; + if (parseindex >= 0) + return (c); + } + if (pushback_index < MAXPUSHBACK-1) + return (pushback_buffer[pushback_index++] = c); + else + return (EOF); +} + +int +findeol(void) +{ + int c; + + parsebuf = NULL; + + /* skip to either EOF or the first real EOL */ + while (1) { + if (pushback_index) + c = pushback_buffer[--pushback_index]; + else + c = lgetc(0); + if (c == '\n') { + file->lineno++; + break; + } + if (c == EOF) + break; + } + return (ERROR); +} + +int +yylex(void) +{ + char buf[8096]; + char *p, *val; + int quotec, next, c; + int token; + +top: + p = buf; + while ((c = lgetc(0)) == ' ' || c == '\t') + ; /* nothing */ + + yylval.lineno = file->lineno; + if (c == '#') + while ((c = lgetc(0)) != '\n' && c != EOF) + ; /* nothing */ + if (c == '$' && parsebuf == NULL) { + while (1) { + if ((c = lgetc(0)) == EOF) + return (0); + + if (p + 1 >= buf + sizeof(buf) - 1) { + yyerror("string too long"); + return (findeol()); + } + if (isalnum(c) || c == '_') { + *p++ = (char)c; + continue; + } + *p = '\0'; + lungetc(c); + break; + } + val = symget(buf); + if (val == NULL) { + yyerror("macro '%s' not defined", buf); + return (findeol()); + } + parsebuf = val; + parseindex = 0; + goto top; + } + + switch (c) { + case '\'': + case '"': + quotec = c; + while (1) { + if ((c = lgetc(quotec)) == EOF) + return (0); + if (c == '\n') { + file->lineno++; + continue; + } else if (c == '\\') { + if ((next = lgetc(quotec)) == EOF) + return (0); + if (next == quotec || c == ' ' || c == '\t') + c = next; + else if (next == '\n') + continue; + else + lungetc(next); + } else if (c == quotec) { + *p = '\0'; + break; + } + if (p + 1 >= buf + sizeof(buf) - 1) { + yyerror("string too long"); + return (findeol()); + } + *p++ = (char)c; + } + yylval.v.string = strdup(buf); + if (yylval.v.string == NULL) + err(1, "yylex: strdup"); + return (STRING); + case '<': + next = lgetc(0); + if (next == '>') { + yylval.v.i = PF_OP_XRG; + return (PORTBINARY); + } + lungetc(next); + break; + case '>': + next = lgetc(0); + if (next == '<') { + yylval.v.i = PF_OP_IRG; + return (PORTBINARY); + } + lungetc(next); + break; + case '-': + next = lgetc(0); + if (next == '>') + return (ARROW); + lungetc(next); + break; + } + +#define allowed_to_end_number(x) \ + (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') + + if (c == '-' || isdigit(c)) { + do { + *p++ = c; + if ((unsigned)(p-buf) >= sizeof(buf)) { + yyerror("string too long"); + return (findeol()); + } + } while ((c = lgetc(0)) != EOF && isdigit(c)); + lungetc(c); + if (p == buf + 1 && buf[0] == '-') + goto nodigits; + if (c == EOF || allowed_to_end_number(c)) { + const char *errstr = NULL; + + *p = '\0'; + yylval.v.number = strtonum(buf, LLONG_MIN, + LLONG_MAX, &errstr); + if (errstr) { + yyerror("\"%s\" invalid number: %s", + buf, errstr); + return (findeol()); + } + return (NUMBER); + } else { +nodigits: + while (p > buf + 1) + lungetc(*--p); + c = *--p; + if (c == '-') + return (c); + } + } + +#define allowed_in_string(x) \ + (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ + x != '{' && x != '}' && x != '<' && x != '>' && \ + x != '!' && x != '=' && x != '/' && x != '#' && \ + x != ',')) + + if (isalnum(c) || c == ':' || c == '_') { + do { + *p++ = c; + if ((unsigned)(p-buf) >= sizeof(buf)) { + yyerror("string too long"); + return (findeol()); + } + } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); + lungetc(c); + *p = '\0'; + if ((token = lookup(buf)) == STRING) + if ((yylval.v.string = strdup(buf)) == NULL) + err(1, "yylex: strdup"); + return (token); + } + if (c == '\n') { + yylval.lineno = file->lineno; + file->lineno++; + } + if (c == EOF) + return (0); + return (c); +} + +int +check_file_secrecy(int fd, const char *fname) +{ + struct stat st; + + if (fstat(fd, &st)) { + warn("cannot stat %s", fname); + return (-1); + } + if (st.st_uid != 0 && st.st_uid != getuid()) { + warnx("%s: owner not root or current user", fname); + return (-1); + } + if (st.st_mode & (S_IRWXG | S_IRWXO)) { + warnx("%s: group/world readable/writeable", fname); + return (-1); + } + return (0); +} + +struct file * +pushfile(const char *name, int secret) +{ + struct file *nfile; + + if ((nfile = calloc(1, sizeof(struct file))) == NULL || + (nfile->name = strdup(name)) == NULL) { + warn("malloc"); + return (NULL); + } + if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { + nfile->stream = stdin; + free(nfile->name); + if ((nfile->name = strdup("stdin")) == NULL) { + warn("strdup"); + free(nfile); + return (NULL); + } + } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { + warn("%s", nfile->name); + free(nfile->name); + free(nfile); + return (NULL); + } else if (secret && + check_file_secrecy(fileno(nfile->stream), nfile->name)) { + fclose(nfile->stream); + free(nfile->name); + free(nfile); + return (NULL); + } + nfile->lineno = 1; + TAILQ_INSERT_TAIL(&files, nfile, entry); + return (nfile); +} + +int +popfile(void) +{ + struct file *prev; + + if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { + prev->errors += file->errors; + TAILQ_REMOVE(&files, file, entry); + fclose(file->stream); + free(file->name); + free(file); + file = prev; + return (0); + } + return (EOF); +} + +int +parse_config(char *filename, struct pfctl *xpf) +{ + int errors = 0; + struct sym *sym; + + pf = xpf; + errors = 0; + rulestate = PFCTL_STATE_NONE; + returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; + returnicmp6default = + (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; + blockpolicy = PFRULE_DROP; + require_order = 1; + + if ((file = pushfile(filename, 0)) == NULL) { + warn("cannot open the main config file!"); + return (-1); + } + + yyparse(); + errors = file->errors; + popfile(); + + /* Free macros and check which have not been used. */ + while ((sym = TAILQ_FIRST(&symhead))) { + if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) + fprintf(stderr, "warning: macro '%s' not " + "used\n", sym->nam); + free(sym->nam); + free(sym->val); + TAILQ_REMOVE(&symhead, sym, entry); + free(sym); + } + + return (errors ? -1 : 0); +} + +int +symset(const char *nam, const char *val, int persist) +{ + struct sym *sym; + + for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); + sym = TAILQ_NEXT(sym, entry)) + ; /* nothing */ + + if (sym != NULL) { + if (sym->persist == 1) + return (0); + else { + free(sym->nam); + free(sym->val); + TAILQ_REMOVE(&symhead, sym, entry); + free(sym); + } + } + if ((sym = calloc(1, sizeof(*sym))) == NULL) + return (-1); + + sym->nam = strdup(nam); + if (sym->nam == NULL) { + free(sym); + return (-1); + } + sym->val = strdup(val); + if (sym->val == NULL) { + free(sym->nam); + free(sym); + return (-1); + } + sym->used = 0; + sym->persist = persist; + TAILQ_INSERT_TAIL(&symhead, sym, entry); + return (0); +} + +int +pfctl_cmdline_symset(char *s) +{ + char *sym, *val; + int ret; + + if ((val = strrchr(s, '=')) == NULL) + return (-1); + + if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) + err(1, "pfctl_cmdline_symset: malloc"); + + strlcpy(sym, s, strlen(s) - strlen(val) + 1); + + ret = symset(sym, val + 1, 1); + free(sym); + + return (ret); +} + +char * +symget(const char *nam) +{ + struct sym *sym; + + TAILQ_FOREACH(sym, &symhead, entry) + if (strcmp(nam, sym->nam) == 0) { + sym->used = 1; + return (sym->val); + } + return (NULL); +} + +void +mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst) +{ + int i; + struct pf_rule *r; + + for (i = 0; i < PF_RULESET_MAX; ++i) { + while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) + != NULL) { + TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); + TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); + dst->anchor->match++; + } + src->anchor->match = 0; + while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) + != NULL) { + TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); + TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, + r, entries); + } + } +} + +void +decide_address_family(struct node_host *n, sa_family_t *af) +{ + if (*af != 0 || n == NULL) + return; + *af = n->af; + while ((n = n->next) != NULL) { + if (n->af != *af) { + *af = 0; + return; + } + } +} + +void +remove_invalid_hosts(struct node_host **nh, sa_family_t *af) +{ + struct node_host *n = *nh, *prev = NULL; + + while (n != NULL) { + if (*af && n->af && n->af != *af) { + /* unlink and free n */ + struct node_host *next = n->next; + + /* adjust tail pointer */ + if (n == (*nh)->tail) + (*nh)->tail = prev; + /* adjust previous node's next pointer */ + if (prev == NULL) + *nh = next; + else + prev->next = next; + /* free node */ + if (n->ifname != NULL) + free(n->ifname); + free(n); + n = next; + } else { + if (n->af && !*af) + *af = n->af; + prev = n; + n = n->next; + } + } +} + +int +invalid_redirect(struct node_host *nh, sa_family_t af) +{ + if (!af) { + struct node_host *n; + + /* tables and dyniftl are ok without an address family */ + for (n = nh; n != NULL; n = n->next) { + if (n->addr.type != PF_ADDR_TABLE && + n->addr.type != PF_ADDR_DYNIFTL) { + yyerror("address family not given and " + "translation address expands to multiple " + "address families"); + return (1); + } + } + } + if (nh == NULL) { + yyerror("no translation address with matching address family " + "found."); + return (1); + } + return (0); +} + +int +atoul(char *s, u_long *ulvalp) +{ + u_long ulval; + char *ep; + + errno = 0; + ulval = strtoul(s, &ep, 0); + if (s[0] == '\0' || *ep != '\0') + return (-1); + if (errno == ERANGE && ulval == ULONG_MAX) + return (-1); + *ulvalp = ulval; + return (0); +} + +int +getservice(char *n) +{ + struct servent *s; + u_long ulval; + + if (atoul(n, &ulval) == 0) { + if (ulval > 65535) { + yyerror("illegal port value %lu", ulval); + return (-1); + } + return (htons(ulval)); + } else { + s = getservbyname(n, "tcp"); + if (s == NULL) + s = getservbyname(n, "udp"); + if (s == NULL) { + yyerror("unknown port %s", n); + return (-1); + } + return (s->s_port); + } +} + +int +rule_label(struct pf_rule *r, char *s) +{ + if (s) { + if (strlcpy(r->label, s, sizeof(r->label)) >= + sizeof(r->label)) { + yyerror("rule label too long (max %d chars)", + sizeof(r->label)-1); + return (-1); + } + } + return (0); +} + +u_int16_t +parseicmpspec(char *w, sa_family_t af) +{ + const struct icmpcodeent *p; + u_long ulval; + u_int8_t icmptype; + + if (af == AF_INET) + icmptype = returnicmpdefault >> 8; + else + icmptype = returnicmp6default >> 8; + + if (atoul(w, &ulval) == -1) { + if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { + yyerror("unknown icmp code %s", w); + return (0); + } + ulval = p->code; + } + if (ulval > 255) { + yyerror("invalid icmp code %lu", ulval); + return (0); + } + return (icmptype << 8 | ulval); +} + +int +parseport(char *port, struct range *r, int extensions) +{ + char *p = strchr(port, ':'); + + if (p == NULL) { + if ((r->a = getservice(port)) == -1) + return (-1); + r->b = 0; + r->t = PF_OP_NONE; + return (0); + } + if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { + *p = 0; + if ((r->a = getservice(port)) == -1) + return (-1); + r->b = 0; + r->t = PF_OP_IRG; + return (0); + } + if ((extensions & PPORT_RANGE)) { + *p++ = 0; + if ((r->a = getservice(port)) == -1 || + (r->b = getservice(p)) == -1) + return (-1); + if (r->a == r->b) { + r->b = 0; + r->t = PF_OP_NONE; + } else + r->t = PF_OP_RRG; + return (0); + } + return (-1); +} + +int +pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) +{ + struct loadanchors *la; + + TAILQ_FOREACH(la, &loadanchorshead, entries) { + if (pf->opts & PF_OPT_VERBOSE) + fprintf(stderr, "\nLoading anchor %s from %s\n", + la->anchorname, la->filename); + if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, + la->anchorname, trans) == -1) + return (-1); + } + + return (0); +} + +int +rt_tableid_max(void) +{ +#ifdef __FreeBSD__ + int fibs; + size_t l = sizeof(fibs); + + if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1) + fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */ + /* + * As the OpenBSD code only compares > and not >= we need to adjust + * here given we only accept values of 0..n and want to avoid #ifdefs + * in the grammar. + */ + return (fibs - 1); +#else + return (RT_TABLEID_MAX); +#endif +} +#line 4317 "pfctly.tab.c" + +#if YYDEBUG +#include <stdio.h> /* needed for printf */ +#endif + +#include <stdlib.h> /* needed for malloc, etc */ +#include <string.h> /* needed for memset */ + +/* allocate initial stack or double stack size, up to YYMAXDEPTH */ +static int yygrowstack(YYSTACKDATA *data) +{ + int i; + unsigned newsize; + YYINT *newss; + YYSTYPE *newvs; + + if ((newsize = data->stacksize) == 0) + newsize = YYINITSTACKSIZE; + else if (newsize >= YYMAXDEPTH) + return YYENOMEM; + else if ((newsize *= 2) > YYMAXDEPTH) + newsize = YYMAXDEPTH; + + i = (int) (data->s_mark - data->s_base); + newss = (YYINT *)realloc(data->s_base, newsize * sizeof(*newss)); + if (newss == 0) + return YYENOMEM; + + data->s_base = newss; + data->s_mark = newss + i; + + newvs = (YYSTYPE *)realloc(data->l_base, newsize * sizeof(*newvs)); + if (newvs == 0) + return YYENOMEM; + + data->l_base = newvs; + data->l_mark = newvs + i; + + data->stacksize = newsize; + data->s_last = data->s_base + newsize - 1; + return 0; +} + +#if YYPURE || defined(YY_NO_LEAKS) +static void yyfreestack(YYSTACKDATA *data) +{ + free(data->s_base); + free(data->l_base); + memset(data, 0, sizeof(*data)); +} +#else +#define yyfreestack(data) /* nothing */ +#endif + +#define YYABORT goto yyabort +#define YYREJECT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab + +int +YYPARSE_DECL() +{ + int yym, yyn, yystate; +#if YYDEBUG + const char *yys; + + if ((yys = getenv("YYDEBUG")) != 0) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = YYEMPTY; + yystate = 0; + +#if YYPURE + memset(&yystack, 0, sizeof(yystack)); +#endif + + if (yystack.s_base == NULL && yygrowstack(&yystack) == YYENOMEM) goto yyoverflow; + yystack.s_mark = yystack.s_base; + yystack.l_mark = yystack.l_base; + yystate = 0; + *yystack.s_mark = 0; + +yyloop: + if ((yyn = yydefred[yystate]) != 0) goto yyreduce; + if (yychar < 0) + { + if ((yychar = YYLEX) < 0) yychar = YYEOF; +#if YYDEBUG + if (yydebug) + { + yys = yyname[YYTRANSLATE(yychar)]; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, shifting to state %d\n", + YYPREFIX, yystate, yytable[yyn]); +#endif + if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) + { + goto yyoverflow; + } + yystate = yytable[yyn]; + *++yystack.s_mark = yytable[yyn]; + *++yystack.l_mark = yylval; + yychar = YYEMPTY; + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; + + YYERROR_CALL("syntax error"); + + goto yyerrlab; + +yyerrlab: + ++yynerrs; + +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yystack.s_mark]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, error recovery shifting\ + to state %d\n", YYPREFIX, *yystack.s_mark, yytable[yyn]); +#endif + if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) + { + goto yyoverflow; + } + yystate = yytable[yyn]; + *++yystack.s_mark = yytable[yyn]; + *++yystack.l_mark = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: error recovery discarding state %d\n", + YYPREFIX, *yystack.s_mark); +#endif + if (yystack.s_mark <= yystack.s_base) goto yyabort; + --yystack.s_mark; + --yystack.l_mark; + } + } + } + else + { + if (yychar == YYEOF) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = yyname[YYTRANSLATE(yychar)]; + printf("%sdebug: state %d, error recovery discards token %d (%s)\n", + YYPREFIX, yystate, yychar, yys); + } +#endif + yychar = YYEMPTY; + goto yyloop; + } + +yyreduce: +#if YYDEBUG + if (yydebug) + printf("%sdebug: state %d, reducing by rule %d (%s)\n", + YYPREFIX, yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + if (yym) + yyval = yystack.l_mark[1-yym]; + else + memset(&yyval, 0, sizeof yyval); + switch (yyn) + { +case 17: +#line 553 "../../freebsd/sbin/pfctl/parse.y" + { file->errors++; } +break; +case 18: +#line 556 "../../freebsd/sbin/pfctl/parse.y" + { + struct file *nfile; + + if ((nfile = pushfile(yystack.l_mark[0].v.string, 0)) == NULL) { + yyerror("failed to include file %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + + file = nfile; + lungetc('\n'); + } +break; +case 25: +#line 583 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "none")) + yyval.v.i = 0; + else if (!strcmp(yystack.l_mark[0].v.string, "basic")) + yyval.v.i = PF_OPTIMIZE_BASIC; + else if (!strcmp(yystack.l_mark[0].v.string, "profile")) + yyval.v.i = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; + else { + yyerror("unknown ruleset-optimization %s", yystack.l_mark[0].v.string); + YYERROR; + } + } +break; +case 26: +#line 597 "../../freebsd/sbin/pfctl/parse.y" + { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free(yystack.l_mark[0].v.string); + YYERROR; + } + if (pfctl_set_optimization(pf, yystack.l_mark[0].v.string) != 0) { + yyerror("unknown optimization %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 27: +#line 609 "../../freebsd/sbin/pfctl/parse.y" + { + if (!(pf->opts & PF_OPT_OPTIMIZE)) { + pf->opts |= PF_OPT_OPTIMIZE; + pf->optimize = yystack.l_mark[0].v.i; + } + } +break; +case 32: +#line 619 "../../freebsd/sbin/pfctl/parse.y" + { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free(yystack.l_mark[0].v.string); + YYERROR; + } + if (pfctl_set_logif(pf, yystack.l_mark[0].v.string) != 0) { + yyerror("error setting loginterface %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 33: +#line 631 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number == 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("hostid must be non-zero"); + YYERROR; + } + if (pfctl_set_hostid(pf, yystack.l_mark[0].v.number) != 0) { + yyerror("error setting hostid %08x", yystack.l_mark[0].v.number); + YYERROR; + } + } +break; +case 34: +#line 641 "../../freebsd/sbin/pfctl/parse.y" + { + if (pf->opts & PF_OPT_VERBOSE) + printf("set block-policy drop\n"); + if (check_rulestate(PFCTL_STATE_OPTION)) + YYERROR; + blockpolicy = PFRULE_DROP; + } +break; +case 35: +#line 648 "../../freebsd/sbin/pfctl/parse.y" + { + if (pf->opts & PF_OPT_VERBOSE) + printf("set block-policy return\n"); + if (check_rulestate(PFCTL_STATE_OPTION)) + YYERROR; + blockpolicy = PFRULE_RETURN; + } +break; +case 36: +#line 655 "../../freebsd/sbin/pfctl/parse.y" + { + if (pf->opts & PF_OPT_VERBOSE) + printf("set require-order %s\n", + yystack.l_mark[0].v.number == 1 ? "yes" : "no"); + require_order = yystack.l_mark[0].v.number; + } +break; +case 37: +#line 661 "../../freebsd/sbin/pfctl/parse.y" + { + if (pf->opts & PF_OPT_VERBOSE) + printf("set fingerprints \"%s\"\n", yystack.l_mark[0].v.string); + if (check_rulestate(PFCTL_STATE_OPTION)) { + free(yystack.l_mark[0].v.string); + YYERROR; + } + if (!pf->anchor->name[0]) { + if (pfctl_file_fingerprints(pf->dev, + pf->opts, yystack.l_mark[0].v.string)) { + yyerror("error loading " + "fingerprints %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + } + free(yystack.l_mark[0].v.string); + } +break; +case 38: +#line 679 "../../freebsd/sbin/pfctl/parse.y" + { + if (pf->opts & PF_OPT_VERBOSE) + switch (yystack.l_mark[0].v.i) { + case 0: + printf("set state-policy floating\n"); + break; + case PFRULE_IFBOUND: + printf("set state-policy if-bound\n"); + break; + } + default_statelock = yystack.l_mark[0].v.i; + } +break; +case 39: +#line 691 "../../freebsd/sbin/pfctl/parse.y" + { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free(yystack.l_mark[0].v.string); + YYERROR; + } + if (pfctl_set_debug(pf, yystack.l_mark[0].v.string) != 0) { + yyerror("error setting debuglevel %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 40: +#line 703 "../../freebsd/sbin/pfctl/parse.y" + { + if (expand_skip_interface(yystack.l_mark[0].v.interface) != 0) { + yyerror("error setting skip interface(s)"); + YYERROR; + } + } +break; +case 41: +#line 709 "../../freebsd/sbin/pfctl/parse.y" + { + if (keep_state_defaults != NULL) { + yyerror("cannot redefine state-defaults"); + YYERROR; + } + keep_state_defaults = yystack.l_mark[0].v.state_opt; + } +break; +case 42: +#line 718 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.string = yystack.l_mark[0].v.string; } +break; +case 43: +#line 719 "../../freebsd/sbin/pfctl/parse.y" + { + if ((yyval.v.string = strdup("all")) == NULL) { + err(1, "stringall: strdup"); + } + } +break; +case 44: +#line 726 "../../freebsd/sbin/pfctl/parse.y" + { + if (asprintf(&yyval.v.string, "%s %s", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.string) == -1) + err(1, "string: asprintf"); + free(yystack.l_mark[-1].v.string); + free(yystack.l_mark[0].v.string); + } +break; +case 46: +#line 735 "../../freebsd/sbin/pfctl/parse.y" + { + if (asprintf(&yyval.v.string, "%s %s", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.string) == -1) + err(1, "string: asprintf"); + free(yystack.l_mark[-1].v.string); + free(yystack.l_mark[0].v.string); + } +break; +case 48: +#line 744 "../../freebsd/sbin/pfctl/parse.y" + { + char *s; + if (asprintf(&s, "%lld", (long long)yystack.l_mark[0].v.number) == -1) { + yyerror("string: asprintf"); + YYERROR; + } + yyval.v.string = s; + } +break; +case 50: +#line 755 "../../freebsd/sbin/pfctl/parse.y" + { + if (pf->opts & PF_OPT_VERBOSE) + printf("%s = \"%s\"\n", yystack.l_mark[-2].v.string, yystack.l_mark[0].v.string); + if (symset(yystack.l_mark[-2].v.string, yystack.l_mark[0].v.string, 0) == -1) + err(1, "cannot store variable %s", yystack.l_mark[-2].v.string); + free(yystack.l_mark[-2].v.string); + free(yystack.l_mark[0].v.string); + } +break; +case 51: +#line 765 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.string = yystack.l_mark[0].v.string; } +break; +case 52: +#line 766 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.string = NULL; } +break; +case 57: +#line 776 "../../freebsd/sbin/pfctl/parse.y" + { + char ta[PF_ANCHOR_NAME_SIZE]; + struct pf_ruleset *rs; + + /* steping into a brace anchor */ + pf->asd++; + pf->bn++; + pf->brace = 1; + + /* create a holding ruleset in the root */ + snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); + rs = pf_find_or_create_ruleset(ta); + if (rs == NULL) + err(1, "pfa_anchor: pf_find_or_create_ruleset"); + pf->astack[pf->asd] = rs->anchor; + pf->anchor = rs->anchor; + } +break; +case 58: +#line 793 "../../freebsd/sbin/pfctl/parse.y" + { + pf->alast = pf->anchor; + pf->asd--; + pf->anchor = pf->astack[pf->asd]; + } +break; +case 60: +#line 803 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_rule r; + struct node_proto *proto; + + if (check_rulestate(PFCTL_STATE_FILTER)) { + if (yystack.l_mark[-8].v.string) + free(yystack.l_mark[-8].v.string); + YYERROR; + } + + if (yystack.l_mark[-8].v.string && (yystack.l_mark[-8].v.string[0] == '_' || strstr(yystack.l_mark[-8].v.string, "/_") != NULL)) { + free(yystack.l_mark[-8].v.string); + yyerror("anchor names beginning with '_' " + "are reserved for internal use"); + YYERROR; + } + + memset(&r, 0, sizeof(r)); + if (pf->astack[pf->asd + 1]) { + /* move inline rules into relative location */ + pf_anchor_setup(&r, + &pf->astack[pf->asd]->ruleset, + yystack.l_mark[-8].v.string ? yystack.l_mark[-8].v.string : pf->alast->name); + + if (r.anchor == NULL) + err(1, "anchorrule: unable to " + "create ruleset"); + + if (pf->alast != r.anchor) { + if (r.anchor->match) { + yyerror("inline anchor '%s' " + "already exists", + r.anchor->name); + YYERROR; + } + mv_rules(&pf->alast->ruleset, + &r.anchor->ruleset); + } + pf_remove_if_empty_ruleset(&pf->alast->ruleset); + pf->alast = r.anchor; + } else { + if (!yystack.l_mark[-8].v.string) { + yyerror("anchors without explicit " + "rules must specify a name"); + YYERROR; + } + } + r.direction = yystack.l_mark[-7].v.i; + r.quick = yystack.l_mark[-6].v.logquick.quick; + r.af = yystack.l_mark[-4].v.i; + r.prob = yystack.l_mark[-1].v.filter_opts.prob; + r.rtableid = yystack.l_mark[-1].v.filter_opts.rtableid; + + if (yystack.l_mark[-1].v.filter_opts.tag) + if (strlcpy(r.tagname, yystack.l_mark[-1].v.filter_opts.tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + if (yystack.l_mark[-1].v.filter_opts.match_tag) + if (strlcpy(r.match_tagname, yystack.l_mark[-1].v.filter_opts.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = yystack.l_mark[-1].v.filter_opts.match_tag_not; + if (rule_label(&r, yystack.l_mark[-1].v.filter_opts.label)) + YYERROR; + free(yystack.l_mark[-1].v.filter_opts.label); + r.flags = yystack.l_mark[-1].v.filter_opts.flags.b1; + r.flagset = yystack.l_mark[-1].v.filter_opts.flags.b2; + if ((yystack.l_mark[-1].v.filter_opts.flags.b1 & yystack.l_mark[-1].v.filter_opts.flags.b2) != yystack.l_mark[-1].v.filter_opts.flags.b1) { + yyerror("flags always false"); + YYERROR; + } + if (yystack.l_mark[-1].v.filter_opts.flags.b1 || yystack.l_mark[-1].v.filter_opts.flags.b2 || yystack.l_mark[-2].v.fromto.src_os) { + for (proto = yystack.l_mark[-3].v.proto; proto != NULL && + proto->proto != IPPROTO_TCP; + proto = proto->next) + ; /* nothing */ + if (proto == NULL && yystack.l_mark[-3].v.proto != NULL) { + if (yystack.l_mark[-1].v.filter_opts.flags.b1 || yystack.l_mark[-1].v.filter_opts.flags.b2) + yyerror( + "flags only apply to tcp"); + if (yystack.l_mark[-2].v.fromto.src_os) + yyerror( + "OS fingerprinting only " + "applies to tcp"); + YYERROR; + } + } + + r.tos = yystack.l_mark[-1].v.filter_opts.tos; + + if (yystack.l_mark[-1].v.filter_opts.keep.action) { + yyerror("cannot specify state handling " + "on anchors"); + YYERROR; + } + + if (yystack.l_mark[-1].v.filter_opts.match_tag) + if (strlcpy(r.match_tagname, yystack.l_mark[-1].v.filter_opts.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = yystack.l_mark[-1].v.filter_opts.match_tag_not; + if (yystack.l_mark[-1].v.filter_opts.marker & FOM_PRIO) { + if (yystack.l_mark[-1].v.filter_opts.prio == 0) + r.prio = PF_PRIO_ZERO; + else + r.prio = yystack.l_mark[-1].v.filter_opts.prio; + } + if (yystack.l_mark[-1].v.filter_opts.marker & FOM_SETPRIO) { + r.set_prio[0] = yystack.l_mark[-1].v.filter_opts.set_prio[0]; + r.set_prio[1] = yystack.l_mark[-1].v.filter_opts.set_prio[1]; + r.scrub_flags |= PFSTATE_SETPRIO; + } + + decide_address_family(yystack.l_mark[-2].v.fromto.src.host, &r.af); + decide_address_family(yystack.l_mark[-2].v.fromto.dst.host, &r.af); + + expand_rule(&r, yystack.l_mark[-5].v.interface, NULL, yystack.l_mark[-3].v.proto, yystack.l_mark[-2].v.fromto.src_os, + yystack.l_mark[-2].v.fromto.src.host, yystack.l_mark[-2].v.fromto.src.port, yystack.l_mark[-2].v.fromto.dst.host, yystack.l_mark[-2].v.fromto.dst.port, + yystack.l_mark[-1].v.filter_opts.uid, yystack.l_mark[-1].v.filter_opts.gid, yystack.l_mark[-1].v.filter_opts.icmpspec, + pf->astack[pf->asd + 1] ? pf->alast->name : yystack.l_mark[-8].v.string); + free(yystack.l_mark[-8].v.string); + pf->astack[pf->asd + 1] = NULL; + } +break; +case 61: +#line 935 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_NAT)) { + free(yystack.l_mark[-5].v.string); + YYERROR; + } + + memset(&r, 0, sizeof(r)); + r.action = PF_NAT; + r.af = yystack.l_mark[-3].v.i; + r.rtableid = yystack.l_mark[0].v.rtableid; + + decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af); + decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af); + + expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os, + yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port, + 0, 0, 0, yystack.l_mark[-5].v.string); + free(yystack.l_mark[-5].v.string); + } +break; +case 62: +#line 956 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_NAT)) { + free(yystack.l_mark[-5].v.string); + YYERROR; + } + + memset(&r, 0, sizeof(r)); + r.action = PF_RDR; + r.af = yystack.l_mark[-3].v.i; + r.rtableid = yystack.l_mark[0].v.rtableid; + + decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af); + decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af); + + if (yystack.l_mark[-1].v.fromto.src.port != NULL) { + yyerror("source port parameter not supported" + " in rdr-anchor"); + YYERROR; + } + if (yystack.l_mark[-1].v.fromto.dst.port != NULL) { + if (yystack.l_mark[-1].v.fromto.dst.port->next != NULL) { + yyerror("destination port list " + "expansion not supported in " + "rdr-anchor"); + YYERROR; + } else if (yystack.l_mark[-1].v.fromto.dst.port->op != PF_OP_EQ) { + yyerror("destination port operators" + " not supported in rdr-anchor"); + YYERROR; + } + r.dst.port[0] = yystack.l_mark[-1].v.fromto.dst.port->port[0]; + r.dst.port[1] = yystack.l_mark[-1].v.fromto.dst.port->port[1]; + r.dst.port_op = yystack.l_mark[-1].v.fromto.dst.port->op; + } + + expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os, + yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port, + 0, 0, 0, yystack.l_mark[-5].v.string); + free(yystack.l_mark[-5].v.string); + } +break; +case 63: +#line 998 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_NAT)) { + free(yystack.l_mark[-5].v.string); + YYERROR; + } + + memset(&r, 0, sizeof(r)); + r.action = PF_BINAT; + r.af = yystack.l_mark[-3].v.i; + r.rtableid = yystack.l_mark[0].v.rtableid; + if (yystack.l_mark[-2].v.proto != NULL) { + if (yystack.l_mark[-2].v.proto->next != NULL) { + yyerror("proto list expansion" + " not supported in binat-anchor"); + YYERROR; + } + r.proto = yystack.l_mark[-2].v.proto->proto; + free(yystack.l_mark[-2].v.proto); + } + + if (yystack.l_mark[-1].v.fromto.src.host != NULL || yystack.l_mark[-1].v.fromto.src.port != NULL || + yystack.l_mark[-1].v.fromto.dst.host != NULL || yystack.l_mark[-1].v.fromto.dst.port != NULL) { + yyerror("fromto parameter not supported" + " in binat-anchor"); + YYERROR; + } + + decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af); + decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af); + + pfctl_add_rule(pf, &r, yystack.l_mark[-5].v.string); + free(yystack.l_mark[-5].v.string); + } +break; +case 64: +#line 1035 "../../freebsd/sbin/pfctl/parse.y" + { + struct loadanchors *loadanchor; + + if (strlen(pf->anchor->name) + 1 + + strlen(yystack.l_mark[-2].v.string) >= MAXPATHLEN) { + yyerror("anchorname %s too long, max %u\n", + yystack.l_mark[-2].v.string, MAXPATHLEN - 1); + free(yystack.l_mark[-2].v.string); + YYERROR; + } + loadanchor = calloc(1, sizeof(struct loadanchors)); + if (loadanchor == NULL) + err(1, "loadrule: calloc"); + if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == + NULL) + err(1, "loadrule: malloc"); + if (pf->anchor->name[0]) + snprintf(loadanchor->anchorname, MAXPATHLEN, + "%s/%s", pf->anchor->name, yystack.l_mark[-2].v.string); + else + strlcpy(loadanchor->anchorname, yystack.l_mark[-2].v.string, MAXPATHLEN); + if ((loadanchor->filename = strdup(yystack.l_mark[0].v.string)) == NULL) + err(1, "loadrule: strdup"); + + TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, + entries); + + free(yystack.l_mark[-2].v.string); + free(yystack.l_mark[0].v.string); + } +break; +case 65: +#line 1066 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = yyval.v.b.w = 0; + if (yystack.l_mark[-1].v.i) + yyval.v.b.b1 = PF_NOSCRUB; + else + yyval.v.b.b1 = PF_SCRUB; + } +break; +case 66: +#line 1076 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_SCRUB)) + YYERROR; + + memset(&r, 0, sizeof(r)); + + r.action = yystack.l_mark[-7].v.b.b1; + r.direction = yystack.l_mark[-6].v.i; + + r.log = yystack.l_mark[-5].v.logquick.log; + r.logif = yystack.l_mark[-5].v.logquick.logif; + if (yystack.l_mark[-5].v.logquick.quick) { + yyerror("scrub rules do not support 'quick'"); + YYERROR; + } + + r.af = yystack.l_mark[-3].v.i; + if (yystack.l_mark[0].v.scrub_opts.nodf) + r.rule_flag |= PFRULE_NODF; + if (yystack.l_mark[0].v.scrub_opts.randomid) + r.rule_flag |= PFRULE_RANDOMID; + if (yystack.l_mark[0].v.scrub_opts.reassemble_tcp) { + if (r.direction != PF_INOUT) { + yyerror("reassemble tcp rules can not " + "specify direction"); + YYERROR; + } + r.rule_flag |= PFRULE_REASSEMBLE_TCP; + } + if (yystack.l_mark[0].v.scrub_opts.minttl) + r.min_ttl = yystack.l_mark[0].v.scrub_opts.minttl; + if (yystack.l_mark[0].v.scrub_opts.maxmss) + r.max_mss = yystack.l_mark[0].v.scrub_opts.maxmss; + if (yystack.l_mark[0].v.scrub_opts.marker & SOM_SETTOS) { + r.rule_flag |= PFRULE_SET_TOS; + r.set_tos = yystack.l_mark[0].v.scrub_opts.settos; + } + if (yystack.l_mark[0].v.scrub_opts.fragcache) + r.rule_flag |= yystack.l_mark[0].v.scrub_opts.fragcache; + if (yystack.l_mark[0].v.scrub_opts.match_tag) + if (strlcpy(r.match_tagname, yystack.l_mark[0].v.scrub_opts.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = yystack.l_mark[0].v.scrub_opts.match_tag_not; + r.rtableid = yystack.l_mark[0].v.scrub_opts.rtableid; + + expand_rule(&r, yystack.l_mark[-4].v.interface, NULL, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os, + yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port, + NULL, NULL, NULL, ""); + } +break; +case 67: +#line 1133 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&scrub_opts, sizeof scrub_opts); + scrub_opts.rtableid = -1; + } +break; +case 68: +#line 1138 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.scrub_opts = scrub_opts; } +break; +case 69: +#line 1139 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&scrub_opts, sizeof scrub_opts); + scrub_opts.rtableid = -1; + yyval.v.scrub_opts = scrub_opts; + } +break; +case 72: +#line 1150 "../../freebsd/sbin/pfctl/parse.y" + { + if (scrub_opts.nodf) { + yyerror("no-df cannot be respecified"); + YYERROR; + } + scrub_opts.nodf = 1; + } +break; +case 73: +#line 1157 "../../freebsd/sbin/pfctl/parse.y" + { + if (scrub_opts.marker & SOM_MINTTL) { + yyerror("min-ttl cannot be respecified"); + YYERROR; + } + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { + yyerror("illegal min-ttl value %d", yystack.l_mark[0].v.number); + YYERROR; + } + scrub_opts.marker |= SOM_MINTTL; + scrub_opts.minttl = yystack.l_mark[0].v.number; + } +break; +case 74: +#line 1169 "../../freebsd/sbin/pfctl/parse.y" + { + if (scrub_opts.marker & SOM_MAXMSS) { + yyerror("max-mss cannot be respecified"); + YYERROR; + } + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) { + yyerror("illegal max-mss value %d", yystack.l_mark[0].v.number); + YYERROR; + } + scrub_opts.marker |= SOM_MAXMSS; + scrub_opts.maxmss = yystack.l_mark[0].v.number; + } +break; +case 75: +#line 1181 "../../freebsd/sbin/pfctl/parse.y" + { + if (scrub_opts.marker & SOM_SETTOS) { + yyerror("set-tos cannot be respecified"); + YYERROR; + } + scrub_opts.marker |= SOM_SETTOS; + scrub_opts.settos = yystack.l_mark[0].v.number; + } +break; +case 76: +#line 1189 "../../freebsd/sbin/pfctl/parse.y" + { + if (scrub_opts.marker & SOM_FRAGCACHE) { + yyerror("fragcache cannot be respecified"); + YYERROR; + } + scrub_opts.marker |= SOM_FRAGCACHE; + scrub_opts.fragcache = yystack.l_mark[0].v.i; + } +break; +case 77: +#line 1197 "../../freebsd/sbin/pfctl/parse.y" + { + if (strcasecmp(yystack.l_mark[0].v.string, "tcp") != 0) { + yyerror("scrub reassemble supports only tcp, " + "not '%s'", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + if (scrub_opts.reassemble_tcp) { + yyerror("reassemble tcp cannot be respecified"); + YYERROR; + } + scrub_opts.reassemble_tcp = 1; + } +break; +case 78: +#line 1211 "../../freebsd/sbin/pfctl/parse.y" + { + if (scrub_opts.randomid) { + yyerror("random-id cannot be respecified"); + YYERROR; + } + scrub_opts.randomid = 1; + } +break; +case 79: +#line 1218 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) { + yyerror("invalid rtable id"); + YYERROR; + } + scrub_opts.rtableid = yystack.l_mark[0].v.number; + } +break; +case 80: +#line 1225 "../../freebsd/sbin/pfctl/parse.y" + { + scrub_opts.match_tag = yystack.l_mark[0].v.string; + scrub_opts.match_tag_not = yystack.l_mark[-2].v.number; + } +break; +case 81: +#line 1231 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = 0; /* default */ } +break; +case 82: +#line 1232 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = 0; } +break; +case 83: +#line 1233 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = 0; } +break; +case 84: +#line 1236 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_rule r; + struct node_host *h = NULL, *hh; + struct node_if *i, *j; + + if (check_rulestate(PFCTL_STATE_FILTER)) + YYERROR; + + for (i = yystack.l_mark[-2].v.interface; i; i = i->next) { + bzero(&r, sizeof(r)); + + r.action = PF_DROP; + r.direction = PF_IN; + r.log = yystack.l_mark[-3].v.logquick.log; + r.logif = yystack.l_mark[-3].v.logquick.logif; + r.quick = yystack.l_mark[-3].v.logquick.quick; + r.af = yystack.l_mark[-1].v.i; + if (rule_label(&r, yystack.l_mark[0].v.antispoof_opts.label)) + YYERROR; + r.rtableid = yystack.l_mark[0].v.antispoof_opts.rtableid; + j = calloc(1, sizeof(struct node_if)); + if (j == NULL) + err(1, "antispoof: calloc"); + if (strlcpy(j->ifname, i->ifname, + sizeof(j->ifname)) >= sizeof(j->ifname)) { + free(j); + yyerror("interface name too long"); + YYERROR; + } + j->not = 1; + if (i->dynamic) { + h = calloc(1, sizeof(*h)); + if (h == NULL) + err(1, "address: calloc"); + h->addr.type = PF_ADDR_DYNIFTL; + set_ipmask(h, 128); + if (strlcpy(h->addr.v.ifname, i->ifname, + sizeof(h->addr.v.ifname)) >= + sizeof(h->addr.v.ifname)) { + free(h); + yyerror( + "interface name too long"); + YYERROR; + } + hh = malloc(sizeof(*hh)); + if (hh == NULL) + err(1, "address: malloc"); + bcopy(h, hh, sizeof(*hh)); + h->addr.iflags = PFI_AFLAG_NETWORK; + } else { + h = ifa_lookup(j->ifname, + PFI_AFLAG_NETWORK); + hh = NULL; + } + + if (h != NULL) + expand_rule(&r, j, NULL, NULL, NULL, h, + NULL, NULL, NULL, NULL, NULL, + NULL, ""); + + if ((i->ifa_flags & IFF_LOOPBACK) == 0) { + bzero(&r, sizeof(r)); + + r.action = PF_DROP; + r.direction = PF_IN; + r.log = yystack.l_mark[-3].v.logquick.log; + r.logif = yystack.l_mark[-3].v.logquick.logif; + r.quick = yystack.l_mark[-3].v.logquick.quick; + r.af = yystack.l_mark[-1].v.i; + if (rule_label(&r, yystack.l_mark[0].v.antispoof_opts.label)) + YYERROR; + r.rtableid = yystack.l_mark[0].v.antispoof_opts.rtableid; + if (hh != NULL) + h = hh; + else + h = ifa_lookup(i->ifname, 0); + if (h != NULL) + expand_rule(&r, NULL, NULL, + NULL, NULL, h, NULL, NULL, + NULL, NULL, NULL, NULL, ""); + } else + free(hh); + } + free(yystack.l_mark[0].v.antispoof_opts.label); + } +break; +case 85: +#line 1323 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.interface = yystack.l_mark[0].v.interface; } +break; +case 86: +#line 1324 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.interface = yystack.l_mark[-1].v.interface; } +break; +case 87: +#line 1327 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.interface = yystack.l_mark[-1].v.interface; } +break; +case 88: +#line 1328 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.interface->tail->next = yystack.l_mark[-1].v.interface; + yystack.l_mark[-3].v.interface->tail = yystack.l_mark[-1].v.interface; + yyval.v.interface = yystack.l_mark[-3].v.interface; + } +break; +case 89: +#line 1335 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.interface = yystack.l_mark[0].v.interface; } +break; +case 90: +#line 1336 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-1].v.interface->dynamic = 1; + yyval.v.interface = yystack.l_mark[-1].v.interface; + } +break; +case 91: +#line 1342 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&antispoof_opts, sizeof antispoof_opts); + antispoof_opts.rtableid = -1; + } +break; +case 92: +#line 1347 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.antispoof_opts = antispoof_opts; } +break; +case 93: +#line 1348 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&antispoof_opts, sizeof antispoof_opts); + antispoof_opts.rtableid = -1; + yyval.v.antispoof_opts = antispoof_opts; + } +break; +case 96: +#line 1359 "../../freebsd/sbin/pfctl/parse.y" + { + if (antispoof_opts.label) { + yyerror("label cannot be redefined"); + YYERROR; + } + antispoof_opts.label = yystack.l_mark[0].v.string; + } +break; +case 97: +#line 1366 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) { + yyerror("invalid rtable id"); + YYERROR; + } + antispoof_opts.rtableid = yystack.l_mark[0].v.number; + } +break; +case 98: +#line 1375 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.number = 1; } +break; +case 99: +#line 1376 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.number = 0; } +break; +case 100: +#line 1379 "../../freebsd/sbin/pfctl/parse.y" + { + struct node_host *h, *nh; + struct node_tinit *ti, *nti; + + if (strlen(yystack.l_mark[-2].v.string) >= PF_TABLE_NAME_SIZE) { + yyerror("table name too long, max %d chars", + PF_TABLE_NAME_SIZE - 1); + free(yystack.l_mark[-2].v.string); + YYERROR; + } + if (pf->loadopt & PFCTL_FLAG_TABLE) + if (process_tabledef(yystack.l_mark[-2].v.string, &yystack.l_mark[0].v.table_opts)) { + free(yystack.l_mark[-2].v.string); + YYERROR; + } + free(yystack.l_mark[-2].v.string); + for (ti = SIMPLEQ_FIRST(&yystack.l_mark[0].v.table_opts.init_nodes); + ti != SIMPLEQ_END(&yystack.l_mark[0].v.table_opts.init_nodes); ti = nti) { + if (ti->file) + free(ti->file); + for (h = ti->host; h != NULL; h = nh) { + nh = h->next; + free(h); + } + nti = SIMPLEQ_NEXT(ti, entries); + free(ti); + } + } +break; +case 101: +#line 1409 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&table_opts, sizeof table_opts); + SIMPLEQ_INIT(&table_opts.init_nodes); + } +break; +case 102: +#line 1414 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.table_opts = table_opts; } +break; +case 103: +#line 1416 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&table_opts, sizeof table_opts); + SIMPLEQ_INIT(&table_opts.init_nodes); + yyval.v.table_opts = table_opts; + } +break; +case 106: +#line 1427 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "const")) + table_opts.flags |= PFR_TFLAG_CONST; + else if (!strcmp(yystack.l_mark[0].v.string, "persist")) + table_opts.flags |= PFR_TFLAG_PERSIST; + else if (!strcmp(yystack.l_mark[0].v.string, "counters")) + table_opts.flags |= PFR_TFLAG_COUNTERS; + else { + yyerror("invalid table option '%s'", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 107: +#line 1441 "../../freebsd/sbin/pfctl/parse.y" + { table_opts.init_addr = 1; } +break; +case 108: +#line 1442 "../../freebsd/sbin/pfctl/parse.y" + { + struct node_host *n; + struct node_tinit *ti; + + for (n = yystack.l_mark[-1].v.host; n != NULL; n = n->next) { + switch (n->addr.type) { + case PF_ADDR_ADDRMASK: + continue; /* ok */ + case PF_ADDR_RANGE: + yyerror("address ranges are not " + "permitted inside tables"); + break; + case PF_ADDR_DYNIFTL: + yyerror("dynamic addresses are not " + "permitted inside tables"); + break; + case PF_ADDR_TABLE: + yyerror("tables cannot contain tables"); + break; + case PF_ADDR_NOROUTE: + yyerror("\"no-route\" is not permitted " + "inside tables"); + break; + case PF_ADDR_URPFFAILED: + yyerror("\"urpf-failed\" is not " + "permitted inside tables"); + break; + default: + yyerror("unknown address type %d", + n->addr.type); + } + YYERROR; + } + if (!(ti = calloc(1, sizeof(*ti)))) + err(1, "table_opt: calloc"); + ti->host = yystack.l_mark[-1].v.host; + SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, + entries); + table_opts.init_addr = 1; + } +break; +case 109: +#line 1482 "../../freebsd/sbin/pfctl/parse.y" + { + struct node_tinit *ti; + + if (!(ti = calloc(1, sizeof(*ti)))) + err(1, "table_opt: calloc"); + ti->file = yystack.l_mark[0].v.string; + SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, + entries); + table_opts.init_addr = 1; + } +break; +case 110: +#line 1494 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_altq a; + + if (check_rulestate(PFCTL_STATE_QUEUE)) + YYERROR; + + memset(&a, 0, sizeof(a)); + if (yystack.l_mark[-2].v.queue_opts.scheduler.qtype == ALTQT_NONE) { + yyerror("no scheduler specified!"); + YYERROR; + } + a.scheduler = yystack.l_mark[-2].v.queue_opts.scheduler.qtype; + a.qlimit = yystack.l_mark[-2].v.queue_opts.qlimit; + a.tbrsize = yystack.l_mark[-2].v.queue_opts.tbrsize; + if (yystack.l_mark[0].v.queue == NULL && yystack.l_mark[-2].v.queue_opts.scheduler.qtype != ALTQT_CODEL) { + yyerror("no child queues specified"); + YYERROR; + } + if (expand_altq(&a, yystack.l_mark[-3].v.interface, yystack.l_mark[0].v.queue, yystack.l_mark[-2].v.queue_opts.queue_bwspec, + &yystack.l_mark[-2].v.queue_opts.scheduler)) + YYERROR; + } +break; +case 111: +#line 1518 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_altq a; + + if (check_rulestate(PFCTL_STATE_QUEUE)) { + free(yystack.l_mark[-3].v.string); + YYERROR; + } + + memset(&a, 0, sizeof(a)); + + if (strlcpy(a.qname, yystack.l_mark[-3].v.string, sizeof(a.qname)) >= + sizeof(a.qname)) { + yyerror("queue name too long (max " + "%d chars)", PF_QNAME_SIZE-1); + free(yystack.l_mark[-3].v.string); + YYERROR; + } + free(yystack.l_mark[-3].v.string); + if (yystack.l_mark[-1].v.queue_opts.tbrsize) { + yyerror("cannot specify tbrsize for queue"); + YYERROR; + } + if (yystack.l_mark[-1].v.queue_opts.priority > 255) { + yyerror("priority out of range: max 255"); + YYERROR; + } + a.priority = yystack.l_mark[-1].v.queue_opts.priority; + a.qlimit = yystack.l_mark[-1].v.queue_opts.qlimit; + a.scheduler = yystack.l_mark[-1].v.queue_opts.scheduler.qtype; + if (expand_queue(&a, yystack.l_mark[-2].v.interface, yystack.l_mark[0].v.queue, yystack.l_mark[-1].v.queue_opts.queue_bwspec, + &yystack.l_mark[-1].v.queue_opts.scheduler)) { + yyerror("errors in queue definition"); + YYERROR; + } + } +break; +case 112: +#line 1555 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&queue_opts, sizeof queue_opts); + queue_opts.priority = DEFAULT_PRIORITY; + queue_opts.qlimit = DEFAULT_QLIMIT; + queue_opts.scheduler.qtype = ALTQT_NONE; + queue_opts.queue_bwspec.bw_percent = 100; + } +break; +case 113: +#line 1563 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.queue_opts = queue_opts; } +break; +case 114: +#line 1564 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&queue_opts, sizeof queue_opts); + queue_opts.priority = DEFAULT_PRIORITY; + queue_opts.qlimit = DEFAULT_QLIMIT; + queue_opts.scheduler.qtype = ALTQT_NONE; + queue_opts.queue_bwspec.bw_percent = 100; + yyval.v.queue_opts = queue_opts; + } +break; +case 117: +#line 1578 "../../freebsd/sbin/pfctl/parse.y" + { + if (queue_opts.marker & QOM_BWSPEC) { + yyerror("bandwidth cannot be respecified"); + YYERROR; + } + queue_opts.marker |= QOM_BWSPEC; + queue_opts.queue_bwspec = yystack.l_mark[0].v.queue_bwspec; + } +break; +case 118: +#line 1586 "../../freebsd/sbin/pfctl/parse.y" + { + if (queue_opts.marker & QOM_PRIORITY) { + yyerror("priority cannot be respecified"); + YYERROR; + } + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { + yyerror("priority out of range: max 255"); + YYERROR; + } + queue_opts.marker |= QOM_PRIORITY; + queue_opts.priority = yystack.l_mark[0].v.number; + } +break; +case 119: +#line 1598 "../../freebsd/sbin/pfctl/parse.y" + { + if (queue_opts.marker & QOM_QLIMIT) { + yyerror("qlimit cannot be respecified"); + YYERROR; + } + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) { + yyerror("qlimit out of range: max 65535"); + YYERROR; + } + queue_opts.marker |= QOM_QLIMIT; + queue_opts.qlimit = yystack.l_mark[0].v.number; + } +break; +case 120: +#line 1610 "../../freebsd/sbin/pfctl/parse.y" + { + if (queue_opts.marker & QOM_SCHEDULER) { + yyerror("scheduler cannot be respecified"); + YYERROR; + } + queue_opts.marker |= QOM_SCHEDULER; + queue_opts.scheduler = yystack.l_mark[0].v.queue_options; + } +break; +case 121: +#line 1618 "../../freebsd/sbin/pfctl/parse.y" + { + if (queue_opts.marker & QOM_TBRSIZE) { + yyerror("tbrsize cannot be respecified"); + YYERROR; + } + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 65535) { + yyerror("tbrsize too big: max 65535"); + YYERROR; + } + queue_opts.marker |= QOM_TBRSIZE; + queue_opts.tbrsize = yystack.l_mark[0].v.number; + } +break; +case 122: +#line 1632 "../../freebsd/sbin/pfctl/parse.y" + { + double bps; + char *cp; + + yyval.v.queue_bwspec.bw_percent = 0; + + bps = strtod(yystack.l_mark[0].v.string, &cp); + if (cp != NULL) { + if (strlen(cp) > 1) { + char *cu = cp + 1; + if (!strcmp(cu, "Bit") || + !strcmp(cu, "B") || + !strcmp(cu, "bit") || + !strcmp(cu, "b")) { + *cu = 0; + } + } + if (!strcmp(cp, "b")) + ; /* nothing */ + else if (!strcmp(cp, "K")) + bps *= 1000; + else if (!strcmp(cp, "M")) + bps *= 1000 * 1000; + else if (!strcmp(cp, "G")) + bps *= 1000 * 1000 * 1000; + else if (!strcmp(cp, "%")) { + if (bps < 0 || bps > 100) { + yyerror("bandwidth spec " + "out of range"); + free(yystack.l_mark[0].v.string); + YYERROR; + } + yyval.v.queue_bwspec.bw_percent = bps; + bps = 0; + } else { + yyerror("unknown unit %s", cp); + free(yystack.l_mark[0].v.string); + YYERROR; + } + } + free(yystack.l_mark[0].v.string); + yyval.v.queue_bwspec.bw_absolute = (u_int32_t)bps; + } +break; +case 123: +#line 1675 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("bandwidth number too big"); + YYERROR; + } + yyval.v.queue_bwspec.bw_percent = 0; + yyval.v.queue_bwspec.bw_absolute = yystack.l_mark[0].v.number; + } +break; +case 124: +#line 1685 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_CBQ; + yyval.v.queue_options.data.cbq_opts.flags = 0; + } +break; +case 125: +#line 1689 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_CBQ; + yyval.v.queue_options.data.cbq_opts.flags = yystack.l_mark[-1].v.number; + } +break; +case 126: +#line 1693 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_PRIQ; + yyval.v.queue_options.data.priq_opts.flags = 0; + } +break; +case 127: +#line 1697 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_PRIQ; + yyval.v.queue_options.data.priq_opts.flags = yystack.l_mark[-1].v.number; + } +break; +case 128: +#line 1701 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_HFSC; + bzero(&yyval.v.queue_options.data.hfsc_opts, + sizeof(struct node_hfsc_opts)); + } +break; +case 129: +#line 1706 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_HFSC; + yyval.v.queue_options.data.hfsc_opts = yystack.l_mark[-1].v.hfsc_opts; + } +break; +case 130: +#line 1710 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_FAIRQ; + bzero(&yyval.v.queue_options.data.fairq_opts, + sizeof(struct node_fairq_opts)); + } +break; +case 131: +#line 1715 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_FAIRQ; + yyval.v.queue_options.data.fairq_opts = yystack.l_mark[-1].v.fairq_opts; + } +break; +case 132: +#line 1719 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_CODEL; + bzero(&yyval.v.queue_options.data.codel_opts, + sizeof(struct codel_opts)); + } +break; +case 133: +#line 1724 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue_options.qtype = ALTQT_CODEL; + yyval.v.queue_options.data.codel_opts = yystack.l_mark[-1].v.codel_opts; + } +break; +case 134: +#line 1730 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.number |= yystack.l_mark[0].v.number; } +break; +case 135: +#line 1731 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.number |= yystack.l_mark[0].v.number; } +break; +case 136: +#line 1734 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "default")) + yyval.v.number = CBQCLF_DEFCLASS; + else if (!strcmp(yystack.l_mark[0].v.string, "borrow")) + yyval.v.number = CBQCLF_BORROW; + else if (!strcmp(yystack.l_mark[0].v.string, "red")) + yyval.v.number = CBQCLF_RED; + else if (!strcmp(yystack.l_mark[0].v.string, "ecn")) + yyval.v.number = CBQCLF_RED|CBQCLF_ECN; + else if (!strcmp(yystack.l_mark[0].v.string, "rio")) + yyval.v.number = CBQCLF_RIO; + else if (!strcmp(yystack.l_mark[0].v.string, "codel")) + yyval.v.number = CBQCLF_CODEL; + else { + yyerror("unknown cbq flag \"%s\"", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 137: +#line 1756 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.number |= yystack.l_mark[0].v.number; } +break; +case 138: +#line 1757 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.number |= yystack.l_mark[0].v.number; } +break; +case 139: +#line 1760 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "default")) + yyval.v.number = PRCF_DEFAULTCLASS; + else if (!strcmp(yystack.l_mark[0].v.string, "red")) + yyval.v.number = PRCF_RED; + else if (!strcmp(yystack.l_mark[0].v.string, "ecn")) + yyval.v.number = PRCF_RED|PRCF_ECN; + else if (!strcmp(yystack.l_mark[0].v.string, "rio")) + yyval.v.number = PRCF_RIO; + else if (!strcmp(yystack.l_mark[0].v.string, "codel")) + yyval.v.number = PRCF_CODEL; + else { + yyerror("unknown priq flag \"%s\"", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 140: +#line 1780 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&hfsc_opts, + sizeof(struct node_hfsc_opts)); + } +break; +case 141: +#line 1784 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.hfsc_opts = hfsc_opts; + } +break; +case 144: +#line 1793 "../../freebsd/sbin/pfctl/parse.y" + { + if (hfsc_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + hfsc_opts.linkshare.m2 = yystack.l_mark[0].v.queue_bwspec; + hfsc_opts.linkshare.used = 1; + } +break; +case 145: +#line 1802 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) { + yyerror("timing in curve out of range"); + YYERROR; + } + if (hfsc_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + hfsc_opts.linkshare.m1 = yystack.l_mark[-5].v.queue_bwspec; + hfsc_opts.linkshare.d = yystack.l_mark[-3].v.number; + hfsc_opts.linkshare.m2 = yystack.l_mark[-1].v.queue_bwspec; + hfsc_opts.linkshare.used = 1; + } +break; +case 146: +#line 1816 "../../freebsd/sbin/pfctl/parse.y" + { + if (hfsc_opts.realtime.used) { + yyerror("realtime already specified"); + YYERROR; + } + hfsc_opts.realtime.m2 = yystack.l_mark[0].v.queue_bwspec; + hfsc_opts.realtime.used = 1; + } +break; +case 147: +#line 1825 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) { + yyerror("timing in curve out of range"); + YYERROR; + } + if (hfsc_opts.realtime.used) { + yyerror("realtime already specified"); + YYERROR; + } + hfsc_opts.realtime.m1 = yystack.l_mark[-5].v.queue_bwspec; + hfsc_opts.realtime.d = yystack.l_mark[-3].v.number; + hfsc_opts.realtime.m2 = yystack.l_mark[-1].v.queue_bwspec; + hfsc_opts.realtime.used = 1; + } +break; +case 148: +#line 1839 "../../freebsd/sbin/pfctl/parse.y" + { + if (hfsc_opts.upperlimit.used) { + yyerror("upperlimit already specified"); + YYERROR; + } + hfsc_opts.upperlimit.m2 = yystack.l_mark[0].v.queue_bwspec; + hfsc_opts.upperlimit.used = 1; + } +break; +case 149: +#line 1848 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > INT_MAX) { + yyerror("timing in curve out of range"); + YYERROR; + } + if (hfsc_opts.upperlimit.used) { + yyerror("upperlimit already specified"); + YYERROR; + } + hfsc_opts.upperlimit.m1 = yystack.l_mark[-5].v.queue_bwspec; + hfsc_opts.upperlimit.d = yystack.l_mark[-3].v.number; + hfsc_opts.upperlimit.m2 = yystack.l_mark[-1].v.queue_bwspec; + hfsc_opts.upperlimit.used = 1; + } +break; +case 150: +#line 1862 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "default")) + hfsc_opts.flags |= HFCF_DEFAULTCLASS; + else if (!strcmp(yystack.l_mark[0].v.string, "red")) + hfsc_opts.flags |= HFCF_RED; + else if (!strcmp(yystack.l_mark[0].v.string, "ecn")) + hfsc_opts.flags |= HFCF_RED|HFCF_ECN; + else if (!strcmp(yystack.l_mark[0].v.string, "rio")) + hfsc_opts.flags |= HFCF_RIO; + else if (!strcmp(yystack.l_mark[0].v.string, "codel")) + hfsc_opts.flags |= HFCF_CODEL; + else { + yyerror("unknown hfsc flag \"%s\"", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 151: +#line 1882 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&fairq_opts, + sizeof(struct node_fairq_opts)); + } +break; +case 152: +#line 1886 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.fairq_opts = fairq_opts; + } +break; +case 155: +#line 1895 "../../freebsd/sbin/pfctl/parse.y" + { + if (fairq_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + fairq_opts.linkshare.m2 = yystack.l_mark[0].v.queue_bwspec; + fairq_opts.linkshare.used = 1; + } +break; +case 156: +#line 1903 "../../freebsd/sbin/pfctl/parse.y" + { + if (fairq_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + fairq_opts.linkshare.m1 = yystack.l_mark[-3].v.queue_bwspec; + fairq_opts.linkshare.d = yystack.l_mark[-2].v.number; + fairq_opts.linkshare.m2 = yystack.l_mark[-1].v.queue_bwspec; + fairq_opts.linkshare.used = 1; + } +break; +case 157: +#line 1913 "../../freebsd/sbin/pfctl/parse.y" + { + fairq_opts.hogs_bw = yystack.l_mark[0].v.queue_bwspec; + } +break; +case 158: +#line 1916 "../../freebsd/sbin/pfctl/parse.y" + { + fairq_opts.nbuckets = yystack.l_mark[0].v.number; + } +break; +case 159: +#line 1919 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "default")) + fairq_opts.flags |= FARF_DEFAULTCLASS; + else if (!strcmp(yystack.l_mark[0].v.string, "red")) + fairq_opts.flags |= FARF_RED; + else if (!strcmp(yystack.l_mark[0].v.string, "ecn")) + fairq_opts.flags |= FARF_RED|FARF_ECN; + else if (!strcmp(yystack.l_mark[0].v.string, "rio")) + fairq_opts.flags |= FARF_RIO; + else if (!strcmp(yystack.l_mark[0].v.string, "codel")) + fairq_opts.flags |= FARF_CODEL; + else { + yyerror("unknown fairq flag \"%s\"", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 160: +#line 1939 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&codel_opts, + sizeof(struct codel_opts)); + } +break; +case 161: +#line 1943 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.codel_opts = codel_opts; + } +break; +case 164: +#line 1952 "../../freebsd/sbin/pfctl/parse.y" + { + if (codel_opts.interval) { + yyerror("interval already specified"); + YYERROR; + } + codel_opts.interval = yystack.l_mark[0].v.number; + } +break; +case 165: +#line 1959 "../../freebsd/sbin/pfctl/parse.y" + { + if (codel_opts.target) { + yyerror("target already specified"); + YYERROR; + } + codel_opts.target = yystack.l_mark[0].v.number; + } +break; +case 166: +#line 1966 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "ecn")) + codel_opts.ecn = 1; + else { + yyerror("unknown codel option \"%s\"", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 167: +#line 1978 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.queue = NULL; } +break; +case 168: +#line 1979 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.queue = yystack.l_mark[0].v.queue; } +break; +case 169: +#line 1980 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.queue = yystack.l_mark[-1].v.queue; } +break; +case 170: +#line 1983 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.queue = yystack.l_mark[-1].v.queue; } +break; +case 171: +#line 1984 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.queue->tail->next = yystack.l_mark[-1].v.queue; + yystack.l_mark[-3].v.queue->tail = yystack.l_mark[-1].v.queue; + yyval.v.queue = yystack.l_mark[-3].v.queue; + } +break; +case 172: +#line 1991 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.queue = calloc(1, sizeof(struct node_queue)); + if (yyval.v.queue == NULL) + err(1, "qassign_item: calloc"); + if (strlcpy(yyval.v.queue->queue, yystack.l_mark[0].v.string, sizeof(yyval.v.queue->queue)) >= + sizeof(yyval.v.queue->queue)) { + yyerror("queue name '%s' too long (max " + "%d chars)", yystack.l_mark[0].v.string, sizeof(yyval.v.queue->queue)-1); + free(yystack.l_mark[0].v.string); + free(yyval.v.queue); + YYERROR; + } + free(yystack.l_mark[0].v.string); + yyval.v.queue->next = NULL; + yyval.v.queue->tail = yyval.v.queue; + } +break; +case 173: +#line 2011 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_rule r; + struct node_state_opt *o; + struct node_proto *proto; + int srctrack = 0; + int statelock = 0; + int adaptive = 0; + int defaults = 0; + + if (check_rulestate(PFCTL_STATE_FILTER)) + YYERROR; + + memset(&r, 0, sizeof(r)); + + r.action = yystack.l_mark[-8].v.b.b1; + switch (yystack.l_mark[-8].v.b.b2) { + case PFRULE_RETURNRST: + r.rule_flag |= PFRULE_RETURNRST; + r.return_ttl = yystack.l_mark[-8].v.b.w; + break; + case PFRULE_RETURNICMP: + r.rule_flag |= PFRULE_RETURNICMP; + r.return_icmp = yystack.l_mark[-8].v.b.w; + r.return_icmp6 = yystack.l_mark[-8].v.b.w2; + break; + case PFRULE_RETURN: + r.rule_flag |= PFRULE_RETURN; + r.return_icmp = yystack.l_mark[-8].v.b.w; + r.return_icmp6 = yystack.l_mark[-8].v.b.w2; + break; + } + r.direction = yystack.l_mark[-7].v.i; + r.log = yystack.l_mark[-6].v.logquick.log; + r.logif = yystack.l_mark[-6].v.logquick.logif; + r.quick = yystack.l_mark[-6].v.logquick.quick; + r.prob = yystack.l_mark[0].v.filter_opts.prob; + r.rtableid = yystack.l_mark[0].v.filter_opts.rtableid; + + if (yystack.l_mark[0].v.filter_opts.marker & FOM_PRIO) { + if (yystack.l_mark[0].v.filter_opts.prio == 0) + r.prio = PF_PRIO_ZERO; + else + r.prio = yystack.l_mark[0].v.filter_opts.prio; + } + if (yystack.l_mark[0].v.filter_opts.marker & FOM_SETPRIO) { + r.set_prio[0] = yystack.l_mark[0].v.filter_opts.set_prio[0]; + r.set_prio[1] = yystack.l_mark[0].v.filter_opts.set_prio[1]; + r.scrub_flags |= PFSTATE_SETPRIO; + } + + r.af = yystack.l_mark[-3].v.i; + if (yystack.l_mark[0].v.filter_opts.tag) + if (strlcpy(r.tagname, yystack.l_mark[0].v.filter_opts.tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + if (yystack.l_mark[0].v.filter_opts.match_tag) + if (strlcpy(r.match_tagname, yystack.l_mark[0].v.filter_opts.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = yystack.l_mark[0].v.filter_opts.match_tag_not; + if (rule_label(&r, yystack.l_mark[0].v.filter_opts.label)) + YYERROR; + free(yystack.l_mark[0].v.filter_opts.label); + r.flags = yystack.l_mark[0].v.filter_opts.flags.b1; + r.flagset = yystack.l_mark[0].v.filter_opts.flags.b2; + if ((yystack.l_mark[0].v.filter_opts.flags.b1 & yystack.l_mark[0].v.filter_opts.flags.b2) != yystack.l_mark[0].v.filter_opts.flags.b1) { + yyerror("flags always false"); + YYERROR; + } + if (yystack.l_mark[0].v.filter_opts.flags.b1 || yystack.l_mark[0].v.filter_opts.flags.b2 || yystack.l_mark[-1].v.fromto.src_os) { + for (proto = yystack.l_mark[-2].v.proto; proto != NULL && + proto->proto != IPPROTO_TCP; + proto = proto->next) + ; /* nothing */ + if (proto == NULL && yystack.l_mark[-2].v.proto != NULL) { + if (yystack.l_mark[0].v.filter_opts.flags.b1 || yystack.l_mark[0].v.filter_opts.flags.b2) + yyerror( + "flags only apply to tcp"); + if (yystack.l_mark[-1].v.fromto.src_os) + yyerror( + "OS fingerprinting only " + "apply to tcp"); + YYERROR; + } +#if 0 + if ((yystack.l_mark[0].v.filter_opts.flags.b1 & parse_flags("S")) == 0 && + yystack.l_mark[-1].v.fromto.src_os) { + yyerror("OS fingerprinting requires " + "the SYN TCP flag (flags S/SA)"); + YYERROR; + } +#endif + } + + r.tos = yystack.l_mark[0].v.filter_opts.tos; + r.keep_state = yystack.l_mark[0].v.filter_opts.keep.action; + o = yystack.l_mark[0].v.filter_opts.keep.options; + + /* 'keep state' by default on pass rules. */ + if (!r.keep_state && !r.action && + !(yystack.l_mark[0].v.filter_opts.marker & FOM_KEEP)) { + r.keep_state = PF_STATE_NORMAL; + o = keep_state_defaults; + defaults = 1; + } + + while (o) { + struct node_state_opt *p = o; + + switch (o->type) { + case PF_STATE_OPT_MAX: + if (r.max_states) { + yyerror("state option 'max' " + "multiple definitions"); + YYERROR; + } + r.max_states = o->data.max_states; + break; + case PF_STATE_OPT_NOSYNC: + if (r.rule_flag & PFRULE_NOSYNC) { + yyerror("state option 'sync' " + "multiple definitions"); + YYERROR; + } + r.rule_flag |= PFRULE_NOSYNC; + break; + case PF_STATE_OPT_SRCTRACK: + if (srctrack) { + yyerror("state option " + "'source-track' " + "multiple definitions"); + YYERROR; + } + srctrack = o->data.src_track; + r.rule_flag |= PFRULE_SRCTRACK; + break; + case PF_STATE_OPT_MAX_SRC_STATES: + if (r.max_src_states) { + yyerror("state option " + "'max-src-states' " + "multiple definitions"); + YYERROR; + } + if (o->data.max_src_states == 0) { + yyerror("'max-src-states' must " + "be > 0"); + YYERROR; + } + r.max_src_states = + o->data.max_src_states; + r.rule_flag |= PFRULE_SRCTRACK; + break; + case PF_STATE_OPT_OVERLOAD: + if (r.overload_tblname[0]) { + yyerror("multiple 'overload' " + "table definitions"); + YYERROR; + } + if (strlcpy(r.overload_tblname, + o->data.overload.tblname, + PF_TABLE_NAME_SIZE) >= + PF_TABLE_NAME_SIZE) { + yyerror("state option: " + "strlcpy"); + YYERROR; + } + r.flush = o->data.overload.flush; + break; + case PF_STATE_OPT_MAX_SRC_CONN: + if (r.max_src_conn) { + yyerror("state option " + "'max-src-conn' " + "multiple definitions"); + YYERROR; + } + if (o->data.max_src_conn == 0) { + yyerror("'max-src-conn' " + "must be > 0"); + YYERROR; + } + r.max_src_conn = + o->data.max_src_conn; + r.rule_flag |= PFRULE_SRCTRACK | + PFRULE_RULESRCTRACK; + break; + case PF_STATE_OPT_MAX_SRC_CONN_RATE: + if (r.max_src_conn_rate.limit) { + yyerror("state option " + "'max-src-conn-rate' " + "multiple definitions"); + YYERROR; + } + if (!o->data.max_src_conn_rate.limit || + !o->data.max_src_conn_rate.seconds) { + yyerror("'max-src-conn-rate' " + "values must be > 0"); + YYERROR; + } + if (o->data.max_src_conn_rate.limit > + PF_THRESHOLD_MAX) { + yyerror("'max-src-conn-rate' " + "maximum rate must be < %u", + PF_THRESHOLD_MAX); + YYERROR; + } + r.max_src_conn_rate.limit = + o->data.max_src_conn_rate.limit; + r.max_src_conn_rate.seconds = + o->data.max_src_conn_rate.seconds; + r.rule_flag |= PFRULE_SRCTRACK | + PFRULE_RULESRCTRACK; + break; + case PF_STATE_OPT_MAX_SRC_NODES: + if (r.max_src_nodes) { + yyerror("state option " + "'max-src-nodes' " + "multiple definitions"); + YYERROR; + } + if (o->data.max_src_nodes == 0) { + yyerror("'max-src-nodes' must " + "be > 0"); + YYERROR; + } + r.max_src_nodes = + o->data.max_src_nodes; + r.rule_flag |= PFRULE_SRCTRACK | + PFRULE_RULESRCTRACK; + break; + case PF_STATE_OPT_STATELOCK: + if (statelock) { + yyerror("state locking option: " + "multiple definitions"); + YYERROR; + } + statelock = 1; + r.rule_flag |= o->data.statelock; + break; + case PF_STATE_OPT_SLOPPY: + if (r.rule_flag & PFRULE_STATESLOPPY) { + yyerror("state sloppy option: " + "multiple definitions"); + YYERROR; + } + r.rule_flag |= PFRULE_STATESLOPPY; + break; + case PF_STATE_OPT_TIMEOUT: + if (o->data.timeout.number == + PFTM_ADAPTIVE_START || + o->data.timeout.number == + PFTM_ADAPTIVE_END) + adaptive = 1; + if (r.timeout[o->data.timeout.number]) { + yyerror("state timeout %s " + "multiple definitions", + pf_timeouts[o->data. + timeout.number].name); + YYERROR; + } + r.timeout[o->data.timeout.number] = + o->data.timeout.seconds; + } + o = o->next; + if (!defaults) + free(p); + } + + /* 'flags S/SA' by default on stateful rules */ + if (!r.action && !r.flags && !r.flagset && + !yystack.l_mark[0].v.filter_opts.fragment && !(yystack.l_mark[0].v.filter_opts.marker & FOM_FLAGS) && + r.keep_state) { + r.flags = parse_flags("S"); + r.flagset = parse_flags("SA"); + } + if (!adaptive && r.max_states) { + r.timeout[PFTM_ADAPTIVE_START] = + (r.max_states / 10) * 6; + r.timeout[PFTM_ADAPTIVE_END] = + (r.max_states / 10) * 12; + } + if (r.rule_flag & PFRULE_SRCTRACK) { + if (srctrack == PF_SRCTRACK_GLOBAL && + r.max_src_nodes) { + yyerror("'max-src-nodes' is " + "incompatible with " + "'source-track global'"); + YYERROR; + } + if (srctrack == PF_SRCTRACK_GLOBAL && + r.max_src_conn) { + yyerror("'max-src-conn' is " + "incompatible with " + "'source-track global'"); + YYERROR; + } + if (srctrack == PF_SRCTRACK_GLOBAL && + r.max_src_conn_rate.seconds) { + yyerror("'max-src-conn-rate' is " + "incompatible with " + "'source-track global'"); + YYERROR; + } + if (r.timeout[PFTM_SRC_NODE] < + r.max_src_conn_rate.seconds) + r.timeout[PFTM_SRC_NODE] = + r.max_src_conn_rate.seconds; + r.rule_flag |= PFRULE_SRCTRACK; + if (srctrack == PF_SRCTRACK_RULE) + r.rule_flag |= PFRULE_RULESRCTRACK; + } + if (r.keep_state && !statelock) + r.rule_flag |= default_statelock; + + if (yystack.l_mark[0].v.filter_opts.fragment) + r.rule_flag |= PFRULE_FRAGMENT; + r.allow_opts = yystack.l_mark[0].v.filter_opts.allowopts; + + decide_address_family(yystack.l_mark[-1].v.fromto.src.host, &r.af); + decide_address_family(yystack.l_mark[-1].v.fromto.dst.host, &r.af); + + if (yystack.l_mark[-4].v.route.rt) { + if (!r.direction) { + yyerror("direction must be explicit " + "with rules that specify routing"); + YYERROR; + } + r.rt = yystack.l_mark[-4].v.route.rt; + r.rpool.opts = yystack.l_mark[-4].v.route.pool_opts; + if (yystack.l_mark[-4].v.route.key != NULL) + memcpy(&r.rpool.key, yystack.l_mark[-4].v.route.key, + sizeof(struct pf_poolhashkey)); + } + if (r.rt && r.rt != PF_FASTROUTE) { + decide_address_family(yystack.l_mark[-4].v.route.host, &r.af); + remove_invalid_hosts(&yystack.l_mark[-4].v.route.host, &r.af); + if (yystack.l_mark[-4].v.route.host == NULL) { + yyerror("no routing address with " + "matching address family found."); + YYERROR; + } + if ((r.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_NONE && (yystack.l_mark[-4].v.route.host->next != NULL || + yystack.l_mark[-4].v.route.host->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR(yystack.l_mark[-4].v.route.host->addr))) + r.rpool.opts |= PF_POOL_ROUNDROBIN; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_table(yystack.l_mark[-4].v.route.host, "tables are only " + "supported in round-robin routing pools")) + YYERROR; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_alias(yystack.l_mark[-4].v.route.host, "interface (%s) " + "is only supported in round-robin " + "routing pools")) + YYERROR; + if (yystack.l_mark[-4].v.route.host->next != NULL) { + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN) { + yyerror("r.rpool.opts must " + "be PF_POOL_ROUNDROBIN"); + YYERROR; + } + } + } + if (yystack.l_mark[0].v.filter_opts.queues.qname != NULL) { + if (strlcpy(r.qname, yystack.l_mark[0].v.filter_opts.queues.qname, + sizeof(r.qname)) >= sizeof(r.qname)) { + yyerror("rule qname too long (max " + "%d chars)", sizeof(r.qname)-1); + YYERROR; + } + free(yystack.l_mark[0].v.filter_opts.queues.qname); + } + if (yystack.l_mark[0].v.filter_opts.queues.pqname != NULL) { + if (strlcpy(r.pqname, yystack.l_mark[0].v.filter_opts.queues.pqname, + sizeof(r.pqname)) >= sizeof(r.pqname)) { + yyerror("rule pqname too long (max " + "%d chars)", sizeof(r.pqname)-1); + YYERROR; + } + free(yystack.l_mark[0].v.filter_opts.queues.pqname); + } +#ifdef __FreeBSD__ + r.divert.port = yystack.l_mark[0].v.filter_opts.divert.port; +#else + if ((r.divert.port = yystack.l_mark[0].v.filter_opts.divert.port)) { + if (r.direction == PF_OUT) { + if (yystack.l_mark[0].v.filter_opts.divert.addr) { + yyerror("address specified " + "for outgoing divert"); + YYERROR; + } + bzero(&r.divert.addr, + sizeof(r.divert.addr)); + } else { + if (!yystack.l_mark[0].v.filter_opts.divert.addr) { + yyerror("no address specified " + "for incoming divert"); + YYERROR; + } + if (yystack.l_mark[0].v.filter_opts.divert.addr->af != r.af) { + yyerror("address family " + "mismatch for divert"); + YYERROR; + } + r.divert.addr = + yystack.l_mark[0].v.filter_opts.divert.addr->addr.v.a.addr; + } + } +#endif + + expand_rule(&r, yystack.l_mark[-5].v.interface, yystack.l_mark[-4].v.route.host, yystack.l_mark[-2].v.proto, yystack.l_mark[-1].v.fromto.src_os, + yystack.l_mark[-1].v.fromto.src.host, yystack.l_mark[-1].v.fromto.src.port, yystack.l_mark[-1].v.fromto.dst.host, yystack.l_mark[-1].v.fromto.dst.port, + yystack.l_mark[0].v.filter_opts.uid, yystack.l_mark[0].v.filter_opts.gid, yystack.l_mark[0].v.filter_opts.icmpspec, ""); + } +break; +case 174: +#line 2435 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&filter_opts, sizeof filter_opts); + filter_opts.rtableid = -1; + } +break; +case 175: +#line 2440 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.filter_opts = filter_opts; } +break; +case 176: +#line 2441 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&filter_opts, sizeof filter_opts); + filter_opts.rtableid = -1; + yyval.v.filter_opts = filter_opts; + } +break; +case 179: +#line 2452 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.uid) + yystack.l_mark[0].v.uid->tail->next = filter_opts.uid; + filter_opts.uid = yystack.l_mark[0].v.uid; + } +break; +case 180: +#line 2457 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.gid) + yystack.l_mark[0].v.gid->tail->next = filter_opts.gid; + filter_opts.gid = yystack.l_mark[0].v.gid; + } +break; +case 181: +#line 2462 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.marker & FOM_FLAGS) { + yyerror("flags cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_FLAGS; + filter_opts.flags.b1 |= yystack.l_mark[0].v.b.b1; + filter_opts.flags.b2 |= yystack.l_mark[0].v.b.b2; + filter_opts.flags.w |= yystack.l_mark[0].v.b.w; + filter_opts.flags.w2 |= yystack.l_mark[0].v.b.w2; + } +break; +case 182: +#line 2473 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.marker & FOM_ICMP) { + yyerror("icmp-type cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_ICMP; + filter_opts.icmpspec = yystack.l_mark[0].v.icmp; + } +break; +case 183: +#line 2481 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.marker & FOM_PRIO) { + yyerror("prio cannot be redefined"); + YYERROR; + } + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > PF_PRIO_MAX) { + yyerror("prio must be 0 - %u", PF_PRIO_MAX); + YYERROR; + } + filter_opts.marker |= FOM_PRIO; + filter_opts.prio = yystack.l_mark[0].v.number; + } +break; +case 184: +#line 2493 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.marker & FOM_TOS) { + yyerror("tos cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_TOS; + filter_opts.tos = yystack.l_mark[0].v.number; + } +break; +case 185: +#line 2501 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.marker & FOM_KEEP) { + yyerror("modulate or keep cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_KEEP; + filter_opts.keep.action = yystack.l_mark[0].v.keep_state.action; + filter_opts.keep.options = yystack.l_mark[0].v.keep_state.options; + } +break; +case 186: +#line 2510 "../../freebsd/sbin/pfctl/parse.y" + { + filter_opts.fragment = 1; + } +break; +case 187: +#line 2513 "../../freebsd/sbin/pfctl/parse.y" + { + filter_opts.allowopts = 1; + } +break; +case 188: +#line 2516 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.label) { + yyerror("label cannot be redefined"); + YYERROR; + } + filter_opts.label = yystack.l_mark[0].v.string; + } +break; +case 189: +#line 2523 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.queues.qname) { + yyerror("queue cannot be redefined"); + YYERROR; + } + filter_opts.queues = yystack.l_mark[0].v.qassign; + } +break; +case 190: +#line 2530 "../../freebsd/sbin/pfctl/parse.y" + { + filter_opts.tag = yystack.l_mark[0].v.string; + } +break; +case 191: +#line 2533 "../../freebsd/sbin/pfctl/parse.y" + { + filter_opts.match_tag = yystack.l_mark[0].v.string; + filter_opts.match_tag_not = yystack.l_mark[-2].v.number; + } +break; +case 192: +#line 2537 "../../freebsd/sbin/pfctl/parse.y" + { + double p; + + p = floor(yystack.l_mark[0].v.probability * UINT_MAX + 0.5); + if (p < 0.0 || p > UINT_MAX) { + yyerror("invalid probability: %lf", p); + YYERROR; + } + filter_opts.prob = (u_int32_t)p; + if (filter_opts.prob == 0) + filter_opts.prob = 1; + } +break; +case 193: +#line 2549 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) { + yyerror("invalid rtable id"); + YYERROR; + } + filter_opts.rtableid = yystack.l_mark[0].v.number; + } +break; +case 194: +#line 2556 "../../freebsd/sbin/pfctl/parse.y" + { +#ifdef __FreeBSD__ + filter_opts.divert.port = yystack.l_mark[0].v.range.a; + if (!filter_opts.divert.port) { + yyerror("invalid divert port: %u", ntohs(yystack.l_mark[0].v.range.a)); + YYERROR; + } +#endif + } +break; +case 195: +#line 2565 "../../freebsd/sbin/pfctl/parse.y" + { +#ifndef __FreeBSD__ + if ((filter_opts.divert.addr = host(yystack.l_mark[-2].v.string)) == NULL) { + yyerror("could not parse divert address: %s", + yystack.l_mark[-2].v.string); + free(yystack.l_mark[-2].v.string); + YYERROR; + } +#else + if (yystack.l_mark[-2].v.string) +#endif + free(yystack.l_mark[-2].v.string); + filter_opts.divert.port = yystack.l_mark[0].v.range.a; + if (!filter_opts.divert.port) { + yyerror("invalid divert port: %u", ntohs(yystack.l_mark[0].v.range.a)); + YYERROR; + } + } +break; +case 196: +#line 2583 "../../freebsd/sbin/pfctl/parse.y" + { +#ifdef __FreeBSD__ + yyerror("divert-reply has no meaning in FreeBSD pf(4)"); + YYERROR; +#else + filter_opts.divert.port = 1; /* some random value */ +#endif + } +break; +case 198: +#line 2594 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.filter_opts = filter_opts; } +break; +case 199: +#line 2595 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.filter_opts = filter_opts; } +break; +case 202: +#line 2602 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.marker & FOM_SETPRIO) { + yyerror("prio cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_SETPRIO; + filter_opts.set_prio[0] = yystack.l_mark[0].v.b.b1; + filter_opts.set_prio[1] = yystack.l_mark[0].v.b.b2; + } +break; +case 203: +#line 2611 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > PF_PRIO_MAX) { + yyerror("prio must be 0 - %u", PF_PRIO_MAX); + YYERROR; + } + yyval.v.b.b1 = yyval.v.b.b2 = yystack.l_mark[0].v.number; + } +break; +case 204: +#line 2618 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-3].v.number < 0 || yystack.l_mark[-3].v.number > PF_PRIO_MAX || + yystack.l_mark[-1].v.number < 0 || yystack.l_mark[-1].v.number > PF_PRIO_MAX) { + yyerror("prio must be 0 - %u", PF_PRIO_MAX); + YYERROR; + } + yyval.v.b.b1 = yystack.l_mark[-3].v.number; + yyval.v.b.b2 = yystack.l_mark[-1].v.number; + } +break; +case 205: +#line 2629 "../../freebsd/sbin/pfctl/parse.y" + { + char *e; + double p = strtod(yystack.l_mark[0].v.string, &e); + + if (*e == '%') { + p *= 0.01; + e++; + } + if (*e) { + yyerror("invalid probability: %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + yyval.v.probability = p; + } +break; +case 206: +#line 2645 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.probability = (double)yystack.l_mark[0].v.number; + } +break; +case 207: +#line 2651 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.b.b1 = PF_PASS; yyval.v.b.b2 = yyval.v.b.w = 0; } +break; +case 208: +#line 2652 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.b = yystack.l_mark[0].v.b; yyval.v.b.b1 = PF_DROP; } +break; +case 209: +#line 2655 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = blockpolicy; + yyval.v.b.w = returnicmpdefault; + yyval.v.b.w2 = returnicmp6default; + } +break; +case 210: +#line 2660 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = PFRULE_DROP; + yyval.v.b.w = 0; + yyval.v.b.w2 = 0; + } +break; +case 211: +#line 2665 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = PFRULE_RETURNRST; + yyval.v.b.w = 0; + yyval.v.b.w2 = 0; + } +break; +case 212: +#line 2670 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-1].v.number < 0 || yystack.l_mark[-1].v.number > 255) { + yyerror("illegal ttl value %d", yystack.l_mark[-1].v.number); + YYERROR; + } + yyval.v.b.b2 = PFRULE_RETURNRST; + yyval.v.b.w = yystack.l_mark[-1].v.number; + yyval.v.b.w2 = 0; + } +break; +case 213: +#line 2679 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = PFRULE_RETURNICMP; + yyval.v.b.w = returnicmpdefault; + yyval.v.b.w2 = returnicmp6default; + } +break; +case 214: +#line 2684 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = PFRULE_RETURNICMP; + yyval.v.b.w = returnicmpdefault; + yyval.v.b.w2 = returnicmp6default; + } +break; +case 215: +#line 2689 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = PFRULE_RETURNICMP; + yyval.v.b.w = yystack.l_mark[-1].v.number; + yyval.v.b.w2 = returnicmpdefault; + } +break; +case 216: +#line 2694 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = PFRULE_RETURNICMP; + yyval.v.b.w = returnicmpdefault; + yyval.v.b.w2 = yystack.l_mark[-1].v.number; + } +break; +case 217: +#line 2699 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = PFRULE_RETURNICMP; + yyval.v.b.w = yystack.l_mark[-3].v.number; + yyval.v.b.w2 = yystack.l_mark[-1].v.number; + } +break; +case 218: +#line 2704 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.b.b2 = PFRULE_RETURN; + yyval.v.b.w = returnicmpdefault; + yyval.v.b.w2 = returnicmp6default; + } +break; +case 219: +#line 2711 "../../freebsd/sbin/pfctl/parse.y" + { + if (!(yyval.v.number = parseicmpspec(yystack.l_mark[0].v.string, AF_INET))) { + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 220: +#line 2718 "../../freebsd/sbin/pfctl/parse.y" + { + u_int8_t icmptype; + + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { + yyerror("invalid icmp code %lu", yystack.l_mark[0].v.number); + YYERROR; + } + icmptype = returnicmpdefault >> 8; + yyval.v.number = (icmptype << 8 | yystack.l_mark[0].v.number); + } +break; +case 221: +#line 2730 "../../freebsd/sbin/pfctl/parse.y" + { + if (!(yyval.v.number = parseicmpspec(yystack.l_mark[0].v.string, AF_INET6))) { + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 222: +#line 2737 "../../freebsd/sbin/pfctl/parse.y" + { + u_int8_t icmptype; + + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { + yyerror("invalid icmp code %lu", yystack.l_mark[0].v.number); + YYERROR; + } + icmptype = returnicmp6default >> 8; + yyval.v.number = (icmptype << 8 | yystack.l_mark[0].v.number); + } +break; +case 223: +#line 2749 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_INOUT; } +break; +case 224: +#line 2750 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_IN; } +break; +case 225: +#line 2751 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_OUT; } +break; +case 226: +#line 2754 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick.quick = 0; } +break; +case 227: +#line 2755 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick.quick = 1; } +break; +case 228: +#line 2758 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick.log = 0; yyval.v.logquick.quick = 0; yyval.v.logquick.logif = 0; } +break; +case 229: +#line 2759 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick = yystack.l_mark[0].v.logquick; yyval.v.logquick.quick = 0; } +break; +case 230: +#line 2760 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick.quick = 1; yyval.v.logquick.log = 0; yyval.v.logquick.logif = 0; } +break; +case 231: +#line 2761 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick = yystack.l_mark[-1].v.logquick; yyval.v.logquick.quick = 1; } +break; +case 232: +#line 2762 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick = yystack.l_mark[0].v.logquick; yyval.v.logquick.quick = 1; } +break; +case 233: +#line 2765 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick.log = PF_LOG; yyval.v.logquick.logif = 0; } +break; +case 234: +#line 2766 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.logquick.log = PF_LOG | yystack.l_mark[-1].v.logquick.log; + yyval.v.logquick.logif = yystack.l_mark[-1].v.logquick.logif; + } +break; +case 235: +#line 2772 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick = yystack.l_mark[0].v.logquick; } +break; +case 236: +#line 2773 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.logquick.log = yystack.l_mark[-2].v.logquick.log | yystack.l_mark[0].v.logquick.log; + yyval.v.logquick.logif = yystack.l_mark[0].v.logquick.logif; + if (yyval.v.logquick.logif == 0) + yyval.v.logquick.logif = yystack.l_mark[-2].v.logquick.logif; + } +break; +case 237: +#line 2781 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick.log = PF_LOG_ALL; yyval.v.logquick.logif = 0; } +break; +case 238: +#line 2782 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick.log = PF_LOG_SOCKET_LOOKUP; yyval.v.logquick.logif = 0; } +break; +case 239: +#line 2783 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.logquick.log = PF_LOG_SOCKET_LOOKUP; yyval.v.logquick.logif = 0; } +break; +case 240: +#line 2784 "../../freebsd/sbin/pfctl/parse.y" + { + const char *errstr; + u_int i; + + yyval.v.logquick.log = 0; + if (strncmp(yystack.l_mark[0].v.string, "pflog", 5)) { + yyerror("%s: should be a pflog interface", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + i = strtonum(yystack.l_mark[0].v.string + 5, 0, 255, &errstr); + if (errstr) { + yyerror("%s: %s", yystack.l_mark[0].v.string, errstr); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + yyval.v.logquick.logif = i; + } +break; +case 241: +#line 2805 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.interface = NULL; } +break; +case 242: +#line 2806 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.interface = yystack.l_mark[0].v.interface; } +break; +case 243: +#line 2807 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.interface = yystack.l_mark[-1].v.interface; } +break; +case 244: +#line 2810 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.interface = yystack.l_mark[-1].v.interface; } +break; +case 245: +#line 2811 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.interface->tail->next = yystack.l_mark[-1].v.interface; + yystack.l_mark[-3].v.interface->tail = yystack.l_mark[-1].v.interface; + yyval.v.interface = yystack.l_mark[-3].v.interface; + } +break; +case 246: +#line 2818 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.interface = yystack.l_mark[0].v.interface; yyval.v.interface->not = yystack.l_mark[-1].v.number; } +break; +case 247: +#line 2821 "../../freebsd/sbin/pfctl/parse.y" + { + struct node_host *n; + + yyval.v.interface = calloc(1, sizeof(struct node_if)); + if (yyval.v.interface == NULL) + err(1, "if_item: calloc"); + if (strlcpy(yyval.v.interface->ifname, yystack.l_mark[0].v.string, sizeof(yyval.v.interface->ifname)) >= + sizeof(yyval.v.interface->ifname)) { + free(yystack.l_mark[0].v.string); + free(yyval.v.interface); + yyerror("interface name too long"); + YYERROR; + } + + if ((n = ifa_exists(yystack.l_mark[0].v.string)) != NULL) + yyval.v.interface->ifa_flags = n->ifa_flags; + + free(yystack.l_mark[0].v.string); + yyval.v.interface->not = 0; + yyval.v.interface->next = NULL; + yyval.v.interface->tail = yyval.v.interface; + } +break; +case 248: +#line 2845 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = 0; } +break; +case 249: +#line 2846 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = AF_INET; } +break; +case 250: +#line 2847 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = AF_INET6; } +break; +case 251: +#line 2850 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.proto = NULL; } +break; +case 252: +#line 2851 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.proto = yystack.l_mark[0].v.proto; } +break; +case 253: +#line 2852 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.proto = yystack.l_mark[-1].v.proto; } +break; +case 254: +#line 2855 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.proto = yystack.l_mark[-1].v.proto; } +break; +case 255: +#line 2856 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.proto->tail->next = yystack.l_mark[-1].v.proto; + yystack.l_mark[-3].v.proto->tail = yystack.l_mark[-1].v.proto; + yyval.v.proto = yystack.l_mark[-3].v.proto; + } +break; +case 256: +#line 2863 "../../freebsd/sbin/pfctl/parse.y" + { + u_int8_t pr; + + pr = (u_int8_t)yystack.l_mark[0].v.number; + if (pr == 0) { + yyerror("proto 0 cannot be used"); + YYERROR; + } + yyval.v.proto = calloc(1, sizeof(struct node_proto)); + if (yyval.v.proto == NULL) + err(1, "proto_item: calloc"); + yyval.v.proto->proto = pr; + yyval.v.proto->next = NULL; + yyval.v.proto->tail = yyval.v.proto; + } +break; +case 257: +#line 2880 "../../freebsd/sbin/pfctl/parse.y" + { + struct protoent *p; + + p = getprotobyname(yystack.l_mark[0].v.string); + if (p == NULL) { + yyerror("unknown protocol %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + yyval.v.number = p->p_proto; + free(yystack.l_mark[0].v.string); + } +break; +case 258: +#line 2892 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { + yyerror("protocol outside range"); + YYERROR; + } + } +break; +case 259: +#line 2900 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.fromto.src.host = NULL; + yyval.v.fromto.src.port = NULL; + yyval.v.fromto.dst.host = NULL; + yyval.v.fromto.dst.port = NULL; + yyval.v.fromto.src_os = NULL; + } +break; +case 260: +#line 2907 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.fromto.src = yystack.l_mark[-2].v.peer; + yyval.v.fromto.src_os = yystack.l_mark[-1].v.os; + yyval.v.fromto.dst = yystack.l_mark[0].v.peer; + } +break; +case 261: +#line 2914 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.os = NULL; } +break; +case 262: +#line 2915 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.os = yystack.l_mark[0].v.os; } +break; +case 263: +#line 2916 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.os = yystack.l_mark[-1].v.os; } +break; +case 264: +#line 2919 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.os = calloc(1, sizeof(struct node_os)); + if (yyval.v.os == NULL) + err(1, "os: calloc"); + yyval.v.os->os = yystack.l_mark[0].v.string; + yyval.v.os->tail = yyval.v.os; + } +break; +case 265: +#line 2928 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.os = yystack.l_mark[-1].v.os; } +break; +case 266: +#line 2929 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.os->tail->next = yystack.l_mark[-1].v.os; + yystack.l_mark[-3].v.os->tail = yystack.l_mark[-1].v.os; + yyval.v.os = yystack.l_mark[-3].v.os; + } +break; +case 267: +#line 2936 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.peer.host = NULL; + yyval.v.peer.port = NULL; + } +break; +case 268: +#line 2940 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.peer = yystack.l_mark[0].v.peer; + } +break; +case 269: +#line 2945 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.peer.host = NULL; + yyval.v.peer.port = NULL; + } +break; +case 270: +#line 2949 "../../freebsd/sbin/pfctl/parse.y" + { + if (disallow_urpf_failed(yystack.l_mark[0].v.peer.host, "\"urpf-failed\" is " + "not permitted in a destination address")) + YYERROR; + yyval.v.peer = yystack.l_mark[0].v.peer; + } +break; +case 271: +#line 2957 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.peer.host = yystack.l_mark[0].v.host; + yyval.v.peer.port = NULL; + } +break; +case 272: +#line 2961 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.peer.host = yystack.l_mark[-2].v.host; + yyval.v.peer.port = yystack.l_mark[0].v.port; + } +break; +case 273: +#line 2965 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.peer.host = NULL; + yyval.v.peer.port = yystack.l_mark[0].v.port; + } +break; +case 276: +#line 2975 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = NULL; } +break; +case 277: +#line 2976 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[0].v.host; } +break; +case 278: +#line 2977 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[-1].v.host; } +break; +case 279: +#line 2980 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[0].v.host; } +break; +case 280: +#line 2981 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = NULL; } +break; +case 281: +#line 2984 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[-1].v.host; } +break; +case 282: +#line 2985 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-1].v.host == NULL) + yyval.v.host = yystack.l_mark[-3].v.host; + else if (yystack.l_mark[-3].v.host == NULL) + yyval.v.host = yystack.l_mark[-1].v.host; + else { + yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host; + yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail; + yyval.v.host = yystack.l_mark[-3].v.host; + } + } +break; +case 283: +#line 2998 "../../freebsd/sbin/pfctl/parse.y" + { + struct node_host *n; + + for (n = yystack.l_mark[0].v.host; n != NULL; n = n->next) + n->not = yystack.l_mark[-1].v.number; + yyval.v.host = yystack.l_mark[0].v.host; + } +break; +case 284: +#line 3005 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.host = calloc(1, sizeof(struct node_host)); + if (yyval.v.host == NULL) + err(1, "xhost: calloc"); + yyval.v.host->addr.type = PF_ADDR_NOROUTE; + yyval.v.host->next = NULL; + yyval.v.host->not = yystack.l_mark[-1].v.number; + yyval.v.host->tail = yyval.v.host; + } +break; +case 285: +#line 3014 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.host = calloc(1, sizeof(struct node_host)); + if (yyval.v.host == NULL) + err(1, "xhost: calloc"); + yyval.v.host->addr.type = PF_ADDR_URPFFAILED; + yyval.v.host->next = NULL; + yyval.v.host->not = yystack.l_mark[-1].v.number; + yyval.v.host->tail = yyval.v.host; + } +break; +case 286: +#line 3025 "../../freebsd/sbin/pfctl/parse.y" + { + if ((yyval.v.host = host(yystack.l_mark[0].v.string)) == NULL) { + /* error. "any" is handled elsewhere */ + free(yystack.l_mark[0].v.string); + yyerror("could not parse host specification"); + YYERROR; + } + free(yystack.l_mark[0].v.string); + + } +break; +case 287: +#line 3035 "../../freebsd/sbin/pfctl/parse.y" + { + struct node_host *b, *e; + + if ((b = host(yystack.l_mark[-2].v.string)) == NULL || (e = host(yystack.l_mark[0].v.string)) == NULL) { + free(yystack.l_mark[-2].v.string); + free(yystack.l_mark[0].v.string); + yyerror("could not parse host specification"); + YYERROR; + } + if (b->af != e->af || + b->addr.type != PF_ADDR_ADDRMASK || + e->addr.type != PF_ADDR_ADDRMASK || + unmask(&b->addr.v.a.mask, b->af) != + (b->af == AF_INET ? 32 : 128) || + unmask(&e->addr.v.a.mask, e->af) != + (e->af == AF_INET ? 32 : 128) || + b->next != NULL || b->not || + e->next != NULL || e->not) { + free(b); + free(e); + free(yystack.l_mark[-2].v.string); + free(yystack.l_mark[0].v.string); + yyerror("invalid address range"); + YYERROR; + } + memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr, + sizeof(b->addr.v.a.mask)); + b->addr.type = PF_ADDR_RANGE; + yyval.v.host = b; + free(e); + free(yystack.l_mark[-2].v.string); + free(yystack.l_mark[0].v.string); + } +break; +case 288: +#line 3068 "../../freebsd/sbin/pfctl/parse.y" + { + char *buf; + + if (asprintf(&buf, "%s/%lld", yystack.l_mark[-2].v.string, (long long)yystack.l_mark[0].v.number) == -1) + err(1, "host: asprintf"); + free(yystack.l_mark[-2].v.string); + if ((yyval.v.host = host(buf)) == NULL) { + /* error. "any" is handled elsewhere */ + free(buf); + yyerror("could not parse host specification"); + YYERROR; + } + free(buf); + } +break; +case 289: +#line 3082 "../../freebsd/sbin/pfctl/parse.y" + { + char *buf; + + /* ie. for 10/8 parsing */ +#ifdef __FreeBSD__ + if (asprintf(&buf, "%lld/%lld", (long long)yystack.l_mark[-2].v.number, (long long)yystack.l_mark[0].v.number) == -1) +#else + if (asprintf(&buf, "%lld/%lld", yystack.l_mark[-2].v.number, yystack.l_mark[0].v.number) == -1) +#endif + err(1, "host: asprintf"); + if ((yyval.v.host = host(buf)) == NULL) { + /* error. "any" is handled elsewhere */ + free(buf); + yyerror("could not parse host specification"); + YYERROR; + } + free(buf); + } +break; +case 291: +#line 3101 "../../freebsd/sbin/pfctl/parse.y" + { + struct node_host *n; + + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 128) { + yyerror("bit number too big"); + YYERROR; + } + yyval.v.host = yystack.l_mark[-2].v.host; + for (n = yystack.l_mark[-2].v.host; n != NULL; n = n->next) + set_ipmask(n, yystack.l_mark[0].v.number); + } +break; +case 292: +#line 3112 "../../freebsd/sbin/pfctl/parse.y" + { + if (strlen(yystack.l_mark[-1].v.string) >= PF_TABLE_NAME_SIZE) { + yyerror("table name '%s' too long", yystack.l_mark[-1].v.string); + free(yystack.l_mark[-1].v.string); + YYERROR; + } + yyval.v.host = calloc(1, sizeof(struct node_host)); + if (yyval.v.host == NULL) + err(1, "host: calloc"); + yyval.v.host->addr.type = PF_ADDR_TABLE; + if (strlcpy(yyval.v.host->addr.v.tblname, yystack.l_mark[-1].v.string, + sizeof(yyval.v.host->addr.v.tblname)) >= + sizeof(yyval.v.host->addr.v.tblname)) + errx(1, "host: strlcpy"); + free(yystack.l_mark[-1].v.string); + yyval.v.host->next = NULL; + yyval.v.host->tail = yyval.v.host; + } +break; +case 294: +#line 3133 "../../freebsd/sbin/pfctl/parse.y" + { + u_long ulval; + + if (atoul(yystack.l_mark[0].v.string, &ulval) == -1) { + yyerror("%s is not a number", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } else + yyval.v.number = ulval; + free(yystack.l_mark[0].v.string); + } +break; +case 295: +#line 3146 "../../freebsd/sbin/pfctl/parse.y" + { + int flags = 0; + char *p, *op; + + op = yystack.l_mark[-1].v.string; + if (!isalpha(op[0])) { + yyerror("invalid interface name '%s'", op); + free(op); + YYERROR; + } + while ((p = strrchr(yystack.l_mark[-1].v.string, ':')) != NULL) { + if (!strcmp(p+1, "network")) + flags |= PFI_AFLAG_NETWORK; + else if (!strcmp(p+1, "broadcast")) + flags |= PFI_AFLAG_BROADCAST; + else if (!strcmp(p+1, "peer")) + flags |= PFI_AFLAG_PEER; + else if (!strcmp(p+1, "0")) + flags |= PFI_AFLAG_NOALIAS; + else { + yyerror("interface %s has bad modifier", + yystack.l_mark[-1].v.string); + free(op); + YYERROR; + } + *p = '\0'; + } + if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { + free(op); + yyerror("illegal combination of " + "interface modifiers"); + YYERROR; + } + yyval.v.host = calloc(1, sizeof(struct node_host)); + if (yyval.v.host == NULL) + err(1, "address: calloc"); + yyval.v.host->af = 0; + set_ipmask(yyval.v.host, 128); + yyval.v.host->addr.type = PF_ADDR_DYNIFTL; + yyval.v.host->addr.iflags = flags; + if (strlcpy(yyval.v.host->addr.v.ifname, yystack.l_mark[-1].v.string, + sizeof(yyval.v.host->addr.v.ifname)) >= + sizeof(yyval.v.host->addr.v.ifname)) { + free(op); + free(yyval.v.host); + yyerror("interface name too long"); + YYERROR; + } + free(op); + yyval.v.host->next = NULL; + yyval.v.host->tail = yyval.v.host; + } +break; +case 296: +#line 3200 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.port = yystack.l_mark[0].v.port; } +break; +case 297: +#line 3201 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.port = yystack.l_mark[-1].v.port; } +break; +case 298: +#line 3204 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.port = yystack.l_mark[-1].v.port; } +break; +case 299: +#line 3205 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.port->tail->next = yystack.l_mark[-1].v.port; + yystack.l_mark[-3].v.port->tail = yystack.l_mark[-1].v.port; + yyval.v.port = yystack.l_mark[-3].v.port; + } +break; +case 300: +#line 3212 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.port = calloc(1, sizeof(struct node_port)); + if (yyval.v.port == NULL) + err(1, "port_item: calloc"); + yyval.v.port->port[0] = yystack.l_mark[0].v.range.a; + yyval.v.port->port[1] = yystack.l_mark[0].v.range.b; + if (yystack.l_mark[0].v.range.t) + yyval.v.port->op = PF_OP_RRG; + else + yyval.v.port->op = PF_OP_EQ; + yyval.v.port->next = NULL; + yyval.v.port->tail = yyval.v.port; + } +break; +case 301: +#line 3225 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.range.t) { + yyerror("':' cannot be used with an other " + "port operator"); + YYERROR; + } + yyval.v.port = calloc(1, sizeof(struct node_port)); + if (yyval.v.port == NULL) + err(1, "port_item: calloc"); + yyval.v.port->port[0] = yystack.l_mark[0].v.range.a; + yyval.v.port->port[1] = yystack.l_mark[0].v.range.b; + yyval.v.port->op = yystack.l_mark[-1].v.i; + yyval.v.port->next = NULL; + yyval.v.port->tail = yyval.v.port; + } +break; +case 302: +#line 3240 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-2].v.range.t || yystack.l_mark[0].v.range.t) { + yyerror("':' cannot be used with an other " + "port operator"); + YYERROR; + } + yyval.v.port = calloc(1, sizeof(struct node_port)); + if (yyval.v.port == NULL) + err(1, "port_item: calloc"); + yyval.v.port->port[0] = yystack.l_mark[-2].v.range.a; + yyval.v.port->port[1] = yystack.l_mark[0].v.range.a; + yyval.v.port->op = yystack.l_mark[-1].v.i; + yyval.v.port->next = NULL; + yyval.v.port->tail = yyval.v.port; + } +break; +case 303: +#line 3257 "../../freebsd/sbin/pfctl/parse.y" + { + if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, 0) == -1) { + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 304: +#line 3266 "../../freebsd/sbin/pfctl/parse.y" + { + if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, PPORT_RANGE) == -1) { + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 305: +#line 3275 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.uid = yystack.l_mark[0].v.uid; } +break; +case 306: +#line 3276 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.uid = yystack.l_mark[-1].v.uid; } +break; +case 307: +#line 3279 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.uid = yystack.l_mark[-1].v.uid; } +break; +case 308: +#line 3280 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.uid->tail->next = yystack.l_mark[-1].v.uid; + yystack.l_mark[-3].v.uid->tail = yystack.l_mark[-1].v.uid; + yyval.v.uid = yystack.l_mark[-3].v.uid; + } +break; +case 309: +#line 3287 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.uid = calloc(1, sizeof(struct node_uid)); + if (yyval.v.uid == NULL) + err(1, "uid_item: calloc"); + yyval.v.uid->uid[0] = yystack.l_mark[0].v.number; + yyval.v.uid->uid[1] = yystack.l_mark[0].v.number; + yyval.v.uid->op = PF_OP_EQ; + yyval.v.uid->next = NULL; + yyval.v.uid->tail = yyval.v.uid; + } +break; +case 310: +#line 3297 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number == UID_MAX && yystack.l_mark[-1].v.i != PF_OP_EQ && yystack.l_mark[-1].v.i != PF_OP_NE) { + yyerror("user unknown requires operator = or " + "!="); + YYERROR; + } + yyval.v.uid = calloc(1, sizeof(struct node_uid)); + if (yyval.v.uid == NULL) + err(1, "uid_item: calloc"); + yyval.v.uid->uid[0] = yystack.l_mark[0].v.number; + yyval.v.uid->uid[1] = yystack.l_mark[0].v.number; + yyval.v.uid->op = yystack.l_mark[-1].v.i; + yyval.v.uid->next = NULL; + yyval.v.uid->tail = yyval.v.uid; + } +break; +case 311: +#line 3312 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-2].v.number == UID_MAX || yystack.l_mark[0].v.number == UID_MAX) { + yyerror("user unknown requires operator = or " + "!="); + YYERROR; + } + yyval.v.uid = calloc(1, sizeof(struct node_uid)); + if (yyval.v.uid == NULL) + err(1, "uid_item: calloc"); + yyval.v.uid->uid[0] = yystack.l_mark[-2].v.number; + yyval.v.uid->uid[1] = yystack.l_mark[0].v.number; + yyval.v.uid->op = yystack.l_mark[-1].v.i; + yyval.v.uid->next = NULL; + yyval.v.uid->tail = yyval.v.uid; + } +break; +case 312: +#line 3329 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "unknown")) + yyval.v.number = UID_MAX; + else { + struct passwd *pw; + + if ((pw = getpwnam(yystack.l_mark[0].v.string)) == NULL) { + yyerror("unknown user %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + yyval.v.number = pw->pw_uid; + } + free(yystack.l_mark[0].v.string); + } +break; +case 313: +#line 3344 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number >= UID_MAX) { + yyerror("illegal uid value %lu", yystack.l_mark[0].v.number); + YYERROR; + } + yyval.v.number = yystack.l_mark[0].v.number; + } +break; +case 314: +#line 3353 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.gid = yystack.l_mark[0].v.gid; } +break; +case 315: +#line 3354 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.gid = yystack.l_mark[-1].v.gid; } +break; +case 316: +#line 3357 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.gid = yystack.l_mark[-1].v.gid; } +break; +case 317: +#line 3358 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.gid->tail->next = yystack.l_mark[-1].v.gid; + yystack.l_mark[-3].v.gid->tail = yystack.l_mark[-1].v.gid; + yyval.v.gid = yystack.l_mark[-3].v.gid; + } +break; +case 318: +#line 3365 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.gid = calloc(1, sizeof(struct node_gid)); + if (yyval.v.gid == NULL) + err(1, "gid_item: calloc"); + yyval.v.gid->gid[0] = yystack.l_mark[0].v.number; + yyval.v.gid->gid[1] = yystack.l_mark[0].v.number; + yyval.v.gid->op = PF_OP_EQ; + yyval.v.gid->next = NULL; + yyval.v.gid->tail = yyval.v.gid; + } +break; +case 319: +#line 3375 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number == GID_MAX && yystack.l_mark[-1].v.i != PF_OP_EQ && yystack.l_mark[-1].v.i != PF_OP_NE) { + yyerror("group unknown requires operator = or " + "!="); + YYERROR; + } + yyval.v.gid = calloc(1, sizeof(struct node_gid)); + if (yyval.v.gid == NULL) + err(1, "gid_item: calloc"); + yyval.v.gid->gid[0] = yystack.l_mark[0].v.number; + yyval.v.gid->gid[1] = yystack.l_mark[0].v.number; + yyval.v.gid->op = yystack.l_mark[-1].v.i; + yyval.v.gid->next = NULL; + yyval.v.gid->tail = yyval.v.gid; + } +break; +case 320: +#line 3390 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-2].v.number == GID_MAX || yystack.l_mark[0].v.number == GID_MAX) { + yyerror("group unknown requires operator = or " + "!="); + YYERROR; + } + yyval.v.gid = calloc(1, sizeof(struct node_gid)); + if (yyval.v.gid == NULL) + err(1, "gid_item: calloc"); + yyval.v.gid->gid[0] = yystack.l_mark[-2].v.number; + yyval.v.gid->gid[1] = yystack.l_mark[0].v.number; + yyval.v.gid->op = yystack.l_mark[-1].v.i; + yyval.v.gid->next = NULL; + yyval.v.gid->tail = yyval.v.gid; + } +break; +case 321: +#line 3407 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "unknown")) + yyval.v.number = GID_MAX; + else { + struct group *grp; + + if ((grp = getgrnam(yystack.l_mark[0].v.string)) == NULL) { + yyerror("unknown group %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + yyval.v.number = grp->gr_gid; + } + free(yystack.l_mark[0].v.string); + } +break; +case 322: +#line 3422 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number >= GID_MAX) { + yyerror("illegal gid value %lu", yystack.l_mark[0].v.number); + YYERROR; + } + yyval.v.number = yystack.l_mark[0].v.number; + } +break; +case 323: +#line 3431 "../../freebsd/sbin/pfctl/parse.y" + { + int f; + + if ((f = parse_flags(yystack.l_mark[0].v.string)) < 0) { + yyerror("bad flags %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + yyval.v.b.b1 = f; + } +break; +case 324: +#line 3444 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.b.b1 = yystack.l_mark[-2].v.b.b1; yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; } +break; +case 325: +#line 3445 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.b.b1 = 0; yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; } +break; +case 326: +#line 3446 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.b.b1 = 0; yyval.v.b.b2 = 0; } +break; +case 327: +#line 3449 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.icmp = yystack.l_mark[0].v.icmp; } +break; +case 328: +#line 3450 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.icmp = yystack.l_mark[-1].v.icmp; } +break; +case 329: +#line 3451 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.icmp = yystack.l_mark[0].v.icmp; } +break; +case 330: +#line 3452 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.icmp = yystack.l_mark[-1].v.icmp; } +break; +case 331: +#line 3455 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.icmp = yystack.l_mark[-1].v.icmp; } +break; +case 332: +#line 3456 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.icmp->tail->next = yystack.l_mark[-1].v.icmp; + yystack.l_mark[-3].v.icmp->tail = yystack.l_mark[-1].v.icmp; + yyval.v.icmp = yystack.l_mark[-3].v.icmp; + } +break; +case 333: +#line 3463 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.icmp = yystack.l_mark[-1].v.icmp; } +break; +case 334: +#line 3464 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.icmp->tail->next = yystack.l_mark[-1].v.icmp; + yystack.l_mark[-3].v.icmp->tail = yystack.l_mark[-1].v.icmp; + yyval.v.icmp = yystack.l_mark[-3].v.icmp; + } +break; +case 335: +#line 3471 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); + if (yyval.v.icmp == NULL) + err(1, "icmp_item: calloc"); + yyval.v.icmp->type = yystack.l_mark[0].v.number; + yyval.v.icmp->code = 0; + yyval.v.icmp->proto = IPPROTO_ICMP; + yyval.v.icmp->next = NULL; + yyval.v.icmp->tail = yyval.v.icmp; + } +break; +case 336: +#line 3481 "../../freebsd/sbin/pfctl/parse.y" + { + const struct icmpcodeent *p; + + if ((p = geticmpcodebyname(yystack.l_mark[-2].v.number-1, yystack.l_mark[0].v.string, AF_INET)) == NULL) { + yyerror("unknown icmp-code %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + + free(yystack.l_mark[0].v.string); + yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); + if (yyval.v.icmp == NULL) + err(1, "icmp_item: calloc"); + yyval.v.icmp->type = yystack.l_mark[-2].v.number; + yyval.v.icmp->code = p->code + 1; + yyval.v.icmp->proto = IPPROTO_ICMP; + yyval.v.icmp->next = NULL; + yyval.v.icmp->tail = yyval.v.icmp; + } +break; +case 337: +#line 3500 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { + yyerror("illegal icmp-code %lu", yystack.l_mark[0].v.number); + YYERROR; + } + yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); + if (yyval.v.icmp == NULL) + err(1, "icmp_item: calloc"); + yyval.v.icmp->type = yystack.l_mark[-2].v.number; + yyval.v.icmp->code = yystack.l_mark[0].v.number + 1; + yyval.v.icmp->proto = IPPROTO_ICMP; + yyval.v.icmp->next = NULL; + yyval.v.icmp->tail = yyval.v.icmp; + } +break; +case 338: +#line 3516 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); + if (yyval.v.icmp == NULL) + err(1, "icmp_item: calloc"); + yyval.v.icmp->type = yystack.l_mark[0].v.number; + yyval.v.icmp->code = 0; + yyval.v.icmp->proto = IPPROTO_ICMPV6; + yyval.v.icmp->next = NULL; + yyval.v.icmp->tail = yyval.v.icmp; + } +break; +case 339: +#line 3526 "../../freebsd/sbin/pfctl/parse.y" + { + const struct icmpcodeent *p; + + if ((p = geticmpcodebyname(yystack.l_mark[-2].v.number-1, yystack.l_mark[0].v.string, AF_INET6)) == NULL) { + yyerror("unknown icmp6-code %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + + yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); + if (yyval.v.icmp == NULL) + err(1, "icmp_item: calloc"); + yyval.v.icmp->type = yystack.l_mark[-2].v.number; + yyval.v.icmp->code = p->code + 1; + yyval.v.icmp->proto = IPPROTO_ICMPV6; + yyval.v.icmp->next = NULL; + yyval.v.icmp->tail = yyval.v.icmp; + } +break; +case 340: +#line 3545 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { + yyerror("illegal icmp-code %lu", yystack.l_mark[0].v.number); + YYERROR; + } + yyval.v.icmp = calloc(1, sizeof(struct node_icmp)); + if (yyval.v.icmp == NULL) + err(1, "icmp_item: calloc"); + yyval.v.icmp->type = yystack.l_mark[-2].v.number; + yyval.v.icmp->code = yystack.l_mark[0].v.number + 1; + yyval.v.icmp->proto = IPPROTO_ICMPV6; + yyval.v.icmp->next = NULL; + yyval.v.icmp->tail = yyval.v.icmp; + } +break; +case 341: +#line 3561 "../../freebsd/sbin/pfctl/parse.y" + { + const struct icmptypeent *p; + + if ((p = geticmptypebyname(yystack.l_mark[0].v.string, AF_INET)) == NULL) { + yyerror("unknown icmp-type %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + yyval.v.number = p->type + 1; + free(yystack.l_mark[0].v.string); + } +break; +case 342: +#line 3572 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { + yyerror("illegal icmp-type %lu", yystack.l_mark[0].v.number); + YYERROR; + } + yyval.v.number = yystack.l_mark[0].v.number + 1; + } +break; +case 343: +#line 3581 "../../freebsd/sbin/pfctl/parse.y" + { + const struct icmptypeent *p; + + if ((p = geticmptypebyname(yystack.l_mark[0].v.string, AF_INET6)) == + NULL) { + yyerror("unknown icmp6-type %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + yyval.v.number = p->type + 1; + free(yystack.l_mark[0].v.string); + } +break; +case 344: +#line 3593 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > 255) { + yyerror("illegal icmp6-type %lu", yystack.l_mark[0].v.number); + YYERROR; + } + yyval.v.number = yystack.l_mark[0].v.number + 1; + } +break; +case 345: +#line 3602 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "lowdelay")) + yyval.v.number = IPTOS_LOWDELAY; + else if (!strcmp(yystack.l_mark[0].v.string, "throughput")) + yyval.v.number = IPTOS_THROUGHPUT; + else if (!strcmp(yystack.l_mark[0].v.string, "reliability")) + yyval.v.number = IPTOS_RELIABILITY; + else if (yystack.l_mark[0].v.string[0] == '0' && yystack.l_mark[0].v.string[1] == 'x') + yyval.v.number = strtoul(yystack.l_mark[0].v.string, NULL, 16); + else + yyval.v.number = 256; /* flag bad argument */ + if (yyval.v.number < 0 || yyval.v.number > 255) { + yyerror("illegal tos value %s", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 346: +#line 3620 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.number = yystack.l_mark[0].v.number; + if (yyval.v.number < 0 || yyval.v.number > 255) { + yyerror("illegal tos value %s", yystack.l_mark[0].v.number); + YYERROR; + } + } +break; +case 347: +#line 3629 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_SRCTRACK; } +break; +case 348: +#line 3630 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_SRCTRACK_GLOBAL; } +break; +case 349: +#line 3631 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_SRCTRACK_RULE; } +break; +case 350: +#line 3634 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.i = PFRULE_IFBOUND; + } +break; +case 351: +#line 3637 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.i = 0; + } +break; +case 352: +#line 3642 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.keep_state.action = 0; + yyval.v.keep_state.options = NULL; + } +break; +case 353: +#line 3646 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.keep_state.action = PF_STATE_NORMAL; + yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt; + } +break; +case 354: +#line 3650 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.keep_state.action = PF_STATE_MODULATE; + yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt; + } +break; +case 355: +#line 3654 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.keep_state.action = PF_STATE_SYNPROXY; + yyval.v.keep_state.options = yystack.l_mark[0].v.state_opt; + } +break; +case 356: +#line 3660 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = 0; } +break; +case 357: +#line 3661 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_FLUSH; } +break; +case 358: +#line 3662 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.i = PF_FLUSH | PF_FLUSH_GLOBAL; + } +break; +case 359: +#line 3667 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.state_opt = yystack.l_mark[-1].v.state_opt; } +break; +case 360: +#line 3668 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.state_opt = NULL; } +break; +case 361: +#line 3671 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.state_opt = yystack.l_mark[0].v.state_opt; } +break; +case 362: +#line 3672 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-2].v.state_opt->tail->next = yystack.l_mark[0].v.state_opt; + yystack.l_mark[-2].v.state_opt->tail = yystack.l_mark[0].v.state_opt; + yyval.v.state_opt = yystack.l_mark[-2].v.state_opt; + } +break; +case 363: +#line 3679 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_MAX; + yyval.v.state_opt->data.max_states = yystack.l_mark[0].v.number; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 364: +#line 3692 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_NOSYNC; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 365: +#line 3700 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_STATES; + yyval.v.state_opt->data.max_src_states = yystack.l_mark[0].v.number; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 366: +#line 3713 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_CONN; + yyval.v.state_opt->data.max_src_conn = yystack.l_mark[0].v.number; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 367: +#line 3726 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-2].v.number < 0 || yystack.l_mark[-2].v.number > UINT_MAX || + yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_CONN_RATE; + yyval.v.state_opt->data.max_src_conn_rate.limit = yystack.l_mark[-2].v.number; + yyval.v.state_opt->data.max_src_conn_rate.seconds = yystack.l_mark[0].v.number; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 368: +#line 3741 "../../freebsd/sbin/pfctl/parse.y" + { + if (strlen(yystack.l_mark[-2].v.string) >= PF_TABLE_NAME_SIZE) { + yyerror("table name '%s' too long", yystack.l_mark[-2].v.string); + free(yystack.l_mark[-2].v.string); + YYERROR; + } + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + if (strlcpy(yyval.v.state_opt->data.overload.tblname, yystack.l_mark[-2].v.string, + PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE) + errx(1, "state_opt_item: strlcpy"); + free(yystack.l_mark[-2].v.string); + yyval.v.state_opt->type = PF_STATE_OPT_OVERLOAD; + yyval.v.state_opt->data.overload.flush = yystack.l_mark[0].v.i; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 369: +#line 3759 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_MAX_SRC_NODES; + yyval.v.state_opt->data.max_src_nodes = yystack.l_mark[0].v.number; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 370: +#line 3772 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_SRCTRACK; + yyval.v.state_opt->data.src_track = yystack.l_mark[0].v.i; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 371: +#line 3781 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_STATELOCK; + yyval.v.state_opt->data.statelock = yystack.l_mark[0].v.i; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 372: +#line 3790 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_SLOPPY; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 373: +#line 3798 "../../freebsd/sbin/pfctl/parse.y" + { + int i; + + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + for (i = 0; pf_timeouts[i].name && + strcmp(pf_timeouts[i].name, yystack.l_mark[-1].v.string); ++i) + ; /* nothing */ + if (!pf_timeouts[i].name) { + yyerror("illegal timeout name %s", yystack.l_mark[-1].v.string); + free(yystack.l_mark[-1].v.string); + YYERROR; + } + if (strchr(pf_timeouts[i].name, '.') == NULL) { + yyerror("illegal state timeout %s", yystack.l_mark[-1].v.string); + free(yystack.l_mark[-1].v.string); + YYERROR; + } + free(yystack.l_mark[-1].v.string); + yyval.v.state_opt = calloc(1, sizeof(struct node_state_opt)); + if (yyval.v.state_opt == NULL) + err(1, "state_opt_item: calloc"); + yyval.v.state_opt->type = PF_STATE_OPT_TIMEOUT; + yyval.v.state_opt->data.timeout.number = pf_timeouts[i].timeout; + yyval.v.state_opt->data.timeout.seconds = yystack.l_mark[0].v.number; + yyval.v.state_opt->next = NULL; + yyval.v.state_opt->tail = yyval.v.state_opt; + } +break; +case 374: +#line 3830 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.string = yystack.l_mark[0].v.string; + } +break; +case 375: +#line 3835 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.qassign.qname = yystack.l_mark[0].v.string; + yyval.v.qassign.pqname = NULL; + } +break; +case 376: +#line 3839 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.qassign.qname = yystack.l_mark[-1].v.string; + yyval.v.qassign.pqname = NULL; + } +break; +case 377: +#line 3843 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.qassign.qname = yystack.l_mark[-3].v.string; + yyval.v.qassign.pqname = yystack.l_mark[-1].v.string; + } +break; +case 378: +#line 3849 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = 0; } +break; +case 379: +#line 3850 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = 1; } +break; +case 380: +#line 3853 "../../freebsd/sbin/pfctl/parse.y" + { + if (parseport(yystack.l_mark[0].v.string, &yyval.v.range, PPORT_RANGE|PPORT_STAR) == -1) { + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 381: +#line 3862 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[0].v.host; } +break; +case 382: +#line 3863 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[-1].v.host; } +break; +case 383: +#line 3866 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[-1].v.host; } +break; +case 384: +#line 3867 "../../freebsd/sbin/pfctl/parse.y" + { + yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host; + yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail; + yyval.v.host = yystack.l_mark[-3].v.host; + } +break; +case 385: +#line 3874 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.redirection = NULL; } +break; +case 386: +#line 3875 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.redirection = calloc(1, sizeof(struct redirection)); + if (yyval.v.redirection == NULL) + err(1, "redirection: calloc"); + yyval.v.redirection->host = yystack.l_mark[0].v.host; + yyval.v.redirection->rport.a = yyval.v.redirection->rport.b = yyval.v.redirection->rport.t = 0; + } +break; +case 387: +#line 3882 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.redirection = calloc(1, sizeof(struct redirection)); + if (yyval.v.redirection == NULL) + err(1, "redirection: calloc"); + yyval.v.redirection->host = yystack.l_mark[-2].v.host; + yyval.v.redirection->rport = yystack.l_mark[0].v.range; + } +break; +case 388: +#line 3892 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey)); + if (yyval.v.hashkey == NULL) + err(1, "hashkey: calloc"); + yyval.v.hashkey->key32[0] = arc4random(); + yyval.v.hashkey->key32[1] = arc4random(); + yyval.v.hashkey->key32[2] = arc4random(); + yyval.v.hashkey->key32[3] = arc4random(); + } +break; +case 389: +#line 3902 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strncmp(yystack.l_mark[0].v.string, "0x", 2)) { + if (strlen(yystack.l_mark[0].v.string) != 34) { + free(yystack.l_mark[0].v.string); + yyerror("hex key must be 128 bits " + "(32 hex digits) long"); + YYERROR; + } + yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey)); + if (yyval.v.hashkey == NULL) + err(1, "hashkey: calloc"); + + if (sscanf(yystack.l_mark[0].v.string, "0x%8x%8x%8x%8x", + &yyval.v.hashkey->key32[0], &yyval.v.hashkey->key32[1], + &yyval.v.hashkey->key32[2], &yyval.v.hashkey->key32[3]) != 4) { + free(yyval.v.hashkey); + free(yystack.l_mark[0].v.string); + yyerror("invalid hex key"); + YYERROR; + } + } else { + MD5_CTX context; + + yyval.v.hashkey = calloc(1, sizeof(struct pf_poolhashkey)); + if (yyval.v.hashkey == NULL) + err(1, "hashkey: calloc"); + MD5Init(&context); + MD5Update(&context, (unsigned char *)yystack.l_mark[0].v.string, + strlen(yystack.l_mark[0].v.string)); + MD5Final((unsigned char *)yyval.v.hashkey, &context); + HTONL(yyval.v.hashkey->key32[0]); + HTONL(yyval.v.hashkey->key32[1]); + HTONL(yyval.v.hashkey->key32[2]); + HTONL(yyval.v.hashkey->key32[3]); + } + free(yystack.l_mark[0].v.string); + } +break; +case 390: +#line 3941 "../../freebsd/sbin/pfctl/parse.y" + { bzero(&pool_opts, sizeof pool_opts); } +break; +case 391: +#line 3943 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.pool_opts = pool_opts; } +break; +case 392: +#line 3944 "../../freebsd/sbin/pfctl/parse.y" + { + bzero(&pool_opts, sizeof pool_opts); + yyval.v.pool_opts = pool_opts; + } +break; +case 395: +#line 3954 "../../freebsd/sbin/pfctl/parse.y" + { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_BITMASK; + } +break; +case 396: +#line 3961 "../../freebsd/sbin/pfctl/parse.y" + { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_RANDOM; + } +break; +case 397: +#line 3968 "../../freebsd/sbin/pfctl/parse.y" + { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_SRCHASH; + pool_opts.key = yystack.l_mark[0].v.hashkey; + } +break; +case 398: +#line 3976 "../../freebsd/sbin/pfctl/parse.y" + { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_ROUNDROBIN; + } +break; +case 399: +#line 3983 "../../freebsd/sbin/pfctl/parse.y" + { + if (pool_opts.staticport) { + yyerror("static-port cannot be redefined"); + YYERROR; + } + pool_opts.staticport = 1; + } +break; +case 400: +#line 3990 "../../freebsd/sbin/pfctl/parse.y" + { + if (filter_opts.marker & POM_STICKYADDRESS) { + yyerror("sticky-address cannot be redefined"); + YYERROR; + } + pool_opts.marker |= POM_STICKYADDRESS; + pool_opts.opts |= PF_POOL_STICKYADDR; + } +break; +case 401: +#line 4000 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.redirection = NULL; } +break; +case 402: +#line 4001 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.redirection = calloc(1, sizeof(struct redirection)); + if (yyval.v.redirection == NULL) + err(1, "redirection: calloc"); + yyval.v.redirection->host = yystack.l_mark[0].v.host; + yyval.v.redirection->rport.a = yyval.v.redirection->rport.b = yyval.v.redirection->rport.t = 0; + } +break; +case 403: +#line 4008 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.redirection = calloc(1, sizeof(struct redirection)); + if (yyval.v.redirection == NULL) + err(1, "redirection: calloc"); + yyval.v.redirection->host = yystack.l_mark[-2].v.host; + yyval.v.redirection->rport = yystack.l_mark[0].v.range; + } +break; +case 404: +#line 4017 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.b.b1 = yyval.v.b.b2 = 0; yyval.v.b.w2 = 0; } +break; +case 405: +#line 4018 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.b.b1 = 1; yyval.v.b.b2 = 0; yyval.v.b.w2 = 0; } +break; +case 406: +#line 4019 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.b.b1 = 1; yyval.v.b.b2 = yystack.l_mark[0].v.logquick.log; yyval.v.b.w2 = yystack.l_mark[0].v.logquick.logif; } +break; +case 407: +#line 4020 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.b.b1 = 0; yyval.v.b.b2 = yystack.l_mark[0].v.logquick.log; yyval.v.b.w2 = yystack.l_mark[0].v.logquick.logif; } +break; +case 408: +#line 4023 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-2].v.i && yystack.l_mark[0].v.b.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } + if (yystack.l_mark[-2].v.i) + yyval.v.b.b1 = PF_NONAT; + else + yyval.v.b.b1 = PF_NAT; + yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; + yyval.v.b.w = yystack.l_mark[0].v.b.b2; + yyval.v.b.w2 = yystack.l_mark[0].v.b.w2; + } +break; +case 409: +#line 4036 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-2].v.i && yystack.l_mark[0].v.b.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } + if (yystack.l_mark[-2].v.i) + yyval.v.b.b1 = PF_NORDR; + else + yyval.v.b.b1 = PF_RDR; + yyval.v.b.b2 = yystack.l_mark[0].v.b.b1; + yyval.v.b.w = yystack.l_mark[0].v.b.b2; + yyval.v.b.w2 = yystack.l_mark[0].v.b.w2; + } +break; +case 410: +#line 4053 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_NAT)) + YYERROR; + + memset(&r, 0, sizeof(r)); + + r.action = yystack.l_mark[-9].v.b.b1; + r.natpass = yystack.l_mark[-9].v.b.b2; + r.log = yystack.l_mark[-9].v.b.w; + r.logif = yystack.l_mark[-9].v.b.w2; + r.af = yystack.l_mark[-7].v.i; + + if (!r.af) { + if (yystack.l_mark[-5].v.fromto.src.host && yystack.l_mark[-5].v.fromto.src.host->af && + !yystack.l_mark[-5].v.fromto.src.host->ifindex) + r.af = yystack.l_mark[-5].v.fromto.src.host->af; + else if (yystack.l_mark[-5].v.fromto.dst.host && yystack.l_mark[-5].v.fromto.dst.host->af && + !yystack.l_mark[-5].v.fromto.dst.host->ifindex) + r.af = yystack.l_mark[-5].v.fromto.dst.host->af; + } + + if (yystack.l_mark[-4].v.string != NULL) + if (strlcpy(r.tagname, yystack.l_mark[-4].v.string, PF_TAG_NAME_SIZE) >= + PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + + if (yystack.l_mark[-3].v.tagged.name) + if (strlcpy(r.match_tagname, yystack.l_mark[-3].v.tagged.name, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = yystack.l_mark[-3].v.tagged.neg; + r.rtableid = yystack.l_mark[-2].v.rtableid; + + if (r.action == PF_NONAT || r.action == PF_NORDR) { + if (yystack.l_mark[-1].v.redirection != NULL) { + yyerror("translation rule with 'no' " + "does not need '->'"); + YYERROR; + } + } else { + if (yystack.l_mark[-1].v.redirection == NULL || yystack.l_mark[-1].v.redirection->host == NULL) { + yyerror("translation rule requires '-> " + "address'"); + YYERROR; + } + if (!r.af && ! yystack.l_mark[-1].v.redirection->host->ifindex) + r.af = yystack.l_mark[-1].v.redirection->host->af; + + remove_invalid_hosts(&yystack.l_mark[-1].v.redirection->host, &r.af); + if (invalid_redirect(yystack.l_mark[-1].v.redirection->host, r.af)) + YYERROR; + if (check_netmask(yystack.l_mark[-1].v.redirection->host, r.af)) + YYERROR; + + r.rpool.proxy_port[0] = ntohs(yystack.l_mark[-1].v.redirection->rport.a); + + switch (r.action) { + case PF_RDR: + if (!yystack.l_mark[-1].v.redirection->rport.b && yystack.l_mark[-1].v.redirection->rport.t && + yystack.l_mark[-5].v.fromto.dst.port != NULL) { + r.rpool.proxy_port[1] = + ntohs(yystack.l_mark[-1].v.redirection->rport.a) + + (ntohs( + yystack.l_mark[-5].v.fromto.dst.port->port[1]) - + ntohs( + yystack.l_mark[-5].v.fromto.dst.port->port[0])); + } else + r.rpool.proxy_port[1] = + ntohs(yystack.l_mark[-1].v.redirection->rport.b); + break; + case PF_NAT: + r.rpool.proxy_port[1] = + ntohs(yystack.l_mark[-1].v.redirection->rport.b); + if (!r.rpool.proxy_port[0] && + !r.rpool.proxy_port[1]) { + r.rpool.proxy_port[0] = + PF_NAT_PROXY_PORT_LOW; + r.rpool.proxy_port[1] = + PF_NAT_PROXY_PORT_HIGH; + } else if (!r.rpool.proxy_port[1]) + r.rpool.proxy_port[1] = + r.rpool.proxy_port[0]; + break; + default: + break; + } + + r.rpool.opts = yystack.l_mark[0].v.pool_opts.type; + if ((r.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_NONE && (yystack.l_mark[-1].v.redirection->host->next != NULL || + yystack.l_mark[-1].v.redirection->host->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR(yystack.l_mark[-1].v.redirection->host->addr))) + r.rpool.opts = PF_POOL_ROUNDROBIN; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_table(yystack.l_mark[-1].v.redirection->host, "tables are only " + "supported in round-robin redirection " + "pools")) + YYERROR; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_alias(yystack.l_mark[-1].v.redirection->host, "interface (%s) " + "is only supported in round-robin " + "redirection pools")) + YYERROR; + if (yystack.l_mark[-1].v.redirection->host->next != NULL) { + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN) { + yyerror("only round-robin " + "valid for multiple " + "redirection addresses"); + YYERROR; + } + } + } + + if (yystack.l_mark[0].v.pool_opts.key != NULL) + memcpy(&r.rpool.key, yystack.l_mark[0].v.pool_opts.key, + sizeof(struct pf_poolhashkey)); + + if (yystack.l_mark[0].v.pool_opts.opts) + r.rpool.opts |= yystack.l_mark[0].v.pool_opts.opts; + + if (yystack.l_mark[0].v.pool_opts.staticport) { + if (r.action != PF_NAT) { + yyerror("the 'static-port' option is " + "only valid with nat rules"); + YYERROR; + } + if (r.rpool.proxy_port[0] != + PF_NAT_PROXY_PORT_LOW && + r.rpool.proxy_port[1] != + PF_NAT_PROXY_PORT_HIGH) { + yyerror("the 'static-port' option can't" + " be used when specifying a port" + " range"); + YYERROR; + } + r.rpool.proxy_port[0] = 0; + r.rpool.proxy_port[1] = 0; + } + + expand_rule(&r, yystack.l_mark[-8].v.interface, yystack.l_mark[-1].v.redirection == NULL ? NULL : yystack.l_mark[-1].v.redirection->host, yystack.l_mark[-6].v.proto, + yystack.l_mark[-5].v.fromto.src_os, yystack.l_mark[-5].v.fromto.src.host, yystack.l_mark[-5].v.fromto.src.port, yystack.l_mark[-5].v.fromto.dst.host, + yystack.l_mark[-5].v.fromto.dst.port, 0, 0, 0, ""); + free(yystack.l_mark[-1].v.redirection); + } +break; +case 411: +#line 4212 "../../freebsd/sbin/pfctl/parse.y" + { + struct pf_rule binat; + struct pf_pooladdr *pa; + + if (check_rulestate(PFCTL_STATE_NAT)) + YYERROR; + if (disallow_urpf_failed(yystack.l_mark[-4].v.host, "\"urpf-failed\" is not " + "permitted as a binat destination")) + YYERROR; + + memset(&binat, 0, sizeof(binat)); + + if (yystack.l_mark[-12].v.i && yystack.l_mark[-10].v.b.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } + if (yystack.l_mark[-12].v.i) + binat.action = PF_NOBINAT; + else + binat.action = PF_BINAT; + binat.natpass = yystack.l_mark[-10].v.b.b1; + binat.log = yystack.l_mark[-10].v.b.b2; + binat.logif = yystack.l_mark[-10].v.b.w2; + binat.af = yystack.l_mark[-8].v.i; + if (!binat.af && yystack.l_mark[-5].v.host != NULL && yystack.l_mark[-5].v.host->af) + binat.af = yystack.l_mark[-5].v.host->af; + if (!binat.af && yystack.l_mark[-4].v.host != NULL && yystack.l_mark[-4].v.host->af) + binat.af = yystack.l_mark[-4].v.host->af; + + if (!binat.af && yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host) + binat.af = yystack.l_mark[0].v.redirection->host->af; + if (!binat.af) { + yyerror("address family (inet/inet6) " + "undefined"); + YYERROR; + } + + if (yystack.l_mark[-9].v.interface != NULL) { + memcpy(binat.ifname, yystack.l_mark[-9].v.interface->ifname, + sizeof(binat.ifname)); + binat.ifnot = yystack.l_mark[-9].v.interface->not; + free(yystack.l_mark[-9].v.interface); + } + + if (yystack.l_mark[-3].v.string != NULL) + if (strlcpy(binat.tagname, yystack.l_mark[-3].v.string, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + if (yystack.l_mark[-2].v.tagged.name) + if (strlcpy(binat.match_tagname, yystack.l_mark[-2].v.tagged.name, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + binat.match_tag_not = yystack.l_mark[-2].v.tagged.neg; + binat.rtableid = yystack.l_mark[-1].v.rtableid; + + if (yystack.l_mark[-7].v.proto != NULL) { + binat.proto = yystack.l_mark[-7].v.proto->proto; + free(yystack.l_mark[-7].v.proto); + } + + if (yystack.l_mark[-5].v.host != NULL && disallow_table(yystack.l_mark[-5].v.host, "invalid use of " + "table <%s> as the source address of a binat rule")) + YYERROR; + if (yystack.l_mark[-5].v.host != NULL && disallow_alias(yystack.l_mark[-5].v.host, "invalid use of " + "interface (%s) as the source address of a binat " + "rule")) + YYERROR; + if (yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host != NULL && disallow_table( + yystack.l_mark[0].v.redirection->host, "invalid use of table <%s> as the " + "redirect address of a binat rule")) + YYERROR; + if (yystack.l_mark[0].v.redirection != NULL && yystack.l_mark[0].v.redirection->host != NULL && disallow_alias( + yystack.l_mark[0].v.redirection->host, "invalid use of interface (%s) as the " + "redirect address of a binat rule")) + YYERROR; + + if (yystack.l_mark[-5].v.host != NULL) { + if (yystack.l_mark[-5].v.host->next) { + yyerror("multiple binat ip addresses"); + YYERROR; + } + if (yystack.l_mark[-5].v.host->addr.type == PF_ADDR_DYNIFTL) + yystack.l_mark[-5].v.host->af = binat.af; + if (yystack.l_mark[-5].v.host->af != binat.af) { + yyerror("binat ip versions must match"); + YYERROR; + } + if (check_netmask(yystack.l_mark[-5].v.host, binat.af)) + YYERROR; + memcpy(&binat.src.addr, &yystack.l_mark[-5].v.host->addr, + sizeof(binat.src.addr)); + free(yystack.l_mark[-5].v.host); + } + if (yystack.l_mark[-4].v.host != NULL) { + if (yystack.l_mark[-4].v.host->next) { + yyerror("multiple binat ip addresses"); + YYERROR; + } + if (yystack.l_mark[-4].v.host->af != binat.af && yystack.l_mark[-4].v.host->af) { + yyerror("binat ip versions must match"); + YYERROR; + } + if (check_netmask(yystack.l_mark[-4].v.host, binat.af)) + YYERROR; + memcpy(&binat.dst.addr, &yystack.l_mark[-4].v.host->addr, + sizeof(binat.dst.addr)); + binat.dst.neg = yystack.l_mark[-4].v.host->not; + free(yystack.l_mark[-4].v.host); + } + + if (binat.action == PF_NOBINAT) { + if (yystack.l_mark[0].v.redirection != NULL) { + yyerror("'no binat' rule does not need" + " '->'"); + YYERROR; + } + } else { + if (yystack.l_mark[0].v.redirection == NULL || yystack.l_mark[0].v.redirection->host == NULL) { + yyerror("'binat' rule requires" + " '-> address'"); + YYERROR; + } + + remove_invalid_hosts(&yystack.l_mark[0].v.redirection->host, &binat.af); + if (invalid_redirect(yystack.l_mark[0].v.redirection->host, binat.af)) + YYERROR; + if (yystack.l_mark[0].v.redirection->host->next != NULL) { + yyerror("binat rule must redirect to " + "a single address"); + YYERROR; + } + if (check_netmask(yystack.l_mark[0].v.redirection->host, binat.af)) + YYERROR; + + if (!PF_AZERO(&binat.src.addr.v.a.mask, + binat.af) && + !PF_AEQ(&binat.src.addr.v.a.mask, + &yystack.l_mark[0].v.redirection->host->addr.v.a.mask, binat.af)) { + yyerror("'binat' source mask and " + "redirect mask must be the same"); + YYERROR; + } + + TAILQ_INIT(&binat.rpool.list); + pa = calloc(1, sizeof(struct pf_pooladdr)); + if (pa == NULL) + err(1, "binat: calloc"); + pa->addr = yystack.l_mark[0].v.redirection->host->addr; + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&binat.rpool.list, + pa, entries); + + free(yystack.l_mark[0].v.redirection); + } + + pfctl_add_rule(pf, &binat, ""); + } +break; +case 412: +#line 4377 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.string = NULL; } +break; +case 413: +#line 4378 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.string = yystack.l_mark[0].v.string; } +break; +case 414: +#line 4381 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.tagged.neg = 0; yyval.v.tagged.name = NULL; } +break; +case 415: +#line 4382 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.tagged.neg = yystack.l_mark[-2].v.number; yyval.v.tagged.name = yystack.l_mark[0].v.string; } +break; +case 416: +#line 4385 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.rtableid = -1; } +break; +case 417: +#line 4386 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > rt_tableid_max()) { + yyerror("invalid rtable id"); + YYERROR; + } + yyval.v.rtableid = yystack.l_mark[0].v.number; + } +break; +case 418: +#line 4395 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.host = calloc(1, sizeof(struct node_host)); + if (yyval.v.host == NULL) + err(1, "route_host: calloc"); + yyval.v.host->ifname = yystack.l_mark[0].v.string; + set_ipmask(yyval.v.host, 128); + yyval.v.host->next = NULL; + yyval.v.host->tail = yyval.v.host; + } +break; +case 419: +#line 4404 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.host = yystack.l_mark[-1].v.host; + yyval.v.host->ifname = yystack.l_mark[-2].v.string; + } +break; +case 420: +#line 4410 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[-1].v.host; } +break; +case 421: +#line 4411 "../../freebsd/sbin/pfctl/parse.y" + { + if (yystack.l_mark[-3].v.host->af == 0) + yystack.l_mark[-3].v.host->af = yystack.l_mark[-1].v.host->af; + if (yystack.l_mark[-3].v.host->af != yystack.l_mark[-1].v.host->af) { + yyerror("all pool addresses must be in the " + "same address family"); + YYERROR; + } + yystack.l_mark[-3].v.host->tail->next = yystack.l_mark[-1].v.host; + yystack.l_mark[-3].v.host->tail = yystack.l_mark[-1].v.host->tail; + yyval.v.host = yystack.l_mark[-3].v.host; + } +break; +case 422: +#line 4425 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[0].v.host; } +break; +case 423: +#line 4426 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.host = yystack.l_mark[-1].v.host; } +break; +case 424: +#line 4429 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.route.host = NULL; + yyval.v.route.rt = 0; + yyval.v.route.pool_opts = 0; + } +break; +case 425: +#line 4434 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.route.host = NULL; + yyval.v.route.rt = PF_FASTROUTE; + yyval.v.route.pool_opts = 0; + } +break; +case 426: +#line 4439 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.route.host = yystack.l_mark[-1].v.host; + yyval.v.route.rt = PF_ROUTETO; + yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts; + if (yystack.l_mark[0].v.pool_opts.key != NULL) + yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key; + } +break; +case 427: +#line 4446 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.route.host = yystack.l_mark[-1].v.host; + yyval.v.route.rt = PF_REPLYTO; + yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts; + if (yystack.l_mark[0].v.pool_opts.key != NULL) + yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key; + } +break; +case 428: +#line 4453 "../../freebsd/sbin/pfctl/parse.y" + { + yyval.v.route.host = yystack.l_mark[-1].v.host; + yyval.v.route.rt = PF_DUPTO; + yyval.v.route.pool_opts = yystack.l_mark[0].v.pool_opts.type | yystack.l_mark[0].v.pool_opts.opts; + if (yystack.l_mark[0].v.pool_opts.key != NULL) + yyval.v.route.key = yystack.l_mark[0].v.pool_opts.key; + } +break; +case 429: +#line 4463 "../../freebsd/sbin/pfctl/parse.y" + { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free(yystack.l_mark[-1].v.string); + YYERROR; + } + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + if (pfctl_set_timeout(pf, yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number, 0) != 0) { + yyerror("unknown timeout %s", yystack.l_mark[-1].v.string); + free(yystack.l_mark[-1].v.string); + YYERROR; + } + free(yystack.l_mark[-1].v.string); + } +break; +case 430: +#line 4479 "../../freebsd/sbin/pfctl/parse.y" + { + if (check_rulestate(PFCTL_STATE_OPTION)) + YYERROR; + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + if (pfctl_set_timeout(pf, "interval", yystack.l_mark[0].v.number, 0) != 0) + YYERROR; + } +break; +case 433: +#line 4496 "../../freebsd/sbin/pfctl/parse.y" + { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free(yystack.l_mark[-1].v.string); + YYERROR; + } + if (yystack.l_mark[0].v.number < 0 || yystack.l_mark[0].v.number > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + if (pfctl_set_limit(pf, yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number) != 0) { + yyerror("unable to set limit %s %u", yystack.l_mark[-1].v.string, yystack.l_mark[0].v.number); + free(yystack.l_mark[-1].v.string); + YYERROR; + } + free(yystack.l_mark[-1].v.string); + } +break; +case 438: +#line 4522 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.number = 0; } +break; +case 439: +#line 4523 "../../freebsd/sbin/pfctl/parse.y" + { + if (!strcmp(yystack.l_mark[0].v.string, "yes")) + yyval.v.number = 1; + else { + yyerror("invalid value '%s', expected 'yes' " + "or 'no'", yystack.l_mark[0].v.string); + free(yystack.l_mark[0].v.string); + YYERROR; + } + free(yystack.l_mark[0].v.string); + } +break; +case 440: +#line 4536 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_OP_EQ; } +break; +case 441: +#line 4537 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_OP_NE; } +break; +case 442: +#line 4538 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_OP_LE; } +break; +case 443: +#line 4539 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_OP_LT; } +break; +case 444: +#line 4540 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_OP_GE; } +break; +case 445: +#line 4541 "../../freebsd/sbin/pfctl/parse.y" + { yyval.v.i = PF_OP_GT; } +break; +#line 9257 "pfctly.tab.c" + } + yystack.s_mark -= yym; + yystate = *yystack.s_mark; + yystack.l_mark -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state 0 to\ + state %d\n", YYPREFIX, YYFINAL); +#endif + yystate = YYFINAL; + *++yystack.s_mark = YYFINAL; + *++yystack.l_mark = yyval; + if (yychar < 0) + { + if ((yychar = YYLEX) < 0) yychar = YYEOF; +#if YYDEBUG + if (yydebug) + { + yys = yyname[YYTRANSLATE(yychar)]; + printf("%sdebug: state %d, reading %d (%s)\n", + YYPREFIX, YYFINAL, yychar, yys); + } +#endif + } + if (yychar == YYEOF) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#if YYDEBUG + if (yydebug) + printf("%sdebug: after reduction, shifting from state %d \ +to state %d\n", YYPREFIX, *yystack.s_mark, yystate); +#endif + if (yystack.s_mark >= yystack.s_last && yygrowstack(&yystack) == YYENOMEM) + { + goto yyoverflow; + } + *++yystack.s_mark = (YYINT) yystate; + *++yystack.l_mark = yyval; + goto yyloop; + +yyoverflow: + YYERROR_CALL("yacc stack overflow"); + +yyabort: + yyfreestack(&yystack); + return (1); + +yyaccept: + yyfreestack(&yystack); + return (0); +} diff --git a/freebsd/sbin/pfctl/parse.h b/freebsd/sbin/pfctl/parse.h new file mode 100644 index 00000000..929f9956 --- /dev/null +++ b/freebsd/sbin/pfctl/parse.h @@ -0,0 +1,337 @@ +/* A Bison parser, made by GNU Bison 2.7. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_PFCTLY_PFCTLY_TAB_H_INCLUDED +# define YY_PFCTLY_PFCTLY_TAB_H_INCLUDED +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int pfctlydebug; +#endif + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + PASS = 258, + BLOCK = 259, + SCRUB = 260, + RETURN = 261, + IN = 262, + OS = 263, + OUT = 264, + LOG = 265, + QUICK = 266, + ON = 267, + FROM = 268, + TO = 269, + FLAGS = 270, + RETURNRST = 271, + RETURNICMP = 272, + RETURNICMP6 = 273, + PROTO = 274, + INET = 275, + INET6 = 276, + ALL = 277, + ANY = 278, + ICMPTYPE = 279, + ICMP6TYPE = 280, + CODE = 281, + KEEP = 282, + MODULATE = 283, + STATE = 284, + PORT = 285, + RDR = 286, + NAT = 287, + BINAT = 288, + ARROW = 289, + NODF = 290, + MINTTL = 291, + ERROR = 292, + ALLOWOPTS = 293, + FASTROUTE = 294, + FILENAME = 295, + ROUTETO = 296, + DUPTO = 297, + REPLYTO = 298, + NO = 299, + LABEL = 300, + NOROUTE = 301, + URPFFAILED = 302, + FRAGMENT = 303, + USER = 304, + GROUP = 305, + MAXMSS = 306, + MAXIMUM = 307, + TTL = 308, + TOS = 309, + DROP = 310, + TABLE = 311, + REASSEMBLE = 312, + FRAGDROP = 313, + FRAGCROP = 314, + ANCHOR = 315, + NATANCHOR = 316, + RDRANCHOR = 317, + BINATANCHOR = 318, + SET = 319, + OPTIMIZATION = 320, + TIMEOUT = 321, + LIMIT = 322, + LOGINTERFACE = 323, + BLOCKPOLICY = 324, + RANDOMID = 325, + REQUIREORDER = 326, + SYNPROXY = 327, + FINGERPRINTS = 328, + NOSYNC = 329, + DEBUG = 330, + SKIP = 331, + HOSTID = 332, + ANTISPOOF = 333, + FOR = 334, + INCLUDE = 335, + BITMASK = 336, + RANDOM = 337, + SOURCEHASH = 338, + ROUNDROBIN = 339, + STATICPORT = 340, + PROBABILITY = 341, + ALTQ = 342, + CBQ = 343, + CODEL = 344, + PRIQ = 345, + HFSC = 346, + FAIRQ = 347, + BANDWIDTH = 348, + TBRSIZE = 349, + LINKSHARE = 350, + REALTIME = 351, + UPPERLIMIT = 352, + QUEUE = 353, + PRIORITY = 354, + QLIMIT = 355, + HOGS = 356, + BUCKETS = 357, + RTABLE = 358, + TARGET = 359, + INTERVAL = 360, + LOAD = 361, + RULESET_OPTIMIZATION = 362, + PRIO = 363, + STICKYADDRESS = 364, + MAXSRCSTATES = 365, + MAXSRCNODES = 366, + SOURCETRACK = 367, + GLOBAL = 368, + RULE = 369, + MAXSRCCONN = 370, + MAXSRCCONNRATE = 371, + OVERLOAD = 372, + FLUSH = 373, + SLOPPY = 374, + TAGGED = 375, + TAG = 376, + IFBOUND = 377, + FLOATING = 378, + STATEPOLICY = 379, + STATEDEFAULTS = 380, + ROUTE = 381, + SETTOS = 382, + DIVERTTO = 383, + DIVERTREPLY = 384, + STRING = 385, + NUMBER = 386, + PORTBINARY = 387 + }; +#endif +/* Tokens. */ +#define PASS 258 +#define BLOCK 259 +#define SCRUB 260 +#define RETURN 261 +#define IN 262 +#define OS 263 +#define OUT 264 +#define LOG 265 +#define QUICK 266 +#define ON 267 +#define FROM 268 +#define TO 269 +#define FLAGS 270 +#define RETURNRST 271 +#define RETURNICMP 272 +#define RETURNICMP6 273 +#define PROTO 274 +#define INET 275 +#define INET6 276 +#define ALL 277 +#define ANY 278 +#define ICMPTYPE 279 +#define ICMP6TYPE 280 +#define CODE 281 +#define KEEP 282 +#define MODULATE 283 +#define STATE 284 +#define PORT 285 +#define RDR 286 +#define NAT 287 +#define BINAT 288 +#define ARROW 289 +#define NODF 290 +#define MINTTL 291 +#define ERROR 292 +#define ALLOWOPTS 293 +#define FASTROUTE 294 +#define FILENAME 295 +#define ROUTETO 296 +#define DUPTO 297 +#define REPLYTO 298 +#define NO 299 +#define LABEL 300 +#define NOROUTE 301 +#define URPFFAILED 302 +#define FRAGMENT 303 +#define USER 304 +#define GROUP 305 +#define MAXMSS 306 +#define MAXIMUM 307 +#define TTL 308 +#define TOS 309 +#define DROP 310 +#define TABLE 311 +#define REASSEMBLE 312 +#define FRAGDROP 313 +#define FRAGCROP 314 +#define ANCHOR 315 +#define NATANCHOR 316 +#define RDRANCHOR 317 +#define BINATANCHOR 318 +#define SET 319 +#define OPTIMIZATION 320 +#define TIMEOUT 321 +#define LIMIT 322 +#define LOGINTERFACE 323 +#define BLOCKPOLICY 324 +#define RANDOMID 325 +#define REQUIREORDER 326 +#define SYNPROXY 327 +#define FINGERPRINTS 328 +#define NOSYNC 329 +#define DEBUG 330 +#define SKIP 331 +#define HOSTID 332 +#define ANTISPOOF 333 +#define FOR 334 +#define INCLUDE 335 +#define BITMASK 336 +#define RANDOM 337 +#define SOURCEHASH 338 +#define ROUNDROBIN 339 +#define STATICPORT 340 +#define PROBABILITY 341 +#define ALTQ 342 +#define CBQ 343 +#define CODEL 344 +#define PRIQ 345 +#define HFSC 346 +#define FAIRQ 347 +#define BANDWIDTH 348 +#define TBRSIZE 349 +#define LINKSHARE 350 +#define REALTIME 351 +#define UPPERLIMIT 352 +#define QUEUE 353 +#define PRIORITY 354 +#define QLIMIT 355 +#define HOGS 356 +#define BUCKETS 357 +#define RTABLE 358 +#define TARGET 359 +#define INTERVAL 360 +#define LOAD 361 +#define RULESET_OPTIMIZATION 362 +#define PRIO 363 +#define STICKYADDRESS 364 +#define MAXSRCSTATES 365 +#define MAXSRCNODES 366 +#define SOURCETRACK 367 +#define GLOBAL 368 +#define RULE 369 +#define MAXSRCCONN 370 +#define MAXSRCCONNRATE 371 +#define OVERLOAD 372 +#define FLUSH 373 +#define SLOPPY 374 +#define TAGGED 375 +#define TAG 376 +#define IFBOUND 377 +#define FLOATING 378 +#define STATEPOLICY 379 +#define STATEDEFAULTS 380 +#define ROUTE 381 +#define SETTOS 382 +#define DIVERTTO 383 +#define DIVERTREPLY 384 +#define STRING 385 +#define NUMBER 386 +#define PORTBINARY 387 + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE pfctlylval; + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int pfctlyparse (void *YYPARSE_PARAM); +#else +int pfctlyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int pfctlyparse (void); +#else +int pfctlyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + +#endif /* !YY_PFCTLY_PFCTLY_TAB_H_INCLUDED */ diff --git a/freebsd/sbin/pfctl/parse.y b/freebsd/sbin/pfctl/parse.y new file mode 100644 index 00000000..33edd3e5 --- /dev/null +++ b/freebsd/sbin/pfctl/parse.y @@ -0,0 +1,6290 @@ +/* $OpenBSD: parse.y,v 1.554 2008/10/17 12:59:53 henning Exp $ */ + +/* + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. + * Copyright (c) 2001 Theo de Raadt. All rights reserved. + * Copyright (c) 2002,2003 Henning Brauer. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +%{ +#ifdef __rtems__ +#include <machine/rtems-bsd-user-space.h> +#endif /* __rtems__ */ + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset +#define pf_anchor_setup _bsd_pf_anchor_setup +#define pf_remove_if_empty_ruleset _bsd_pf_remove_if_empty_ruleset +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#ifdef __FreeBSD__ +#include <sys/sysctl.h> +#endif +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp6.h> +#include <net/pfvar.h> +#include <arpa/inet.h> +#include <net/altq/altq.h> +#include <net/altq/altq_cbq.h> +#include <net/altq/altq_codel.h> +#include <net/altq/altq_priq.h> +#include <net/altq/altq_hfsc.h> +#include <net/altq/altq_fairq.h> + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <netdb.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <math.h> +#include <err.h> +#include <limits.h> +#include <pwd.h> +#include <grp.h> +#include <md5.h> + +#include "pfctl_parser.h" +#include "pfctl.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-parse-data.h" +#endif /* __rtems__ */ + +static struct pfctl *pf = NULL; +static int debug = 0; +static int rulestate = 0; +static u_int16_t returnicmpdefault = + (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; +static u_int16_t returnicmp6default = + (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; +static int blockpolicy = PFRULE_DROP; +static int require_order = 1; +static int default_statelock; + +static TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); +static struct file { + TAILQ_ENTRY(file) entry; + FILE *stream; + char *name; + int lineno; + int errors; +} *file; +struct file *pushfile(const char *, int); +int popfile(void); +int check_file_secrecy(int, const char *); +int yyparse(void); +int yylex(void); +int yyerror(const char *, ...); +int kw_cmp(const void *, const void *); +int lookup(char *); +int lgetc(int); +int lungetc(int); +int findeol(void); + +static TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); +struct sym { + TAILQ_ENTRY(sym) entry; + int used; + int persist; + char *nam; + char *val; +}; +int symset(const char *, const char *, int); +char *symget(const char *); + +int atoul(char *, u_long *); + +enum { + PFCTL_STATE_NONE, + PFCTL_STATE_OPTION, + PFCTL_STATE_SCRUB, + PFCTL_STATE_QUEUE, + PFCTL_STATE_NAT, + PFCTL_STATE_FILTER +}; + +struct node_proto { + u_int8_t proto; + struct node_proto *next; + struct node_proto *tail; +}; + +struct node_port { + u_int16_t port[2]; + u_int8_t op; + struct node_port *next; + struct node_port *tail; +}; + +struct node_uid { + uid_t uid[2]; + u_int8_t op; + struct node_uid *next; + struct node_uid *tail; +}; + +struct node_gid { + gid_t gid[2]; + u_int8_t op; + struct node_gid *next; + struct node_gid *tail; +}; + +struct node_icmp { + u_int8_t code; + u_int8_t type; + u_int8_t proto; + struct node_icmp *next; + struct node_icmp *tail; +}; + +enum { PF_STATE_OPT_MAX, PF_STATE_OPT_NOSYNC, PF_STATE_OPT_SRCTRACK, + PF_STATE_OPT_MAX_SRC_STATES, PF_STATE_OPT_MAX_SRC_CONN, + PF_STATE_OPT_MAX_SRC_CONN_RATE, PF_STATE_OPT_MAX_SRC_NODES, + PF_STATE_OPT_OVERLOAD, PF_STATE_OPT_STATELOCK, + PF_STATE_OPT_TIMEOUT, PF_STATE_OPT_SLOPPY, }; + +enum { PF_SRCTRACK_NONE, PF_SRCTRACK, PF_SRCTRACK_GLOBAL, PF_SRCTRACK_RULE }; + +struct node_state_opt { + int type; + union { + u_int32_t max_states; + u_int32_t max_src_states; + u_int32_t max_src_conn; + struct { + u_int32_t limit; + u_int32_t seconds; + } max_src_conn_rate; + struct { + u_int8_t flush; + char tblname[PF_TABLE_NAME_SIZE]; + } overload; + u_int32_t max_src_nodes; + u_int8_t src_track; + u_int32_t statelock; + struct { + int number; + u_int32_t seconds; + } timeout; + } data; + struct node_state_opt *next; + struct node_state_opt *tail; +}; + +struct peer { + struct node_host *host; + struct node_port *port; +}; + +static struct node_queue { + char queue[PF_QNAME_SIZE]; + char parent[PF_QNAME_SIZE]; + char ifname[IFNAMSIZ]; + int scheduler; + struct node_queue *next; + struct node_queue *tail; +} *queues = NULL; + +struct node_qassign { + char *qname; + char *pqname; +}; + +static struct filter_opts { + int marker; +#define FOM_FLAGS 0x01 +#define FOM_ICMP 0x02 +#define FOM_TOS 0x04 +#define FOM_KEEP 0x08 +#define FOM_SRCTRACK 0x10 +#define FOM_SETPRIO 0x0400 +#define FOM_PRIO 0x2000 + struct node_uid *uid; + struct node_gid *gid; + struct { + u_int8_t b1; + u_int8_t b2; + u_int16_t w; + u_int16_t w2; + } flags; + struct node_icmp *icmpspec; + u_int32_t tos; + u_int32_t prob; + struct { + int action; + struct node_state_opt *options; + } keep; + int fragment; + int allowopts; + char *label; + struct node_qassign queues; + char *tag; + char *match_tag; + u_int8_t match_tag_not; + u_int rtableid; + u_int8_t prio; + u_int8_t set_prio[2]; + struct { + struct node_host *addr; + u_int16_t port; + } divert; +} filter_opts; + +static struct antispoof_opts { + char *label; + u_int rtableid; +} antispoof_opts; + +static struct scrub_opts { + int marker; +#define SOM_MINTTL 0x01 +#define SOM_MAXMSS 0x02 +#define SOM_FRAGCACHE 0x04 +#define SOM_SETTOS 0x08 + int nodf; + int minttl; + int maxmss; + int settos; + int fragcache; + int randomid; + int reassemble_tcp; + char *match_tag; + u_int8_t match_tag_not; + u_int rtableid; +} scrub_opts; + +static struct queue_opts { + int marker; +#define QOM_BWSPEC 0x01 +#define QOM_SCHEDULER 0x02 +#define QOM_PRIORITY 0x04 +#define QOM_TBRSIZE 0x08 +#define QOM_QLIMIT 0x10 + struct node_queue_bw queue_bwspec; + struct node_queue_opt scheduler; + int priority; + int tbrsize; + int qlimit; +} queue_opts; + +static struct table_opts { + int flags; + int init_addr; + struct node_tinithead init_nodes; +} table_opts; + +static struct pool_opts { + int marker; +#define POM_TYPE 0x01 +#define POM_STICKYADDRESS 0x02 + u_int8_t opts; + int type; + int staticport; + struct pf_poolhashkey *key; + +} pool_opts; + +static struct codel_opts codel_opts; +static struct node_hfsc_opts hfsc_opts; +static struct node_fairq_opts fairq_opts; +static struct node_state_opt *keep_state_defaults = NULL; + +int disallow_table(struct node_host *, const char *); +int disallow_urpf_failed(struct node_host *, const char *); +int disallow_alias(struct node_host *, const char *); +int rule_consistent(struct pf_rule *, int); +int filter_consistent(struct pf_rule *, int); +int nat_consistent(struct pf_rule *); +int rdr_consistent(struct pf_rule *); +int process_tabledef(char *, struct table_opts *); +void expand_label_str(char *, size_t, const char *, const char *); +void expand_label_if(const char *, char *, size_t, const char *); +void expand_label_addr(const char *, char *, size_t, u_int8_t, + struct node_host *); +void expand_label_port(const char *, char *, size_t, + struct node_port *); +void expand_label_proto(const char *, char *, size_t, u_int8_t); +void expand_label_nr(const char *, char *, size_t); +void expand_label(char *, size_t, const char *, u_int8_t, + struct node_host *, struct node_port *, struct node_host *, + struct node_port *, u_int8_t); +void expand_rule(struct pf_rule *, struct node_if *, + struct node_host *, struct node_proto *, struct node_os *, + struct node_host *, struct node_port *, struct node_host *, + struct node_port *, struct node_uid *, struct node_gid *, + struct node_icmp *, const char *); +int expand_altq(struct pf_altq *, struct node_if *, + struct node_queue *, struct node_queue_bw bwspec, + struct node_queue_opt *); +int expand_queue(struct pf_altq *, struct node_if *, + struct node_queue *, struct node_queue_bw, + struct node_queue_opt *); +int expand_skip_interface(struct node_if *); + +int check_rulestate(int); +int getservice(char *); +int rule_label(struct pf_rule *, char *); +int rt_tableid_max(void); + +void mv_rules(struct pf_ruleset *, struct pf_ruleset *); +void decide_address_family(struct node_host *, sa_family_t *); +void remove_invalid_hosts(struct node_host **, sa_family_t *); +int invalid_redirect(struct node_host *, sa_family_t); +u_int16_t parseicmpspec(char *, sa_family_t); + +static TAILQ_HEAD(loadanchorshead, loadanchors) + loadanchorshead = TAILQ_HEAD_INITIALIZER(loadanchorshead); + +struct loadanchors { + TAILQ_ENTRY(loadanchors) entries; + char *anchorname; + char *filename; +}; + +typedef struct { + union { + int64_t number; + double probability; + int i; + char *string; + u_int rtableid; + struct { + u_int8_t b1; + u_int8_t b2; + u_int16_t w; + u_int16_t w2; + } b; + struct range { + int a; + int b; + int t; + } range; + struct node_if *interface; + struct node_proto *proto; + struct node_icmp *icmp; + struct node_host *host; + struct node_os *os; + struct node_port *port; + struct node_uid *uid; + struct node_gid *gid; + struct node_state_opt *state_opt; + struct peer peer; + struct { + struct peer src, dst; + struct node_os *src_os; + } fromto; + struct { + struct node_host *host; + u_int8_t rt; + u_int8_t pool_opts; + sa_family_t af; + struct pf_poolhashkey *key; + } route; + struct redirection { + struct node_host *host; + struct range rport; + } *redirection; + struct { + int action; + struct node_state_opt *options; + } keep_state; + struct { + u_int8_t log; + u_int8_t logif; + u_int8_t quick; + } logquick; + struct { + int neg; + char *name; + } tagged; + struct pf_poolhashkey *hashkey; + struct node_queue *queue; + struct node_queue_opt queue_options; + struct node_queue_bw queue_bwspec; + struct node_qassign qassign; + struct filter_opts filter_opts; + struct antispoof_opts antispoof_opts; + struct queue_opts queue_opts; + struct scrub_opts scrub_opts; + struct table_opts table_opts; + struct pool_opts pool_opts; + struct node_hfsc_opts hfsc_opts; + struct node_fairq_opts fairq_opts; + struct codel_opts codel_opts; + } v; + int lineno; +} YYSTYPE; + +#define PPORT_RANGE 1 +#define PPORT_STAR 2 +int parseport(char *, struct range *r, int); + +#define DYNIF_MULTIADDR(addr) ((addr).type == PF_ADDR_DYNIFTL && \ + (!((addr).iflags & PFI_AFLAG_NOALIAS) || \ + !isdigit((addr).v.ifname[strlen((addr).v.ifname)-1]))) + +%} + +%token PASS BLOCK SCRUB RETURN IN OS OUT LOG QUICK ON FROM TO FLAGS +%token RETURNRST RETURNICMP RETURNICMP6 PROTO INET INET6 ALL ANY ICMPTYPE +%token ICMP6TYPE CODE KEEP MODULATE STATE PORT RDR NAT BINAT ARROW NODF +%token MINTTL ERROR ALLOWOPTS FASTROUTE FILENAME ROUTETO DUPTO REPLYTO NO LABEL +%token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE +%token REASSEMBLE FRAGDROP FRAGCROP ANCHOR NATANCHOR RDRANCHOR BINATANCHOR +%token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID +%token REQUIREORDER SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID +%token ANTISPOOF FOR INCLUDE +%token BITMASK RANDOM SOURCEHASH ROUNDROBIN STATICPORT PROBABILITY +%token ALTQ CBQ CODEL PRIQ HFSC FAIRQ BANDWIDTH TBRSIZE LINKSHARE REALTIME +%token UPPERLIMIT QUEUE PRIORITY QLIMIT HOGS BUCKETS RTABLE TARGET INTERVAL +%token LOAD RULESET_OPTIMIZATION PRIO +%token STICKYADDRESS MAXSRCSTATES MAXSRCNODES SOURCETRACK GLOBAL RULE +%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY +%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS +%token DIVERTTO DIVERTREPLY +%token <v.string> STRING +%token <v.number> NUMBER +%token <v.i> PORTBINARY +%type <v.interface> interface if_list if_item_not if_item +%type <v.number> number icmptype icmp6type uid gid +%type <v.number> tos not yesno +%type <v.probability> probability +%type <v.i> no dir af fragcache optimizer +%type <v.i> sourcetrack flush unaryop statelock +%type <v.b> action nataction natpasslog scrubaction +%type <v.b> flags flag blockspec prio +%type <v.range> portplain portstar portrange +%type <v.hashkey> hashkey +%type <v.proto> proto proto_list proto_item +%type <v.number> protoval +%type <v.icmp> icmpspec +%type <v.icmp> icmp_list icmp_item +%type <v.icmp> icmp6_list icmp6_item +%type <v.number> reticmpspec reticmp6spec +%type <v.fromto> fromto +%type <v.peer> ipportspec from to +%type <v.host> ipspec toipspec xhost host dynaddr host_list +%type <v.host> redir_host_list redirspec +%type <v.host> route_host route_host_list routespec +%type <v.os> os xos os_list +%type <v.port> portspec port_list port_item +%type <v.uid> uids uid_list uid_item +%type <v.gid> gids gid_list gid_item +%type <v.route> route +%type <v.redirection> redirection redirpool +%type <v.string> label stringall tag anchorname +%type <v.string> string varstring numberstring +%type <v.keep_state> keep +%type <v.state_opt> state_opt_spec state_opt_list state_opt_item +%type <v.logquick> logquick quick log logopts logopt +%type <v.interface> antispoof_ifspc antispoof_iflst antispoof_if +%type <v.qassign> qname +%type <v.queue> qassign qassign_list qassign_item +%type <v.queue_options> scheduler +%type <v.number> cbqflags_list cbqflags_item +%type <v.number> priqflags_list priqflags_item +%type <v.hfsc_opts> hfscopts_list hfscopts_item hfsc_opts +%type <v.fairq_opts> fairqopts_list fairqopts_item fairq_opts +%type <v.codel_opts> codelopts_list codelopts_item codel_opts +%type <v.queue_bwspec> bandwidth +%type <v.filter_opts> filter_opts filter_opt filter_opts_l +%type <v.filter_opts> filter_sets filter_set filter_sets_l +%type <v.antispoof_opts> antispoof_opts antispoof_opt antispoof_opts_l +%type <v.queue_opts> queue_opts queue_opt queue_opts_l +%type <v.scrub_opts> scrub_opts scrub_opt scrub_opts_l +%type <v.table_opts> table_opts table_opt table_opts_l +%type <v.pool_opts> pool_opts pool_opt pool_opts_l +%type <v.tagged> tagged +%type <v.rtableid> rtable +%% + +ruleset : /* empty */ + | ruleset include '\n' + | ruleset '\n' + | ruleset option '\n' + | ruleset scrubrule '\n' + | ruleset natrule '\n' + | ruleset binatrule '\n' + | ruleset pfrule '\n' + | ruleset anchorrule '\n' + | ruleset loadrule '\n' + | ruleset altqif '\n' + | ruleset queuespec '\n' + | ruleset varset '\n' + | ruleset antispoof '\n' + | ruleset tabledef '\n' + | '{' fakeanchor '}' '\n'; + | ruleset error '\n' { file->errors++; } + ; + +include : INCLUDE STRING { + struct file *nfile; + + if ((nfile = pushfile($2, 0)) == NULL) { + yyerror("failed to include file %s", $2); + free($2); + YYERROR; + } + free($2); + + file = nfile; + lungetc('\n'); + } + ; + +/* + * apply to previouslys specified rule: must be careful to note + * what that is: pf or nat or binat or rdr + */ +fakeanchor : fakeanchor '\n' + | fakeanchor anchorrule '\n' + | fakeanchor binatrule '\n' + | fakeanchor natrule '\n' + | fakeanchor pfrule '\n' + | fakeanchor error '\n' + ; + +optimizer : string { + if (!strcmp($1, "none")) + $$ = 0; + else if (!strcmp($1, "basic")) + $$ = PF_OPTIMIZE_BASIC; + else if (!strcmp($1, "profile")) + $$ = PF_OPTIMIZE_BASIC | PF_OPTIMIZE_PROFILE; + else { + yyerror("unknown ruleset-optimization %s", $1); + YYERROR; + } + } + ; + +option : SET OPTIMIZATION STRING { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($3); + YYERROR; + } + if (pfctl_set_optimization(pf, $3) != 0) { + yyerror("unknown optimization %s", $3); + free($3); + YYERROR; + } + free($3); + } + | SET RULESET_OPTIMIZATION optimizer { + if (!(pf->opts & PF_OPT_OPTIMIZE)) { + pf->opts |= PF_OPT_OPTIMIZE; + pf->optimize = $3; + } + } + | SET TIMEOUT timeout_spec + | SET TIMEOUT '{' optnl timeout_list '}' + | SET LIMIT limit_spec + | SET LIMIT '{' optnl limit_list '}' + | SET LOGINTERFACE stringall { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($3); + YYERROR; + } + if (pfctl_set_logif(pf, $3) != 0) { + yyerror("error setting loginterface %s", $3); + free($3); + YYERROR; + } + free($3); + } + | SET HOSTID number { + if ($3 == 0 || $3 > UINT_MAX) { + yyerror("hostid must be non-zero"); + YYERROR; + } + if (pfctl_set_hostid(pf, $3) != 0) { + yyerror("error setting hostid %08x", $3); + YYERROR; + } + } + | SET BLOCKPOLICY DROP { + if (pf->opts & PF_OPT_VERBOSE) + printf("set block-policy drop\n"); + if (check_rulestate(PFCTL_STATE_OPTION)) + YYERROR; + blockpolicy = PFRULE_DROP; + } + | SET BLOCKPOLICY RETURN { + if (pf->opts & PF_OPT_VERBOSE) + printf("set block-policy return\n"); + if (check_rulestate(PFCTL_STATE_OPTION)) + YYERROR; + blockpolicy = PFRULE_RETURN; + } + | SET REQUIREORDER yesno { + if (pf->opts & PF_OPT_VERBOSE) + printf("set require-order %s\n", + $3 == 1 ? "yes" : "no"); + require_order = $3; + } + | SET FINGERPRINTS STRING { + if (pf->opts & PF_OPT_VERBOSE) + printf("set fingerprints \"%s\"\n", $3); + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($3); + YYERROR; + } + if (!pf->anchor->name[0]) { + if (pfctl_file_fingerprints(pf->dev, + pf->opts, $3)) { + yyerror("error loading " + "fingerprints %s", $3); + free($3); + YYERROR; + } + } + free($3); + } + | SET STATEPOLICY statelock { + if (pf->opts & PF_OPT_VERBOSE) + switch ($3) { + case 0: + printf("set state-policy floating\n"); + break; + case PFRULE_IFBOUND: + printf("set state-policy if-bound\n"); + break; + } + default_statelock = $3; + } + | SET DEBUG STRING { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($3); + YYERROR; + } + if (pfctl_set_debug(pf, $3) != 0) { + yyerror("error setting debuglevel %s", $3); + free($3); + YYERROR; + } + free($3); + } + | SET SKIP interface { + if (expand_skip_interface($3) != 0) { + yyerror("error setting skip interface(s)"); + YYERROR; + } + } + | SET STATEDEFAULTS state_opt_list { + if (keep_state_defaults != NULL) { + yyerror("cannot redefine state-defaults"); + YYERROR; + } + keep_state_defaults = $3; + } + ; + +stringall : STRING { $$ = $1; } + | ALL { + if (($$ = strdup("all")) == NULL) { + err(1, "stringall: strdup"); + } + } + ; + +string : STRING string { + if (asprintf(&$$, "%s %s", $1, $2) == -1) + err(1, "string: asprintf"); + free($1); + free($2); + } + | STRING + ; + +varstring : numberstring varstring { + if (asprintf(&$$, "%s %s", $1, $2) == -1) + err(1, "string: asprintf"); + free($1); + free($2); + } + | numberstring + ; + +numberstring : NUMBER { + char *s; + if (asprintf(&s, "%lld", (long long)$1) == -1) { + yyerror("string: asprintf"); + YYERROR; + } + $$ = s; + } + | STRING + ; + +varset : STRING '=' varstring { + if (pf->opts & PF_OPT_VERBOSE) + printf("%s = \"%s\"\n", $1, $3); + if (symset($1, $3, 0) == -1) + err(1, "cannot store variable %s", $1); + free($1); + free($3); + } + ; + +anchorname : STRING { $$ = $1; } + | /* empty */ { $$ = NULL; } + ; + +pfa_anchorlist : /* empty */ + | pfa_anchorlist '\n' + | pfa_anchorlist pfrule '\n' + | pfa_anchorlist anchorrule '\n' + ; + +pfa_anchor : '{' + { + char ta[PF_ANCHOR_NAME_SIZE]; + struct pf_ruleset *rs; + + /* steping into a brace anchor */ + pf->asd++; + pf->bn++; + pf->brace = 1; + + /* create a holding ruleset in the root */ + snprintf(ta, PF_ANCHOR_NAME_SIZE, "_%d", pf->bn); + rs = pf_find_or_create_ruleset(ta); + if (rs == NULL) + err(1, "pfa_anchor: pf_find_or_create_ruleset"); + pf->astack[pf->asd] = rs->anchor; + pf->anchor = rs->anchor; + } '\n' pfa_anchorlist '}' + { + pf->alast = pf->anchor; + pf->asd--; + pf->anchor = pf->astack[pf->asd]; + } + | /* empty */ + ; + +anchorrule : ANCHOR anchorname dir quick interface af proto fromto + filter_opts pfa_anchor + { + struct pf_rule r; + struct node_proto *proto; + + if (check_rulestate(PFCTL_STATE_FILTER)) { + if ($2) + free($2); + YYERROR; + } + + if ($2 && ($2[0] == '_' || strstr($2, "/_") != NULL)) { + free($2); + yyerror("anchor names beginning with '_' " + "are reserved for internal use"); + YYERROR; + } + + memset(&r, 0, sizeof(r)); + if (pf->astack[pf->asd + 1]) { + /* move inline rules into relative location */ + pf_anchor_setup(&r, + &pf->astack[pf->asd]->ruleset, + $2 ? $2 : pf->alast->name); + + if (r.anchor == NULL) + err(1, "anchorrule: unable to " + "create ruleset"); + + if (pf->alast != r.anchor) { + if (r.anchor->match) { + yyerror("inline anchor '%s' " + "already exists", + r.anchor->name); + YYERROR; + } + mv_rules(&pf->alast->ruleset, + &r.anchor->ruleset); + } + pf_remove_if_empty_ruleset(&pf->alast->ruleset); + pf->alast = r.anchor; + } else { + if (!$2) { + yyerror("anchors without explicit " + "rules must specify a name"); + YYERROR; + } + } + r.direction = $3; + r.quick = $4.quick; + r.af = $6; + r.prob = $9.prob; + r.rtableid = $9.rtableid; + + if ($9.tag) + if (strlcpy(r.tagname, $9.tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + if ($9.match_tag) + if (strlcpy(r.match_tagname, $9.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = $9.match_tag_not; + if (rule_label(&r, $9.label)) + YYERROR; + free($9.label); + r.flags = $9.flags.b1; + r.flagset = $9.flags.b2; + if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { + yyerror("flags always false"); + YYERROR; + } + if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { + for (proto = $7; proto != NULL && + proto->proto != IPPROTO_TCP; + proto = proto->next) + ; /* nothing */ + if (proto == NULL && $7 != NULL) { + if ($9.flags.b1 || $9.flags.b2) + yyerror( + "flags only apply to tcp"); + if ($8.src_os) + yyerror( + "OS fingerprinting only " + "applies to tcp"); + YYERROR; + } + } + + r.tos = $9.tos; + + if ($9.keep.action) { + yyerror("cannot specify state handling " + "on anchors"); + YYERROR; + } + + if ($9.match_tag) + if (strlcpy(r.match_tagname, $9.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = $9.match_tag_not; + if ($9.marker & FOM_PRIO) { + if ($9.prio == 0) + r.prio = PF_PRIO_ZERO; + else + r.prio = $9.prio; + } + if ($9.marker & FOM_SETPRIO) { + r.set_prio[0] = $9.set_prio[0]; + r.set_prio[1] = $9.set_prio[1]; + r.scrub_flags |= PFSTATE_SETPRIO; + } + + decide_address_family($8.src.host, &r.af); + decide_address_family($8.dst.host, &r.af); + + expand_rule(&r, $5, NULL, $7, $8.src_os, + $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, + $9.uid, $9.gid, $9.icmpspec, + pf->astack[pf->asd + 1] ? pf->alast->name : $2); + free($2); + pf->astack[pf->asd + 1] = NULL; + } + | NATANCHOR string interface af proto fromto rtable { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_NAT)) { + free($2); + YYERROR; + } + + memset(&r, 0, sizeof(r)); + r.action = PF_NAT; + r.af = $4; + r.rtableid = $7; + + decide_address_family($6.src.host, &r.af); + decide_address_family($6.dst.host, &r.af); + + expand_rule(&r, $3, NULL, $5, $6.src_os, + $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, + 0, 0, 0, $2); + free($2); + } + | RDRANCHOR string interface af proto fromto rtable { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_NAT)) { + free($2); + YYERROR; + } + + memset(&r, 0, sizeof(r)); + r.action = PF_RDR; + r.af = $4; + r.rtableid = $7; + + decide_address_family($6.src.host, &r.af); + decide_address_family($6.dst.host, &r.af); + + if ($6.src.port != NULL) { + yyerror("source port parameter not supported" + " in rdr-anchor"); + YYERROR; + } + if ($6.dst.port != NULL) { + if ($6.dst.port->next != NULL) { + yyerror("destination port list " + "expansion not supported in " + "rdr-anchor"); + YYERROR; + } else if ($6.dst.port->op != PF_OP_EQ) { + yyerror("destination port operators" + " not supported in rdr-anchor"); + YYERROR; + } + r.dst.port[0] = $6.dst.port->port[0]; + r.dst.port[1] = $6.dst.port->port[1]; + r.dst.port_op = $6.dst.port->op; + } + + expand_rule(&r, $3, NULL, $5, $6.src_os, + $6.src.host, $6.src.port, $6.dst.host, $6.dst.port, + 0, 0, 0, $2); + free($2); + } + | BINATANCHOR string interface af proto fromto rtable { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_NAT)) { + free($2); + YYERROR; + } + + memset(&r, 0, sizeof(r)); + r.action = PF_BINAT; + r.af = $4; + r.rtableid = $7; + if ($5 != NULL) { + if ($5->next != NULL) { + yyerror("proto list expansion" + " not supported in binat-anchor"); + YYERROR; + } + r.proto = $5->proto; + free($5); + } + + if ($6.src.host != NULL || $6.src.port != NULL || + $6.dst.host != NULL || $6.dst.port != NULL) { + yyerror("fromto parameter not supported" + " in binat-anchor"); + YYERROR; + } + + decide_address_family($6.src.host, &r.af); + decide_address_family($6.dst.host, &r.af); + + pfctl_add_rule(pf, &r, $2); + free($2); + } + ; + +loadrule : LOAD ANCHOR string FROM string { + struct loadanchors *loadanchor; + + if (strlen(pf->anchor->name) + 1 + + strlen($3) >= MAXPATHLEN) { + yyerror("anchorname %s too long, max %u\n", + $3, MAXPATHLEN - 1); + free($3); + YYERROR; + } + loadanchor = calloc(1, sizeof(struct loadanchors)); + if (loadanchor == NULL) + err(1, "loadrule: calloc"); + if ((loadanchor->anchorname = malloc(MAXPATHLEN)) == + NULL) + err(1, "loadrule: malloc"); + if (pf->anchor->name[0]) + snprintf(loadanchor->anchorname, MAXPATHLEN, + "%s/%s", pf->anchor->name, $3); + else + strlcpy(loadanchor->anchorname, $3, MAXPATHLEN); + if ((loadanchor->filename = strdup($5)) == NULL) + err(1, "loadrule: strdup"); + + TAILQ_INSERT_TAIL(&loadanchorshead, loadanchor, + entries); + + free($3); + free($5); + }; + +scrubaction : no SCRUB { + $$.b2 = $$.w = 0; + if ($1) + $$.b1 = PF_NOSCRUB; + else + $$.b1 = PF_SCRUB; + } + ; + +scrubrule : scrubaction dir logquick interface af proto fromto scrub_opts + { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_SCRUB)) + YYERROR; + + memset(&r, 0, sizeof(r)); + + r.action = $1.b1; + r.direction = $2; + + r.log = $3.log; + r.logif = $3.logif; + if ($3.quick) { + yyerror("scrub rules do not support 'quick'"); + YYERROR; + } + + r.af = $5; + if ($8.nodf) + r.rule_flag |= PFRULE_NODF; + if ($8.randomid) + r.rule_flag |= PFRULE_RANDOMID; + if ($8.reassemble_tcp) { + if (r.direction != PF_INOUT) { + yyerror("reassemble tcp rules can not " + "specify direction"); + YYERROR; + } + r.rule_flag |= PFRULE_REASSEMBLE_TCP; + } + if ($8.minttl) + r.min_ttl = $8.minttl; + if ($8.maxmss) + r.max_mss = $8.maxmss; + if ($8.marker & SOM_SETTOS) { + r.rule_flag |= PFRULE_SET_TOS; + r.set_tos = $8.settos; + } + if ($8.fragcache) + r.rule_flag |= $8.fragcache; + if ($8.match_tag) + if (strlcpy(r.match_tagname, $8.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = $8.match_tag_not; + r.rtableid = $8.rtableid; + + expand_rule(&r, $4, NULL, $6, $7.src_os, + $7.src.host, $7.src.port, $7.dst.host, $7.dst.port, + NULL, NULL, NULL, ""); + } + ; + +scrub_opts : { + bzero(&scrub_opts, sizeof scrub_opts); + scrub_opts.rtableid = -1; + } + scrub_opts_l + { $$ = scrub_opts; } + | /* empty */ { + bzero(&scrub_opts, sizeof scrub_opts); + scrub_opts.rtableid = -1; + $$ = scrub_opts; + } + ; + +scrub_opts_l : scrub_opts_l scrub_opt + | scrub_opt + ; + +scrub_opt : NODF { + if (scrub_opts.nodf) { + yyerror("no-df cannot be respecified"); + YYERROR; + } + scrub_opts.nodf = 1; + } + | MINTTL NUMBER { + if (scrub_opts.marker & SOM_MINTTL) { + yyerror("min-ttl cannot be respecified"); + YYERROR; + } + if ($2 < 0 || $2 > 255) { + yyerror("illegal min-ttl value %d", $2); + YYERROR; + } + scrub_opts.marker |= SOM_MINTTL; + scrub_opts.minttl = $2; + } + | MAXMSS NUMBER { + if (scrub_opts.marker & SOM_MAXMSS) { + yyerror("max-mss cannot be respecified"); + YYERROR; + } + if ($2 < 0 || $2 > 65535) { + yyerror("illegal max-mss value %d", $2); + YYERROR; + } + scrub_opts.marker |= SOM_MAXMSS; + scrub_opts.maxmss = $2; + } + | SETTOS tos { + if (scrub_opts.marker & SOM_SETTOS) { + yyerror("set-tos cannot be respecified"); + YYERROR; + } + scrub_opts.marker |= SOM_SETTOS; + scrub_opts.settos = $2; + } + | fragcache { + if (scrub_opts.marker & SOM_FRAGCACHE) { + yyerror("fragcache cannot be respecified"); + YYERROR; + } + scrub_opts.marker |= SOM_FRAGCACHE; + scrub_opts.fragcache = $1; + } + | REASSEMBLE STRING { + if (strcasecmp($2, "tcp") != 0) { + yyerror("scrub reassemble supports only tcp, " + "not '%s'", $2); + free($2); + YYERROR; + } + free($2); + if (scrub_opts.reassemble_tcp) { + yyerror("reassemble tcp cannot be respecified"); + YYERROR; + } + scrub_opts.reassemble_tcp = 1; + } + | RANDOMID { + if (scrub_opts.randomid) { + yyerror("random-id cannot be respecified"); + YYERROR; + } + scrub_opts.randomid = 1; + } + | RTABLE NUMBER { + if ($2 < 0 || $2 > rt_tableid_max()) { + yyerror("invalid rtable id"); + YYERROR; + } + scrub_opts.rtableid = $2; + } + | not TAGGED string { + scrub_opts.match_tag = $3; + scrub_opts.match_tag_not = $1; + } + ; + +fragcache : FRAGMENT REASSEMBLE { $$ = 0; /* default */ } + | FRAGMENT FRAGCROP { $$ = 0; } + | FRAGMENT FRAGDROP { $$ = 0; } + ; + +antispoof : ANTISPOOF logquick antispoof_ifspc af antispoof_opts { + struct pf_rule r; + struct node_host *h = NULL, *hh; + struct node_if *i, *j; + + if (check_rulestate(PFCTL_STATE_FILTER)) + YYERROR; + + for (i = $3; i; i = i->next) { + bzero(&r, sizeof(r)); + + r.action = PF_DROP; + r.direction = PF_IN; + r.log = $2.log; + r.logif = $2.logif; + r.quick = $2.quick; + r.af = $4; + if (rule_label(&r, $5.label)) + YYERROR; + r.rtableid = $5.rtableid; + j = calloc(1, sizeof(struct node_if)); + if (j == NULL) + err(1, "antispoof: calloc"); + if (strlcpy(j->ifname, i->ifname, + sizeof(j->ifname)) >= sizeof(j->ifname)) { + free(j); + yyerror("interface name too long"); + YYERROR; + } + j->not = 1; + if (i->dynamic) { + h = calloc(1, sizeof(*h)); + if (h == NULL) + err(1, "address: calloc"); + h->addr.type = PF_ADDR_DYNIFTL; + set_ipmask(h, 128); + if (strlcpy(h->addr.v.ifname, i->ifname, + sizeof(h->addr.v.ifname)) >= + sizeof(h->addr.v.ifname)) { + free(h); + yyerror( + "interface name too long"); + YYERROR; + } + hh = malloc(sizeof(*hh)); + if (hh == NULL) + err(1, "address: malloc"); + bcopy(h, hh, sizeof(*hh)); + h->addr.iflags = PFI_AFLAG_NETWORK; + } else { + h = ifa_lookup(j->ifname, + PFI_AFLAG_NETWORK); + hh = NULL; + } + + if (h != NULL) + expand_rule(&r, j, NULL, NULL, NULL, h, + NULL, NULL, NULL, NULL, NULL, + NULL, ""); + + if ((i->ifa_flags & IFF_LOOPBACK) == 0) { + bzero(&r, sizeof(r)); + + r.action = PF_DROP; + r.direction = PF_IN; + r.log = $2.log; + r.logif = $2.logif; + r.quick = $2.quick; + r.af = $4; + if (rule_label(&r, $5.label)) + YYERROR; + r.rtableid = $5.rtableid; + if (hh != NULL) + h = hh; + else + h = ifa_lookup(i->ifname, 0); + if (h != NULL) + expand_rule(&r, NULL, NULL, + NULL, NULL, h, NULL, NULL, + NULL, NULL, NULL, NULL, ""); + } else + free(hh); + } + free($5.label); + } + ; + +antispoof_ifspc : FOR antispoof_if { $$ = $2; } + | FOR '{' optnl antispoof_iflst '}' { $$ = $4; } + ; + +antispoof_iflst : antispoof_if optnl { $$ = $1; } + | antispoof_iflst comma antispoof_if optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +antispoof_if : if_item { $$ = $1; } + | '(' if_item ')' { + $2->dynamic = 1; + $$ = $2; + } + ; + +antispoof_opts : { + bzero(&antispoof_opts, sizeof antispoof_opts); + antispoof_opts.rtableid = -1; + } + antispoof_opts_l + { $$ = antispoof_opts; } + | /* empty */ { + bzero(&antispoof_opts, sizeof antispoof_opts); + antispoof_opts.rtableid = -1; + $$ = antispoof_opts; + } + ; + +antispoof_opts_l : antispoof_opts_l antispoof_opt + | antispoof_opt + ; + +antispoof_opt : label { + if (antispoof_opts.label) { + yyerror("label cannot be redefined"); + YYERROR; + } + antispoof_opts.label = $1; + } + | RTABLE NUMBER { + if ($2 < 0 || $2 > rt_tableid_max()) { + yyerror("invalid rtable id"); + YYERROR; + } + antispoof_opts.rtableid = $2; + } + ; + +not : '!' { $$ = 1; } + | /* empty */ { $$ = 0; } + ; + +tabledef : TABLE '<' STRING '>' table_opts { + struct node_host *h, *nh; + struct node_tinit *ti, *nti; + + if (strlen($3) >= PF_TABLE_NAME_SIZE) { + yyerror("table name too long, max %d chars", + PF_TABLE_NAME_SIZE - 1); + free($3); + YYERROR; + } + if (pf->loadopt & PFCTL_FLAG_TABLE) + if (process_tabledef($3, &$5)) { + free($3); + YYERROR; + } + free($3); + for (ti = SIMPLEQ_FIRST(&$5.init_nodes); + ti != SIMPLEQ_END(&$5.init_nodes); ti = nti) { + if (ti->file) + free(ti->file); + for (h = ti->host; h != NULL; h = nh) { + nh = h->next; + free(h); + } + nti = SIMPLEQ_NEXT(ti, entries); + free(ti); + } + } + ; + +table_opts : { + bzero(&table_opts, sizeof table_opts); + SIMPLEQ_INIT(&table_opts.init_nodes); + } + table_opts_l + { $$ = table_opts; } + | /* empty */ + { + bzero(&table_opts, sizeof table_opts); + SIMPLEQ_INIT(&table_opts.init_nodes); + $$ = table_opts; + } + ; + +table_opts_l : table_opts_l table_opt + | table_opt + ; + +table_opt : STRING { + if (!strcmp($1, "const")) + table_opts.flags |= PFR_TFLAG_CONST; + else if (!strcmp($1, "persist")) + table_opts.flags |= PFR_TFLAG_PERSIST; + else if (!strcmp($1, "counters")) + table_opts.flags |= PFR_TFLAG_COUNTERS; + else { + yyerror("invalid table option '%s'", $1); + free($1); + YYERROR; + } + free($1); + } + | '{' optnl '}' { table_opts.init_addr = 1; } + | '{' optnl host_list '}' { + struct node_host *n; + struct node_tinit *ti; + + for (n = $3; n != NULL; n = n->next) { + switch (n->addr.type) { + case PF_ADDR_ADDRMASK: + continue; /* ok */ + case PF_ADDR_RANGE: + yyerror("address ranges are not " + "permitted inside tables"); + break; + case PF_ADDR_DYNIFTL: + yyerror("dynamic addresses are not " + "permitted inside tables"); + break; + case PF_ADDR_TABLE: + yyerror("tables cannot contain tables"); + break; + case PF_ADDR_NOROUTE: + yyerror("\"no-route\" is not permitted " + "inside tables"); + break; + case PF_ADDR_URPFFAILED: + yyerror("\"urpf-failed\" is not " + "permitted inside tables"); + break; + default: + yyerror("unknown address type %d", + n->addr.type); + } + YYERROR; + } + if (!(ti = calloc(1, sizeof(*ti)))) + err(1, "table_opt: calloc"); + ti->host = $3; + SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, + entries); + table_opts.init_addr = 1; + } + | FILENAME STRING { + struct node_tinit *ti; + + if (!(ti = calloc(1, sizeof(*ti)))) + err(1, "table_opt: calloc"); + ti->file = $2; + SIMPLEQ_INSERT_TAIL(&table_opts.init_nodes, ti, + entries); + table_opts.init_addr = 1; + } + ; + +altqif : ALTQ interface queue_opts QUEUE qassign { + struct pf_altq a; + + if (check_rulestate(PFCTL_STATE_QUEUE)) + YYERROR; + + memset(&a, 0, sizeof(a)); + if ($3.scheduler.qtype == ALTQT_NONE) { + yyerror("no scheduler specified!"); + YYERROR; + } + a.scheduler = $3.scheduler.qtype; + a.qlimit = $3.qlimit; + a.tbrsize = $3.tbrsize; + if ($5 == NULL && $3.scheduler.qtype != ALTQT_CODEL) { + yyerror("no child queues specified"); + YYERROR; + } + if (expand_altq(&a, $2, $5, $3.queue_bwspec, + &$3.scheduler)) + YYERROR; + } + ; + +queuespec : QUEUE STRING interface queue_opts qassign { + struct pf_altq a; + + if (check_rulestate(PFCTL_STATE_QUEUE)) { + free($2); + YYERROR; + } + + memset(&a, 0, sizeof(a)); + + if (strlcpy(a.qname, $2, sizeof(a.qname)) >= + sizeof(a.qname)) { + yyerror("queue name too long (max " + "%d chars)", PF_QNAME_SIZE-1); + free($2); + YYERROR; + } + free($2); + if ($4.tbrsize) { + yyerror("cannot specify tbrsize for queue"); + YYERROR; + } + if ($4.priority > 255) { + yyerror("priority out of range: max 255"); + YYERROR; + } + a.priority = $4.priority; + a.qlimit = $4.qlimit; + a.scheduler = $4.scheduler.qtype; + if (expand_queue(&a, $3, $5, $4.queue_bwspec, + &$4.scheduler)) { + yyerror("errors in queue definition"); + YYERROR; + } + } + ; + +queue_opts : { + bzero(&queue_opts, sizeof queue_opts); + queue_opts.priority = DEFAULT_PRIORITY; + queue_opts.qlimit = DEFAULT_QLIMIT; + queue_opts.scheduler.qtype = ALTQT_NONE; + queue_opts.queue_bwspec.bw_percent = 100; + } + queue_opts_l + { $$ = queue_opts; } + | /* empty */ { + bzero(&queue_opts, sizeof queue_opts); + queue_opts.priority = DEFAULT_PRIORITY; + queue_opts.qlimit = DEFAULT_QLIMIT; + queue_opts.scheduler.qtype = ALTQT_NONE; + queue_opts.queue_bwspec.bw_percent = 100; + $$ = queue_opts; + } + ; + +queue_opts_l : queue_opts_l queue_opt + | queue_opt + ; + +queue_opt : BANDWIDTH bandwidth { + if (queue_opts.marker & QOM_BWSPEC) { + yyerror("bandwidth cannot be respecified"); + YYERROR; + } + queue_opts.marker |= QOM_BWSPEC; + queue_opts.queue_bwspec = $2; + } + | PRIORITY NUMBER { + if (queue_opts.marker & QOM_PRIORITY) { + yyerror("priority cannot be respecified"); + YYERROR; + } + if ($2 < 0 || $2 > 255) { + yyerror("priority out of range: max 255"); + YYERROR; + } + queue_opts.marker |= QOM_PRIORITY; + queue_opts.priority = $2; + } + | QLIMIT NUMBER { + if (queue_opts.marker & QOM_QLIMIT) { + yyerror("qlimit cannot be respecified"); + YYERROR; + } + if ($2 < 0 || $2 > 65535) { + yyerror("qlimit out of range: max 65535"); + YYERROR; + } + queue_opts.marker |= QOM_QLIMIT; + queue_opts.qlimit = $2; + } + | scheduler { + if (queue_opts.marker & QOM_SCHEDULER) { + yyerror("scheduler cannot be respecified"); + YYERROR; + } + queue_opts.marker |= QOM_SCHEDULER; + queue_opts.scheduler = $1; + } + | TBRSIZE NUMBER { + if (queue_opts.marker & QOM_TBRSIZE) { + yyerror("tbrsize cannot be respecified"); + YYERROR; + } + if ($2 < 0 || $2 > 65535) { + yyerror("tbrsize too big: max 65535"); + YYERROR; + } + queue_opts.marker |= QOM_TBRSIZE; + queue_opts.tbrsize = $2; + } + ; + +bandwidth : STRING { + double bps; + char *cp; + + $$.bw_percent = 0; + + bps = strtod($1, &cp); + if (cp != NULL) { + if (strlen(cp) > 1) { + char *cu = cp + 1; + if (!strcmp(cu, "Bit") || + !strcmp(cu, "B") || + !strcmp(cu, "bit") || + !strcmp(cu, "b")) { + *cu = 0; + } + } + if (!strcmp(cp, "b")) + ; /* nothing */ + else if (!strcmp(cp, "K")) + bps *= 1000; + else if (!strcmp(cp, "M")) + bps *= 1000 * 1000; + else if (!strcmp(cp, "G")) + bps *= 1000 * 1000 * 1000; + else if (!strcmp(cp, "%")) { + if (bps < 0 || bps > 100) { + yyerror("bandwidth spec " + "out of range"); + free($1); + YYERROR; + } + $$.bw_percent = bps; + bps = 0; + } else { + yyerror("unknown unit %s", cp); + free($1); + YYERROR; + } + } + free($1); + $$.bw_absolute = (u_int32_t)bps; + } + | NUMBER { + if ($1 < 0 || $1 > UINT_MAX) { + yyerror("bandwidth number too big"); + YYERROR; + } + $$.bw_percent = 0; + $$.bw_absolute = $1; + } + ; + +scheduler : CBQ { + $$.qtype = ALTQT_CBQ; + $$.data.cbq_opts.flags = 0; + } + | CBQ '(' cbqflags_list ')' { + $$.qtype = ALTQT_CBQ; + $$.data.cbq_opts.flags = $3; + } + | PRIQ { + $$.qtype = ALTQT_PRIQ; + $$.data.priq_opts.flags = 0; + } + | PRIQ '(' priqflags_list ')' { + $$.qtype = ALTQT_PRIQ; + $$.data.priq_opts.flags = $3; + } + | HFSC { + $$.qtype = ALTQT_HFSC; + bzero(&$$.data.hfsc_opts, + sizeof(struct node_hfsc_opts)); + } + | HFSC '(' hfsc_opts ')' { + $$.qtype = ALTQT_HFSC; + $$.data.hfsc_opts = $3; + } + | FAIRQ { + $$.qtype = ALTQT_FAIRQ; + bzero(&$$.data.fairq_opts, + sizeof(struct node_fairq_opts)); + } + | FAIRQ '(' fairq_opts ')' { + $$.qtype = ALTQT_FAIRQ; + $$.data.fairq_opts = $3; + } + | CODEL { + $$.qtype = ALTQT_CODEL; + bzero(&$$.data.codel_opts, + sizeof(struct codel_opts)); + } + | CODEL '(' codel_opts ')' { + $$.qtype = ALTQT_CODEL; + $$.data.codel_opts = $3; + } + ; + +cbqflags_list : cbqflags_item { $$ |= $1; } + | cbqflags_list comma cbqflags_item { $$ |= $3; } + ; + +cbqflags_item : STRING { + if (!strcmp($1, "default")) + $$ = CBQCLF_DEFCLASS; + else if (!strcmp($1, "borrow")) + $$ = CBQCLF_BORROW; + else if (!strcmp($1, "red")) + $$ = CBQCLF_RED; + else if (!strcmp($1, "ecn")) + $$ = CBQCLF_RED|CBQCLF_ECN; + else if (!strcmp($1, "rio")) + $$ = CBQCLF_RIO; + else if (!strcmp($1, "codel")) + $$ = CBQCLF_CODEL; + else { + yyerror("unknown cbq flag \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + } + ; + +priqflags_list : priqflags_item { $$ |= $1; } + | priqflags_list comma priqflags_item { $$ |= $3; } + ; + +priqflags_item : STRING { + if (!strcmp($1, "default")) + $$ = PRCF_DEFAULTCLASS; + else if (!strcmp($1, "red")) + $$ = PRCF_RED; + else if (!strcmp($1, "ecn")) + $$ = PRCF_RED|PRCF_ECN; + else if (!strcmp($1, "rio")) + $$ = PRCF_RIO; + else if (!strcmp($1, "codel")) + $$ = PRCF_CODEL; + else { + yyerror("unknown priq flag \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + } + ; + +hfsc_opts : { + bzero(&hfsc_opts, + sizeof(struct node_hfsc_opts)); + } + hfscopts_list { + $$ = hfsc_opts; + } + ; + +hfscopts_list : hfscopts_item + | hfscopts_list comma hfscopts_item + ; + +hfscopts_item : LINKSHARE bandwidth { + if (hfsc_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + hfsc_opts.linkshare.m2 = $2; + hfsc_opts.linkshare.used = 1; + } + | LINKSHARE '(' bandwidth comma NUMBER comma bandwidth ')' + { + if ($5 < 0 || $5 > INT_MAX) { + yyerror("timing in curve out of range"); + YYERROR; + } + if (hfsc_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + hfsc_opts.linkshare.m1 = $3; + hfsc_opts.linkshare.d = $5; + hfsc_opts.linkshare.m2 = $7; + hfsc_opts.linkshare.used = 1; + } + | REALTIME bandwidth { + if (hfsc_opts.realtime.used) { + yyerror("realtime already specified"); + YYERROR; + } + hfsc_opts.realtime.m2 = $2; + hfsc_opts.realtime.used = 1; + } + | REALTIME '(' bandwidth comma NUMBER comma bandwidth ')' + { + if ($5 < 0 || $5 > INT_MAX) { + yyerror("timing in curve out of range"); + YYERROR; + } + if (hfsc_opts.realtime.used) { + yyerror("realtime already specified"); + YYERROR; + } + hfsc_opts.realtime.m1 = $3; + hfsc_opts.realtime.d = $5; + hfsc_opts.realtime.m2 = $7; + hfsc_opts.realtime.used = 1; + } + | UPPERLIMIT bandwidth { + if (hfsc_opts.upperlimit.used) { + yyerror("upperlimit already specified"); + YYERROR; + } + hfsc_opts.upperlimit.m2 = $2; + hfsc_opts.upperlimit.used = 1; + } + | UPPERLIMIT '(' bandwidth comma NUMBER comma bandwidth ')' + { + if ($5 < 0 || $5 > INT_MAX) { + yyerror("timing in curve out of range"); + YYERROR; + } + if (hfsc_opts.upperlimit.used) { + yyerror("upperlimit already specified"); + YYERROR; + } + hfsc_opts.upperlimit.m1 = $3; + hfsc_opts.upperlimit.d = $5; + hfsc_opts.upperlimit.m2 = $7; + hfsc_opts.upperlimit.used = 1; + } + | STRING { + if (!strcmp($1, "default")) + hfsc_opts.flags |= HFCF_DEFAULTCLASS; + else if (!strcmp($1, "red")) + hfsc_opts.flags |= HFCF_RED; + else if (!strcmp($1, "ecn")) + hfsc_opts.flags |= HFCF_RED|HFCF_ECN; + else if (!strcmp($1, "rio")) + hfsc_opts.flags |= HFCF_RIO; + else if (!strcmp($1, "codel")) + hfsc_opts.flags |= HFCF_CODEL; + else { + yyerror("unknown hfsc flag \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + } + ; + +fairq_opts : { + bzero(&fairq_opts, + sizeof(struct node_fairq_opts)); + } + fairqopts_list { + $$ = fairq_opts; + } + ; + +fairqopts_list : fairqopts_item + | fairqopts_list comma fairqopts_item + ; + +fairqopts_item : LINKSHARE bandwidth { + if (fairq_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + fairq_opts.linkshare.m2 = $2; + fairq_opts.linkshare.used = 1; + } + | LINKSHARE '(' bandwidth number bandwidth ')' { + if (fairq_opts.linkshare.used) { + yyerror("linkshare already specified"); + YYERROR; + } + fairq_opts.linkshare.m1 = $3; + fairq_opts.linkshare.d = $4; + fairq_opts.linkshare.m2 = $5; + fairq_opts.linkshare.used = 1; + } + | HOGS bandwidth { + fairq_opts.hogs_bw = $2; + } + | BUCKETS number { + fairq_opts.nbuckets = $2; + } + | STRING { + if (!strcmp($1, "default")) + fairq_opts.flags |= FARF_DEFAULTCLASS; + else if (!strcmp($1, "red")) + fairq_opts.flags |= FARF_RED; + else if (!strcmp($1, "ecn")) + fairq_opts.flags |= FARF_RED|FARF_ECN; + else if (!strcmp($1, "rio")) + fairq_opts.flags |= FARF_RIO; + else if (!strcmp($1, "codel")) + fairq_opts.flags |= FARF_CODEL; + else { + yyerror("unknown fairq flag \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + } + ; + +codel_opts : { + bzero(&codel_opts, + sizeof(struct codel_opts)); + } + codelopts_list { + $$ = codel_opts; + } + ; + +codelopts_list : codelopts_item + | codelopts_list comma codelopts_item + ; + +codelopts_item : INTERVAL number { + if (codel_opts.interval) { + yyerror("interval already specified"); + YYERROR; + } + codel_opts.interval = $2; + } + | TARGET number { + if (codel_opts.target) { + yyerror("target already specified"); + YYERROR; + } + codel_opts.target = $2; + } + | STRING { + if (!strcmp($1, "ecn")) + codel_opts.ecn = 1; + else { + yyerror("unknown codel option \"%s\"", $1); + free($1); + YYERROR; + } + free($1); + } + ; + +qassign : /* empty */ { $$ = NULL; } + | qassign_item { $$ = $1; } + | '{' optnl qassign_list '}' { $$ = $3; } + ; + +qassign_list : qassign_item optnl { $$ = $1; } + | qassign_list comma qassign_item optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +qassign_item : STRING { + $$ = calloc(1, sizeof(struct node_queue)); + if ($$ == NULL) + err(1, "qassign_item: calloc"); + if (strlcpy($$->queue, $1, sizeof($$->queue)) >= + sizeof($$->queue)) { + yyerror("queue name '%s' too long (max " + "%d chars)", $1, sizeof($$->queue)-1); + free($1); + free($$); + YYERROR; + } + free($1); + $$->next = NULL; + $$->tail = $$; + } + ; + +pfrule : action dir logquick interface route af proto fromto + filter_opts + { + struct pf_rule r; + struct node_state_opt *o; + struct node_proto *proto; + int srctrack = 0; + int statelock = 0; + int adaptive = 0; + int defaults = 0; + + if (check_rulestate(PFCTL_STATE_FILTER)) + YYERROR; + + memset(&r, 0, sizeof(r)); + + r.action = $1.b1; + switch ($1.b2) { + case PFRULE_RETURNRST: + r.rule_flag |= PFRULE_RETURNRST; + r.return_ttl = $1.w; + break; + case PFRULE_RETURNICMP: + r.rule_flag |= PFRULE_RETURNICMP; + r.return_icmp = $1.w; + r.return_icmp6 = $1.w2; + break; + case PFRULE_RETURN: + r.rule_flag |= PFRULE_RETURN; + r.return_icmp = $1.w; + r.return_icmp6 = $1.w2; + break; + } + r.direction = $2; + r.log = $3.log; + r.logif = $3.logif; + r.quick = $3.quick; + r.prob = $9.prob; + r.rtableid = $9.rtableid; + + if ($9.marker & FOM_PRIO) { + if ($9.prio == 0) + r.prio = PF_PRIO_ZERO; + else + r.prio = $9.prio; + } + if ($9.marker & FOM_SETPRIO) { + r.set_prio[0] = $9.set_prio[0]; + r.set_prio[1] = $9.set_prio[1]; + r.scrub_flags |= PFSTATE_SETPRIO; + } + + r.af = $6; + if ($9.tag) + if (strlcpy(r.tagname, $9.tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + if ($9.match_tag) + if (strlcpy(r.match_tagname, $9.match_tag, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = $9.match_tag_not; + if (rule_label(&r, $9.label)) + YYERROR; + free($9.label); + r.flags = $9.flags.b1; + r.flagset = $9.flags.b2; + if (($9.flags.b1 & $9.flags.b2) != $9.flags.b1) { + yyerror("flags always false"); + YYERROR; + } + if ($9.flags.b1 || $9.flags.b2 || $8.src_os) { + for (proto = $7; proto != NULL && + proto->proto != IPPROTO_TCP; + proto = proto->next) + ; /* nothing */ + if (proto == NULL && $7 != NULL) { + if ($9.flags.b1 || $9.flags.b2) + yyerror( + "flags only apply to tcp"); + if ($8.src_os) + yyerror( + "OS fingerprinting only " + "apply to tcp"); + YYERROR; + } +#if 0 + if (($9.flags.b1 & parse_flags("S")) == 0 && + $8.src_os) { + yyerror("OS fingerprinting requires " + "the SYN TCP flag (flags S/SA)"); + YYERROR; + } +#endif + } + + r.tos = $9.tos; + r.keep_state = $9.keep.action; + o = $9.keep.options; + + /* 'keep state' by default on pass rules. */ + if (!r.keep_state && !r.action && + !($9.marker & FOM_KEEP)) { + r.keep_state = PF_STATE_NORMAL; + o = keep_state_defaults; + defaults = 1; + } + + while (o) { + struct node_state_opt *p = o; + + switch (o->type) { + case PF_STATE_OPT_MAX: + if (r.max_states) { + yyerror("state option 'max' " + "multiple definitions"); + YYERROR; + } + r.max_states = o->data.max_states; + break; + case PF_STATE_OPT_NOSYNC: + if (r.rule_flag & PFRULE_NOSYNC) { + yyerror("state option 'sync' " + "multiple definitions"); + YYERROR; + } + r.rule_flag |= PFRULE_NOSYNC; + break; + case PF_STATE_OPT_SRCTRACK: + if (srctrack) { + yyerror("state option " + "'source-track' " + "multiple definitions"); + YYERROR; + } + srctrack = o->data.src_track; + r.rule_flag |= PFRULE_SRCTRACK; + break; + case PF_STATE_OPT_MAX_SRC_STATES: + if (r.max_src_states) { + yyerror("state option " + "'max-src-states' " + "multiple definitions"); + YYERROR; + } + if (o->data.max_src_states == 0) { + yyerror("'max-src-states' must " + "be > 0"); + YYERROR; + } + r.max_src_states = + o->data.max_src_states; + r.rule_flag |= PFRULE_SRCTRACK; + break; + case PF_STATE_OPT_OVERLOAD: + if (r.overload_tblname[0]) { + yyerror("multiple 'overload' " + "table definitions"); + YYERROR; + } + if (strlcpy(r.overload_tblname, + o->data.overload.tblname, + PF_TABLE_NAME_SIZE) >= + PF_TABLE_NAME_SIZE) { + yyerror("state option: " + "strlcpy"); + YYERROR; + } + r.flush = o->data.overload.flush; + break; + case PF_STATE_OPT_MAX_SRC_CONN: + if (r.max_src_conn) { + yyerror("state option " + "'max-src-conn' " + "multiple definitions"); + YYERROR; + } + if (o->data.max_src_conn == 0) { + yyerror("'max-src-conn' " + "must be > 0"); + YYERROR; + } + r.max_src_conn = + o->data.max_src_conn; + r.rule_flag |= PFRULE_SRCTRACK | + PFRULE_RULESRCTRACK; + break; + case PF_STATE_OPT_MAX_SRC_CONN_RATE: + if (r.max_src_conn_rate.limit) { + yyerror("state option " + "'max-src-conn-rate' " + "multiple definitions"); + YYERROR; + } + if (!o->data.max_src_conn_rate.limit || + !o->data.max_src_conn_rate.seconds) { + yyerror("'max-src-conn-rate' " + "values must be > 0"); + YYERROR; + } + if (o->data.max_src_conn_rate.limit > + PF_THRESHOLD_MAX) { + yyerror("'max-src-conn-rate' " + "maximum rate must be < %u", + PF_THRESHOLD_MAX); + YYERROR; + } + r.max_src_conn_rate.limit = + o->data.max_src_conn_rate.limit; + r.max_src_conn_rate.seconds = + o->data.max_src_conn_rate.seconds; + r.rule_flag |= PFRULE_SRCTRACK | + PFRULE_RULESRCTRACK; + break; + case PF_STATE_OPT_MAX_SRC_NODES: + if (r.max_src_nodes) { + yyerror("state option " + "'max-src-nodes' " + "multiple definitions"); + YYERROR; + } + if (o->data.max_src_nodes == 0) { + yyerror("'max-src-nodes' must " + "be > 0"); + YYERROR; + } + r.max_src_nodes = + o->data.max_src_nodes; + r.rule_flag |= PFRULE_SRCTRACK | + PFRULE_RULESRCTRACK; + break; + case PF_STATE_OPT_STATELOCK: + if (statelock) { + yyerror("state locking option: " + "multiple definitions"); + YYERROR; + } + statelock = 1; + r.rule_flag |= o->data.statelock; + break; + case PF_STATE_OPT_SLOPPY: + if (r.rule_flag & PFRULE_STATESLOPPY) { + yyerror("state sloppy option: " + "multiple definitions"); + YYERROR; + } + r.rule_flag |= PFRULE_STATESLOPPY; + break; + case PF_STATE_OPT_TIMEOUT: + if (o->data.timeout.number == + PFTM_ADAPTIVE_START || + o->data.timeout.number == + PFTM_ADAPTIVE_END) + adaptive = 1; + if (r.timeout[o->data.timeout.number]) { + yyerror("state timeout %s " + "multiple definitions", + pf_timeouts[o->data. + timeout.number].name); + YYERROR; + } + r.timeout[o->data.timeout.number] = + o->data.timeout.seconds; + } + o = o->next; + if (!defaults) + free(p); + } + + /* 'flags S/SA' by default on stateful rules */ + if (!r.action && !r.flags && !r.flagset && + !$9.fragment && !($9.marker & FOM_FLAGS) && + r.keep_state) { + r.flags = parse_flags("S"); + r.flagset = parse_flags("SA"); + } + if (!adaptive && r.max_states) { + r.timeout[PFTM_ADAPTIVE_START] = + (r.max_states / 10) * 6; + r.timeout[PFTM_ADAPTIVE_END] = + (r.max_states / 10) * 12; + } + if (r.rule_flag & PFRULE_SRCTRACK) { + if (srctrack == PF_SRCTRACK_GLOBAL && + r.max_src_nodes) { + yyerror("'max-src-nodes' is " + "incompatible with " + "'source-track global'"); + YYERROR; + } + if (srctrack == PF_SRCTRACK_GLOBAL && + r.max_src_conn) { + yyerror("'max-src-conn' is " + "incompatible with " + "'source-track global'"); + YYERROR; + } + if (srctrack == PF_SRCTRACK_GLOBAL && + r.max_src_conn_rate.seconds) { + yyerror("'max-src-conn-rate' is " + "incompatible with " + "'source-track global'"); + YYERROR; + } + if (r.timeout[PFTM_SRC_NODE] < + r.max_src_conn_rate.seconds) + r.timeout[PFTM_SRC_NODE] = + r.max_src_conn_rate.seconds; + r.rule_flag |= PFRULE_SRCTRACK; + if (srctrack == PF_SRCTRACK_RULE) + r.rule_flag |= PFRULE_RULESRCTRACK; + } + if (r.keep_state && !statelock) + r.rule_flag |= default_statelock; + + if ($9.fragment) + r.rule_flag |= PFRULE_FRAGMENT; + r.allow_opts = $9.allowopts; + + decide_address_family($8.src.host, &r.af); + decide_address_family($8.dst.host, &r.af); + + if ($5.rt) { + if (!r.direction) { + yyerror("direction must be explicit " + "with rules that specify routing"); + YYERROR; + } + r.rt = $5.rt; + r.rpool.opts = $5.pool_opts; + if ($5.key != NULL) + memcpy(&r.rpool.key, $5.key, + sizeof(struct pf_poolhashkey)); + } + if (r.rt && r.rt != PF_FASTROUTE) { + decide_address_family($5.host, &r.af); + remove_invalid_hosts(&$5.host, &r.af); + if ($5.host == NULL) { + yyerror("no routing address with " + "matching address family found."); + YYERROR; + } + if ((r.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_NONE && ($5.host->next != NULL || + $5.host->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR($5.host->addr))) + r.rpool.opts |= PF_POOL_ROUNDROBIN; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_table($5.host, "tables are only " + "supported in round-robin routing pools")) + YYERROR; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_alias($5.host, "interface (%s) " + "is only supported in round-robin " + "routing pools")) + YYERROR; + if ($5.host->next != NULL) { + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN) { + yyerror("r.rpool.opts must " + "be PF_POOL_ROUNDROBIN"); + YYERROR; + } + } + } + if ($9.queues.qname != NULL) { + if (strlcpy(r.qname, $9.queues.qname, + sizeof(r.qname)) >= sizeof(r.qname)) { + yyerror("rule qname too long (max " + "%d chars)", sizeof(r.qname)-1); + YYERROR; + } + free($9.queues.qname); + } + if ($9.queues.pqname != NULL) { + if (strlcpy(r.pqname, $9.queues.pqname, + sizeof(r.pqname)) >= sizeof(r.pqname)) { + yyerror("rule pqname too long (max " + "%d chars)", sizeof(r.pqname)-1); + YYERROR; + } + free($9.queues.pqname); + } +#ifdef __FreeBSD__ + r.divert.port = $9.divert.port; +#else + if ((r.divert.port = $9.divert.port)) { + if (r.direction == PF_OUT) { + if ($9.divert.addr) { + yyerror("address specified " + "for outgoing divert"); + YYERROR; + } + bzero(&r.divert.addr, + sizeof(r.divert.addr)); + } else { + if (!$9.divert.addr) { + yyerror("no address specified " + "for incoming divert"); + YYERROR; + } + if ($9.divert.addr->af != r.af) { + yyerror("address family " + "mismatch for divert"); + YYERROR; + } + r.divert.addr = + $9.divert.addr->addr.v.a.addr; + } + } +#endif + + expand_rule(&r, $4, $5.host, $7, $8.src_os, + $8.src.host, $8.src.port, $8.dst.host, $8.dst.port, + $9.uid, $9.gid, $9.icmpspec, ""); + } + ; + +filter_opts : { + bzero(&filter_opts, sizeof filter_opts); + filter_opts.rtableid = -1; + } + filter_opts_l + { $$ = filter_opts; } + | /* empty */ { + bzero(&filter_opts, sizeof filter_opts); + filter_opts.rtableid = -1; + $$ = filter_opts; + } + ; + +filter_opts_l : filter_opts_l filter_opt + | filter_opt + ; + +filter_opt : USER uids { + if (filter_opts.uid) + $2->tail->next = filter_opts.uid; + filter_opts.uid = $2; + } + | GROUP gids { + if (filter_opts.gid) + $2->tail->next = filter_opts.gid; + filter_opts.gid = $2; + } + | flags { + if (filter_opts.marker & FOM_FLAGS) { + yyerror("flags cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_FLAGS; + filter_opts.flags.b1 |= $1.b1; + filter_opts.flags.b2 |= $1.b2; + filter_opts.flags.w |= $1.w; + filter_opts.flags.w2 |= $1.w2; + } + | icmpspec { + if (filter_opts.marker & FOM_ICMP) { + yyerror("icmp-type cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_ICMP; + filter_opts.icmpspec = $1; + } + | PRIO NUMBER { + if (filter_opts.marker & FOM_PRIO) { + yyerror("prio cannot be redefined"); + YYERROR; + } + if ($2 < 0 || $2 > PF_PRIO_MAX) { + yyerror("prio must be 0 - %u", PF_PRIO_MAX); + YYERROR; + } + filter_opts.marker |= FOM_PRIO; + filter_opts.prio = $2; + } + | TOS tos { + if (filter_opts.marker & FOM_TOS) { + yyerror("tos cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_TOS; + filter_opts.tos = $2; + } + | keep { + if (filter_opts.marker & FOM_KEEP) { + yyerror("modulate or keep cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_KEEP; + filter_opts.keep.action = $1.action; + filter_opts.keep.options = $1.options; + } + | FRAGMENT { + filter_opts.fragment = 1; + } + | ALLOWOPTS { + filter_opts.allowopts = 1; + } + | label { + if (filter_opts.label) { + yyerror("label cannot be redefined"); + YYERROR; + } + filter_opts.label = $1; + } + | qname { + if (filter_opts.queues.qname) { + yyerror("queue cannot be redefined"); + YYERROR; + } + filter_opts.queues = $1; + } + | TAG string { + filter_opts.tag = $2; + } + | not TAGGED string { + filter_opts.match_tag = $3; + filter_opts.match_tag_not = $1; + } + | PROBABILITY probability { + double p; + + p = floor($2 * UINT_MAX + 0.5); + if (p < 0.0 || p > UINT_MAX) { + yyerror("invalid probability: %lf", p); + YYERROR; + } + filter_opts.prob = (u_int32_t)p; + if (filter_opts.prob == 0) + filter_opts.prob = 1; + } + | RTABLE NUMBER { + if ($2 < 0 || $2 > rt_tableid_max()) { + yyerror("invalid rtable id"); + YYERROR; + } + filter_opts.rtableid = $2; + } + | DIVERTTO portplain { +#ifdef __FreeBSD__ + filter_opts.divert.port = $2.a; + if (!filter_opts.divert.port) { + yyerror("invalid divert port: %u", ntohs($2.a)); + YYERROR; + } +#endif + } + | DIVERTTO STRING PORT portplain { +#ifndef __FreeBSD__ + if ((filter_opts.divert.addr = host($2)) == NULL) { + yyerror("could not parse divert address: %s", + $2); + free($2); + YYERROR; + } +#else + if ($2) +#endif + free($2); + filter_opts.divert.port = $4.a; + if (!filter_opts.divert.port) { + yyerror("invalid divert port: %u", ntohs($4.a)); + YYERROR; + } + } + | DIVERTREPLY { +#ifdef __FreeBSD__ + yyerror("divert-reply has no meaning in FreeBSD pf(4)"); + YYERROR; +#else + filter_opts.divert.port = 1; /* some random value */ +#endif + } + | filter_sets + ; + +filter_sets : SET '(' filter_sets_l ')' { $$ = filter_opts; } + | SET filter_set { $$ = filter_opts; } + ; + +filter_sets_l : filter_sets_l comma filter_set + | filter_set + ; + +filter_set : prio { + if (filter_opts.marker & FOM_SETPRIO) { + yyerror("prio cannot be redefined"); + YYERROR; + } + filter_opts.marker |= FOM_SETPRIO; + filter_opts.set_prio[0] = $1.b1; + filter_opts.set_prio[1] = $1.b2; + } +prio : PRIO NUMBER { + if ($2 < 0 || $2 > PF_PRIO_MAX) { + yyerror("prio must be 0 - %u", PF_PRIO_MAX); + YYERROR; + } + $$.b1 = $$.b2 = $2; + } + | PRIO '(' NUMBER comma NUMBER ')' { + if ($3 < 0 || $3 > PF_PRIO_MAX || + $5 < 0 || $5 > PF_PRIO_MAX) { + yyerror("prio must be 0 - %u", PF_PRIO_MAX); + YYERROR; + } + $$.b1 = $3; + $$.b2 = $5; + } + ; + +probability : STRING { + char *e; + double p = strtod($1, &e); + + if (*e == '%') { + p *= 0.01; + e++; + } + if (*e) { + yyerror("invalid probability: %s", $1); + free($1); + YYERROR; + } + free($1); + $$ = p; + } + | NUMBER { + $$ = (double)$1; + } + ; + + +action : PASS { $$.b1 = PF_PASS; $$.b2 = $$.w = 0; } + | BLOCK blockspec { $$ = $2; $$.b1 = PF_DROP; } + ; + +blockspec : /* empty */ { + $$.b2 = blockpolicy; + $$.w = returnicmpdefault; + $$.w2 = returnicmp6default; + } + | DROP { + $$.b2 = PFRULE_DROP; + $$.w = 0; + $$.w2 = 0; + } + | RETURNRST { + $$.b2 = PFRULE_RETURNRST; + $$.w = 0; + $$.w2 = 0; + } + | RETURNRST '(' TTL NUMBER ')' { + if ($4 < 0 || $4 > 255) { + yyerror("illegal ttl value %d", $4); + YYERROR; + } + $$.b2 = PFRULE_RETURNRST; + $$.w = $4; + $$.w2 = 0; + } + | RETURNICMP { + $$.b2 = PFRULE_RETURNICMP; + $$.w = returnicmpdefault; + $$.w2 = returnicmp6default; + } + | RETURNICMP6 { + $$.b2 = PFRULE_RETURNICMP; + $$.w = returnicmpdefault; + $$.w2 = returnicmp6default; + } + | RETURNICMP '(' reticmpspec ')' { + $$.b2 = PFRULE_RETURNICMP; + $$.w = $3; + $$.w2 = returnicmpdefault; + } + | RETURNICMP6 '(' reticmp6spec ')' { + $$.b2 = PFRULE_RETURNICMP; + $$.w = returnicmpdefault; + $$.w2 = $3; + } + | RETURNICMP '(' reticmpspec comma reticmp6spec ')' { + $$.b2 = PFRULE_RETURNICMP; + $$.w = $3; + $$.w2 = $5; + } + | RETURN { + $$.b2 = PFRULE_RETURN; + $$.w = returnicmpdefault; + $$.w2 = returnicmp6default; + } + ; + +reticmpspec : STRING { + if (!($$ = parseicmpspec($1, AF_INET))) { + free($1); + YYERROR; + } + free($1); + } + | NUMBER { + u_int8_t icmptype; + + if ($1 < 0 || $1 > 255) { + yyerror("invalid icmp code %lu", $1); + YYERROR; + } + icmptype = returnicmpdefault >> 8; + $$ = (icmptype << 8 | $1); + } + ; + +reticmp6spec : STRING { + if (!($$ = parseicmpspec($1, AF_INET6))) { + free($1); + YYERROR; + } + free($1); + } + | NUMBER { + u_int8_t icmptype; + + if ($1 < 0 || $1 > 255) { + yyerror("invalid icmp code %lu", $1); + YYERROR; + } + icmptype = returnicmp6default >> 8; + $$ = (icmptype << 8 | $1); + } + ; + +dir : /* empty */ { $$ = PF_INOUT; } + | IN { $$ = PF_IN; } + | OUT { $$ = PF_OUT; } + ; + +quick : /* empty */ { $$.quick = 0; } + | QUICK { $$.quick = 1; } + ; + +logquick : /* empty */ { $$.log = 0; $$.quick = 0; $$.logif = 0; } + | log { $$ = $1; $$.quick = 0; } + | QUICK { $$.quick = 1; $$.log = 0; $$.logif = 0; } + | log QUICK { $$ = $1; $$.quick = 1; } + | QUICK log { $$ = $2; $$.quick = 1; } + ; + +log : LOG { $$.log = PF_LOG; $$.logif = 0; } + | LOG '(' logopts ')' { + $$.log = PF_LOG | $3.log; + $$.logif = $3.logif; + } + ; + +logopts : logopt { $$ = $1; } + | logopts comma logopt { + $$.log = $1.log | $3.log; + $$.logif = $3.logif; + if ($$.logif == 0) + $$.logif = $1.logif; + } + ; + +logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; } + | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } + | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; } + | TO string { + const char *errstr; + u_int i; + + $$.log = 0; + if (strncmp($2, "pflog", 5)) { + yyerror("%s: should be a pflog interface", $2); + free($2); + YYERROR; + } + i = strtonum($2 + 5, 0, 255, &errstr); + if (errstr) { + yyerror("%s: %s", $2, errstr); + free($2); + YYERROR; + } + free($2); + $$.logif = i; + } + ; + +interface : /* empty */ { $$ = NULL; } + | ON if_item_not { $$ = $2; } + | ON '{' optnl if_list '}' { $$ = $4; } + ; + +if_list : if_item_not optnl { $$ = $1; } + | if_list comma if_item_not optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +if_item_not : not if_item { $$ = $2; $$->not = $1; } + ; + +if_item : STRING { + struct node_host *n; + + $$ = calloc(1, sizeof(struct node_if)); + if ($$ == NULL) + err(1, "if_item: calloc"); + if (strlcpy($$->ifname, $1, sizeof($$->ifname)) >= + sizeof($$->ifname)) { + free($1); + free($$); + yyerror("interface name too long"); + YYERROR; + } + + if ((n = ifa_exists($1)) != NULL) + $$->ifa_flags = n->ifa_flags; + + free($1); + $$->not = 0; + $$->next = NULL; + $$->tail = $$; + } + ; + +af : /* empty */ { $$ = 0; } + | INET { $$ = AF_INET; } + | INET6 { $$ = AF_INET6; } + ; + +proto : /* empty */ { $$ = NULL; } + | PROTO proto_item { $$ = $2; } + | PROTO '{' optnl proto_list '}' { $$ = $4; } + ; + +proto_list : proto_item optnl { $$ = $1; } + | proto_list comma proto_item optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +proto_item : protoval { + u_int8_t pr; + + pr = (u_int8_t)$1; + if (pr == 0) { + yyerror("proto 0 cannot be used"); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_proto)); + if ($$ == NULL) + err(1, "proto_item: calloc"); + $$->proto = pr; + $$->next = NULL; + $$->tail = $$; + } + ; + +protoval : STRING { + struct protoent *p; + + p = getprotobyname($1); + if (p == NULL) { + yyerror("unknown protocol %s", $1); + free($1); + YYERROR; + } + $$ = p->p_proto; + free($1); + } + | NUMBER { + if ($1 < 0 || $1 > 255) { + yyerror("protocol outside range"); + YYERROR; + } + } + ; + +fromto : ALL { + $$.src.host = NULL; + $$.src.port = NULL; + $$.dst.host = NULL; + $$.dst.port = NULL; + $$.src_os = NULL; + } + | from os to { + $$.src = $1; + $$.src_os = $2; + $$.dst = $3; + } + ; + +os : /* empty */ { $$ = NULL; } + | OS xos { $$ = $2; } + | OS '{' optnl os_list '}' { $$ = $4; } + ; + +xos : STRING { + $$ = calloc(1, sizeof(struct node_os)); + if ($$ == NULL) + err(1, "os: calloc"); + $$->os = $1; + $$->tail = $$; + } + ; + +os_list : xos optnl { $$ = $1; } + | os_list comma xos optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +from : /* empty */ { + $$.host = NULL; + $$.port = NULL; + } + | FROM ipportspec { + $$ = $2; + } + ; + +to : /* empty */ { + $$.host = NULL; + $$.port = NULL; + } + | TO ipportspec { + if (disallow_urpf_failed($2.host, "\"urpf-failed\" is " + "not permitted in a destination address")) + YYERROR; + $$ = $2; + } + ; + +ipportspec : ipspec { + $$.host = $1; + $$.port = NULL; + } + | ipspec PORT portspec { + $$.host = $1; + $$.port = $3; + } + | PORT portspec { + $$.host = NULL; + $$.port = $2; + } + ; + +optnl : '\n' optnl + | + ; + +ipspec : ANY { $$ = NULL; } + | xhost { $$ = $1; } + | '{' optnl host_list '}' { $$ = $3; } + ; + +toipspec : TO ipspec { $$ = $2; } + | /* empty */ { $$ = NULL; } + ; + +host_list : ipspec optnl { $$ = $1; } + | host_list comma ipspec optnl { + if ($3 == NULL) + $$ = $1; + else if ($1 == NULL) + $$ = $3; + else { + $1->tail->next = $3; + $1->tail = $3->tail; + $$ = $1; + } + } + ; + +xhost : not host { + struct node_host *n; + + for (n = $2; n != NULL; n = n->next) + n->not = $1; + $$ = $2; + } + | not NOROUTE { + $$ = calloc(1, sizeof(struct node_host)); + if ($$ == NULL) + err(1, "xhost: calloc"); + $$->addr.type = PF_ADDR_NOROUTE; + $$->next = NULL; + $$->not = $1; + $$->tail = $$; + } + | not URPFFAILED { + $$ = calloc(1, sizeof(struct node_host)); + if ($$ == NULL) + err(1, "xhost: calloc"); + $$->addr.type = PF_ADDR_URPFFAILED; + $$->next = NULL; + $$->not = $1; + $$->tail = $$; + } + ; + +host : STRING { + if (($$ = host($1)) == NULL) { + /* error. "any" is handled elsewhere */ + free($1); + yyerror("could not parse host specification"); + YYERROR; + } + free($1); + + } + | STRING '-' STRING { + struct node_host *b, *e; + + if ((b = host($1)) == NULL || (e = host($3)) == NULL) { + free($1); + free($3); + yyerror("could not parse host specification"); + YYERROR; + } + if (b->af != e->af || + b->addr.type != PF_ADDR_ADDRMASK || + e->addr.type != PF_ADDR_ADDRMASK || + unmask(&b->addr.v.a.mask, b->af) != + (b->af == AF_INET ? 32 : 128) || + unmask(&e->addr.v.a.mask, e->af) != + (e->af == AF_INET ? 32 : 128) || + b->next != NULL || b->not || + e->next != NULL || e->not) { + free(b); + free(e); + free($1); + free($3); + yyerror("invalid address range"); + YYERROR; + } + memcpy(&b->addr.v.a.mask, &e->addr.v.a.addr, + sizeof(b->addr.v.a.mask)); + b->addr.type = PF_ADDR_RANGE; + $$ = b; + free(e); + free($1); + free($3); + } + | STRING '/' NUMBER { + char *buf; + + if (asprintf(&buf, "%s/%lld", $1, (long long)$3) == -1) + err(1, "host: asprintf"); + free($1); + if (($$ = host(buf)) == NULL) { + /* error. "any" is handled elsewhere */ + free(buf); + yyerror("could not parse host specification"); + YYERROR; + } + free(buf); + } + | NUMBER '/' NUMBER { + char *buf; + + /* ie. for 10/8 parsing */ +#ifdef __FreeBSD__ + if (asprintf(&buf, "%lld/%lld", (long long)$1, (long long)$3) == -1) +#else + if (asprintf(&buf, "%lld/%lld", $1, $3) == -1) +#endif + err(1, "host: asprintf"); + if (($$ = host(buf)) == NULL) { + /* error. "any" is handled elsewhere */ + free(buf); + yyerror("could not parse host specification"); + YYERROR; + } + free(buf); + } + | dynaddr + | dynaddr '/' NUMBER { + struct node_host *n; + + if ($3 < 0 || $3 > 128) { + yyerror("bit number too big"); + YYERROR; + } + $$ = $1; + for (n = $1; n != NULL; n = n->next) + set_ipmask(n, $3); + } + | '<' STRING '>' { + if (strlen($2) >= PF_TABLE_NAME_SIZE) { + yyerror("table name '%s' too long", $2); + free($2); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_host)); + if ($$ == NULL) + err(1, "host: calloc"); + $$->addr.type = PF_ADDR_TABLE; + if (strlcpy($$->addr.v.tblname, $2, + sizeof($$->addr.v.tblname)) >= + sizeof($$->addr.v.tblname)) + errx(1, "host: strlcpy"); + free($2); + $$->next = NULL; + $$->tail = $$; + } + ; + +number : NUMBER + | STRING { + u_long ulval; + + if (atoul($1, &ulval) == -1) { + yyerror("%s is not a number", $1); + free($1); + YYERROR; + } else + $$ = ulval; + free($1); + } + ; + +dynaddr : '(' STRING ')' { + int flags = 0; + char *p, *op; + + op = $2; + if (!isalpha(op[0])) { + yyerror("invalid interface name '%s'", op); + free(op); + YYERROR; + } + while ((p = strrchr($2, ':')) != NULL) { + if (!strcmp(p+1, "network")) + flags |= PFI_AFLAG_NETWORK; + else if (!strcmp(p+1, "broadcast")) + flags |= PFI_AFLAG_BROADCAST; + else if (!strcmp(p+1, "peer")) + flags |= PFI_AFLAG_PEER; + else if (!strcmp(p+1, "0")) + flags |= PFI_AFLAG_NOALIAS; + else { + yyerror("interface %s has bad modifier", + $2); + free(op); + YYERROR; + } + *p = '\0'; + } + if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { + free(op); + yyerror("illegal combination of " + "interface modifiers"); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_host)); + if ($$ == NULL) + err(1, "address: calloc"); + $$->af = 0; + set_ipmask($$, 128); + $$->addr.type = PF_ADDR_DYNIFTL; + $$->addr.iflags = flags; + if (strlcpy($$->addr.v.ifname, $2, + sizeof($$->addr.v.ifname)) >= + sizeof($$->addr.v.ifname)) { + free(op); + free($$); + yyerror("interface name too long"); + YYERROR; + } + free(op); + $$->next = NULL; + $$->tail = $$; + } + ; + +portspec : port_item { $$ = $1; } + | '{' optnl port_list '}' { $$ = $3; } + ; + +port_list : port_item optnl { $$ = $1; } + | port_list comma port_item optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +port_item : portrange { + $$ = calloc(1, sizeof(struct node_port)); + if ($$ == NULL) + err(1, "port_item: calloc"); + $$->port[0] = $1.a; + $$->port[1] = $1.b; + if ($1.t) + $$->op = PF_OP_RRG; + else + $$->op = PF_OP_EQ; + $$->next = NULL; + $$->tail = $$; + } + | unaryop portrange { + if ($2.t) { + yyerror("':' cannot be used with an other " + "port operator"); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_port)); + if ($$ == NULL) + err(1, "port_item: calloc"); + $$->port[0] = $2.a; + $$->port[1] = $2.b; + $$->op = $1; + $$->next = NULL; + $$->tail = $$; + } + | portrange PORTBINARY portrange { + if ($1.t || $3.t) { + yyerror("':' cannot be used with an other " + "port operator"); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_port)); + if ($$ == NULL) + err(1, "port_item: calloc"); + $$->port[0] = $1.a; + $$->port[1] = $3.a; + $$->op = $2; + $$->next = NULL; + $$->tail = $$; + } + ; + +portplain : numberstring { + if (parseport($1, &$$, 0) == -1) { + free($1); + YYERROR; + } + free($1); + } + ; + +portrange : numberstring { + if (parseport($1, &$$, PPORT_RANGE) == -1) { + free($1); + YYERROR; + } + free($1); + } + ; + +uids : uid_item { $$ = $1; } + | '{' optnl uid_list '}' { $$ = $3; } + ; + +uid_list : uid_item optnl { $$ = $1; } + | uid_list comma uid_item optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +uid_item : uid { + $$ = calloc(1, sizeof(struct node_uid)); + if ($$ == NULL) + err(1, "uid_item: calloc"); + $$->uid[0] = $1; + $$->uid[1] = $1; + $$->op = PF_OP_EQ; + $$->next = NULL; + $$->tail = $$; + } + | unaryop uid { + if ($2 == UID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { + yyerror("user unknown requires operator = or " + "!="); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_uid)); + if ($$ == NULL) + err(1, "uid_item: calloc"); + $$->uid[0] = $2; + $$->uid[1] = $2; + $$->op = $1; + $$->next = NULL; + $$->tail = $$; + } + | uid PORTBINARY uid { + if ($1 == UID_MAX || $3 == UID_MAX) { + yyerror("user unknown requires operator = or " + "!="); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_uid)); + if ($$ == NULL) + err(1, "uid_item: calloc"); + $$->uid[0] = $1; + $$->uid[1] = $3; + $$->op = $2; + $$->next = NULL; + $$->tail = $$; + } + ; + +uid : STRING { + if (!strcmp($1, "unknown")) + $$ = UID_MAX; + else { + struct passwd *pw; + + if ((pw = getpwnam($1)) == NULL) { + yyerror("unknown user %s", $1); + free($1); + YYERROR; + } + $$ = pw->pw_uid; + } + free($1); + } + | NUMBER { + if ($1 < 0 || $1 >= UID_MAX) { + yyerror("illegal uid value %lu", $1); + YYERROR; + } + $$ = $1; + } + ; + +gids : gid_item { $$ = $1; } + | '{' optnl gid_list '}' { $$ = $3; } + ; + +gid_list : gid_item optnl { $$ = $1; } + | gid_list comma gid_item optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +gid_item : gid { + $$ = calloc(1, sizeof(struct node_gid)); + if ($$ == NULL) + err(1, "gid_item: calloc"); + $$->gid[0] = $1; + $$->gid[1] = $1; + $$->op = PF_OP_EQ; + $$->next = NULL; + $$->tail = $$; + } + | unaryop gid { + if ($2 == GID_MAX && $1 != PF_OP_EQ && $1 != PF_OP_NE) { + yyerror("group unknown requires operator = or " + "!="); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_gid)); + if ($$ == NULL) + err(1, "gid_item: calloc"); + $$->gid[0] = $2; + $$->gid[1] = $2; + $$->op = $1; + $$->next = NULL; + $$->tail = $$; + } + | gid PORTBINARY gid { + if ($1 == GID_MAX || $3 == GID_MAX) { + yyerror("group unknown requires operator = or " + "!="); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_gid)); + if ($$ == NULL) + err(1, "gid_item: calloc"); + $$->gid[0] = $1; + $$->gid[1] = $3; + $$->op = $2; + $$->next = NULL; + $$->tail = $$; + } + ; + +gid : STRING { + if (!strcmp($1, "unknown")) + $$ = GID_MAX; + else { + struct group *grp; + + if ((grp = getgrnam($1)) == NULL) { + yyerror("unknown group %s", $1); + free($1); + YYERROR; + } + $$ = grp->gr_gid; + } + free($1); + } + | NUMBER { + if ($1 < 0 || $1 >= GID_MAX) { + yyerror("illegal gid value %lu", $1); + YYERROR; + } + $$ = $1; + } + ; + +flag : STRING { + int f; + + if ((f = parse_flags($1)) < 0) { + yyerror("bad flags %s", $1); + free($1); + YYERROR; + } + free($1); + $$.b1 = f; + } + ; + +flags : FLAGS flag '/' flag { $$.b1 = $2.b1; $$.b2 = $4.b1; } + | FLAGS '/' flag { $$.b1 = 0; $$.b2 = $3.b1; } + | FLAGS ANY { $$.b1 = 0; $$.b2 = 0; } + ; + +icmpspec : ICMPTYPE icmp_item { $$ = $2; } + | ICMPTYPE '{' optnl icmp_list '}' { $$ = $4; } + | ICMP6TYPE icmp6_item { $$ = $2; } + | ICMP6TYPE '{' optnl icmp6_list '}' { $$ = $4; } + ; + +icmp_list : icmp_item optnl { $$ = $1; } + | icmp_list comma icmp_item optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +icmp6_list : icmp6_item optnl { $$ = $1; } + | icmp6_list comma icmp6_item optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +icmp_item : icmptype { + $$ = calloc(1, sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: calloc"); + $$->type = $1; + $$->code = 0; + $$->proto = IPPROTO_ICMP; + $$->next = NULL; + $$->tail = $$; + } + | icmptype CODE STRING { + const struct icmpcodeent *p; + + if ((p = geticmpcodebyname($1-1, $3, AF_INET)) == NULL) { + yyerror("unknown icmp-code %s", $3); + free($3); + YYERROR; + } + + free($3); + $$ = calloc(1, sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: calloc"); + $$->type = $1; + $$->code = p->code + 1; + $$->proto = IPPROTO_ICMP; + $$->next = NULL; + $$->tail = $$; + } + | icmptype CODE NUMBER { + if ($3 < 0 || $3 > 255) { + yyerror("illegal icmp-code %lu", $3); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: calloc"); + $$->type = $1; + $$->code = $3 + 1; + $$->proto = IPPROTO_ICMP; + $$->next = NULL; + $$->tail = $$; + } + ; + +icmp6_item : icmp6type { + $$ = calloc(1, sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: calloc"); + $$->type = $1; + $$->code = 0; + $$->proto = IPPROTO_ICMPV6; + $$->next = NULL; + $$->tail = $$; + } + | icmp6type CODE STRING { + const struct icmpcodeent *p; + + if ((p = geticmpcodebyname($1-1, $3, AF_INET6)) == NULL) { + yyerror("unknown icmp6-code %s", $3); + free($3); + YYERROR; + } + free($3); + + $$ = calloc(1, sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: calloc"); + $$->type = $1; + $$->code = p->code + 1; + $$->proto = IPPROTO_ICMPV6; + $$->next = NULL; + $$->tail = $$; + } + | icmp6type CODE NUMBER { + if ($3 < 0 || $3 > 255) { + yyerror("illegal icmp-code %lu", $3); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_icmp)); + if ($$ == NULL) + err(1, "icmp_item: calloc"); + $$->type = $1; + $$->code = $3 + 1; + $$->proto = IPPROTO_ICMPV6; + $$->next = NULL; + $$->tail = $$; + } + ; + +icmptype : STRING { + const struct icmptypeent *p; + + if ((p = geticmptypebyname($1, AF_INET)) == NULL) { + yyerror("unknown icmp-type %s", $1); + free($1); + YYERROR; + } + $$ = p->type + 1; + free($1); + } + | NUMBER { + if ($1 < 0 || $1 > 255) { + yyerror("illegal icmp-type %lu", $1); + YYERROR; + } + $$ = $1 + 1; + } + ; + +icmp6type : STRING { + const struct icmptypeent *p; + + if ((p = geticmptypebyname($1, AF_INET6)) == + NULL) { + yyerror("unknown icmp6-type %s", $1); + free($1); + YYERROR; + } + $$ = p->type + 1; + free($1); + } + | NUMBER { + if ($1 < 0 || $1 > 255) { + yyerror("illegal icmp6-type %lu", $1); + YYERROR; + } + $$ = $1 + 1; + } + ; + +tos : STRING { + if (!strcmp($1, "lowdelay")) + $$ = IPTOS_LOWDELAY; + else if (!strcmp($1, "throughput")) + $$ = IPTOS_THROUGHPUT; + else if (!strcmp($1, "reliability")) + $$ = IPTOS_RELIABILITY; + else if ($1[0] == '0' && $1[1] == 'x') + $$ = strtoul($1, NULL, 16); + else + $$ = 256; /* flag bad argument */ + if ($$ < 0 || $$ > 255) { + yyerror("illegal tos value %s", $1); + free($1); + YYERROR; + } + free($1); + } + | NUMBER { + $$ = $1; + if ($$ < 0 || $$ > 255) { + yyerror("illegal tos value %s", $1); + YYERROR; + } + } + ; + +sourcetrack : SOURCETRACK { $$ = PF_SRCTRACK; } + | SOURCETRACK GLOBAL { $$ = PF_SRCTRACK_GLOBAL; } + | SOURCETRACK RULE { $$ = PF_SRCTRACK_RULE; } + ; + +statelock : IFBOUND { + $$ = PFRULE_IFBOUND; + } + | FLOATING { + $$ = 0; + } + ; + +keep : NO STATE { + $$.action = 0; + $$.options = NULL; + } + | KEEP STATE state_opt_spec { + $$.action = PF_STATE_NORMAL; + $$.options = $3; + } + | MODULATE STATE state_opt_spec { + $$.action = PF_STATE_MODULATE; + $$.options = $3; + } + | SYNPROXY STATE state_opt_spec { + $$.action = PF_STATE_SYNPROXY; + $$.options = $3; + } + ; + +flush : /* empty */ { $$ = 0; } + | FLUSH { $$ = PF_FLUSH; } + | FLUSH GLOBAL { + $$ = PF_FLUSH | PF_FLUSH_GLOBAL; + } + ; + +state_opt_spec : '(' state_opt_list ')' { $$ = $2; } + | /* empty */ { $$ = NULL; } + ; + +state_opt_list : state_opt_item { $$ = $1; } + | state_opt_list comma state_opt_item { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; + +state_opt_item : MAXIMUM NUMBER { + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_MAX; + $$->data.max_states = $2; + $$->next = NULL; + $$->tail = $$; + } + | NOSYNC { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_NOSYNC; + $$->next = NULL; + $$->tail = $$; + } + | MAXSRCSTATES NUMBER { + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_MAX_SRC_STATES; + $$->data.max_src_states = $2; + $$->next = NULL; + $$->tail = $$; + } + | MAXSRCCONN NUMBER { + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_MAX_SRC_CONN; + $$->data.max_src_conn = $2; + $$->next = NULL; + $$->tail = $$; + } + | MAXSRCCONNRATE NUMBER '/' NUMBER { + if ($2 < 0 || $2 > UINT_MAX || + $4 < 0 || $4 > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_MAX_SRC_CONN_RATE; + $$->data.max_src_conn_rate.limit = $2; + $$->data.max_src_conn_rate.seconds = $4; + $$->next = NULL; + $$->tail = $$; + } + | OVERLOAD '<' STRING '>' flush { + if (strlen($3) >= PF_TABLE_NAME_SIZE) { + yyerror("table name '%s' too long", $3); + free($3); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + if (strlcpy($$->data.overload.tblname, $3, + PF_TABLE_NAME_SIZE) >= PF_TABLE_NAME_SIZE) + errx(1, "state_opt_item: strlcpy"); + free($3); + $$->type = PF_STATE_OPT_OVERLOAD; + $$->data.overload.flush = $5; + $$->next = NULL; + $$->tail = $$; + } + | MAXSRCNODES NUMBER { + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_MAX_SRC_NODES; + $$->data.max_src_nodes = $2; + $$->next = NULL; + $$->tail = $$; + } + | sourcetrack { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_SRCTRACK; + $$->data.src_track = $1; + $$->next = NULL; + $$->tail = $$; + } + | statelock { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_STATELOCK; + $$->data.statelock = $1; + $$->next = NULL; + $$->tail = $$; + } + | SLOPPY { + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_SLOPPY; + $$->next = NULL; + $$->tail = $$; + } + | STRING NUMBER { + int i; + + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + for (i = 0; pf_timeouts[i].name && + strcmp(pf_timeouts[i].name, $1); ++i) + ; /* nothing */ + if (!pf_timeouts[i].name) { + yyerror("illegal timeout name %s", $1); + free($1); + YYERROR; + } + if (strchr(pf_timeouts[i].name, '.') == NULL) { + yyerror("illegal state timeout %s", $1); + free($1); + YYERROR; + } + free($1); + $$ = calloc(1, sizeof(struct node_state_opt)); + if ($$ == NULL) + err(1, "state_opt_item: calloc"); + $$->type = PF_STATE_OPT_TIMEOUT; + $$->data.timeout.number = pf_timeouts[i].timeout; + $$->data.timeout.seconds = $2; + $$->next = NULL; + $$->tail = $$; + } + ; + +label : LABEL STRING { + $$ = $2; + } + ; + +qname : QUEUE STRING { + $$.qname = $2; + $$.pqname = NULL; + } + | QUEUE '(' STRING ')' { + $$.qname = $3; + $$.pqname = NULL; + } + | QUEUE '(' STRING comma STRING ')' { + $$.qname = $3; + $$.pqname = $5; + } + ; + +no : /* empty */ { $$ = 0; } + | NO { $$ = 1; } + ; + +portstar : numberstring { + if (parseport($1, &$$, PPORT_RANGE|PPORT_STAR) == -1) { + free($1); + YYERROR; + } + free($1); + } + ; + +redirspec : host { $$ = $1; } + | '{' optnl redir_host_list '}' { $$ = $3; } + ; + +redir_host_list : host optnl { $$ = $1; } + | redir_host_list comma host optnl { + $1->tail->next = $3; + $1->tail = $3->tail; + $$ = $1; + } + ; + +redirpool : /* empty */ { $$ = NULL; } + | ARROW redirspec { + $$ = calloc(1, sizeof(struct redirection)); + if ($$ == NULL) + err(1, "redirection: calloc"); + $$->host = $2; + $$->rport.a = $$->rport.b = $$->rport.t = 0; + } + | ARROW redirspec PORT portstar { + $$ = calloc(1, sizeof(struct redirection)); + if ($$ == NULL) + err(1, "redirection: calloc"); + $$->host = $2; + $$->rport = $4; + } + ; + +hashkey : /* empty */ + { + $$ = calloc(1, sizeof(struct pf_poolhashkey)); + if ($$ == NULL) + err(1, "hashkey: calloc"); + $$->key32[0] = arc4random(); + $$->key32[1] = arc4random(); + $$->key32[2] = arc4random(); + $$->key32[3] = arc4random(); + } + | string + { + if (!strncmp($1, "0x", 2)) { + if (strlen($1) != 34) { + free($1); + yyerror("hex key must be 128 bits " + "(32 hex digits) long"); + YYERROR; + } + $$ = calloc(1, sizeof(struct pf_poolhashkey)); + if ($$ == NULL) + err(1, "hashkey: calloc"); + + if (sscanf($1, "0x%8x%8x%8x%8x", + &$$->key32[0], &$$->key32[1], + &$$->key32[2], &$$->key32[3]) != 4) { + free($$); + free($1); + yyerror("invalid hex key"); + YYERROR; + } + } else { + MD5_CTX context; + + $$ = calloc(1, sizeof(struct pf_poolhashkey)); + if ($$ == NULL) + err(1, "hashkey: calloc"); + MD5Init(&context); + MD5Update(&context, (unsigned char *)$1, + strlen($1)); + MD5Final((unsigned char *)$$, &context); + HTONL($$->key32[0]); + HTONL($$->key32[1]); + HTONL($$->key32[2]); + HTONL($$->key32[3]); + } + free($1); + } + ; + +pool_opts : { bzero(&pool_opts, sizeof pool_opts); } + pool_opts_l + { $$ = pool_opts; } + | /* empty */ { + bzero(&pool_opts, sizeof pool_opts); + $$ = pool_opts; + } + ; + +pool_opts_l : pool_opts_l pool_opt + | pool_opt + ; + +pool_opt : BITMASK { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_BITMASK; + } + | RANDOM { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_RANDOM; + } + | SOURCEHASH hashkey { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_SRCHASH; + pool_opts.key = $2; + } + | ROUNDROBIN { + if (pool_opts.type) { + yyerror("pool type cannot be redefined"); + YYERROR; + } + pool_opts.type = PF_POOL_ROUNDROBIN; + } + | STATICPORT { + if (pool_opts.staticport) { + yyerror("static-port cannot be redefined"); + YYERROR; + } + pool_opts.staticport = 1; + } + | STICKYADDRESS { + if (filter_opts.marker & POM_STICKYADDRESS) { + yyerror("sticky-address cannot be redefined"); + YYERROR; + } + pool_opts.marker |= POM_STICKYADDRESS; + pool_opts.opts |= PF_POOL_STICKYADDR; + } + ; + +redirection : /* empty */ { $$ = NULL; } + | ARROW host { + $$ = calloc(1, sizeof(struct redirection)); + if ($$ == NULL) + err(1, "redirection: calloc"); + $$->host = $2; + $$->rport.a = $$->rport.b = $$->rport.t = 0; + } + | ARROW host PORT portstar { + $$ = calloc(1, sizeof(struct redirection)); + if ($$ == NULL) + err(1, "redirection: calloc"); + $$->host = $2; + $$->rport = $4; + } + ; + +natpasslog : /* empty */ { $$.b1 = $$.b2 = 0; $$.w2 = 0; } + | PASS { $$.b1 = 1; $$.b2 = 0; $$.w2 = 0; } + | PASS log { $$.b1 = 1; $$.b2 = $2.log; $$.w2 = $2.logif; } + | log { $$.b1 = 0; $$.b2 = $1.log; $$.w2 = $1.logif; } + ; + +nataction : no NAT natpasslog { + if ($1 && $3.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } + if ($1) + $$.b1 = PF_NONAT; + else + $$.b1 = PF_NAT; + $$.b2 = $3.b1; + $$.w = $3.b2; + $$.w2 = $3.w2; + } + | no RDR natpasslog { + if ($1 && $3.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } + if ($1) + $$.b1 = PF_NORDR; + else + $$.b1 = PF_RDR; + $$.b2 = $3.b1; + $$.w = $3.b2; + $$.w2 = $3.w2; + } + ; + +natrule : nataction interface af proto fromto tag tagged rtable + redirpool pool_opts + { + struct pf_rule r; + + if (check_rulestate(PFCTL_STATE_NAT)) + YYERROR; + + memset(&r, 0, sizeof(r)); + + r.action = $1.b1; + r.natpass = $1.b2; + r.log = $1.w; + r.logif = $1.w2; + r.af = $3; + + if (!r.af) { + if ($5.src.host && $5.src.host->af && + !$5.src.host->ifindex) + r.af = $5.src.host->af; + else if ($5.dst.host && $5.dst.host->af && + !$5.dst.host->ifindex) + r.af = $5.dst.host->af; + } + + if ($6 != NULL) + if (strlcpy(r.tagname, $6, PF_TAG_NAME_SIZE) >= + PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + + if ($7.name) + if (strlcpy(r.match_tagname, $7.name, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + r.match_tag_not = $7.neg; + r.rtableid = $8; + + if (r.action == PF_NONAT || r.action == PF_NORDR) { + if ($9 != NULL) { + yyerror("translation rule with 'no' " + "does not need '->'"); + YYERROR; + } + } else { + if ($9 == NULL || $9->host == NULL) { + yyerror("translation rule requires '-> " + "address'"); + YYERROR; + } + if (!r.af && ! $9->host->ifindex) + r.af = $9->host->af; + + remove_invalid_hosts(&$9->host, &r.af); + if (invalid_redirect($9->host, r.af)) + YYERROR; + if (check_netmask($9->host, r.af)) + YYERROR; + + r.rpool.proxy_port[0] = ntohs($9->rport.a); + + switch (r.action) { + case PF_RDR: + if (!$9->rport.b && $9->rport.t && + $5.dst.port != NULL) { + r.rpool.proxy_port[1] = + ntohs($9->rport.a) + + (ntohs( + $5.dst.port->port[1]) - + ntohs( + $5.dst.port->port[0])); + } else + r.rpool.proxy_port[1] = + ntohs($9->rport.b); + break; + case PF_NAT: + r.rpool.proxy_port[1] = + ntohs($9->rport.b); + if (!r.rpool.proxy_port[0] && + !r.rpool.proxy_port[1]) { + r.rpool.proxy_port[0] = + PF_NAT_PROXY_PORT_LOW; + r.rpool.proxy_port[1] = + PF_NAT_PROXY_PORT_HIGH; + } else if (!r.rpool.proxy_port[1]) + r.rpool.proxy_port[1] = + r.rpool.proxy_port[0]; + break; + default: + break; + } + + r.rpool.opts = $10.type; + if ((r.rpool.opts & PF_POOL_TYPEMASK) == + PF_POOL_NONE && ($9->host->next != NULL || + $9->host->addr.type == PF_ADDR_TABLE || + DYNIF_MULTIADDR($9->host->addr))) + r.rpool.opts = PF_POOL_ROUNDROBIN; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_table($9->host, "tables are only " + "supported in round-robin redirection " + "pools")) + YYERROR; + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN && + disallow_alias($9->host, "interface (%s) " + "is only supported in round-robin " + "redirection pools")) + YYERROR; + if ($9->host->next != NULL) { + if ((r.rpool.opts & PF_POOL_TYPEMASK) != + PF_POOL_ROUNDROBIN) { + yyerror("only round-robin " + "valid for multiple " + "redirection addresses"); + YYERROR; + } + } + } + + if ($10.key != NULL) + memcpy(&r.rpool.key, $10.key, + sizeof(struct pf_poolhashkey)); + + if ($10.opts) + r.rpool.opts |= $10.opts; + + if ($10.staticport) { + if (r.action != PF_NAT) { + yyerror("the 'static-port' option is " + "only valid with nat rules"); + YYERROR; + } + if (r.rpool.proxy_port[0] != + PF_NAT_PROXY_PORT_LOW && + r.rpool.proxy_port[1] != + PF_NAT_PROXY_PORT_HIGH) { + yyerror("the 'static-port' option can't" + " be used when specifying a port" + " range"); + YYERROR; + } + r.rpool.proxy_port[0] = 0; + r.rpool.proxy_port[1] = 0; + } + + expand_rule(&r, $2, $9 == NULL ? NULL : $9->host, $4, + $5.src_os, $5.src.host, $5.src.port, $5.dst.host, + $5.dst.port, 0, 0, 0, ""); + free($9); + } + ; + +binatrule : no BINAT natpasslog interface af proto FROM host toipspec tag + tagged rtable redirection + { + struct pf_rule binat; + struct pf_pooladdr *pa; + + if (check_rulestate(PFCTL_STATE_NAT)) + YYERROR; + if (disallow_urpf_failed($9, "\"urpf-failed\" is not " + "permitted as a binat destination")) + YYERROR; + + memset(&binat, 0, sizeof(binat)); + + if ($1 && $3.b1) { + yyerror("\"pass\" not valid with \"no\""); + YYERROR; + } + if ($1) + binat.action = PF_NOBINAT; + else + binat.action = PF_BINAT; + binat.natpass = $3.b1; + binat.log = $3.b2; + binat.logif = $3.w2; + binat.af = $5; + if (!binat.af && $8 != NULL && $8->af) + binat.af = $8->af; + if (!binat.af && $9 != NULL && $9->af) + binat.af = $9->af; + + if (!binat.af && $13 != NULL && $13->host) + binat.af = $13->host->af; + if (!binat.af) { + yyerror("address family (inet/inet6) " + "undefined"); + YYERROR; + } + + if ($4 != NULL) { + memcpy(binat.ifname, $4->ifname, + sizeof(binat.ifname)); + binat.ifnot = $4->not; + free($4); + } + + if ($10 != NULL) + if (strlcpy(binat.tagname, $10, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + if ($11.name) + if (strlcpy(binat.match_tagname, $11.name, + PF_TAG_NAME_SIZE) >= PF_TAG_NAME_SIZE) { + yyerror("tag too long, max %u chars", + PF_TAG_NAME_SIZE - 1); + YYERROR; + } + binat.match_tag_not = $11.neg; + binat.rtableid = $12; + + if ($6 != NULL) { + binat.proto = $6->proto; + free($6); + } + + if ($8 != NULL && disallow_table($8, "invalid use of " + "table <%s> as the source address of a binat rule")) + YYERROR; + if ($8 != NULL && disallow_alias($8, "invalid use of " + "interface (%s) as the source address of a binat " + "rule")) + YYERROR; + if ($13 != NULL && $13->host != NULL && disallow_table( + $13->host, "invalid use of table <%s> as the " + "redirect address of a binat rule")) + YYERROR; + if ($13 != NULL && $13->host != NULL && disallow_alias( + $13->host, "invalid use of interface (%s) as the " + "redirect address of a binat rule")) + YYERROR; + + if ($8 != NULL) { + if ($8->next) { + yyerror("multiple binat ip addresses"); + YYERROR; + } + if ($8->addr.type == PF_ADDR_DYNIFTL) + $8->af = binat.af; + if ($8->af != binat.af) { + yyerror("binat ip versions must match"); + YYERROR; + } + if (check_netmask($8, binat.af)) + YYERROR; + memcpy(&binat.src.addr, &$8->addr, + sizeof(binat.src.addr)); + free($8); + } + if ($9 != NULL) { + if ($9->next) { + yyerror("multiple binat ip addresses"); + YYERROR; + } + if ($9->af != binat.af && $9->af) { + yyerror("binat ip versions must match"); + YYERROR; + } + if (check_netmask($9, binat.af)) + YYERROR; + memcpy(&binat.dst.addr, &$9->addr, + sizeof(binat.dst.addr)); + binat.dst.neg = $9->not; + free($9); + } + + if (binat.action == PF_NOBINAT) { + if ($13 != NULL) { + yyerror("'no binat' rule does not need" + " '->'"); + YYERROR; + } + } else { + if ($13 == NULL || $13->host == NULL) { + yyerror("'binat' rule requires" + " '-> address'"); + YYERROR; + } + + remove_invalid_hosts(&$13->host, &binat.af); + if (invalid_redirect($13->host, binat.af)) + YYERROR; + if ($13->host->next != NULL) { + yyerror("binat rule must redirect to " + "a single address"); + YYERROR; + } + if (check_netmask($13->host, binat.af)) + YYERROR; + + if (!PF_AZERO(&binat.src.addr.v.a.mask, + binat.af) && + !PF_AEQ(&binat.src.addr.v.a.mask, + &$13->host->addr.v.a.mask, binat.af)) { + yyerror("'binat' source mask and " + "redirect mask must be the same"); + YYERROR; + } + + TAILQ_INIT(&binat.rpool.list); + pa = calloc(1, sizeof(struct pf_pooladdr)); + if (pa == NULL) + err(1, "binat: calloc"); + pa->addr = $13->host->addr; + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&binat.rpool.list, + pa, entries); + + free($13); + } + + pfctl_add_rule(pf, &binat, ""); + } + ; + +tag : /* empty */ { $$ = NULL; } + | TAG STRING { $$ = $2; } + ; + +tagged : /* empty */ { $$.neg = 0; $$.name = NULL; } + | not TAGGED string { $$.neg = $1; $$.name = $3; } + ; + +rtable : /* empty */ { $$ = -1; } + | RTABLE NUMBER { + if ($2 < 0 || $2 > rt_tableid_max()) { + yyerror("invalid rtable id"); + YYERROR; + } + $$ = $2; + } + ; + +route_host : STRING { + $$ = calloc(1, sizeof(struct node_host)); + if ($$ == NULL) + err(1, "route_host: calloc"); + $$->ifname = $1; + set_ipmask($$, 128); + $$->next = NULL; + $$->tail = $$; + } + | '(' STRING host ')' { + $$ = $3; + $$->ifname = $2; + } + ; + +route_host_list : route_host optnl { $$ = $1; } + | route_host_list comma route_host optnl { + if ($1->af == 0) + $1->af = $3->af; + if ($1->af != $3->af) { + yyerror("all pool addresses must be in the " + "same address family"); + YYERROR; + } + $1->tail->next = $3; + $1->tail = $3->tail; + $$ = $1; + } + ; + +routespec : route_host { $$ = $1; } + | '{' optnl route_host_list '}' { $$ = $3; } + ; + +route : /* empty */ { + $$.host = NULL; + $$.rt = 0; + $$.pool_opts = 0; + } + | FASTROUTE { + $$.host = NULL; + $$.rt = PF_FASTROUTE; + $$.pool_opts = 0; + } + | ROUTETO routespec pool_opts { + $$.host = $2; + $$.rt = PF_ROUTETO; + $$.pool_opts = $3.type | $3.opts; + if ($3.key != NULL) + $$.key = $3.key; + } + | REPLYTO routespec pool_opts { + $$.host = $2; + $$.rt = PF_REPLYTO; + $$.pool_opts = $3.type | $3.opts; + if ($3.key != NULL) + $$.key = $3.key; + } + | DUPTO routespec pool_opts { + $$.host = $2; + $$.rt = PF_DUPTO; + $$.pool_opts = $3.type | $3.opts; + if ($3.key != NULL) + $$.key = $3.key; + } + ; + +timeout_spec : STRING NUMBER + { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($1); + YYERROR; + } + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + if (pfctl_set_timeout(pf, $1, $2, 0) != 0) { + yyerror("unknown timeout %s", $1); + free($1); + YYERROR; + } + free($1); + } + | INTERVAL NUMBER { + if (check_rulestate(PFCTL_STATE_OPTION)) + YYERROR; + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + if (pfctl_set_timeout(pf, "interval", $2, 0) != 0) + YYERROR; + } + ; + +timeout_list : timeout_list comma timeout_spec optnl + | timeout_spec optnl + ; + +limit_spec : STRING NUMBER + { + if (check_rulestate(PFCTL_STATE_OPTION)) { + free($1); + YYERROR; + } + if ($2 < 0 || $2 > UINT_MAX) { + yyerror("only positive values permitted"); + YYERROR; + } + if (pfctl_set_limit(pf, $1, $2) != 0) { + yyerror("unable to set limit %s %u", $1, $2); + free($1); + YYERROR; + } + free($1); + } + ; + +limit_list : limit_list comma limit_spec optnl + | limit_spec optnl + ; + +comma : ',' + | /* empty */ + ; + +yesno : NO { $$ = 0; } + | STRING { + if (!strcmp($1, "yes")) + $$ = 1; + else { + yyerror("invalid value '%s', expected 'yes' " + "or 'no'", $1); + free($1); + YYERROR; + } + free($1); + } + ; + +unaryop : '=' { $$ = PF_OP_EQ; } + | '!' '=' { $$ = PF_OP_NE; } + | '<' '=' { $$ = PF_OP_LE; } + | '<' { $$ = PF_OP_LT; } + | '>' '=' { $$ = PF_OP_GE; } + | '>' { $$ = PF_OP_GT; } + ; + +%% +#ifdef __rtems__ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlyval); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlylval); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack); +#endif /* __rtems__ */ + +int +yyerror(const char *fmt, ...) +{ + va_list ap; + + file->errors++; + va_start(ap, fmt); + fprintf(stderr, "%s:%d: ", file->name, yylval.lineno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + return (0); +} + +int +disallow_table(struct node_host *h, const char *fmt) +{ + for (; h != NULL; h = h->next) + if (h->addr.type == PF_ADDR_TABLE) { + yyerror(fmt, h->addr.v.tblname); + return (1); + } + return (0); +} + +int +disallow_urpf_failed(struct node_host *h, const char *fmt) +{ + for (; h != NULL; h = h->next) + if (h->addr.type == PF_ADDR_URPFFAILED) { + yyerror(fmt); + return (1); + } + return (0); +} + +int +disallow_alias(struct node_host *h, const char *fmt) +{ + for (; h != NULL; h = h->next) + if (DYNIF_MULTIADDR(h->addr)) { + yyerror(fmt, h->addr.v.tblname); + return (1); + } + return (0); +} + +int +rule_consistent(struct pf_rule *r, int anchor_call) +{ + int problems = 0; + + switch (r->action) { + case PF_PASS: + case PF_DROP: + case PF_SCRUB: + case PF_NOSCRUB: + problems = filter_consistent(r, anchor_call); + break; + case PF_NAT: + case PF_NONAT: + problems = nat_consistent(r); + break; + case PF_RDR: + case PF_NORDR: + problems = rdr_consistent(r); + break; + case PF_BINAT: + case PF_NOBINAT: + default: + break; + } + return (problems); +} + +int +filter_consistent(struct pf_rule *r, int anchor_call) +{ + int problems = 0; + + if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP && + (r->src.port_op || r->dst.port_op)) { + yyerror("port only applies to tcp/udp"); + problems++; + } + if (r->proto != IPPROTO_ICMP && r->proto != IPPROTO_ICMPV6 && + (r->type || r->code)) { + yyerror("icmp-type/code only applies to icmp"); + problems++; + } + if (!r->af && (r->type || r->code)) { + yyerror("must indicate address family with icmp-type/code"); + problems++; + } + if (r->overload_tblname[0] && + r->max_src_conn == 0 && r->max_src_conn_rate.seconds == 0) { + yyerror("'overload' requires 'max-src-conn' " + "or 'max-src-conn-rate'"); + problems++; + } + if ((r->proto == IPPROTO_ICMP && r->af == AF_INET6) || + (r->proto == IPPROTO_ICMPV6 && r->af == AF_INET)) { + yyerror("proto %s doesn't match address family %s", + r->proto == IPPROTO_ICMP ? "icmp" : "icmp6", + r->af == AF_INET ? "inet" : "inet6"); + problems++; + } + if (r->allow_opts && r->action != PF_PASS) { + yyerror("allow-opts can only be specified for pass rules"); + problems++; + } + if (r->rule_flag & PFRULE_FRAGMENT && (r->src.port_op || + r->dst.port_op || r->flagset || r->type || r->code)) { + yyerror("fragments can be filtered only on IP header fields"); + problems++; + } + if (r->rule_flag & PFRULE_RETURNRST && r->proto != IPPROTO_TCP) { + yyerror("return-rst can only be applied to TCP rules"); + problems++; + } + if (r->max_src_nodes && !(r->rule_flag & PFRULE_RULESRCTRACK)) { + yyerror("max-src-nodes requires 'source-track rule'"); + problems++; + } + if (r->action == PF_DROP && r->keep_state) { + yyerror("keep state on block rules doesn't make sense"); + problems++; + } + if (r->rule_flag & PFRULE_STATESLOPPY && + (r->keep_state == PF_STATE_MODULATE || + r->keep_state == PF_STATE_SYNPROXY)) { + yyerror("sloppy state matching cannot be used with " + "synproxy state or modulate state"); + problems++; + } + return (-problems); +} + +int +nat_consistent(struct pf_rule *r) +{ + return (0); /* yeah! */ +} + +int +rdr_consistent(struct pf_rule *r) +{ + int problems = 0; + + if (r->proto != IPPROTO_TCP && r->proto != IPPROTO_UDP) { + if (r->src.port_op) { + yyerror("src port only applies to tcp/udp"); + problems++; + } + if (r->dst.port_op) { + yyerror("dst port only applies to tcp/udp"); + problems++; + } + if (r->rpool.proxy_port[0]) { + yyerror("rpool port only applies to tcp/udp"); + problems++; + } + } + if (r->dst.port_op && + r->dst.port_op != PF_OP_EQ && r->dst.port_op != PF_OP_RRG) { + yyerror("invalid port operator for rdr destination port"); + problems++; + } + return (-problems); +} + +int +process_tabledef(char *name, struct table_opts *opts) +{ + struct pfr_buffer ab; + struct node_tinit *ti; + + bzero(&ab, sizeof(ab)); + ab.pfrb_type = PFRB_ADDRS; + SIMPLEQ_FOREACH(ti, &opts->init_nodes, entries) { + if (ti->file) + if (pfr_buf_load(&ab, ti->file, 0, append_addr)) { + if (errno) + yyerror("cannot load \"%s\": %s", + ti->file, strerror(errno)); + else + yyerror("file \"%s\" contains bad data", + ti->file); + goto _error; + } + if (ti->host) + if (append_addr_host(&ab, ti->host, 0, 0)) { + yyerror("cannot create address buffer: %s", + strerror(errno)); + goto _error; + } + } + if (pf->opts & PF_OPT_VERBOSE) + print_tabledef(name, opts->flags, opts->init_addr, + &opts->init_nodes); + if (!(pf->opts & PF_OPT_NOACTION) && + pfctl_define_table(name, opts->flags, opts->init_addr, + pf->anchor->name, &ab, pf->anchor->ruleset.tticket)) { + yyerror("cannot define table %s: %s", name, + pfr_strerror(errno)); + goto _error; + } + pf->tdirty = 1; + pfr_buf_clear(&ab); + return (0); +_error: + pfr_buf_clear(&ab); + return (-1); +} + +struct keywords { + const char *k_name; + int k_val; +}; + +/* macro gore, but you should've seen the prior indentation nightmare... */ + +#define FREE_LIST(T,r) \ + do { \ + T *p, *node = r; \ + while (node != NULL) { \ + p = node; \ + node = node->next; \ + free(p); \ + } \ + } while (0) + +#define LOOP_THROUGH(T,n,r,C) \ + do { \ + T *n; \ + if (r == NULL) { \ + r = calloc(1, sizeof(T)); \ + if (r == NULL) \ + err(1, "LOOP: calloc"); \ + r->next = NULL; \ + } \ + n = r; \ + while (n != NULL) { \ + do { \ + C; \ + } while (0); \ + n = n->next; \ + } \ + } while (0) + +void +expand_label_str(char *label, size_t len, const char *srch, const char *repl) +{ + char *tmp; + char *p, *q; + + if ((tmp = calloc(1, len)) == NULL) + err(1, "expand_label_str: calloc"); + p = q = label; + while ((q = strstr(p, srch)) != NULL) { + *q = '\0'; + if ((strlcat(tmp, p, len) >= len) || + (strlcat(tmp, repl, len) >= len)) + errx(1, "expand_label: label too long"); + q += strlen(srch); + p = q; + } + if (strlcat(tmp, p, len) >= len) + errx(1, "expand_label: label too long"); + strlcpy(label, tmp, len); /* always fits */ + free(tmp); +} + +void +expand_label_if(const char *name, char *label, size_t len, const char *ifname) +{ + if (strstr(label, name) != NULL) { + if (!*ifname) + expand_label_str(label, len, name, "any"); + else + expand_label_str(label, len, name, ifname); + } +} + +void +expand_label_addr(const char *name, char *label, size_t len, sa_family_t af, + struct node_host *h) +{ + char tmp[64], tmp_not[66]; + + if (strstr(label, name) != NULL) { + switch (h->addr.type) { + case PF_ADDR_DYNIFTL: + snprintf(tmp, sizeof(tmp), "(%s)", h->addr.v.ifname); + break; + case PF_ADDR_TABLE: + snprintf(tmp, sizeof(tmp), "<%s>", h->addr.v.tblname); + break; + case PF_ADDR_NOROUTE: + snprintf(tmp, sizeof(tmp), "no-route"); + break; + case PF_ADDR_URPFFAILED: + snprintf(tmp, sizeof(tmp), "urpf-failed"); + break; + case PF_ADDR_ADDRMASK: + if (!af || (PF_AZERO(&h->addr.v.a.addr, af) && + PF_AZERO(&h->addr.v.a.mask, af))) + snprintf(tmp, sizeof(tmp), "any"); + else { + char a[48]; + int bits; + + if (inet_ntop(af, &h->addr.v.a.addr, a, + sizeof(a)) == NULL) + snprintf(tmp, sizeof(tmp), "?"); + else { + bits = unmask(&h->addr.v.a.mask, af); + if ((af == AF_INET && bits < 32) || + (af == AF_INET6 && bits < 128)) + snprintf(tmp, sizeof(tmp), + "%s/%d", a, bits); + else + snprintf(tmp, sizeof(tmp), + "%s", a); + } + } + break; + default: + snprintf(tmp, sizeof(tmp), "?"); + break; + } + + if (h->not) { + snprintf(tmp_not, sizeof(tmp_not), "! %s", tmp); + expand_label_str(label, len, name, tmp_not); + } else + expand_label_str(label, len, name, tmp); + } +} + +void +expand_label_port(const char *name, char *label, size_t len, + struct node_port *port) +{ + char a1[6], a2[6], op[13] = ""; + + if (strstr(label, name) != NULL) { + snprintf(a1, sizeof(a1), "%u", ntohs(port->port[0])); + snprintf(a2, sizeof(a2), "%u", ntohs(port->port[1])); + if (!port->op) + ; + else if (port->op == PF_OP_IRG) + snprintf(op, sizeof(op), "%s><%s", a1, a2); + else if (port->op == PF_OP_XRG) + snprintf(op, sizeof(op), "%s<>%s", a1, a2); + else if (port->op == PF_OP_EQ) + snprintf(op, sizeof(op), "%s", a1); + else if (port->op == PF_OP_NE) + snprintf(op, sizeof(op), "!=%s", a1); + else if (port->op == PF_OP_LT) + snprintf(op, sizeof(op), "<%s", a1); + else if (port->op == PF_OP_LE) + snprintf(op, sizeof(op), "<=%s", a1); + else if (port->op == PF_OP_GT) + snprintf(op, sizeof(op), ">%s", a1); + else if (port->op == PF_OP_GE) + snprintf(op, sizeof(op), ">=%s", a1); + expand_label_str(label, len, name, op); + } +} + +void +expand_label_proto(const char *name, char *label, size_t len, u_int8_t proto) +{ + struct protoent *pe; + char n[4]; + + if (strstr(label, name) != NULL) { + pe = getprotobynumber(proto); + if (pe != NULL) + expand_label_str(label, len, name, pe->p_name); + else { + snprintf(n, sizeof(n), "%u", proto); + expand_label_str(label, len, name, n); + } + } +} + +void +expand_label_nr(const char *name, char *label, size_t len) +{ + char n[11]; + + if (strstr(label, name) != NULL) { + snprintf(n, sizeof(n), "%u", pf->anchor->match); + expand_label_str(label, len, name, n); + } +} + +void +expand_label(char *label, size_t len, const char *ifname, sa_family_t af, + struct node_host *src_host, struct node_port *src_port, + struct node_host *dst_host, struct node_port *dst_port, + u_int8_t proto) +{ + expand_label_if("$if", label, len, ifname); + expand_label_addr("$srcaddr", label, len, af, src_host); + expand_label_addr("$dstaddr", label, len, af, dst_host); + expand_label_port("$srcport", label, len, src_port); + expand_label_port("$dstport", label, len, dst_port); + expand_label_proto("$proto", label, len, proto); + expand_label_nr("$nr", label, len); +} + +int +expand_altq(struct pf_altq *a, struct node_if *interfaces, + struct node_queue *nqueues, struct node_queue_bw bwspec, + struct node_queue_opt *opts) +{ + struct pf_altq pa, pb; + char qname[PF_QNAME_SIZE]; + struct node_queue *n; + struct node_queue_bw bw; + int errs = 0; + + if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { + FREE_LIST(struct node_if, interfaces); + if (nqueues) + FREE_LIST(struct node_queue, nqueues); + return (0); + } + + LOOP_THROUGH(struct node_if, interface, interfaces, + memcpy(&pa, a, sizeof(struct pf_altq)); + if (strlcpy(pa.ifname, interface->ifname, + sizeof(pa.ifname)) >= sizeof(pa.ifname)) + errx(1, "expand_altq: strlcpy"); + + if (interface->not) { + yyerror("altq on ! <interface> is not supported"); + errs++; + } else { + if (eval_pfaltq(pf, &pa, &bwspec, opts)) + errs++; + else + if (pfctl_add_altq(pf, &pa)) + errs++; + + if (pf->opts & PF_OPT_VERBOSE) { + print_altq(&pf->paltq->altq, 0, + &bwspec, opts); + if (nqueues && nqueues->tail) { + printf("queue { "); + LOOP_THROUGH(struct node_queue, queue, + nqueues, + printf("%s ", + queue->queue); + ); + printf("}"); + } + printf("\n"); + } + + if (pa.scheduler == ALTQT_CBQ || + pa.scheduler == ALTQT_HFSC) { + /* now create a root queue */ + memset(&pb, 0, sizeof(struct pf_altq)); + if (strlcpy(qname, "root_", sizeof(qname)) >= + sizeof(qname)) + errx(1, "expand_altq: strlcpy"); + if (strlcat(qname, interface->ifname, + sizeof(qname)) >= sizeof(qname)) + errx(1, "expand_altq: strlcat"); + if (strlcpy(pb.qname, qname, + sizeof(pb.qname)) >= sizeof(pb.qname)) + errx(1, "expand_altq: strlcpy"); + if (strlcpy(pb.ifname, interface->ifname, + sizeof(pb.ifname)) >= sizeof(pb.ifname)) + errx(1, "expand_altq: strlcpy"); + pb.qlimit = pa.qlimit; + pb.scheduler = pa.scheduler; + bw.bw_absolute = pa.ifbandwidth; + bw.bw_percent = 0; + if (eval_pfqueue(pf, &pb, &bw, opts)) + errs++; + else + if (pfctl_add_altq(pf, &pb)) + errs++; + } + + LOOP_THROUGH(struct node_queue, queue, nqueues, + n = calloc(1, sizeof(struct node_queue)); + if (n == NULL) + err(1, "expand_altq: calloc"); + if (pa.scheduler == ALTQT_CBQ || + pa.scheduler == ALTQT_HFSC) + if (strlcpy(n->parent, qname, + sizeof(n->parent)) >= + sizeof(n->parent)) + errx(1, "expand_altq: strlcpy"); + if (strlcpy(n->queue, queue->queue, + sizeof(n->queue)) >= sizeof(n->queue)) + errx(1, "expand_altq: strlcpy"); + if (strlcpy(n->ifname, interface->ifname, + sizeof(n->ifname)) >= sizeof(n->ifname)) + errx(1, "expand_altq: strlcpy"); + n->scheduler = pa.scheduler; + n->next = NULL; + n->tail = n; + if (queues == NULL) + queues = n; + else { + queues->tail->next = n; + queues->tail = n; + } + ); + } + ); + FREE_LIST(struct node_if, interfaces); + if (nqueues) + FREE_LIST(struct node_queue, nqueues); + + return (errs); +} + +int +expand_queue(struct pf_altq *a, struct node_if *interfaces, + struct node_queue *nqueues, struct node_queue_bw bwspec, + struct node_queue_opt *opts) +{ + struct node_queue *n, *nq; + struct pf_altq pa; + u_int8_t found = 0; + u_int8_t errs = 0; + + if ((pf->loadopt & PFCTL_FLAG_ALTQ) == 0) { + FREE_LIST(struct node_queue, nqueues); + return (0); + } + + if (queues == NULL) { + yyerror("queue %s has no parent", a->qname); + FREE_LIST(struct node_queue, nqueues); + return (1); + } + + LOOP_THROUGH(struct node_if, interface, interfaces, + LOOP_THROUGH(struct node_queue, tqueue, queues, + if (!strncmp(a->qname, tqueue->queue, PF_QNAME_SIZE) && + (interface->ifname[0] == 0 || + (!interface->not && !strncmp(interface->ifname, + tqueue->ifname, IFNAMSIZ)) || + (interface->not && strncmp(interface->ifname, + tqueue->ifname, IFNAMSIZ)))) { + /* found ourself in queues */ + found++; + + memcpy(&pa, a, sizeof(struct pf_altq)); + + if (pa.scheduler != ALTQT_NONE && + pa.scheduler != tqueue->scheduler) { + yyerror("exactly one scheduler type " + "per interface allowed"); + return (1); + } + pa.scheduler = tqueue->scheduler; + + /* scheduler dependent error checking */ + switch (pa.scheduler) { + case ALTQT_PRIQ: + if (nqueues != NULL) { + yyerror("priq queues cannot " + "have child queues"); + return (1); + } + if (bwspec.bw_absolute > 0 || + bwspec.bw_percent < 100) { + yyerror("priq doesn't take " + "bandwidth"); + return (1); + } + break; + default: + break; + } + + if (strlcpy(pa.ifname, tqueue->ifname, + sizeof(pa.ifname)) >= sizeof(pa.ifname)) + errx(1, "expand_queue: strlcpy"); + if (strlcpy(pa.parent, tqueue->parent, + sizeof(pa.parent)) >= sizeof(pa.parent)) + errx(1, "expand_queue: strlcpy"); + + if (eval_pfqueue(pf, &pa, &bwspec, opts)) + errs++; + else + if (pfctl_add_altq(pf, &pa)) + errs++; + + for (nq = nqueues; nq != NULL; nq = nq->next) { + if (!strcmp(a->qname, nq->queue)) { + yyerror("queue cannot have " + "itself as child"); + errs++; + continue; + } + n = calloc(1, + sizeof(struct node_queue)); + if (n == NULL) + err(1, "expand_queue: calloc"); + if (strlcpy(n->parent, a->qname, + sizeof(n->parent)) >= + sizeof(n->parent)) + errx(1, "expand_queue strlcpy"); + if (strlcpy(n->queue, nq->queue, + sizeof(n->queue)) >= + sizeof(n->queue)) + errx(1, "expand_queue strlcpy"); + if (strlcpy(n->ifname, tqueue->ifname, + sizeof(n->ifname)) >= + sizeof(n->ifname)) + errx(1, "expand_queue strlcpy"); + n->scheduler = tqueue->scheduler; + n->next = NULL; + n->tail = n; + if (queues == NULL) + queues = n; + else { + queues->tail->next = n; + queues->tail = n; + } + } + if ((pf->opts & PF_OPT_VERBOSE) && ( + (found == 1 && interface->ifname[0] == 0) || + (found > 0 && interface->ifname[0] != 0))) { + print_queue(&pf->paltq->altq, 0, + &bwspec, interface->ifname[0] != 0, + opts); + if (nqueues && nqueues->tail) { + printf("{ "); + LOOP_THROUGH(struct node_queue, + queue, nqueues, + printf("%s ", + queue->queue); + ); + printf("}"); + } + printf("\n"); + } + } + ); + ); + + FREE_LIST(struct node_queue, nqueues); + FREE_LIST(struct node_if, interfaces); + + if (!found) { + yyerror("queue %s has no parent", a->qname); + errs++; + } + + if (errs) + return (1); + else + return (0); +} + +void +expand_rule(struct pf_rule *r, + struct node_if *interfaces, struct node_host *rpool_hosts, + struct node_proto *protos, struct node_os *src_oses, + struct node_host *src_hosts, struct node_port *src_ports, + struct node_host *dst_hosts, struct node_port *dst_ports, + struct node_uid *uids, struct node_gid *gids, struct node_icmp *icmp_types, + const char *anchor_call) +{ + sa_family_t af = r->af; + int added = 0, error = 0; + char ifname[IF_NAMESIZE]; + char label[PF_RULE_LABEL_SIZE]; + char tagname[PF_TAG_NAME_SIZE]; + char match_tagname[PF_TAG_NAME_SIZE]; + struct pf_pooladdr *pa; + struct node_host *h; + u_int8_t flags, flagset, keep_state; + + if (strlcpy(label, r->label, sizeof(label)) >= sizeof(label)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(tagname, r->tagname, sizeof(tagname)) >= sizeof(tagname)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(match_tagname, r->match_tagname, sizeof(match_tagname)) >= + sizeof(match_tagname)) + errx(1, "expand_rule: strlcpy"); + flags = r->flags; + flagset = r->flagset; + keep_state = r->keep_state; + + LOOP_THROUGH(struct node_if, interface, interfaces, + LOOP_THROUGH(struct node_proto, proto, protos, + LOOP_THROUGH(struct node_icmp, icmp_type, icmp_types, + LOOP_THROUGH(struct node_host, src_host, src_hosts, + LOOP_THROUGH(struct node_port, src_port, src_ports, + LOOP_THROUGH(struct node_os, src_os, src_oses, + LOOP_THROUGH(struct node_host, dst_host, dst_hosts, + LOOP_THROUGH(struct node_port, dst_port, dst_ports, + LOOP_THROUGH(struct node_uid, uid, uids, + LOOP_THROUGH(struct node_gid, gid, gids, + + r->af = af; + /* for link-local IPv6 address, interface must match up */ + if ((r->af && src_host->af && r->af != src_host->af) || + (r->af && dst_host->af && r->af != dst_host->af) || + (src_host->af && dst_host->af && + src_host->af != dst_host->af) || + (src_host->ifindex && dst_host->ifindex && + src_host->ifindex != dst_host->ifindex) || + (src_host->ifindex && *interface->ifname && + src_host->ifindex != if_nametoindex(interface->ifname)) || + (dst_host->ifindex && *interface->ifname && + dst_host->ifindex != if_nametoindex(interface->ifname))) + continue; + if (!r->af && src_host->af) + r->af = src_host->af; + else if (!r->af && dst_host->af) + r->af = dst_host->af; + + if (*interface->ifname) + strlcpy(r->ifname, interface->ifname, + sizeof(r->ifname)); + else if (if_indextoname(src_host->ifindex, ifname)) + strlcpy(r->ifname, ifname, sizeof(r->ifname)); + else if (if_indextoname(dst_host->ifindex, ifname)) + strlcpy(r->ifname, ifname, sizeof(r->ifname)); + else + memset(r->ifname, '\0', sizeof(r->ifname)); + + if (strlcpy(r->label, label, sizeof(r->label)) >= + sizeof(r->label)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(r->tagname, tagname, sizeof(r->tagname)) >= + sizeof(r->tagname)) + errx(1, "expand_rule: strlcpy"); + if (strlcpy(r->match_tagname, match_tagname, + sizeof(r->match_tagname)) >= sizeof(r->match_tagname)) + errx(1, "expand_rule: strlcpy"); + expand_label(r->label, PF_RULE_LABEL_SIZE, r->ifname, r->af, + src_host, src_port, dst_host, dst_port, proto->proto); + expand_label(r->tagname, PF_TAG_NAME_SIZE, r->ifname, r->af, + src_host, src_port, dst_host, dst_port, proto->proto); + expand_label(r->match_tagname, PF_TAG_NAME_SIZE, r->ifname, + r->af, src_host, src_port, dst_host, dst_port, + proto->proto); + + error += check_netmask(src_host, r->af); + error += check_netmask(dst_host, r->af); + + r->ifnot = interface->not; + r->proto = proto->proto; + r->src.addr = src_host->addr; + r->src.neg = src_host->not; + r->src.port[0] = src_port->port[0]; + r->src.port[1] = src_port->port[1]; + r->src.port_op = src_port->op; + r->dst.addr = dst_host->addr; + r->dst.neg = dst_host->not; + r->dst.port[0] = dst_port->port[0]; + r->dst.port[1] = dst_port->port[1]; + r->dst.port_op = dst_port->op; + r->uid.op = uid->op; + r->uid.uid[0] = uid->uid[0]; + r->uid.uid[1] = uid->uid[1]; + r->gid.op = gid->op; + r->gid.gid[0] = gid->gid[0]; + r->gid.gid[1] = gid->gid[1]; + r->type = icmp_type->type; + r->code = icmp_type->code; + + if ((keep_state == PF_STATE_MODULATE || + keep_state == PF_STATE_SYNPROXY) && + r->proto && r->proto != IPPROTO_TCP) + r->keep_state = PF_STATE_NORMAL; + else + r->keep_state = keep_state; + + if (r->proto && r->proto != IPPROTO_TCP) { + r->flags = 0; + r->flagset = 0; + } else { + r->flags = flags; + r->flagset = flagset; + } + if (icmp_type->proto && r->proto != icmp_type->proto) { + yyerror("icmp-type mismatch"); + error++; + } + + if (src_os && src_os->os) { + r->os_fingerprint = pfctl_get_fingerprint(src_os->os); + if ((pf->opts & PF_OPT_VERBOSE2) && + r->os_fingerprint == PF_OSFP_NOMATCH) + fprintf(stderr, + "warning: unknown '%s' OS fingerprint\n", + src_os->os); + } else { + r->os_fingerprint = PF_OSFP_ANY; + } + + TAILQ_INIT(&r->rpool.list); + for (h = rpool_hosts; h != NULL; h = h->next) { + pa = calloc(1, sizeof(struct pf_pooladdr)); + if (pa == NULL) + err(1, "expand_rule: calloc"); + pa->addr = h->addr; + if (h->ifname != NULL) { + if (strlcpy(pa->ifname, h->ifname, + sizeof(pa->ifname)) >= + sizeof(pa->ifname)) + errx(1, "expand_rule: strlcpy"); + } else + pa->ifname[0] = 0; + TAILQ_INSERT_TAIL(&r->rpool.list, pa, entries); + } + + if (rule_consistent(r, anchor_call[0]) < 0 || error) + yyerror("skipping rule due to errors"); + else { + r->nr = pf->astack[pf->asd]->match++; + pfctl_add_rule(pf, r, anchor_call); + added++; + } + + )))))))))); + + FREE_LIST(struct node_if, interfaces); + FREE_LIST(struct node_proto, protos); + FREE_LIST(struct node_host, src_hosts); + FREE_LIST(struct node_port, src_ports); + FREE_LIST(struct node_os, src_oses); + FREE_LIST(struct node_host, dst_hosts); + FREE_LIST(struct node_port, dst_ports); + FREE_LIST(struct node_uid, uids); + FREE_LIST(struct node_gid, gids); + FREE_LIST(struct node_icmp, icmp_types); + FREE_LIST(struct node_host, rpool_hosts); + + if (!added) + yyerror("rule expands to no valid combination"); +} + +int +expand_skip_interface(struct node_if *interfaces) +{ + int errs = 0; + + if (!interfaces || (!interfaces->next && !interfaces->not && + !strcmp(interfaces->ifname, "none"))) { + if (pf->opts & PF_OPT_VERBOSE) + printf("set skip on none\n"); + errs = pfctl_set_interface_flags(pf, "", PFI_IFLAG_SKIP, 0); + return (errs); + } + + if (pf->opts & PF_OPT_VERBOSE) + printf("set skip on {"); + LOOP_THROUGH(struct node_if, interface, interfaces, + if (pf->opts & PF_OPT_VERBOSE) + printf(" %s", interface->ifname); + if (interface->not) { + yyerror("skip on ! <interface> is not supported"); + errs++; + } else + errs += pfctl_set_interface_flags(pf, + interface->ifname, PFI_IFLAG_SKIP, 1); + ); + if (pf->opts & PF_OPT_VERBOSE) + printf(" }\n"); + + FREE_LIST(struct node_if, interfaces); + + if (errs) + return (1); + else + return (0); +} + +#undef FREE_LIST +#undef LOOP_THROUGH + +int +check_rulestate(int desired_state) +{ + if (require_order && (rulestate > desired_state)) { + yyerror("Rules must be in order: options, normalization, " + "queueing, translation, filtering"); + return (1); + } + rulestate = desired_state; + return (0); +} + +int +kw_cmp(const void *k, const void *e) +{ + return (strcmp(k, ((const struct keywords *)e)->k_name)); +} + +int +lookup(char *s) +{ + /* this has to be sorted always */ + static const struct keywords keywords[] = { + { "all", ALL}, + { "allow-opts", ALLOWOPTS}, + { "altq", ALTQ}, + { "anchor", ANCHOR}, + { "antispoof", ANTISPOOF}, + { "any", ANY}, + { "bandwidth", BANDWIDTH}, + { "binat", BINAT}, + { "binat-anchor", BINATANCHOR}, + { "bitmask", BITMASK}, + { "block", BLOCK}, + { "block-policy", BLOCKPOLICY}, + { "buckets", BUCKETS}, + { "cbq", CBQ}, + { "code", CODE}, + { "codelq", CODEL}, + { "crop", FRAGCROP}, + { "debug", DEBUG}, + { "divert-reply", DIVERTREPLY}, + { "divert-to", DIVERTTO}, + { "drop", DROP}, + { "drop-ovl", FRAGDROP}, + { "dup-to", DUPTO}, + { "fairq", FAIRQ}, + { "fastroute", FASTROUTE}, + { "file", FILENAME}, + { "fingerprints", FINGERPRINTS}, + { "flags", FLAGS}, + { "floating", FLOATING}, + { "flush", FLUSH}, + { "for", FOR}, + { "fragment", FRAGMENT}, + { "from", FROM}, + { "global", GLOBAL}, + { "group", GROUP}, + { "hfsc", HFSC}, + { "hogs", HOGS}, + { "hostid", HOSTID}, + { "icmp-type", ICMPTYPE}, + { "icmp6-type", ICMP6TYPE}, + { "if-bound", IFBOUND}, + { "in", IN}, + { "include", INCLUDE}, + { "inet", INET}, + { "inet6", INET6}, + { "interval", INTERVAL}, + { "keep", KEEP}, + { "label", LABEL}, + { "limit", LIMIT}, + { "linkshare", LINKSHARE}, + { "load", LOAD}, + { "log", LOG}, + { "loginterface", LOGINTERFACE}, + { "max", MAXIMUM}, + { "max-mss", MAXMSS}, + { "max-src-conn", MAXSRCCONN}, + { "max-src-conn-rate", MAXSRCCONNRATE}, + { "max-src-nodes", MAXSRCNODES}, + { "max-src-states", MAXSRCSTATES}, + { "min-ttl", MINTTL}, + { "modulate", MODULATE}, + { "nat", NAT}, + { "nat-anchor", NATANCHOR}, + { "no", NO}, + { "no-df", NODF}, + { "no-route", NOROUTE}, + { "no-sync", NOSYNC}, + { "on", ON}, + { "optimization", OPTIMIZATION}, + { "os", OS}, + { "out", OUT}, + { "overload", OVERLOAD}, + { "pass", PASS}, + { "port", PORT}, + { "prio", PRIO}, + { "priority", PRIORITY}, + { "priq", PRIQ}, + { "probability", PROBABILITY}, + { "proto", PROTO}, + { "qlimit", QLIMIT}, + { "queue", QUEUE}, + { "quick", QUICK}, + { "random", RANDOM}, + { "random-id", RANDOMID}, + { "rdr", RDR}, + { "rdr-anchor", RDRANCHOR}, + { "realtime", REALTIME}, + { "reassemble", REASSEMBLE}, + { "reply-to", REPLYTO}, + { "require-order", REQUIREORDER}, + { "return", RETURN}, + { "return-icmp", RETURNICMP}, + { "return-icmp6", RETURNICMP6}, + { "return-rst", RETURNRST}, + { "round-robin", ROUNDROBIN}, + { "route", ROUTE}, + { "route-to", ROUTETO}, + { "rtable", RTABLE}, + { "rule", RULE}, + { "ruleset-optimization", RULESET_OPTIMIZATION}, + { "scrub", SCRUB}, + { "set", SET}, + { "set-tos", SETTOS}, + { "skip", SKIP}, + { "sloppy", SLOPPY}, + { "source-hash", SOURCEHASH}, + { "source-track", SOURCETRACK}, + { "state", STATE}, + { "state-defaults", STATEDEFAULTS}, + { "state-policy", STATEPOLICY}, + { "static-port", STATICPORT}, + { "sticky-address", STICKYADDRESS}, + { "synproxy", SYNPROXY}, + { "table", TABLE}, + { "tag", TAG}, + { "tagged", TAGGED}, + { "target", TARGET}, + { "tbrsize", TBRSIZE}, + { "timeout", TIMEOUT}, + { "to", TO}, + { "tos", TOS}, + { "ttl", TTL}, + { "upperlimit", UPPERLIMIT}, + { "urpf-failed", URPFFAILED}, + { "user", USER}, + }; + const struct keywords *p; + + p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), + sizeof(keywords[0]), kw_cmp); + + if (p) { + if (debug > 1) + fprintf(stderr, "%s: %d\n", s, p->k_val); + return (p->k_val); + } else { + if (debug > 1) + fprintf(stderr, "string: %s\n", s); + return (STRING); + } +} + +#define MAXPUSHBACK 128 + +static char *parsebuf; +static int parseindex; +static char pushback_buffer[MAXPUSHBACK]; +static int pushback_index = 0; + +int +lgetc(int quotec) +{ + int c, next; + + if (parsebuf) { + /* Read character from the parsebuffer instead of input. */ + if (parseindex >= 0) { + c = parsebuf[parseindex++]; + if (c != '\0') + return (c); + parsebuf = NULL; + } else + parseindex++; + } + + if (pushback_index) + return (pushback_buffer[--pushback_index]); + + if (quotec) { + if ((c = getc(file->stream)) == EOF) { + yyerror("reached end of file while parsing quoted string"); + if (popfile() == EOF) + return (EOF); + return (quotec); + } + return (c); + } + + while ((c = getc(file->stream)) == '\\') { + next = getc(file->stream); + if (next != '\n') { + c = next; + break; + } + yylval.lineno = file->lineno; + file->lineno++; + } + + while (c == EOF) { + if (popfile() == EOF) + return (EOF); + c = getc(file->stream); + } + return (c); +} + +int +lungetc(int c) +{ + if (c == EOF) + return (EOF); + if (parsebuf) { + parseindex--; + if (parseindex >= 0) + return (c); + } + if (pushback_index < MAXPUSHBACK-1) + return (pushback_buffer[pushback_index++] = c); + else + return (EOF); +} + +int +findeol(void) +{ + int c; + + parsebuf = NULL; + + /* skip to either EOF or the first real EOL */ + while (1) { + if (pushback_index) + c = pushback_buffer[--pushback_index]; + else + c = lgetc(0); + if (c == '\n') { + file->lineno++; + break; + } + if (c == EOF) + break; + } + return (ERROR); +} + +int +yylex(void) +{ + char buf[8096]; + char *p, *val; + int quotec, next, c; + int token; + +top: + p = buf; + while ((c = lgetc(0)) == ' ' || c == '\t') + ; /* nothing */ + + yylval.lineno = file->lineno; + if (c == '#') + while ((c = lgetc(0)) != '\n' && c != EOF) + ; /* nothing */ + if (c == '$' && parsebuf == NULL) { + while (1) { + if ((c = lgetc(0)) == EOF) + return (0); + + if (p + 1 >= buf + sizeof(buf) - 1) { + yyerror("string too long"); + return (findeol()); + } + if (isalnum(c) || c == '_') { + *p++ = (char)c; + continue; + } + *p = '\0'; + lungetc(c); + break; + } + val = symget(buf); + if (val == NULL) { + yyerror("macro '%s' not defined", buf); + return (findeol()); + } + parsebuf = val; + parseindex = 0; + goto top; + } + + switch (c) { + case '\'': + case '"': + quotec = c; + while (1) { + if ((c = lgetc(quotec)) == EOF) + return (0); + if (c == '\n') { + file->lineno++; + continue; + } else if (c == '\\') { + if ((next = lgetc(quotec)) == EOF) + return (0); + if (next == quotec || c == ' ' || c == '\t') + c = next; + else if (next == '\n') + continue; + else + lungetc(next); + } else if (c == quotec) { + *p = '\0'; + break; + } + if (p + 1 >= buf + sizeof(buf) - 1) { + yyerror("string too long"); + return (findeol()); + } + *p++ = (char)c; + } + yylval.v.string = strdup(buf); + if (yylval.v.string == NULL) + err(1, "yylex: strdup"); + return (STRING); + case '<': + next = lgetc(0); + if (next == '>') { + yylval.v.i = PF_OP_XRG; + return (PORTBINARY); + } + lungetc(next); + break; + case '>': + next = lgetc(0); + if (next == '<') { + yylval.v.i = PF_OP_IRG; + return (PORTBINARY); + } + lungetc(next); + break; + case '-': + next = lgetc(0); + if (next == '>') + return (ARROW); + lungetc(next); + break; + } + +#define allowed_to_end_number(x) \ + (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') + + if (c == '-' || isdigit(c)) { + do { + *p++ = c; + if ((unsigned)(p-buf) >= sizeof(buf)) { + yyerror("string too long"); + return (findeol()); + } + } while ((c = lgetc(0)) != EOF && isdigit(c)); + lungetc(c); + if (p == buf + 1 && buf[0] == '-') + goto nodigits; + if (c == EOF || allowed_to_end_number(c)) { + const char *errstr = NULL; + + *p = '\0'; + yylval.v.number = strtonum(buf, LLONG_MIN, + LLONG_MAX, &errstr); + if (errstr) { + yyerror("\"%s\" invalid number: %s", + buf, errstr); + return (findeol()); + } + return (NUMBER); + } else { +nodigits: + while (p > buf + 1) + lungetc(*--p); + c = *--p; + if (c == '-') + return (c); + } + } + +#define allowed_in_string(x) \ + (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ + x != '{' && x != '}' && x != '<' && x != '>' && \ + x != '!' && x != '=' && x != '/' && x != '#' && \ + x != ',')) + + if (isalnum(c) || c == ':' || c == '_') { + do { + *p++ = c; + if ((unsigned)(p-buf) >= sizeof(buf)) { + yyerror("string too long"); + return (findeol()); + } + } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); + lungetc(c); + *p = '\0'; + if ((token = lookup(buf)) == STRING) + if ((yylval.v.string = strdup(buf)) == NULL) + err(1, "yylex: strdup"); + return (token); + } + if (c == '\n') { + yylval.lineno = file->lineno; + file->lineno++; + } + if (c == EOF) + return (0); + return (c); +} + +int +check_file_secrecy(int fd, const char *fname) +{ + struct stat st; + + if (fstat(fd, &st)) { + warn("cannot stat %s", fname); + return (-1); + } + if (st.st_uid != 0 && st.st_uid != getuid()) { + warnx("%s: owner not root or current user", fname); + return (-1); + } + if (st.st_mode & (S_IRWXG | S_IRWXO)) { + warnx("%s: group/world readable/writeable", fname); + return (-1); + } + return (0); +} + +struct file * +pushfile(const char *name, int secret) +{ + struct file *nfile; + + if ((nfile = calloc(1, sizeof(struct file))) == NULL || + (nfile->name = strdup(name)) == NULL) { + warn("malloc"); + return (NULL); + } + if (TAILQ_FIRST(&files) == NULL && strcmp(nfile->name, "-") == 0) { + nfile->stream = stdin; + free(nfile->name); + if ((nfile->name = strdup("stdin")) == NULL) { + warn("strdup"); + free(nfile); + return (NULL); + } + } else if ((nfile->stream = fopen(nfile->name, "r")) == NULL) { + warn("%s", nfile->name); + free(nfile->name); + free(nfile); + return (NULL); + } else if (secret && + check_file_secrecy(fileno(nfile->stream), nfile->name)) { + fclose(nfile->stream); + free(nfile->name); + free(nfile); + return (NULL); + } + nfile->lineno = 1; + TAILQ_INSERT_TAIL(&files, nfile, entry); + return (nfile); +} + +int +popfile(void) +{ + struct file *prev; + + if ((prev = TAILQ_PREV(file, files, entry)) != NULL) { + prev->errors += file->errors; + TAILQ_REMOVE(&files, file, entry); + fclose(file->stream); + free(file->name); + free(file); + file = prev; + return (0); + } + return (EOF); +} + +int +parse_config(char *filename, struct pfctl *xpf) +{ + int errors = 0; + struct sym *sym; + + pf = xpf; + errors = 0; + rulestate = PFCTL_STATE_NONE; + returnicmpdefault = (ICMP_UNREACH << 8) | ICMP_UNREACH_PORT; + returnicmp6default = + (ICMP6_DST_UNREACH << 8) | ICMP6_DST_UNREACH_NOPORT; + blockpolicy = PFRULE_DROP; + require_order = 1; + + if ((file = pushfile(filename, 0)) == NULL) { + warn("cannot open the main config file!"); + return (-1); + } + + yyparse(); + errors = file->errors; + popfile(); + + /* Free macros and check which have not been used. */ + while ((sym = TAILQ_FIRST(&symhead))) { + if ((pf->opts & PF_OPT_VERBOSE2) && !sym->used) + fprintf(stderr, "warning: macro '%s' not " + "used\n", sym->nam); + free(sym->nam); + free(sym->val); + TAILQ_REMOVE(&symhead, sym, entry); + free(sym); + } + + return (errors ? -1 : 0); +} + +int +symset(const char *nam, const char *val, int persist) +{ + struct sym *sym; + + for (sym = TAILQ_FIRST(&symhead); sym && strcmp(nam, sym->nam); + sym = TAILQ_NEXT(sym, entry)) + ; /* nothing */ + + if (sym != NULL) { + if (sym->persist == 1) + return (0); + else { + free(sym->nam); + free(sym->val); + TAILQ_REMOVE(&symhead, sym, entry); + free(sym); + } + } + if ((sym = calloc(1, sizeof(*sym))) == NULL) + return (-1); + + sym->nam = strdup(nam); + if (sym->nam == NULL) { + free(sym); + return (-1); + } + sym->val = strdup(val); + if (sym->val == NULL) { + free(sym->nam); + free(sym); + return (-1); + } + sym->used = 0; + sym->persist = persist; + TAILQ_INSERT_TAIL(&symhead, sym, entry); + return (0); +} + +int +pfctl_cmdline_symset(char *s) +{ + char *sym, *val; + int ret; + + if ((val = strrchr(s, '=')) == NULL) + return (-1); + + if ((sym = malloc(strlen(s) - strlen(val) + 1)) == NULL) + err(1, "pfctl_cmdline_symset: malloc"); + + strlcpy(sym, s, strlen(s) - strlen(val) + 1); + + ret = symset(sym, val + 1, 1); + free(sym); + + return (ret); +} + +char * +symget(const char *nam) +{ + struct sym *sym; + + TAILQ_FOREACH(sym, &symhead, entry) + if (strcmp(nam, sym->nam) == 0) { + sym->used = 1; + return (sym->val); + } + return (NULL); +} + +void +mv_rules(struct pf_ruleset *src, struct pf_ruleset *dst) +{ + int i; + struct pf_rule *r; + + for (i = 0; i < PF_RULESET_MAX; ++i) { + while ((r = TAILQ_FIRST(src->rules[i].active.ptr)) + != NULL) { + TAILQ_REMOVE(src->rules[i].active.ptr, r, entries); + TAILQ_INSERT_TAIL(dst->rules[i].active.ptr, r, entries); + dst->anchor->match++; + } + src->anchor->match = 0; + while ((r = TAILQ_FIRST(src->rules[i].inactive.ptr)) + != NULL) { + TAILQ_REMOVE(src->rules[i].inactive.ptr, r, entries); + TAILQ_INSERT_TAIL(dst->rules[i].inactive.ptr, + r, entries); + } + } +} + +void +decide_address_family(struct node_host *n, sa_family_t *af) +{ + if (*af != 0 || n == NULL) + return; + *af = n->af; + while ((n = n->next) != NULL) { + if (n->af != *af) { + *af = 0; + return; + } + } +} + +void +remove_invalid_hosts(struct node_host **nh, sa_family_t *af) +{ + struct node_host *n = *nh, *prev = NULL; + + while (n != NULL) { + if (*af && n->af && n->af != *af) { + /* unlink and free n */ + struct node_host *next = n->next; + + /* adjust tail pointer */ + if (n == (*nh)->tail) + (*nh)->tail = prev; + /* adjust previous node's next pointer */ + if (prev == NULL) + *nh = next; + else + prev->next = next; + /* free node */ + if (n->ifname != NULL) + free(n->ifname); + free(n); + n = next; + } else { + if (n->af && !*af) + *af = n->af; + prev = n; + n = n->next; + } + } +} + +int +invalid_redirect(struct node_host *nh, sa_family_t af) +{ + if (!af) { + struct node_host *n; + + /* tables and dyniftl are ok without an address family */ + for (n = nh; n != NULL; n = n->next) { + if (n->addr.type != PF_ADDR_TABLE && + n->addr.type != PF_ADDR_DYNIFTL) { + yyerror("address family not given and " + "translation address expands to multiple " + "address families"); + return (1); + } + } + } + if (nh == NULL) { + yyerror("no translation address with matching address family " + "found."); + return (1); + } + return (0); +} + +int +atoul(char *s, u_long *ulvalp) +{ + u_long ulval; + char *ep; + + errno = 0; + ulval = strtoul(s, &ep, 0); + if (s[0] == '\0' || *ep != '\0') + return (-1); + if (errno == ERANGE && ulval == ULONG_MAX) + return (-1); + *ulvalp = ulval; + return (0); +} + +int +getservice(char *n) +{ + struct servent *s; + u_long ulval; + + if (atoul(n, &ulval) == 0) { + if (ulval > 65535) { + yyerror("illegal port value %lu", ulval); + return (-1); + } + return (htons(ulval)); + } else { + s = getservbyname(n, "tcp"); + if (s == NULL) + s = getservbyname(n, "udp"); + if (s == NULL) { + yyerror("unknown port %s", n); + return (-1); + } + return (s->s_port); + } +} + +int +rule_label(struct pf_rule *r, char *s) +{ + if (s) { + if (strlcpy(r->label, s, sizeof(r->label)) >= + sizeof(r->label)) { + yyerror("rule label too long (max %d chars)", + sizeof(r->label)-1); + return (-1); + } + } + return (0); +} + +u_int16_t +parseicmpspec(char *w, sa_family_t af) +{ + const struct icmpcodeent *p; + u_long ulval; + u_int8_t icmptype; + + if (af == AF_INET) + icmptype = returnicmpdefault >> 8; + else + icmptype = returnicmp6default >> 8; + + if (atoul(w, &ulval) == -1) { + if ((p = geticmpcodebyname(icmptype, w, af)) == NULL) { + yyerror("unknown icmp code %s", w); + return (0); + } + ulval = p->code; + } + if (ulval > 255) { + yyerror("invalid icmp code %lu", ulval); + return (0); + } + return (icmptype << 8 | ulval); +} + +int +parseport(char *port, struct range *r, int extensions) +{ + char *p = strchr(port, ':'); + + if (p == NULL) { + if ((r->a = getservice(port)) == -1) + return (-1); + r->b = 0; + r->t = PF_OP_NONE; + return (0); + } + if ((extensions & PPORT_STAR) && !strcmp(p+1, "*")) { + *p = 0; + if ((r->a = getservice(port)) == -1) + return (-1); + r->b = 0; + r->t = PF_OP_IRG; + return (0); + } + if ((extensions & PPORT_RANGE)) { + *p++ = 0; + if ((r->a = getservice(port)) == -1 || + (r->b = getservice(p)) == -1) + return (-1); + if (r->a == r->b) { + r->b = 0; + r->t = PF_OP_NONE; + } else + r->t = PF_OP_RRG; + return (0); + } + return (-1); +} + +int +pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans) +{ + struct loadanchors *la; + + TAILQ_FOREACH(la, &loadanchorshead, entries) { + if (pf->opts & PF_OPT_VERBOSE) + fprintf(stderr, "\nLoading anchor %s from %s\n", + la->anchorname, la->filename); + if (pfctl_rules(dev, la->filename, pf->opts, pf->optimize, + la->anchorname, trans) == -1) + return (-1); + } + + return (0); +} + +int +rt_tableid_max(void) +{ +#ifdef __FreeBSD__ + int fibs; + size_t l = sizeof(fibs); + + if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1) + fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */ + /* + * As the OpenBSD code only compares > and not >= we need to adjust + * here given we only accept values of 0..n and want to avoid #ifdefs + * in the grammar. + */ + return (fibs - 1); +#else + return (RT_TABLEID_MAX); +#endif +} diff --git a/freebsd/sbin/pfctl/pf_print_state.c b/freebsd/sbin/pfctl/pf_print_state.c new file mode 100644 index 00000000..1e09a01f --- /dev/null +++ b/freebsd/sbin/pfctl/pf_print_state.c @@ -0,0 +1,387 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ + +/* $OpenBSD: pf_print_state.c,v 1.52 2008/08/12 16:40:18 david Exp $ */ + +/* + * Copyright (c) 2001 Daniel Hartmeier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/endian.h> +#include <net/if.h> +#define TCPSTATES +#include <netinet/tcp_fsm.h> +#include <net/pfvar.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <stdint.h> +#include <stdio.h> +#include <string.h> + +#include "pfctl_parser.h" +#include "pfctl.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-pf_print_state-data.h" +#endif /* __rtems__ */ + +void print_name(struct pf_addr *, sa_family_t); + +void +print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose) +{ + switch (addr->type) { + case PF_ADDR_DYNIFTL: + printf("(%s", addr->v.ifname); + if (addr->iflags & PFI_AFLAG_NETWORK) + printf(":network"); + if (addr->iflags & PFI_AFLAG_BROADCAST) + printf(":broadcast"); + if (addr->iflags & PFI_AFLAG_PEER) + printf(":peer"); + if (addr->iflags & PFI_AFLAG_NOALIAS) + printf(":0"); + if (verbose) { + if (addr->p.dyncnt <= 0) + printf(":*"); + else + printf(":%d", addr->p.dyncnt); + } + printf(")"); + break; + case PF_ADDR_TABLE: + if (verbose) + if (addr->p.tblcnt == -1) + printf("<%s:*>", addr->v.tblname); + else + printf("<%s:%d>", addr->v.tblname, + addr->p.tblcnt); + else + printf("<%s>", addr->v.tblname); + return; + case PF_ADDR_RANGE: { + char buf[48]; + + if (inet_ntop(af, &addr->v.a.addr, buf, sizeof(buf)) == NULL) + printf("?"); + else + printf("%s", buf); + if (inet_ntop(af, &addr->v.a.mask, buf, sizeof(buf)) == NULL) + printf(" - ?"); + else + printf(" - %s", buf); + break; + } + case PF_ADDR_ADDRMASK: + if (PF_AZERO(&addr->v.a.addr, AF_INET6) && + PF_AZERO(&addr->v.a.mask, AF_INET6)) + printf("any"); + else { + char buf[48]; + + if (inet_ntop(af, &addr->v.a.addr, buf, + sizeof(buf)) == NULL) + printf("?"); + else + printf("%s", buf); + } + break; + case PF_ADDR_NOROUTE: + printf("no-route"); + return; + case PF_ADDR_URPFFAILED: + printf("urpf-failed"); + return; + default: + printf("?"); + return; + } + + /* mask if not _both_ address and mask are zero */ + if (addr->type != PF_ADDR_RANGE && + !(PF_AZERO(&addr->v.a.addr, AF_INET6) && + PF_AZERO(&addr->v.a.mask, AF_INET6))) { + int bits = unmask(&addr->v.a.mask, af); + + if (bits != (af == AF_INET ? 32 : 128)) + printf("/%d", bits); + } +} + +void +print_name(struct pf_addr *addr, sa_family_t af) +{ + char host[NI_MAXHOST]; + + strlcpy(host, "?", sizeof(host)); + switch (af) { + case AF_INET: { + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_addr = addr->v4; + getnameinfo((struct sockaddr *)&sin, sin.sin_len, + host, sizeof(host), NULL, 0, NI_NOFQDN); + break; + } + case AF_INET6: { + struct sockaddr_in6 sin6; + + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_len = sizeof(sin6); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = addr->v6; + getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, + host, sizeof(host), NULL, 0, NI_NOFQDN); + break; + } + } + printf("%s", host); +} + +void +print_host(struct pf_addr *addr, u_int16_t port, sa_family_t af, int opts) +{ + if (opts & PF_OPT_USEDNS) + print_name(addr, af); + else { + struct pf_addr_wrap aw; + + memset(&aw, 0, sizeof(aw)); + aw.v.a.addr = *addr; + if (af == AF_INET) + aw.v.a.mask.addr32[0] = 0xffffffff; + else { + memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); + af = AF_INET6; + } + print_addr(&aw, af, opts & PF_OPT_VERBOSE2); + } + + if (port) { + if (af == AF_INET) + printf(":%u", ntohs(port)); + else + printf("[%u]", ntohs(port)); + } +} + +void +print_seq(struct pfsync_state_peer *p) +{ + if (p->seqdiff) + printf("[%u + %u](+%u)", ntohl(p->seqlo), + ntohl(p->seqhi) - ntohl(p->seqlo), ntohl(p->seqdiff)); + else + printf("[%u + %u]", ntohl(p->seqlo), + ntohl(p->seqhi) - ntohl(p->seqlo)); +} + +void +print_state(struct pfsync_state *s, int opts) +{ + struct pfsync_state_peer *src, *dst; + struct pfsync_state_key *key, *sk, *nk; + struct protoent *p; + int min, sec; +#ifndef __NO_STRICT_ALIGNMENT + struct pfsync_state_key aligned_key[2]; + + bcopy(&s->key, aligned_key, sizeof(aligned_key)); + key = aligned_key; +#else + key = s->key; +#endif + + if (s->direction == PF_OUT) { + src = &s->src; + dst = &s->dst; + sk = &key[PF_SK_STACK]; + nk = &key[PF_SK_WIRE]; + if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6) + sk->port[0] = nk->port[0]; + } else { + src = &s->dst; + dst = &s->src; + sk = &key[PF_SK_WIRE]; + nk = &key[PF_SK_STACK]; + if (s->proto == IPPROTO_ICMP || s->proto == IPPROTO_ICMPV6) + sk->port[1] = nk->port[1]; + } + printf("%s ", s->ifname); + if ((p = getprotobynumber(s->proto)) != NULL) + printf("%s ", p->p_name); + else + printf("%u ", s->proto); + + print_host(&nk->addr[1], nk->port[1], s->af, opts); + if (PF_ANEQ(&nk->addr[1], &sk->addr[1], s->af) || + nk->port[1] != sk->port[1]) { + printf(" ("); + print_host(&sk->addr[1], sk->port[1], s->af, opts); + printf(")"); + } + if (s->direction == PF_OUT) + printf(" -> "); + else + printf(" <- "); + print_host(&nk->addr[0], nk->port[0], s->af, opts); + if (PF_ANEQ(&nk->addr[0], &sk->addr[0], s->af) || + nk->port[0] != sk->port[0]) { + printf(" ("); + print_host(&sk->addr[0], sk->port[0], s->af, opts); + printf(")"); + } + + printf(" "); + if (s->proto == IPPROTO_TCP) { + if (src->state <= TCPS_TIME_WAIT && + dst->state <= TCPS_TIME_WAIT) + printf(" %s:%s\n", tcpstates[src->state], + tcpstates[dst->state]); + else if (src->state == PF_TCPS_PROXY_SRC || + dst->state == PF_TCPS_PROXY_SRC) + printf(" PROXY:SRC\n"); + else if (src->state == PF_TCPS_PROXY_DST || + dst->state == PF_TCPS_PROXY_DST) + printf(" PROXY:DST\n"); + else + printf(" <BAD STATE LEVELS %u:%u>\n", + src->state, dst->state); + if (opts & PF_OPT_VERBOSE) { + printf(" "); + print_seq(src); + if (src->wscale && dst->wscale) + printf(" wscale %u", + src->wscale & PF_WSCALE_MASK); + printf(" "); + print_seq(dst); + if (src->wscale && dst->wscale) + printf(" wscale %u", + dst->wscale & PF_WSCALE_MASK); + printf("\n"); + } + } else if (s->proto == IPPROTO_UDP && src->state < PFUDPS_NSTATES && + dst->state < PFUDPS_NSTATES) { + const char *states[] = PFUDPS_NAMES; + + printf(" %s:%s\n", states[src->state], states[dst->state]); +#ifndef INET6 + } else if (s->proto != IPPROTO_ICMP && src->state < PFOTHERS_NSTATES && + dst->state < PFOTHERS_NSTATES) { +#else + } else if (s->proto != IPPROTO_ICMP && s->proto != IPPROTO_ICMPV6 && + src->state < PFOTHERS_NSTATES && dst->state < PFOTHERS_NSTATES) { +#endif + /* XXX ICMP doesn't really have state levels */ + const char *states[] = PFOTHERS_NAMES; + + printf(" %s:%s\n", states[src->state], states[dst->state]); + } else { + printf(" %u:%u\n", src->state, dst->state); + } + + if (opts & PF_OPT_VERBOSE) { + u_int64_t packets[2]; + u_int64_t bytes[2]; + u_int32_t creation = ntohl(s->creation); + u_int32_t expire = ntohl(s->expire); + + sec = creation % 60; + creation /= 60; + min = creation % 60; + creation /= 60; + printf(" age %.2u:%.2u:%.2u", creation, min, sec); + sec = expire % 60; + expire /= 60; + min = expire % 60; + expire /= 60; + printf(", expires in %.2u:%.2u:%.2u", expire, min, sec); + + bcopy(s->packets[0], &packets[0], sizeof(u_int64_t)); + bcopy(s->packets[1], &packets[1], sizeof(u_int64_t)); + bcopy(s->bytes[0], &bytes[0], sizeof(u_int64_t)); + bcopy(s->bytes[1], &bytes[1], sizeof(u_int64_t)); + printf(", %ju:%ju pkts, %ju:%ju bytes", + (uintmax_t )be64toh(packets[0]), + (uintmax_t )be64toh(packets[1]), + (uintmax_t )be64toh(bytes[0]), + (uintmax_t )be64toh(bytes[1])); + if (ntohl(s->anchor) != -1) + printf(", anchor %u", ntohl(s->anchor)); + if (ntohl(s->rule) != -1) + printf(", rule %u", ntohl(s->rule)); + if (s->state_flags & PFSTATE_SLOPPY) + printf(", sloppy"); + if (s->sync_flags & PFSYNC_FLAG_SRCNODE) + printf(", source-track"); + if (s->sync_flags & PFSYNC_FLAG_NATSRCNODE) + printf(", sticky-address"); + printf("\n"); + } + if (opts & PF_OPT_VERBOSE2) { + u_int64_t id; + + bcopy(&s->id, &id, sizeof(u_int64_t)); + printf(" id: %016jx creatorid: %08x", + (uintmax_t )be64toh(id), ntohl(s->creatorid)); + printf("\n"); + } +} + +int +unmask(struct pf_addr *m, sa_family_t af) +{ + int i = 31, j = 0, b = 0; + u_int32_t tmp; + + while (j < 4 && m->addr32[j] == 0xffffffff) { + b += 32; + j++; + } + if (j < 4) { + tmp = ntohl(m->addr32[j]); + for (i = 31; tmp & (1 << i); --i) + b++; + } + return (b); +} diff --git a/freebsd/sbin/pfctl/pfctl.c b/freebsd/sbin/pfctl/pfctl.c new file mode 100644 index 00000000..ab597068 --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl.c @@ -0,0 +1,2445 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ + +/* $OpenBSD: pfctl.c,v 1.278 2008/08/31 20:18:17 jmc Exp $ */ + +/* + * Copyright (c) 2001 Daniel Hartmeier + * Copyright (c) 2002,2003 Henning Brauer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#define __need_getopt_newlib +#include <getopt.h> +#include <machine/rtems-bsd-program.h> +#include <machine/rtems-bsd-commands.h> +#define pf_get_ruleset_number _bsd_pf_get_ruleset_number +#define pf_init_ruleset _bsd_pf_init_ruleset +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/endian.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <net/pfvar.h> +#include <arpa/inet.h> +#include <net/altq/altq.h> +#include <sys/sysctl.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <netdb.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pfctl_parser.h" +#include "pfctl.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-pfctl-data.h" +#endif /* __rtems__ */ + +void usage(void); +int pfctl_enable(int, int); +int pfctl_disable(int, int); +int pfctl_clear_stats(int, int); +int pfctl_clear_interface_flags(int, int); +int pfctl_clear_rules(int, int, char *); +int pfctl_clear_nat(int, int, char *); +int pfctl_clear_altq(int, int); +int pfctl_clear_src_nodes(int, int); +int pfctl_clear_states(int, const char *, int); +void pfctl_addrprefix(char *, struct pf_addr *); +int pfctl_kill_src_nodes(int, const char *, int); +int pfctl_net_kill_states(int, const char *, int); +int pfctl_label_kill_states(int, const char *, int); +int pfctl_id_kill_states(int, const char *, int); +void pfctl_init_options(struct pfctl *); +int pfctl_load_options(struct pfctl *); +int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int); +int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int); +int pfctl_load_debug(struct pfctl *, unsigned int); +int pfctl_load_logif(struct pfctl *, char *); +int pfctl_load_hostid(struct pfctl *, u_int32_t); +int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int, + char *); +void pfctl_print_rule_counters(struct pf_rule *, int); +int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int); +int pfctl_show_nat(int, int, char *); +int pfctl_show_src_nodes(int, int); +int pfctl_show_states(int, const char *, int); +int pfctl_show_status(int, int); +int pfctl_show_timeouts(int, int); +int pfctl_show_limits(int, int); +void pfctl_debug(int, u_int32_t, int); +int pfctl_test_altqsupport(int, int); +int pfctl_show_anchors(int, int, char *); +int pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *); +int pfctl_load_ruleset(struct pfctl *, char *, + struct pf_ruleset *, int, int); +int pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int); +const char *pfctl_lookup_option(char *, const char * const *); + +static struct pf_anchor_global pf_anchors; +static struct pf_anchor pf_main_anchor; + +static const char *clearopt; +static char *rulesopt; +static const char *showopt; +static const char *debugopt; +static char *anchoropt; +static const char *optiopt = NULL; +static const char *pf_device = "/dev/pf"; +static char *ifaceopt; +static char *tableopt; +static const char *tblcmdopt; +static int src_node_killers; +static char *src_node_kill[2]; +static int state_killers; +static char *state_kill[2]; +int loadopt; +int altqsupport; + +int dev = -1; +static int first_title = 1; +static int labels = 0; + +#define INDENT(d, o) do { \ + if (o) { \ + int i; \ + for (i=0; i < d; i++) \ + printf(" "); \ + } \ + } while (0); \ + + +static const struct { + const char *name; + int index; +} pf_limits[] = { + { "states", PF_LIMIT_STATES }, + { "src-nodes", PF_LIMIT_SRC_NODES }, + { "frags", PF_LIMIT_FRAGS }, + { "table-entries", PF_LIMIT_TABLE_ENTRIES }, + { NULL, 0 } +}; + +struct pf_hint { + const char *name; + int timeout; +}; +static const struct pf_hint pf_hint_normal[] = { + { "tcp.first", 2 * 60 }, + { "tcp.opening", 30 }, + { "tcp.established", 24 * 60 * 60 }, + { "tcp.closing", 15 * 60 }, + { "tcp.finwait", 45 }, + { "tcp.closed", 90 }, + { "tcp.tsdiff", 30 }, + { NULL, 0 } +}; +static const struct pf_hint pf_hint_satellite[] = { + { "tcp.first", 3 * 60 }, + { "tcp.opening", 30 + 5 }, + { "tcp.established", 24 * 60 * 60 }, + { "tcp.closing", 15 * 60 + 5 }, + { "tcp.finwait", 45 + 5 }, + { "tcp.closed", 90 + 5 }, + { "tcp.tsdiff", 60 }, + { NULL, 0 } +}; +static const struct pf_hint pf_hint_conservative[] = { + { "tcp.first", 60 * 60 }, + { "tcp.opening", 15 * 60 }, + { "tcp.established", 5 * 24 * 60 * 60 }, + { "tcp.closing", 60 * 60 }, + { "tcp.finwait", 10 * 60 }, + { "tcp.closed", 3 * 60 }, + { "tcp.tsdiff", 60 }, + { NULL, 0 } +}; +static const struct pf_hint pf_hint_aggressive[] = { + { "tcp.first", 30 }, + { "tcp.opening", 5 }, + { "tcp.established", 5 * 60 * 60 }, + { "tcp.closing", 60 }, + { "tcp.finwait", 30 }, + { "tcp.closed", 30 }, + { "tcp.tsdiff", 10 }, + { NULL, 0 } +}; + +static const struct { + const char *name; + const struct pf_hint *hint; +} pf_hints[] = { + { "normal", pf_hint_normal }, + { "satellite", pf_hint_satellite }, + { "high-latency", pf_hint_satellite }, + { "conservative", pf_hint_conservative }, + { "aggressive", pf_hint_aggressive }, + { NULL, NULL } +}; + +static const char * const clearopt_list[] = { + "nat", "queue", "rules", "Sources", + "states", "info", "Tables", "osfp", "all", NULL +}; + +static const char * const showopt_list[] = { + "nat", "queue", "rules", "Anchors", "Sources", "states", "info", + "Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", + "all", NULL +}; + +static const char * const tblcmdopt_list[] = { + "kill", "flush", "add", "delete", "load", "replace", "show", + "test", "zero", "expire", NULL +}; + +static const char * const debugopt_list[] = { + "none", "urgent", "misc", "loud", NULL +}; + +static const char * const optiopt_list[] = { + "none", "basic", "profile", NULL +}; + +void +usage(void) +{ +#ifndef __rtems__ + extern char *__progname; +#else /* __rtems__ */ +#define __progname "pfctl" +#endif /* __rtems__ */ + + fprintf(stderr, +"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n" + "\t[-f file] [-i interface] [-K host | network]\n" + "\t[-k host | network | label | id] [-o level] [-p device]\n" + "\t[-s modifier] [-t table -T command [address ...]] [-x level]\n", + __progname); + + exit(1); +} + +int +pfctl_enable(int dev, int opts) +{ + if (ioctl(dev, DIOCSTART)) { + if (errno == EEXIST) + errx(1, "pf already enabled"); + else if (errno == ESRCH) + errx(1, "pfil registeration failed"); + else + err(1, "DIOCSTART"); + } + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "pf enabled\n"); + + if (altqsupport && ioctl(dev, DIOCSTARTALTQ)) + if (errno != EEXIST) + err(1, "DIOCSTARTALTQ"); + + return (0); +} + +int +pfctl_disable(int dev, int opts) +{ + if (ioctl(dev, DIOCSTOP)) { + if (errno == ENOENT) + errx(1, "pf not enabled"); + else + err(1, "DIOCSTOP"); + } + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "pf disabled\n"); + + if (altqsupport && ioctl(dev, DIOCSTOPALTQ)) + if (errno != ENOENT) + err(1, "DIOCSTOPALTQ"); + + return (0); +} + +int +pfctl_clear_stats(int dev, int opts) +{ + if (ioctl(dev, DIOCCLRSTATUS)) + err(1, "DIOCCLRSTATUS"); + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "pf: statistics cleared\n"); + return (0); +} + +int +pfctl_clear_interface_flags(int dev, int opts) +{ + struct pfioc_iface pi; + + if ((opts & PF_OPT_NOACTION) == 0) { + bzero(&pi, sizeof(pi)); + pi.pfiio_flags = PFI_IFLAG_SKIP; + + if (ioctl(dev, DIOCCLRIFFLAG, &pi)) + err(1, "DIOCCLRIFFLAG"); + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "pf: interface flags reset\n"); + } + return (0); +} + +int +pfctl_clear_rules(int dev, int opts, char *anchorname) +{ + struct pfr_buffer t; + + memset(&t, 0, sizeof(t)); + t.pfrb_type = PFRB_TRANS; + if (pfctl_add_trans(&t, PF_RULESET_SCRUB, anchorname) || + pfctl_add_trans(&t, PF_RULESET_FILTER, anchorname) || + pfctl_trans(dev, &t, DIOCXBEGIN, 0) || + pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) + err(1, "pfctl_clear_rules"); + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "rules cleared\n"); + return (0); +} + +int +pfctl_clear_nat(int dev, int opts, char *anchorname) +{ + struct pfr_buffer t; + + memset(&t, 0, sizeof(t)); + t.pfrb_type = PFRB_TRANS; + if (pfctl_add_trans(&t, PF_RULESET_NAT, anchorname) || + pfctl_add_trans(&t, PF_RULESET_BINAT, anchorname) || + pfctl_add_trans(&t, PF_RULESET_RDR, anchorname) || + pfctl_trans(dev, &t, DIOCXBEGIN, 0) || + pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) + err(1, "pfctl_clear_nat"); + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "nat cleared\n"); + return (0); +} + +int +pfctl_clear_altq(int dev, int opts) +{ + struct pfr_buffer t; + + if (!altqsupport) + return (-1); + memset(&t, 0, sizeof(t)); + t.pfrb_type = PFRB_TRANS; + if (pfctl_add_trans(&t, PF_RULESET_ALTQ, "") || + pfctl_trans(dev, &t, DIOCXBEGIN, 0) || + pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) + err(1, "pfctl_clear_altq"); + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "altq cleared\n"); + return (0); +} + +int +pfctl_clear_src_nodes(int dev, int opts) +{ + if (ioctl(dev, DIOCCLRSRCNODES)) + err(1, "DIOCCLRSRCNODES"); + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "source tracking entries cleared\n"); + return (0); +} + +int +pfctl_clear_states(int dev, const char *iface, int opts) +{ + struct pfioc_state_kill psk; + + memset(&psk, 0, sizeof(psk)); + if (iface != NULL && strlcpy(psk.psk_ifname, iface, + sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) + errx(1, "invalid interface: %s", iface); + + if (ioctl(dev, DIOCCLRSTATES, &psk)) + err(1, "DIOCCLRSTATES"); + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "%d states cleared\n", psk.psk_killed); + return (0); +} + +void +pfctl_addrprefix(char *addr, struct pf_addr *mask) +{ + char *p; + const char *errstr; + int prefix, ret_ga, q, r; + struct addrinfo hints, *res; + + if ((p = strchr(addr, '/')) == NULL) + return; + + *p++ = '\0'; + prefix = strtonum(p, 0, 128, &errstr); + if (errstr) + errx(1, "prefix is %s: %s", errstr, p); + + bzero(&hints, sizeof(hints)); + /* prefix only with numeric addresses */ + hints.ai_flags |= AI_NUMERICHOST; + + if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) { + errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); + /* NOTREACHED */ + } + + if (res->ai_family == AF_INET && prefix > 32) + errx(1, "prefix too long for AF_INET"); + else if (res->ai_family == AF_INET6 && prefix > 128) + errx(1, "prefix too long for AF_INET6"); + + q = prefix >> 3; + r = prefix & 7; + switch (res->ai_family) { + case AF_INET: + bzero(&mask->v4, sizeof(mask->v4)); + mask->v4.s_addr = htonl((u_int32_t) + (0xffffffffffULL << (32 - prefix))); + break; + case AF_INET6: + bzero(&mask->v6, sizeof(mask->v6)); + if (q > 0) + memset((void *)&mask->v6, 0xff, q); + if (r > 0) + *((u_char *)&mask->v6 + q) = + (0xff00 >> r) & 0xff; + break; + } + freeaddrinfo(res); +} + +int +pfctl_kill_src_nodes(int dev, const char *iface, int opts) +{ + struct pfioc_src_node_kill psnk; + struct addrinfo *res[2], *resp[2]; + struct sockaddr last_src, last_dst; + int killed, sources, dests; + int ret_ga; + + killed = sources = dests = 0; + + memset(&psnk, 0, sizeof(psnk)); + memset(&psnk.psnk_src.addr.v.a.mask, 0xff, + sizeof(psnk.psnk_src.addr.v.a.mask)); + memset(&last_src, 0xff, sizeof(last_src)); + memset(&last_dst, 0xff, sizeof(last_dst)); + + pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask); + + if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) { + errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); + /* NOTREACHED */ + } + for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { + if (resp[0]->ai_addr == NULL) + continue; + /* We get lots of duplicates. Catch the easy ones */ + if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) + continue; + last_src = *(struct sockaddr *)resp[0]->ai_addr; + + psnk.psnk_af = resp[0]->ai_family; + sources++; + + if (psnk.psnk_af == AF_INET) + psnk.psnk_src.addr.v.a.addr.v4 = + ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; + else if (psnk.psnk_af == AF_INET6) + psnk.psnk_src.addr.v.a.addr.v6 = + ((struct sockaddr_in6 *)resp[0]->ai_addr)-> + sin6_addr; + else + errx(1, "Unknown address family %d", psnk.psnk_af); + + if (src_node_killers > 1) { + dests = 0; + memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, + sizeof(psnk.psnk_dst.addr.v.a.mask)); + memset(&last_dst, 0xff, sizeof(last_dst)); + pfctl_addrprefix(src_node_kill[1], + &psnk.psnk_dst.addr.v.a.mask); + if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL, + &res[1]))) { + errx(1, "getaddrinfo: %s", + gai_strerror(ret_ga)); + /* NOTREACHED */ + } + for (resp[1] = res[1]; resp[1]; + resp[1] = resp[1]->ai_next) { + if (resp[1]->ai_addr == NULL) + continue; + if (psnk.psnk_af != resp[1]->ai_family) + continue; + + if (memcmp(&last_dst, resp[1]->ai_addr, + sizeof(last_dst)) == 0) + continue; + last_dst = *(struct sockaddr *)resp[1]->ai_addr; + + dests++; + + if (psnk.psnk_af == AF_INET) + psnk.psnk_dst.addr.v.a.addr.v4 = + ((struct sockaddr_in *)resp[1]-> + ai_addr)->sin_addr; + else if (psnk.psnk_af == AF_INET6) + psnk.psnk_dst.addr.v.a.addr.v6 = + ((struct sockaddr_in6 *)resp[1]-> + ai_addr)->sin6_addr; + else + errx(1, "Unknown address family %d", + psnk.psnk_af); + + if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) + err(1, "DIOCKILLSRCNODES"); + killed += psnk.psnk_killed; + } + freeaddrinfo(res[1]); + } else { + if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) + err(1, "DIOCKILLSRCNODES"); + killed += psnk.psnk_killed; + } + } + + freeaddrinfo(res[0]); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "killed %d src nodes from %d sources and %d " + "destinations\n", killed, sources, dests); + return (0); +} + +int +pfctl_net_kill_states(int dev, const char *iface, int opts) +{ + struct pfioc_state_kill psk; + struct addrinfo *res[2], *resp[2]; + struct sockaddr last_src, last_dst; + int killed, sources, dests; + int ret_ga; + + killed = sources = dests = 0; + + memset(&psk, 0, sizeof(psk)); + memset(&psk.psk_src.addr.v.a.mask, 0xff, + sizeof(psk.psk_src.addr.v.a.mask)); + memset(&last_src, 0xff, sizeof(last_src)); + memset(&last_dst, 0xff, sizeof(last_dst)); + if (iface != NULL && strlcpy(psk.psk_ifname, iface, + sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) + errx(1, "invalid interface: %s", iface); + + pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask); + + if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { + errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); + /* NOTREACHED */ + } + for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { + if (resp[0]->ai_addr == NULL) + continue; + /* We get lots of duplicates. Catch the easy ones */ + if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) + continue; + last_src = *(struct sockaddr *)resp[0]->ai_addr; + + psk.psk_af = resp[0]->ai_family; + sources++; + + if (psk.psk_af == AF_INET) + psk.psk_src.addr.v.a.addr.v4 = + ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; + else if (psk.psk_af == AF_INET6) + psk.psk_src.addr.v.a.addr.v6 = + ((struct sockaddr_in6 *)resp[0]->ai_addr)-> + sin6_addr; + else + errx(1, "Unknown address family %d", psk.psk_af); + + if (state_killers > 1) { + dests = 0; + memset(&psk.psk_dst.addr.v.a.mask, 0xff, + sizeof(psk.psk_dst.addr.v.a.mask)); + memset(&last_dst, 0xff, sizeof(last_dst)); + pfctl_addrprefix(state_kill[1], + &psk.psk_dst.addr.v.a.mask); + if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, + &res[1]))) { + errx(1, "getaddrinfo: %s", + gai_strerror(ret_ga)); + /* NOTREACHED */ + } + for (resp[1] = res[1]; resp[1]; + resp[1] = resp[1]->ai_next) { + if (resp[1]->ai_addr == NULL) + continue; + if (psk.psk_af != resp[1]->ai_family) + continue; + + if (memcmp(&last_dst, resp[1]->ai_addr, + sizeof(last_dst)) == 0) + continue; + last_dst = *(struct sockaddr *)resp[1]->ai_addr; + + dests++; + + if (psk.psk_af == AF_INET) + psk.psk_dst.addr.v.a.addr.v4 = + ((struct sockaddr_in *)resp[1]-> + ai_addr)->sin_addr; + else if (psk.psk_af == AF_INET6) + psk.psk_dst.addr.v.a.addr.v6 = + ((struct sockaddr_in6 *)resp[1]-> + ai_addr)->sin6_addr; + else + errx(1, "Unknown address family %d", + psk.psk_af); + + if (ioctl(dev, DIOCKILLSTATES, &psk)) + err(1, "DIOCKILLSTATES"); + killed += psk.psk_killed; + } + freeaddrinfo(res[1]); + } else { + if (ioctl(dev, DIOCKILLSTATES, &psk)) + err(1, "DIOCKILLSTATES"); + killed += psk.psk_killed; + } + } + + freeaddrinfo(res[0]); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "killed %d states from %d sources and %d " + "destinations\n", killed, sources, dests); + return (0); +} + +int +pfctl_label_kill_states(int dev, const char *iface, int opts) +{ + struct pfioc_state_kill psk; + + if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { + warnx("no label specified"); + usage(); + } + memset(&psk, 0, sizeof(psk)); + if (iface != NULL && strlcpy(psk.psk_ifname, iface, + sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) + errx(1, "invalid interface: %s", iface); + + if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >= + sizeof(psk.psk_label)) + errx(1, "label too long: %s", state_kill[1]); + + if (ioctl(dev, DIOCKILLSTATES, &psk)) + err(1, "DIOCKILLSTATES"); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "killed %d states\n", psk.psk_killed); + + return (0); +} + +int +pfctl_id_kill_states(int dev, const char *iface, int opts) +{ + struct pfioc_state_kill psk; + + if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { + warnx("no id specified"); + usage(); + } + + memset(&psk, 0, sizeof(psk)); + if ((sscanf(state_kill[1], "%jx/%x", + &psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2) + HTONL(psk.psk_pfcmp.creatorid); + else if ((sscanf(state_kill[1], "%jx", &psk.psk_pfcmp.id)) == 1) { + psk.psk_pfcmp.creatorid = 0; + } else { + warnx("wrong id format specified"); + usage(); + } + if (psk.psk_pfcmp.id == 0) { + warnx("cannot kill id 0"); + usage(); + } + + psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id); + if (ioctl(dev, DIOCKILLSTATES, &psk)) + err(1, "DIOCKILLSTATES"); + + if ((opts & PF_OPT_QUIET) == 0) + fprintf(stderr, "killed %d states\n", psk.psk_killed); + + return (0); +} + +int +pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr, + u_int32_t ticket, int r_action, char *anchorname) +{ + struct pfioc_pooladdr pp; + struct pf_pooladdr *pa; + u_int32_t pnr, mpnr; + + memset(&pp, 0, sizeof(pp)); + memcpy(pp.anchor, anchorname, sizeof(pp.anchor)); + pp.r_action = r_action; + pp.r_num = nr; + pp.ticket = ticket; + if (ioctl(dev, DIOCGETADDRS, &pp)) { + warn("DIOCGETADDRS"); + return (-1); + } + mpnr = pp.nr; + TAILQ_INIT(&pool->list); + for (pnr = 0; pnr < mpnr; ++pnr) { + pp.nr = pnr; + if (ioctl(dev, DIOCGETADDR, &pp)) { + warn("DIOCGETADDR"); + return (-1); + } + pa = calloc(1, sizeof(struct pf_pooladdr)); + if (pa == NULL) + err(1, "calloc"); + bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr)); + TAILQ_INSERT_TAIL(&pool->list, pa, entries); + } + + return (0); +} + +void +pfctl_move_pool(struct pf_pool *src, struct pf_pool *dst) +{ + struct pf_pooladdr *pa; + + while ((pa = TAILQ_FIRST(&src->list)) != NULL) { + TAILQ_REMOVE(&src->list, pa, entries); + TAILQ_INSERT_TAIL(&dst->list, pa, entries); + } +} + +void +pfctl_clear_pool(struct pf_pool *pool) +{ + struct pf_pooladdr *pa; + + while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { + TAILQ_REMOVE(&pool->list, pa, entries); + free(pa); + } +} + +void +pfctl_print_rule_counters(struct pf_rule *rule, int opts) +{ + if (opts & PF_OPT_DEBUG) { + const char *t[PF_SKIP_COUNT] = { "i", "d", "f", + "p", "sa", "sp", "da", "dp" }; + int i; + + printf(" [ Skip steps: "); + for (i = 0; i < PF_SKIP_COUNT; ++i) { + if (rule->skip[i].nr == rule->nr + 1) + continue; + printf("%s=", t[i]); + if (rule->skip[i].nr == -1) + printf("end "); + else + printf("%u ", rule->skip[i].nr); + } + printf("]\n"); + + printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", + rule->qname, rule->qid, rule->pqname, rule->pqid); + } + if (opts & PF_OPT_VERBOSE) { + printf(" [ Evaluations: %-8llu Packets: %-8llu " + "Bytes: %-10llu States: %-6ju]\n", + (unsigned long long)rule->evaluations, + (unsigned long long)(rule->packets[0] + + rule->packets[1]), + (unsigned long long)(rule->bytes[0] + + rule->bytes[1]), (uintmax_t)rule->u_states_cur); + if (!(opts & PF_OPT_DEBUG)) + printf(" [ Inserted: uid %u pid %u " + "State Creations: %-6ju]\n", + (unsigned)rule->cuid, (unsigned)rule->cpid, + (uintmax_t)rule->u_states_tot); + } +} + +void +pfctl_print_title(char *title) +{ + if (!first_title) + printf("\n"); + first_title = 0; + printf("%s\n", title); +} + +int +pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, + char *anchorname, int depth) +{ + struct pfioc_rule pr; + u_int32_t nr, mnr, header = 0; + int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); + int numeric = opts & PF_OPT_NUMERIC; + int len = strlen(path); + int brace; + char *p; + + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, "/%s", anchorname); + else + snprintf(&path[len], MAXPATHLEN - len, "%s", anchorname); + + memset(&pr, 0, sizeof(pr)); + memcpy(pr.anchor, path, sizeof(pr.anchor)); + if (opts & PF_OPT_SHOWALL) { + pr.rule.action = PF_PASS; + if (ioctl(dev, DIOCGETRULES, &pr)) { + warn("DIOCGETRULES"); + goto error; + } + header++; + } + pr.rule.action = PF_SCRUB; + if (ioctl(dev, DIOCGETRULES, &pr)) { + warn("DIOCGETRULES"); + goto error; + } + if (opts & PF_OPT_SHOWALL) { + if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header)) + pfctl_print_title("FILTER RULES:"); + else if (format == PFCTL_SHOW_LABELS && labels) + pfctl_print_title("LABEL COUNTERS:"); + } + mnr = pr.nr; + if (opts & PF_OPT_CLRRULECTRS) + pr.action = PF_GET_CLR_CNTR; + + for (nr = 0; nr < mnr; ++nr) { + pr.nr = nr; + if (ioctl(dev, DIOCGETRULE, &pr)) { + warn("DIOCGETRULE"); + goto error; + } + + if (pfctl_get_pool(dev, &pr.rule.rpool, + nr, pr.ticket, PF_SCRUB, path) != 0) + goto error; + + switch (format) { + case PFCTL_SHOW_LABELS: + break; + case PFCTL_SHOW_RULES: + if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) + labels = 1; + print_rule(&pr.rule, pr.anchor_call, rule_numbers, numeric); + printf("\n"); + pfctl_print_rule_counters(&pr.rule, opts); + break; + case PFCTL_SHOW_NOTHING: + break; + } + pfctl_clear_pool(&pr.rule.rpool); + } + pr.rule.action = PF_PASS; + if (ioctl(dev, DIOCGETRULES, &pr)) { + warn("DIOCGETRULES"); + goto error; + } + mnr = pr.nr; + for (nr = 0; nr < mnr; ++nr) { + pr.nr = nr; + if (ioctl(dev, DIOCGETRULE, &pr)) { + warn("DIOCGETRULE"); + goto error; + } + + if (pfctl_get_pool(dev, &pr.rule.rpool, + nr, pr.ticket, PF_PASS, path) != 0) + goto error; + + switch (format) { + case PFCTL_SHOW_LABELS: + if (pr.rule.label[0]) { + printf("%s %llu %llu %llu %llu" + " %llu %llu %llu %ju\n", + pr.rule.label, + (unsigned long long)pr.rule.evaluations, + (unsigned long long)(pr.rule.packets[0] + + pr.rule.packets[1]), + (unsigned long long)(pr.rule.bytes[0] + + pr.rule.bytes[1]), + (unsigned long long)pr.rule.packets[0], + (unsigned long long)pr.rule.bytes[0], + (unsigned long long)pr.rule.packets[1], + (unsigned long long)pr.rule.bytes[1], + (uintmax_t)pr.rule.u_states_tot); + } + break; + case PFCTL_SHOW_RULES: + brace = 0; + if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) + labels = 1; + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + if (pr.anchor_call[0] && + ((((p = strrchr(pr.anchor_call, '_')) != NULL) && + ((void *)p == (void *)pr.anchor_call || + *(--p) == '/')) || (opts & PF_OPT_RECURSE))) { + brace++; + if ((p = strrchr(pr.anchor_call, '/')) != + NULL) + p++; + else + p = &pr.anchor_call[0]; + } else + p = &pr.anchor_call[0]; + + print_rule(&pr.rule, p, rule_numbers, numeric); + if (brace) + printf(" {\n"); + else + printf("\n"); + pfctl_print_rule_counters(&pr.rule, opts); + if (brace) { + pfctl_show_rules(dev, path, opts, format, + p, depth + 1); + INDENT(depth, !(opts & PF_OPT_VERBOSE)); + printf("}\n"); + } + break; + case PFCTL_SHOW_NOTHING: + break; + } + pfctl_clear_pool(&pr.rule.rpool); + } + path[len] = '\0'; + return (0); + + error: + path[len] = '\0'; + return (-1); +} + +int +pfctl_show_nat(int dev, int opts, char *anchorname) +{ + struct pfioc_rule pr; + u_int32_t mnr, nr; +#ifndef __rtems__ + static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; +#else /* __rtems__ */ + static const int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; +#endif /* __rtems__ */ + int i, dotitle = opts & PF_OPT_SHOWALL; + + memset(&pr, 0, sizeof(pr)); + memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); + for (i = 0; i < 3; i++) { + pr.rule.action = nattype[i]; + if (ioctl(dev, DIOCGETRULES, &pr)) { + warn("DIOCGETRULES"); + return (-1); + } + mnr = pr.nr; + for (nr = 0; nr < mnr; ++nr) { + pr.nr = nr; + if (ioctl(dev, DIOCGETRULE, &pr)) { + warn("DIOCGETRULE"); + return (-1); + } + if (pfctl_get_pool(dev, &pr.rule.rpool, nr, + pr.ticket, nattype[i], anchorname) != 0) + return (-1); + if (dotitle) { + pfctl_print_title("TRANSLATION RULES:"); + dotitle = 0; + } + print_rule(&pr.rule, pr.anchor_call, + opts & PF_OPT_VERBOSE2, opts & PF_OPT_NUMERIC); + printf("\n"); + pfctl_print_rule_counters(&pr.rule, opts); + pfctl_clear_pool(&pr.rule.rpool); + } + } + return (0); +} + +int +pfctl_show_src_nodes(int dev, int opts) +{ + struct pfioc_src_nodes psn; + struct pf_src_node *p; + char *inbuf = NULL, *newinbuf = NULL; + unsigned int len = 0; + int i; + + memset(&psn, 0, sizeof(psn)); + for (;;) { + psn.psn_len = len; + if (len) { + newinbuf = realloc(inbuf, len); + if (newinbuf == NULL) + err(1, "realloc"); + psn.psn_buf = inbuf = newinbuf; + } + if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) { + warn("DIOCGETSRCNODES"); + free(inbuf); + return (-1); + } + if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len) + break; + if (len == 0 && psn.psn_len == 0) + goto done; + if (len == 0 && psn.psn_len != 0) + len = psn.psn_len; + if (psn.psn_len == 0) + goto done; /* no src_nodes */ + len *= 2; + } + p = psn.psn_src_nodes; + if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL)) + pfctl_print_title("SOURCE TRACKING NODES:"); + for (i = 0; i < psn.psn_len; i += sizeof(*p)) { + print_src_node(p, opts); + p++; + } +done: + free(inbuf); + return (0); +} + +int +pfctl_show_states(int dev, const char *iface, int opts) +{ + struct pfioc_states ps; + struct pfsync_state *p; + char *inbuf = NULL, *newinbuf = NULL; + unsigned int len = 0; + int i, dotitle = (opts & PF_OPT_SHOWALL); + + memset(&ps, 0, sizeof(ps)); + for (;;) { + ps.ps_len = len; + if (len) { + newinbuf = realloc(inbuf, len); + if (newinbuf == NULL) + err(1, "realloc"); + ps.ps_buf = inbuf = newinbuf; + } + if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { + warn("DIOCGETSTATES"); + free(inbuf); + return (-1); + } + if (ps.ps_len + sizeof(struct pfioc_states) < len) + break; + if (len == 0 && ps.ps_len == 0) + goto done; + if (len == 0 && ps.ps_len != 0) + len = ps.ps_len; + if (ps.ps_len == 0) + goto done; /* no states */ + len *= 2; + } + p = ps.ps_states; + for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { + if (iface != NULL && strcmp(p->ifname, iface)) + continue; + if (dotitle) { + pfctl_print_title("STATES:"); + dotitle = 0; + } + print_state(p, opts); + } +done: + free(inbuf); + return (0); +} + +int +pfctl_show_status(int dev, int opts) +{ + struct pf_status status; + + if (ioctl(dev, DIOCGETSTATUS, &status)) { + warn("DIOCGETSTATUS"); + return (-1); + } + if (opts & PF_OPT_SHOWALL) + pfctl_print_title("INFO:"); + print_status(&status, opts); + return (0); +} + +int +pfctl_show_timeouts(int dev, int opts) +{ + struct pfioc_tm pt; + int i; + + if (opts & PF_OPT_SHOWALL) + pfctl_print_title("TIMEOUTS:"); + memset(&pt, 0, sizeof(pt)); + for (i = 0; pf_timeouts[i].name; i++) { + pt.timeout = pf_timeouts[i].timeout; + if (ioctl(dev, DIOCGETTIMEOUT, &pt)) + err(1, "DIOCGETTIMEOUT"); + printf("%-20s %10d", pf_timeouts[i].name, pt.seconds); + if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START && + pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END) + printf(" states"); + else + printf("s"); + printf("\n"); + } + return (0); + +} + +int +pfctl_show_limits(int dev, int opts) +{ + struct pfioc_limit pl; + int i; + + if (opts & PF_OPT_SHOWALL) + pfctl_print_title("LIMITS:"); + memset(&pl, 0, sizeof(pl)); + for (i = 0; pf_limits[i].name; i++) { + pl.index = pf_limits[i].index; + if (ioctl(dev, DIOCGETLIMIT, &pl)) + err(1, "DIOCGETLIMIT"); + printf("%-13s ", pf_limits[i].name); + if (pl.limit == UINT_MAX) + printf("unlimited\n"); + else + printf("hard limit %8u\n", pl.limit); + } + return (0); +} + +/* callbacks for rule/nat/rdr/addr */ +int +pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) +{ + struct pf_pooladdr *pa; + + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) + err(1, "DIOCBEGINADDRS"); + } + + pf->paddr.af = af; + TAILQ_FOREACH(pa, &p->list, entries) { + memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) + err(1, "DIOCADDADDR"); + } + } + return (0); +} + +int +pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call) +{ + u_int8_t rs_num; + struct pf_rule *rule; + struct pf_ruleset *rs; + char *p; + + rs_num = pf_get_ruleset_number(r->action); + if (rs_num == PF_RULESET_MAX) + errx(1, "Invalid rule type %d", r->action); + + rs = &pf->anchor->ruleset; + + if (anchor_call[0] && r->anchor == NULL) { + /* + * Don't make non-brace anchors part of the main anchor pool. + */ + if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) + err(1, "pfctl_add_rule: calloc"); + + pf_init_ruleset(&r->anchor->ruleset); + r->anchor->ruleset.anchor = r->anchor; + if (strlcpy(r->anchor->path, anchor_call, + sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path)) + errx(1, "pfctl_add_rule: strlcpy"); + if ((p = strrchr(anchor_call, '/')) != NULL) { + if (!strlen(p)) + err(1, "pfctl_add_rule: bad anchor name %s", + anchor_call); + } else + p = (char *)anchor_call; + if (strlcpy(r->anchor->name, p, + sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) + errx(1, "pfctl_add_rule: strlcpy"); + } + + if ((rule = calloc(1, sizeof(*rule))) == NULL) + err(1, "calloc"); + bcopy(r, rule, sizeof(*rule)); + TAILQ_INIT(&rule->rpool.list); + pfctl_move_pool(&r->rpool, &rule->rpool); + + TAILQ_INSERT_TAIL(rs->rules[rs_num].active.ptr, rule, entries); + return (0); +} + +int +pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a) +{ + int osize = pf->trans->pfrb_size; + + if ((pf->loadopt & PFCTL_FLAG_NAT) != 0) { + if (pfctl_add_trans(pf->trans, PF_RULESET_NAT, path) || + pfctl_add_trans(pf->trans, PF_RULESET_BINAT, path) || + pfctl_add_trans(pf->trans, PF_RULESET_RDR, path)) + return (1); + } + if (a == pf->astack[0] && ((altqsupport && + (pf->loadopt & PFCTL_FLAG_ALTQ) != 0))) { + if (pfctl_add_trans(pf->trans, PF_RULESET_ALTQ, path)) + return (2); + } + if ((pf->loadopt & PFCTL_FLAG_FILTER) != 0) { + if (pfctl_add_trans(pf->trans, PF_RULESET_SCRUB, path) || + pfctl_add_trans(pf->trans, PF_RULESET_FILTER, path)) + return (3); + } + if (pf->loadopt & PFCTL_FLAG_TABLE) + if (pfctl_add_trans(pf->trans, PF_RULESET_TABLE, path)) + return (4); + if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize)) + return (5); + + return (0); +} + +int +pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs, + int rs_num, int depth) +{ + struct pf_rule *r; + int error, len = strlen(path); + int brace = 0; + + pf->anchor = rs->anchor; + + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, "/%s", pf->anchor->name); + else + snprintf(&path[len], MAXPATHLEN - len, "%s", pf->anchor->name); + + if (depth) { + if (TAILQ_FIRST(rs->rules[rs_num].active.ptr) != NULL) { + brace++; + if (pf->opts & PF_OPT_VERBOSE) + printf(" {\n"); + if ((pf->opts & PF_OPT_NOACTION) == 0 && + (error = pfctl_ruleset_trans(pf, + path, rs->anchor))) { + printf("pfctl_load_rulesets: " + "pfctl_ruleset_trans %d\n", error); + goto error; + } + } else if (pf->opts & PF_OPT_VERBOSE) + printf("\n"); + + } + + if (pf->optimize && rs_num == PF_RULESET_FILTER) + pfctl_optimize_ruleset(pf, rs); + + while ((r = TAILQ_FIRST(rs->rules[rs_num].active.ptr)) != NULL) { + TAILQ_REMOVE(rs->rules[rs_num].active.ptr, r, entries); + if ((error = pfctl_load_rule(pf, path, r, depth))) + goto error; + if (r->anchor) { + if ((error = pfctl_load_ruleset(pf, path, + &r->anchor->ruleset, rs_num, depth + 1))) + goto error; + } else if (pf->opts & PF_OPT_VERBOSE) + printf("\n"); + free(r); + } + if (brace && pf->opts & PF_OPT_VERBOSE) { + INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE)); + printf("}\n"); + } + path[len] = '\0'; + return (0); + + error: + path[len] = '\0'; + return (error); + +} + +int +pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth) +{ + u_int8_t rs_num = pf_get_ruleset_number(r->action); + char *name; + struct pfioc_rule pr; + int len = strlen(path); + + bzero(&pr, sizeof(pr)); + /* set up anchor before adding to path for anchor_call */ + if ((pf->opts & PF_OPT_NOACTION) == 0) + pr.ticket = pfctl_get_ticket(pf->trans, rs_num, path); + if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor)) + errx(1, "pfctl_load_rule: strlcpy"); + + if (r->anchor) { + if (r->anchor->match) { + if (path[0]) + snprintf(&path[len], MAXPATHLEN - len, + "/%s", r->anchor->name); + else + snprintf(&path[len], MAXPATHLEN - len, + "%s", r->anchor->name); + name = path; + } else + name = r->anchor->path; + } else + name = ""; + + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (pfctl_add_pool(pf, &r->rpool, r->af)) + return (1); + pr.pool_ticket = pf->paddr.ticket; + memcpy(&pr.rule, r, sizeof(pr.rule)); + if (r->anchor && strlcpy(pr.anchor_call, name, + sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call)) + errx(1, "pfctl_load_rule: strlcpy"); + if (ioctl(pf->dev, DIOCADDRULE, &pr)) + err(1, "DIOCADDRULE"); + } + + if (pf->opts & PF_OPT_VERBOSE) { + INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); + print_rule(r, r->anchor ? r->anchor->name : "", + pf->opts & PF_OPT_VERBOSE2, + pf->opts & PF_OPT_NUMERIC); + } + path[len] = '\0'; + pfctl_clear_pool(&r->rpool); + return (0); +} + +int +pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) +{ + if (altqsupport && + (loadopt & PFCTL_FLAG_ALTQ) != 0) { + memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq)); + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) { + if (errno == ENXIO) + errx(1, "qtype not configured"); + else if (errno == ENODEV) + errx(1, "%s: driver does not support " + "altq", a->ifname); + else + err(1, "DIOCADDALTQ"); + } + } + pfaltq_store(&pf->paltq->altq); + } + return (0); +} + +int +pfctl_rules(int dev, char *filename, int opts, int optimize, + char *anchorname, struct pfr_buffer *trans) +{ +#define ERR(x) do { warn(x); goto _error; } while(0) +#define ERRX(x) do { warnx(x); goto _error; } while(0) + + struct pfr_buffer *t, buf; + struct pfioc_altq pa; + struct pfctl pf; + struct pf_ruleset *rs; + struct pfr_table trs; + char *path; + int osize; + + RB_INIT(&pf_anchors); + memset(&pf_main_anchor, 0, sizeof(pf_main_anchor)); + pf_init_ruleset(&pf_main_anchor.ruleset); + pf_main_anchor.ruleset.anchor = &pf_main_anchor; + if (trans == NULL) { + bzero(&buf, sizeof(buf)); + buf.pfrb_type = PFRB_TRANS; + t = &buf; + osize = 0; + } else { + t = trans; + osize = t->pfrb_size; + } + + memset(&pa, 0, sizeof(pa)); + memset(&pf, 0, sizeof(pf)); + memset(&trs, 0, sizeof(trs)); + if ((path = calloc(1, MAXPATHLEN)) == NULL) + ERRX("pfctl_rules: calloc"); + if (strlcpy(trs.pfrt_anchor, anchorname, + sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor)) + ERRX("pfctl_rules: strlcpy"); + pf.dev = dev; + pf.opts = opts; + pf.optimize = optimize; + pf.loadopt = loadopt; + + /* non-brace anchor, create without resolving the path */ + if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL) + ERRX("pfctl_rules: calloc"); + rs = &pf.anchor->ruleset; + pf_init_ruleset(rs); + rs->anchor = pf.anchor; + if (strlcpy(pf.anchor->path, anchorname, + sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path)) + errx(1, "pfctl_add_rule: strlcpy"); + if (strlcpy(pf.anchor->name, anchorname, + sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name)) + errx(1, "pfctl_add_rule: strlcpy"); + + + pf.astack[0] = pf.anchor; + pf.asd = 0; + if (anchorname[0]) + pf.loadopt &= ~PFCTL_FLAG_ALTQ; + pf.paltq = &pa; + pf.trans = t; + pfctl_init_options(&pf); + + if ((opts & PF_OPT_NOACTION) == 0) { + /* + * XXX For the time being we need to open transactions for + * the main ruleset before parsing, because tables are still + * loaded at parse time. + */ + if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor)) + ERRX("pfctl_rules"); + if (altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ)) + pa.ticket = + pfctl_get_ticket(t, PF_RULESET_ALTQ, anchorname); + if (pf.loadopt & PFCTL_FLAG_TABLE) + pf.astack[0]->ruleset.tticket = + pfctl_get_ticket(t, PF_RULESET_TABLE, anchorname); + } + + if (parse_config(filename, &pf) < 0) { + if ((opts & PF_OPT_NOACTION) == 0) + ERRX("Syntax error in config file: " + "pf rules not loaded"); + else + goto _error; + } + + if ((pf.loadopt & PFCTL_FLAG_FILTER && + (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_SCRUB, 0))) || + (pf.loadopt & PFCTL_FLAG_NAT && + (pfctl_load_ruleset(&pf, path, rs, PF_RULESET_NAT, 0) || + pfctl_load_ruleset(&pf, path, rs, PF_RULESET_RDR, 0) || + pfctl_load_ruleset(&pf, path, rs, PF_RULESET_BINAT, 0))) || + (pf.loadopt & PFCTL_FLAG_FILTER && + pfctl_load_ruleset(&pf, path, rs, PF_RULESET_FILTER, 0))) { + if ((opts & PF_OPT_NOACTION) == 0) + ERRX("Unable to load rules into kernel"); + else + goto _error; + } + + if ((altqsupport && (pf.loadopt & PFCTL_FLAG_ALTQ) != 0)) + if (check_commit_altq(dev, opts) != 0) + ERRX("errors in altq config"); + + /* process "load anchor" directives */ + if (!anchorname[0]) + if (pfctl_load_anchors(dev, &pf, t) == -1) + ERRX("load anchors"); + + if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) { + if (!anchorname[0]) + if (pfctl_load_options(&pf)) + goto _error; + if (pfctl_trans(dev, t, DIOCXCOMMIT, osize)) + ERR("DIOCXCOMMIT"); + } + return (0); + +_error: + if (trans == NULL) { /* main ruleset */ + if ((opts & PF_OPT_NOACTION) == 0) + if (pfctl_trans(dev, t, DIOCXROLLBACK, osize)) + err(1, "DIOCXROLLBACK"); + exit(1); + } else { /* sub ruleset */ + return (-1); + } + +#undef ERR +#undef ERRX +} + +FILE * +pfctl_fopen(const char *name, const char *mode) +{ + struct stat st; + FILE *fp; + + fp = fopen(name, mode); + if (fp == NULL) + return (NULL); + if (fstat(fileno(fp), &st)) { + fclose(fp); + return (NULL); + } + if (S_ISDIR(st.st_mode)) { + fclose(fp); + errno = EISDIR; + return (NULL); + } + return (fp); +} + +void +pfctl_init_options(struct pfctl *pf) +{ + + pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; + pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; + pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; + pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; + pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; + pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; + pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; + pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; + pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; + pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; + pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; + pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; + pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; + pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; + pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL; + pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; + pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; + pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; + pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; + pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; + + pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT; + pf->limit[PF_LIMIT_FRAGS] = PFFRAG_FRENT_HIWAT; + pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT; + pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; + + pf->debug = PF_DEBUG_URGENT; +} + +int +pfctl_load_options(struct pfctl *pf) +{ + int i, error = 0; + + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + /* load limits */ + for (i = 0; i < PF_LIMIT_MAX; i++) { + if ((pf->opts & PF_OPT_MERGE) && !pf->limit_set[i]) + continue; + if (pfctl_load_limit(pf, i, pf->limit[i])) + error = 1; + } + + /* + * If we've set the limit, but haven't explicitly set adaptive + * timeouts, do it now with a start of 60% and end of 120%. + */ + if (pf->limit_set[PF_LIMIT_STATES] && + !pf->timeout_set[PFTM_ADAPTIVE_START] && + !pf->timeout_set[PFTM_ADAPTIVE_END]) { + pf->timeout[PFTM_ADAPTIVE_START] = + (pf->limit[PF_LIMIT_STATES] / 10) * 6; + pf->timeout_set[PFTM_ADAPTIVE_START] = 1; + pf->timeout[PFTM_ADAPTIVE_END] = + (pf->limit[PF_LIMIT_STATES] / 10) * 12; + pf->timeout_set[PFTM_ADAPTIVE_END] = 1; + } + + /* load timeouts */ + for (i = 0; i < PFTM_MAX; i++) { + if ((pf->opts & PF_OPT_MERGE) && !pf->timeout_set[i]) + continue; + if (pfctl_load_timeout(pf, i, pf->timeout[i])) + error = 1; + } + + /* load debug */ + if (!(pf->opts & PF_OPT_MERGE) || pf->debug_set) + if (pfctl_load_debug(pf, pf->debug)) + error = 1; + + /* load logif */ + if (!(pf->opts & PF_OPT_MERGE) || pf->ifname_set) + if (pfctl_load_logif(pf, pf->ifname)) + error = 1; + + /* load hostid */ + if (!(pf->opts & PF_OPT_MERGE) || pf->hostid_set) + if (pfctl_load_hostid(pf, pf->hostid)) + error = 1; + + return (error); +} + +int +pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) +{ + int i; + + + for (i = 0; pf_limits[i].name; i++) { + if (strcasecmp(opt, pf_limits[i].name) == 0) { + pf->limit[pf_limits[i].index] = limit; + pf->limit_set[pf_limits[i].index] = 1; + break; + } + } + if (pf_limits[i].name == NULL) { + warnx("Bad pool name."); + return (1); + } + + if (pf->opts & PF_OPT_VERBOSE) + printf("set limit %s %d\n", opt, limit); + + return (0); +} + +int +pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit) +{ + struct pfioc_limit pl; + + memset(&pl, 0, sizeof(pl)); + pl.index = index; + pl.limit = limit; + if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) { + if (errno == EBUSY) + warnx("Current pool size exceeds requested hard limit"); + else + warnx("DIOCSETLIMIT"); + return (1); + } + return (0); +} + +int +pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) +{ + int i; + + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + for (i = 0; pf_timeouts[i].name; i++) { + if (strcasecmp(opt, pf_timeouts[i].name) == 0) { + pf->timeout[pf_timeouts[i].timeout] = seconds; + pf->timeout_set[pf_timeouts[i].timeout] = 1; + break; + } + } + + if (pf_timeouts[i].name == NULL) { + warnx("Bad timeout name."); + return (1); + } + + + if (pf->opts & PF_OPT_VERBOSE && ! quiet) + printf("set timeout %s %d\n", opt, seconds); + + return (0); +} + +int +pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds) +{ + struct pfioc_tm pt; + + memset(&pt, 0, sizeof(pt)); + pt.timeout = timeout; + pt.seconds = seconds; + if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) { + warnx("DIOCSETTIMEOUT"); + return (1); + } + return (0); +} + +int +pfctl_set_optimization(struct pfctl *pf, const char *opt) +{ + const struct pf_hint *hint; + int i, r; + + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + for (i = 0; pf_hints[i].name; i++) + if (strcasecmp(opt, pf_hints[i].name) == 0) + break; + + hint = pf_hints[i].hint; + if (hint == NULL) { + warnx("invalid state timeouts optimization"); + return (1); + } + + for (i = 0; hint[i].name; i++) + if ((r = pfctl_set_timeout(pf, hint[i].name, + hint[i].timeout, 1))) + return (r); + + if (pf->opts & PF_OPT_VERBOSE) + printf("set optimization %s\n", opt); + + return (0); +} + +int +pfctl_set_logif(struct pfctl *pf, char *ifname) +{ + + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + if (!strcmp(ifname, "none")) { + free(pf->ifname); + pf->ifname = NULL; + } else { + pf->ifname = strdup(ifname); + if (!pf->ifname) + errx(1, "pfctl_set_logif: strdup"); + } + pf->ifname_set = 1; + + if (pf->opts & PF_OPT_VERBOSE) + printf("set loginterface %s\n", ifname); + + return (0); +} + +int +pfctl_load_logif(struct pfctl *pf, char *ifname) +{ + struct pfioc_if pi; + + memset(&pi, 0, sizeof(pi)); + if (ifname && strlcpy(pi.ifname, ifname, + sizeof(pi.ifname)) >= sizeof(pi.ifname)) { + warnx("pfctl_load_logif: strlcpy"); + return (1); + } + if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) { + warnx("DIOCSETSTATUSIF"); + return (1); + } + return (0); +} + +int +pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) +{ + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + HTONL(hostid); + + pf->hostid = hostid; + pf->hostid_set = 1; + + if (pf->opts & PF_OPT_VERBOSE) + printf("set hostid 0x%08x\n", ntohl(hostid)); + + return (0); +} + +int +pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid) +{ + if (ioctl(dev, DIOCSETHOSTID, &hostid)) { + warnx("DIOCSETHOSTID"); + return (1); + } + return (0); +} + +int +pfctl_set_debug(struct pfctl *pf, char *d) +{ + u_int32_t level; + + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + if (!strcmp(d, "none")) + pf->debug = PF_DEBUG_NONE; + else if (!strcmp(d, "urgent")) + pf->debug = PF_DEBUG_URGENT; + else if (!strcmp(d, "misc")) + pf->debug = PF_DEBUG_MISC; + else if (!strcmp(d, "loud")) + pf->debug = PF_DEBUG_NOISY; + else { + warnx("unknown debug level \"%s\"", d); + return (-1); + } + + pf->debug_set = 1; + level = pf->debug; + + if ((pf->opts & PF_OPT_NOACTION) == 0) + if (ioctl(dev, DIOCSETDEBUG, &level)) + err(1, "DIOCSETDEBUG"); + + if (pf->opts & PF_OPT_VERBOSE) + printf("set debug %s\n", d); + + return (0); +} + +int +pfctl_load_debug(struct pfctl *pf, unsigned int level) +{ + if (ioctl(pf->dev, DIOCSETDEBUG, &level)) { + warnx("DIOCSETDEBUG"); + return (1); + } + return (0); +} + +int +pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how) +{ + struct pfioc_iface pi; + + if ((loadopt & PFCTL_FLAG_OPTION) == 0) + return (0); + + bzero(&pi, sizeof(pi)); + + pi.pfiio_flags = flags; + + if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >= + sizeof(pi.pfiio_name)) + errx(1, "pfctl_set_interface_flags: strlcpy"); + + if ((pf->opts & PF_OPT_NOACTION) == 0) { + if (how == 0) { + if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi)) + err(1, "DIOCCLRIFFLAG"); + } else { + if (ioctl(pf->dev, DIOCSETIFFLAG, &pi)) + err(1, "DIOCSETIFFLAG"); + } + } + return (0); +} + +void +pfctl_debug(int dev, u_int32_t level, int opts) +{ + if (ioctl(dev, DIOCSETDEBUG, &level)) + err(1, "DIOCSETDEBUG"); + if ((opts & PF_OPT_QUIET) == 0) { + fprintf(stderr, "debug level set to '"); + switch (level) { + case PF_DEBUG_NONE: + fprintf(stderr, "none"); + break; + case PF_DEBUG_URGENT: + fprintf(stderr, "urgent"); + break; + case PF_DEBUG_MISC: + fprintf(stderr, "misc"); + break; + case PF_DEBUG_NOISY: + fprintf(stderr, "loud"); + break; + default: + fprintf(stderr, "<invalid>"); + break; + } + fprintf(stderr, "'\n"); + } +} + +int +pfctl_test_altqsupport(int dev, int opts) +{ + struct pfioc_altq pa; + + if (ioctl(dev, DIOCGETALTQS, &pa)) { + if (errno == ENODEV) { + if (opts & PF_OPT_VERBOSE) + fprintf(stderr, "No ALTQ support in kernel\n" + "ALTQ related functions disabled\n"); + return (0); + } else + err(1, "DIOCGETALTQS"); + } + return (1); +} + +int +pfctl_show_anchors(int dev, int opts, char *anchorname) +{ + struct pfioc_ruleset pr; + u_int32_t mnr, nr; + + memset(&pr, 0, sizeof(pr)); + memcpy(pr.path, anchorname, sizeof(pr.path)); + if (ioctl(dev, DIOCGETRULESETS, &pr)) { + if (errno == EINVAL) + fprintf(stderr, "Anchor '%s' not found.\n", + anchorname); + else + err(1, "DIOCGETRULESETS"); + return (-1); + } + mnr = pr.nr; + for (nr = 0; nr < mnr; ++nr) { + char sub[MAXPATHLEN]; + + pr.nr = nr; + if (ioctl(dev, DIOCGETRULESET, &pr)) + err(1, "DIOCGETRULESET"); + if (!strcmp(pr.name, PF_RESERVED_ANCHOR)) + continue; + sub[0] = 0; + if (pr.path[0]) { + strlcat(sub, pr.path, sizeof(sub)); + strlcat(sub, "/", sizeof(sub)); + } + strlcat(sub, pr.name, sizeof(sub)); + if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) + printf(" %s\n", sub); + if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub)) + return (-1); + } + return (0); +} + +const char * +pfctl_lookup_option(char *cmd, const char * const *list) +{ + if (cmd != NULL && *cmd) + for (; *list; list++) + if (!strncmp(cmd, *list, strlen(cmd))) + return (*list); + return (NULL); +} + +#ifdef __rtems__ +static int main(int argc, char *argv[]); + +RTEMS_LINKER_RWSET(bsd_prog_pfctl, char); + +int +rtems_bsd_command_pfctl(int argc, char *argv[]) +{ + int exit_code; + void *data_begin; + size_t data_size; + + data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_pfctl); + data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_pfctl); + + rtems_bsd_program_lock(); + exit_code = rtems_bsd_program_call_main_with_data_restore("pfctl", + main, argc, argv, data_begin, data_size); + rtems_bsd_program_unlock(); + + return exit_code; +} +#endif /* __rtems__ */ +int +main(int argc, char *argv[]) +{ + int error = 0; + int ch; + int mode = O_RDONLY; + int opts = 0; + int optimize = PF_OPTIMIZE_BASIC; + char anchorname[MAXPATHLEN]; + char *path; +#ifdef __rtems__ + struct getopt_data getopt_data; + memset(&getopt_data, 0, sizeof(getopt_data)); +#define optind getopt_data.optind +#define optarg getopt_data.optarg +#define opterr getopt_data.opterr +#define optopt getopt_data.optopt +#define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data) +#endif /* __rtems__ */ + + if (argc < 2) + usage(); + + while ((ch = getopt(argc, argv, + "a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:z")) != -1) { + switch (ch) { + case 'a': + anchoropt = optarg; + break; + case 'd': + opts |= PF_OPT_DISABLE; + mode = O_RDWR; + break; + case 'D': + if (pfctl_cmdline_symset(optarg) < 0) + warnx("could not parse macro definition %s", + optarg); + break; + case 'e': + opts |= PF_OPT_ENABLE; + mode = O_RDWR; + break; + case 'q': + opts |= PF_OPT_QUIET; + break; + case 'F': + clearopt = pfctl_lookup_option(optarg, clearopt_list); + if (clearopt == NULL) { + warnx("Unknown flush modifier '%s'", optarg); + usage(); + } + mode = O_RDWR; + break; + case 'i': + ifaceopt = optarg; + break; + case 'k': + if (state_killers >= 2) { + warnx("can only specify -k twice"); + usage(); + /* NOTREACHED */ + } + state_kill[state_killers++] = optarg; + mode = O_RDWR; + break; + case 'K': + if (src_node_killers >= 2) { + warnx("can only specify -K twice"); + usage(); + /* NOTREACHED */ + } + src_node_kill[src_node_killers++] = optarg; + mode = O_RDWR; + break; + case 'm': + opts |= PF_OPT_MERGE; + break; + case 'n': + opts |= PF_OPT_NOACTION; + break; + case 'N': + loadopt |= PFCTL_FLAG_NAT; + break; + case 'r': + opts |= PF_OPT_USEDNS; + break; + case 'f': + rulesopt = optarg; + mode = O_RDWR; + break; + case 'g': + opts |= PF_OPT_DEBUG; + break; + case 'A': + loadopt |= PFCTL_FLAG_ALTQ; + break; + case 'R': + loadopt |= PFCTL_FLAG_FILTER; + break; + case 'o': + optiopt = pfctl_lookup_option(optarg, optiopt_list); + if (optiopt == NULL) { + warnx("Unknown optimization '%s'", optarg); + usage(); + } + opts |= PF_OPT_OPTIMIZE; + break; + case 'O': + loadopt |= PFCTL_FLAG_OPTION; + break; + case 'p': + pf_device = optarg; + break; + case 'P': + opts |= PF_OPT_NUMERIC; + break; + case 's': + showopt = pfctl_lookup_option(optarg, showopt_list); + if (showopt == NULL) { + warnx("Unknown show modifier '%s'", optarg); + usage(); + } + break; + case 't': + tableopt = optarg; + break; + case 'T': + tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list); + if (tblcmdopt == NULL) { + warnx("Unknown table command '%s'", optarg); + usage(); + } + break; + case 'v': + if (opts & PF_OPT_VERBOSE) + opts |= PF_OPT_VERBOSE2; + opts |= PF_OPT_VERBOSE; + break; + case 'x': + debugopt = pfctl_lookup_option(optarg, debugopt_list); + if (debugopt == NULL) { + warnx("Unknown debug level '%s'", optarg); + usage(); + } + mode = O_RDWR; + break; + case 'z': + opts |= PF_OPT_CLRRULECTRS; + mode = O_RDWR; + break; + case 'h': + /* FALLTHROUGH */ + default: + usage(); + /* NOTREACHED */ + } + } + + if (tblcmdopt != NULL) { + argc -= optind; + argv += optind; + ch = *tblcmdopt; + if (ch == 'l') { + loadopt |= PFCTL_FLAG_TABLE; + tblcmdopt = NULL; + } else + mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY; + } else if (argc != optind) { + warnx("unknown command line argument: %s ...", argv[optind]); + usage(); + /* NOTREACHED */ + } + if (loadopt == 0) + loadopt = ~0; + + if ((path = calloc(1, MAXPATHLEN)) == NULL) + errx(1, "pfctl: calloc"); + memset(anchorname, 0, sizeof(anchorname)); + if (anchoropt != NULL) { + int len = strlen(anchoropt); + + if (anchoropt[len - 1] == '*') { + if (len >= 2 && anchoropt[len - 2] == '/') + anchoropt[len - 2] = '\0'; + else + anchoropt[len - 1] = '\0'; + opts |= PF_OPT_RECURSE; + } + if (strlcpy(anchorname, anchoropt, + sizeof(anchorname)) >= sizeof(anchorname)) + errx(1, "anchor name '%s' too long", + anchoropt); + loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE; + } + + if ((opts & PF_OPT_NOACTION) == 0) { + dev = open(pf_device, mode); + if (dev == -1) + err(1, "%s", pf_device); + altqsupport = pfctl_test_altqsupport(dev, opts); + } else { + dev = open(pf_device, O_RDONLY); + if (dev >= 0) + opts |= PF_OPT_DUMMYACTION; + /* turn off options */ + opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); + clearopt = showopt = debugopt = NULL; +#if !defined(ENABLE_ALTQ) + altqsupport = 0; +#else + altqsupport = 1; +#endif + } + + if (opts & PF_OPT_DISABLE) + if (pfctl_disable(dev, opts)) + error = 1; + + if (showopt != NULL) { + switch (*showopt) { + case 'A': + pfctl_show_anchors(dev, opts, anchorname); + break; + case 'r': + pfctl_load_fingerprints(dev, opts); + pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES, + anchorname, 0); + break; + case 'l': + pfctl_load_fingerprints(dev, opts); + pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS, + anchorname, 0); + break; + case 'n': + pfctl_load_fingerprints(dev, opts); + pfctl_show_nat(dev, opts, anchorname); + break; + case 'q': + pfctl_show_altq(dev, ifaceopt, opts, + opts & PF_OPT_VERBOSE2); + break; + case 's': + pfctl_show_states(dev, ifaceopt, opts); + break; + case 'S': + pfctl_show_src_nodes(dev, opts); + break; + case 'i': + pfctl_show_status(dev, opts); + break; + case 't': + pfctl_show_timeouts(dev, opts); + break; + case 'm': + pfctl_show_limits(dev, opts); + break; + case 'a': + opts |= PF_OPT_SHOWALL; + pfctl_load_fingerprints(dev, opts); + + pfctl_show_nat(dev, opts, anchorname); + pfctl_show_rules(dev, path, opts, 0, anchorname, 0); + pfctl_show_altq(dev, ifaceopt, opts, 0); + pfctl_show_states(dev, ifaceopt, opts); + pfctl_show_src_nodes(dev, opts); + pfctl_show_status(dev, opts); + pfctl_show_rules(dev, path, opts, 1, anchorname, 0); + pfctl_show_timeouts(dev, opts); + pfctl_show_limits(dev, opts); + pfctl_show_tables(anchorname, opts); + pfctl_show_fingerprints(opts); + break; + case 'T': + pfctl_show_tables(anchorname, opts); + break; + case 'o': + pfctl_load_fingerprints(dev, opts); + pfctl_show_fingerprints(opts); + break; + case 'I': + pfctl_show_ifaces(ifaceopt, opts); + break; + } + } + + if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) + pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING, + anchorname, 0); + + if (clearopt != NULL) { + if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) + errx(1, "anchor names beginning with '_' cannot " + "be modified from the command line"); + + switch (*clearopt) { + case 'r': + pfctl_clear_rules(dev, opts, anchorname); + break; + case 'n': + pfctl_clear_nat(dev, opts, anchorname); + break; + case 'q': + pfctl_clear_altq(dev, opts); + break; + case 's': + pfctl_clear_states(dev, ifaceopt, opts); + break; + case 'S': + pfctl_clear_src_nodes(dev, opts); + break; + case 'i': + pfctl_clear_stats(dev, opts); + break; + case 'a': + pfctl_clear_rules(dev, opts, anchorname); + pfctl_clear_nat(dev, opts, anchorname); + pfctl_clear_tables(anchorname, opts); + if (!*anchorname) { + pfctl_clear_altq(dev, opts); + pfctl_clear_states(dev, ifaceopt, opts); + pfctl_clear_src_nodes(dev, opts); + pfctl_clear_stats(dev, opts); + pfctl_clear_fingerprints(dev, opts); + pfctl_clear_interface_flags(dev, opts); + } + break; + case 'o': + pfctl_clear_fingerprints(dev, opts); + break; + case 'T': + pfctl_clear_tables(anchorname, opts); + break; + } + } + if (state_killers) { + if (!strcmp(state_kill[0], "label")) + pfctl_label_kill_states(dev, ifaceopt, opts); + else if (!strcmp(state_kill[0], "id")) + pfctl_id_kill_states(dev, ifaceopt, opts); + else + pfctl_net_kill_states(dev, ifaceopt, opts); + } + + if (src_node_killers) + pfctl_kill_src_nodes(dev, ifaceopt, opts); + + if (tblcmdopt != NULL) { + error = pfctl_command_tables(argc, argv, tableopt, + tblcmdopt, rulesopt, anchorname, opts); + rulesopt = NULL; + } + if (optiopt != NULL) { + switch (*optiopt) { + case 'n': + optimize = 0; + break; + case 'b': + optimize |= PF_OPTIMIZE_BASIC; + break; + case 'o': + case 'p': + optimize |= PF_OPTIMIZE_PROFILE; + break; + } + } + + if ((rulesopt != NULL) && (loadopt & PFCTL_FLAG_OPTION) && + !anchorname[0]) + if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET)) + error = 1; + + if (rulesopt != NULL && !(opts & (PF_OPT_MERGE|PF_OPT_NOACTION)) && + !anchorname[0] && (loadopt & PFCTL_FLAG_OPTION)) + if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) + error = 1; + + if (rulesopt != NULL) { + if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) + errx(1, "anchor names beginning with '_' cannot " + "be modified from the command line"); + if (pfctl_rules(dev, rulesopt, opts, optimize, + anchorname, NULL)) + error = 1; + else if (!(opts & PF_OPT_NOACTION) && + (loadopt & PFCTL_FLAG_TABLE)) + warn_namespace_collision(NULL); + } + + if (opts & PF_OPT_ENABLE) + if (pfctl_enable(dev, opts)) + error = 1; + + if (debugopt != NULL) { + switch (*debugopt) { + case 'n': + pfctl_debug(dev, PF_DEBUG_NONE, opts); + break; + case 'u': + pfctl_debug(dev, PF_DEBUG_URGENT, opts); + break; + case 'm': + pfctl_debug(dev, PF_DEBUG_MISC, opts); + break; + case 'l': + pfctl_debug(dev, PF_DEBUG_NOISY, opts); + break; + } + } + + exit(error); +} diff --git a/freebsd/sbin/pfctl/pfctl.h b/freebsd/sbin/pfctl/pfctl.h new file mode 100644 index 00000000..2c69bc20 --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl.h @@ -0,0 +1,130 @@ +/* $OpenBSD: pfctl.h,v 1.42 2007/12/05 12:01:47 chl Exp $ */ + +/* + * Copyright (c) 2001 Daniel Hartmeier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _PFCTL_H_ +#define _PFCTL_H_ + +enum pfctl_show { PFCTL_SHOW_RULES, PFCTL_SHOW_LABELS, PFCTL_SHOW_NOTHING }; + +enum { PFRB_TABLES = 1, PFRB_TSTATS, PFRB_ADDRS, PFRB_ASTATS, + PFRB_IFACES, PFRB_TRANS, PFRB_MAX }; +struct pfr_buffer { + int pfrb_type; /* type of content, see enum above */ + int pfrb_size; /* number of objects in buffer */ + int pfrb_msize; /* maximum number of objects in buffer */ + void *pfrb_caddr; /* malloc'ated memory area */ +}; +#define PFRB_FOREACH(var, buf) \ + for ((var) = pfr_buf_next((buf), NULL); \ + (var) != NULL; \ + (var) = pfr_buf_next((buf), (var))) + +int pfr_get_fd(void); +int pfr_clr_tables(struct pfr_table *, int *, int); +int pfr_add_tables(struct pfr_table *, int, int *, int); +int pfr_del_tables(struct pfr_table *, int, int *, int); +int pfr_get_tables(struct pfr_table *, struct pfr_table *, int *, int); +int pfr_get_tstats(struct pfr_table *, struct pfr_tstats *, int *, int); +int pfr_clr_tstats(struct pfr_table *, int, int *, int); +int pfr_clr_addrs(struct pfr_table *, int *, int); +int pfr_add_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); +int pfr_del_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); +int pfr_set_addrs(struct pfr_table *, struct pfr_addr *, int, int *, + int *, int *, int *, int); +int pfr_get_addrs(struct pfr_table *, struct pfr_addr *, int *, int); +int pfr_get_astats(struct pfr_table *, struct pfr_astats *, int *, int); +int pfr_tst_addrs(struct pfr_table *, struct pfr_addr *, int, int *, int); +int pfr_ina_define(struct pfr_table *, struct pfr_addr *, int, int *, + int *, int, int); +void pfr_buf_clear(struct pfr_buffer *); +int pfr_buf_add(struct pfr_buffer *, const void *); +void *pfr_buf_next(struct pfr_buffer *, const void *); +int pfr_buf_grow(struct pfr_buffer *, int); +int pfr_buf_load(struct pfr_buffer *, char *, int, + int (*)(struct pfr_buffer *, char *, int)); +char *pfr_strerror(int); +int pfi_get_ifaces(const char *, struct pfi_kif *, int *); +int pfi_clr_istats(const char *, int *, int); + +void pfctl_print_title(char *); +int pfctl_clear_tables(const char *, int); +int pfctl_show_tables(const char *, int); +int pfctl_command_tables(int, char *[], char *, const char *, char *, + const char *, int); +int pfctl_show_altq(int, const char *, int, int); +void warn_namespace_collision(const char *); +int pfctl_show_ifaces(const char *, int); +FILE *pfctl_fopen(const char *, const char *); + +#ifdef __FreeBSD__ +extern int altqsupport; +extern int dummynetsupport; +#define HTONL(x) (x) = htonl((__uint32_t)(x)) +#endif + +#ifndef DEFAULT_PRIORITY +#define DEFAULT_PRIORITY 1 +#endif + +#ifndef DEFAULT_QLIMIT +#define DEFAULT_QLIMIT 50 +#endif + +/* + * generalized service curve used for admission control + */ +struct segment { + LIST_ENTRY(segment) _next; + double x, y, d, m; +}; + +extern int loadopt; + +int check_commit_altq(int, int); +void pfaltq_store(struct pf_altq *); +struct pf_altq *pfaltq_lookup(const char *); +char *rate2str(double); + +void print_addr(struct pf_addr_wrap *, sa_family_t, int); +void print_host(struct pf_addr *, u_int16_t p, sa_family_t, int); +void print_seq(struct pfsync_state_peer *); +void print_state(struct pfsync_state *, int); +int unmask(struct pf_addr *, sa_family_t); + +int pfctl_cmdline_symset(char *); +int pfctl_add_trans(struct pfr_buffer *, int, const char *); +u_int32_t + pfctl_get_ticket(struct pfr_buffer *, int, const char *); +int pfctl_trans(int, struct pfr_buffer *, u_long, int); + +#endif /* _PFCTL_H_ */ diff --git a/freebsd/sbin/pfctl/pfctl_altq.c b/freebsd/sbin/pfctl/pfctl_altq.c new file mode 100644 index 00000000..145d60ae --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl_altq.c @@ -0,0 +1,1536 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ + +/* $OpenBSD: pfctl_altq.c,v 1.93 2007/10/15 02:16:35 deraadt Exp $ */ + +/* + * Copyright (c) 2002 + * Sony Computer Science Laboratories Inc. + * Copyright (c) 2002, 2003 Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <net/pfvar.h> + +#include <err.h> +#include <errno.h> +#include <limits.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <net/altq/altq.h> +#include <net/altq/altq_cbq.h> +#include <net/altq/altq_codel.h> +#include <net/altq/altq_priq.h> +#include <net/altq/altq_hfsc.h> +#include <net/altq/altq_fairq.h> + +#include "pfctl_parser.h" +#include "pfctl.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-pfctl_altq-data.h" +#endif /* __rtems__ */ + +#define is_sc_null(sc) (((sc) == NULL) || ((sc)->m1 == 0 && (sc)->m2 == 0)) + +static TAILQ_HEAD(altqs, pf_altq) altqs = TAILQ_HEAD_INITIALIZER(altqs); +static LIST_HEAD(gen_sc, segment) rtsc, lssc; + +struct pf_altq *qname_to_pfaltq(const char *, const char *); +u_int32_t qname_to_qid(const char *); + +static int eval_pfqueue_cbq(struct pfctl *, struct pf_altq *); +static int cbq_compute_idletime(struct pfctl *, struct pf_altq *); +static int check_commit_cbq(int, int, struct pf_altq *); +static int print_cbq_opts(const struct pf_altq *); + +static int print_codel_opts(const struct pf_altq *, + const struct node_queue_opt *); + +static int eval_pfqueue_priq(struct pfctl *, struct pf_altq *); +static int check_commit_priq(int, int, struct pf_altq *); +static int print_priq_opts(const struct pf_altq *); + +static int eval_pfqueue_hfsc(struct pfctl *, struct pf_altq *); +static int check_commit_hfsc(int, int, struct pf_altq *); +static int print_hfsc_opts(const struct pf_altq *, + const struct node_queue_opt *); + +static int eval_pfqueue_fairq(struct pfctl *, struct pf_altq *); +static int print_fairq_opts(const struct pf_altq *, + const struct node_queue_opt *); +static int check_commit_fairq(int, int, struct pf_altq *); + +static void gsc_add_sc(struct gen_sc *, struct service_curve *); +static int is_gsc_under_sc(struct gen_sc *, + struct service_curve *); +static void gsc_destroy(struct gen_sc *); +static struct segment *gsc_getentry(struct gen_sc *, double); +static int gsc_add_seg(struct gen_sc *, double, double, double, + double); +static double sc_x2y(struct service_curve *, double); + +#ifdef __FreeBSD__ +u_int32_t getifspeed(int, char *); +#else +u_int32_t getifspeed(char *); +#endif +u_long getifmtu(char *); +int eval_queue_opts(struct pf_altq *, struct node_queue_opt *, + u_int32_t); +u_int32_t eval_bwspec(struct node_queue_bw *, u_int32_t); +void print_hfsc_sc(const char *, u_int, u_int, u_int, + const struct node_hfsc_sc *); +void print_fairq_sc(const char *, u_int, u_int, u_int, + const struct node_fairq_sc *); + +void +pfaltq_store(struct pf_altq *a) +{ + struct pf_altq *altq; + + if ((altq = malloc(sizeof(*altq))) == NULL) + err(1, "malloc"); + memcpy(altq, a, sizeof(struct pf_altq)); + TAILQ_INSERT_TAIL(&altqs, altq, entries); +} + +struct pf_altq * +pfaltq_lookup(const char *ifname) +{ + struct pf_altq *altq; + + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && + altq->qname[0] == 0) + return (altq); + } + return (NULL); +} + +struct pf_altq * +qname_to_pfaltq(const char *qname, const char *ifname) +{ + struct pf_altq *altq; + + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(ifname, altq->ifname, IFNAMSIZ) == 0 && + strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) + return (altq); + } + return (NULL); +} + +u_int32_t +qname_to_qid(const char *qname) +{ + struct pf_altq *altq; + + /* + * We guarantee that same named queues on different interfaces + * have the same qid, so we do NOT need to limit matching on + * one interface! + */ + + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(qname, altq->qname, PF_QNAME_SIZE) == 0) + return (altq->qid); + } + return (0); +} + +void +print_altq(const struct pf_altq *a, unsigned int level, + struct node_queue_bw *bw, struct node_queue_opt *qopts) +{ + if (a->qname[0] != 0) { + print_queue(a, level, bw, 1, qopts); + return; + } + +#ifdef __FreeBSD__ + if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) + printf("INACTIVE "); +#endif + + printf("altq on %s ", a->ifname); + + switch (a->scheduler) { + case ALTQT_CBQ: + if (!print_cbq_opts(a)) + printf("cbq "); + break; + case ALTQT_PRIQ: + if (!print_priq_opts(a)) + printf("priq "); + break; + case ALTQT_HFSC: + if (!print_hfsc_opts(a, qopts)) + printf("hfsc "); + break; + case ALTQT_FAIRQ: + if (!print_fairq_opts(a, qopts)) + printf("fairq "); + break; + case ALTQT_CODEL: + if (!print_codel_opts(a, qopts)) + printf("codel "); + break; + } + + if (bw != NULL && bw->bw_percent > 0) { + if (bw->bw_percent < 100) + printf("bandwidth %u%% ", bw->bw_percent); + } else + printf("bandwidth %s ", rate2str((double)a->ifbandwidth)); + + if (a->qlimit != DEFAULT_QLIMIT) + printf("qlimit %u ", a->qlimit); + printf("tbrsize %u ", a->tbrsize); +} + +void +print_queue(const struct pf_altq *a, unsigned int level, + struct node_queue_bw *bw, int print_interface, + struct node_queue_opt *qopts) +{ + unsigned int i; + +#ifdef __FreeBSD__ + if (a->local_flags & PFALTQ_FLAG_IF_REMOVED) + printf("INACTIVE "); +#endif + printf("queue "); + for (i = 0; i < level; ++i) + printf(" "); + printf("%s ", a->qname); + if (print_interface) + printf("on %s ", a->ifname); + if (a->scheduler == ALTQT_CBQ || a->scheduler == ALTQT_HFSC || + a->scheduler == ALTQT_FAIRQ) { + if (bw != NULL && bw->bw_percent > 0) { + if (bw->bw_percent < 100) + printf("bandwidth %u%% ", bw->bw_percent); + } else + printf("bandwidth %s ", rate2str((double)a->bandwidth)); + } + if (a->priority != DEFAULT_PRIORITY) + printf("priority %u ", a->priority); + if (a->qlimit != DEFAULT_QLIMIT) + printf("qlimit %u ", a->qlimit); + switch (a->scheduler) { + case ALTQT_CBQ: + print_cbq_opts(a); + break; + case ALTQT_PRIQ: + print_priq_opts(a); + break; + case ALTQT_HFSC: + print_hfsc_opts(a, qopts); + break; + case ALTQT_FAIRQ: + print_fairq_opts(a, qopts); + break; + } +} + +/* + * eval_pfaltq computes the discipline parameters. + */ +int +eval_pfaltq(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, + struct node_queue_opt *opts) +{ + u_int rate, size, errors = 0; + + if (bw->bw_absolute > 0) + pa->ifbandwidth = bw->bw_absolute; + else +#ifdef __FreeBSD__ + if ((rate = getifspeed(pf->dev, pa->ifname)) == 0) { +#else + if ((rate = getifspeed(pa->ifname)) == 0) { +#endif + fprintf(stderr, "interface %s does not know its bandwidth, " + "please specify an absolute bandwidth\n", + pa->ifname); + errors++; + } else if ((pa->ifbandwidth = eval_bwspec(bw, rate)) == 0) + pa->ifbandwidth = rate; + + errors += eval_queue_opts(pa, opts, pa->ifbandwidth); + + /* if tbrsize is not specified, use heuristics */ + if (pa->tbrsize == 0) { + rate = pa->ifbandwidth; + if (rate <= 1 * 1000 * 1000) + size = 1; + else if (rate <= 10 * 1000 * 1000) + size = 4; + else if (rate <= 200 * 1000 * 1000) + size = 8; + else + size = 24; + size = size * getifmtu(pa->ifname); + if (size > 0xffff) + size = 0xffff; + pa->tbrsize = size; + } + return (errors); +} + +/* + * check_commit_altq does consistency check for each interface + */ +int +check_commit_altq(int dev, int opts) +{ + struct pf_altq *altq; + int error = 0; + + /* call the discipline check for each interface. */ + TAILQ_FOREACH(altq, &altqs, entries) { + if (altq->qname[0] == 0) { + switch (altq->scheduler) { + case ALTQT_CBQ: + error = check_commit_cbq(dev, opts, altq); + break; + case ALTQT_PRIQ: + error = check_commit_priq(dev, opts, altq); + break; + case ALTQT_HFSC: + error = check_commit_hfsc(dev, opts, altq); + break; + case ALTQT_FAIRQ: + error = check_commit_fairq(dev, opts, altq); + break; + default: + break; + } + } + } + return (error); +} + +/* + * eval_pfqueue computes the queue parameters. + */ +int +eval_pfqueue(struct pfctl *pf, struct pf_altq *pa, struct node_queue_bw *bw, + struct node_queue_opt *opts) +{ + /* should be merged with expand_queue */ + struct pf_altq *if_pa, *parent, *altq; + u_int32_t bwsum; + int error = 0; + + /* find the corresponding interface and copy fields used by queues */ + if ((if_pa = pfaltq_lookup(pa->ifname)) == NULL) { + fprintf(stderr, "altq not defined on %s\n", pa->ifname); + return (1); + } + pa->scheduler = if_pa->scheduler; + pa->ifbandwidth = if_pa->ifbandwidth; + + if (qname_to_pfaltq(pa->qname, pa->ifname) != NULL) { + fprintf(stderr, "queue %s already exists on interface %s\n", + pa->qname, pa->ifname); + return (1); + } + pa->qid = qname_to_qid(pa->qname); + + parent = NULL; + if (pa->parent[0] != 0) { + parent = qname_to_pfaltq(pa->parent, pa->ifname); + if (parent == NULL) { + fprintf(stderr, "parent %s not found for %s\n", + pa->parent, pa->qname); + return (1); + } + pa->parent_qid = parent->qid; + } + if (pa->qlimit == 0) + pa->qlimit = DEFAULT_QLIMIT; + + if (pa->scheduler == ALTQT_CBQ || pa->scheduler == ALTQT_HFSC || + pa->scheduler == ALTQT_FAIRQ) { + pa->bandwidth = eval_bwspec(bw, + parent == NULL ? 0 : parent->bandwidth); + + if (pa->bandwidth > pa->ifbandwidth) { + fprintf(stderr, "bandwidth for %s higher than " + "interface\n", pa->qname); + return (1); + } + /* check the sum of the child bandwidth is under parent's */ + if (parent != NULL) { + if (pa->bandwidth > parent->bandwidth) { + warnx("bandwidth for %s higher than parent", + pa->qname); + return (1); + } + bwsum = 0; + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, + IFNAMSIZ) == 0 && + altq->qname[0] != 0 && + strncmp(altq->parent, pa->parent, + PF_QNAME_SIZE) == 0) + bwsum += altq->bandwidth; + } + bwsum += pa->bandwidth; + if (bwsum > parent->bandwidth) { + warnx("the sum of the child bandwidth higher" + " than parent \"%s\"", parent->qname); + } + } + } + + if (eval_queue_opts(pa, opts, parent == NULL? 0 : parent->bandwidth)) + return (1); + + switch (pa->scheduler) { + case ALTQT_CBQ: + error = eval_pfqueue_cbq(pf, pa); + break; + case ALTQT_PRIQ: + error = eval_pfqueue_priq(pf, pa); + break; + case ALTQT_HFSC: + error = eval_pfqueue_hfsc(pf, pa); + break; + case ALTQT_FAIRQ: + error = eval_pfqueue_fairq(pf, pa); + break; + default: + break; + } + return (error); +} + +/* + * CBQ support functions + */ +#define RM_FILTER_GAIN 5 /* log2 of gain, e.g., 5 => 31/32 */ +#define RM_NS_PER_SEC (1000000000) + +static int +eval_pfqueue_cbq(struct pfctl *pf, struct pf_altq *pa) +{ + struct cbq_opts *opts; + u_int ifmtu; + + if (pa->priority >= CBQ_MAXPRI) { + warnx("priority out of range: max %d", CBQ_MAXPRI - 1); + return (-1); + } + + ifmtu = getifmtu(pa->ifname); + opts = &pa->pq_u.cbq_opts; + + if (opts->pktsize == 0) { /* use default */ + opts->pktsize = ifmtu; + if (opts->pktsize > MCLBYTES) /* do what TCP does */ + opts->pktsize &= ~MCLBYTES; + } else if (opts->pktsize > ifmtu) + opts->pktsize = ifmtu; + if (opts->maxpktsize == 0) /* use default */ + opts->maxpktsize = ifmtu; + else if (opts->maxpktsize > ifmtu) + opts->pktsize = ifmtu; + + if (opts->pktsize > opts->maxpktsize) + opts->pktsize = opts->maxpktsize; + + if (pa->parent[0] == 0) + opts->flags |= (CBQCLF_ROOTCLASS | CBQCLF_WRR); + + cbq_compute_idletime(pf, pa); + return (0); +} + +/* + * compute ns_per_byte, maxidle, minidle, and offtime + */ +static int +cbq_compute_idletime(struct pfctl *pf, struct pf_altq *pa) +{ + struct cbq_opts *opts; + double maxidle_s, maxidle, minidle; + double offtime, nsPerByte, ifnsPerByte, ptime, cptime; + double z, g, f, gton, gtom; + u_int minburst, maxburst; + + opts = &pa->pq_u.cbq_opts; + ifnsPerByte = (1.0 / (double)pa->ifbandwidth) * RM_NS_PER_SEC * 8; + minburst = opts->minburst; + maxburst = opts->maxburst; + + if (pa->bandwidth == 0) + f = 0.0001; /* small enough? */ + else + f = ((double) pa->bandwidth / (double) pa->ifbandwidth); + + nsPerByte = ifnsPerByte / f; + ptime = (double)opts->pktsize * ifnsPerByte; + cptime = ptime * (1.0 - f) / f; + + if (nsPerByte * (double)opts->maxpktsize > (double)INT_MAX) { + /* + * this causes integer overflow in kernel! + * (bandwidth < 6Kbps when max_pkt_size=1500) + */ + if (pa->bandwidth != 0 && (pf->opts & PF_OPT_QUIET) == 0) + warnx("queue bandwidth must be larger than %s", + rate2str(ifnsPerByte * (double)opts->maxpktsize / + (double)INT_MAX * (double)pa->ifbandwidth)); + fprintf(stderr, "cbq: queue %s is too slow!\n", + pa->qname); + nsPerByte = (double)(INT_MAX / opts->maxpktsize); + } + + if (maxburst == 0) { /* use default */ + if (cptime > 10.0 * 1000000) + maxburst = 4; + else + maxburst = 16; + } + if (minburst == 0) /* use default */ + minburst = 2; + if (minburst > maxburst) + minburst = maxburst; + + z = (double)(1 << RM_FILTER_GAIN); + g = (1.0 - 1.0 / z); + gton = pow(g, (double)maxburst); + gtom = pow(g, (double)(minburst-1)); + maxidle = ((1.0 / f - 1.0) * ((1.0 - gton) / gton)); + maxidle_s = (1.0 - g); + if (maxidle > maxidle_s) + maxidle = ptime * maxidle; + else + maxidle = ptime * maxidle_s; + offtime = cptime * (1.0 + 1.0/(1.0 - g) * (1.0 - gtom) / gtom); + minidle = -((double)opts->maxpktsize * (double)nsPerByte); + + /* scale parameters */ + maxidle = ((maxidle * 8.0) / nsPerByte) * + pow(2.0, (double)RM_FILTER_GAIN); + offtime = (offtime * 8.0) / nsPerByte * + pow(2.0, (double)RM_FILTER_GAIN); + minidle = ((minidle * 8.0) / nsPerByte) * + pow(2.0, (double)RM_FILTER_GAIN); + + maxidle = maxidle / 1000.0; + offtime = offtime / 1000.0; + minidle = minidle / 1000.0; + + opts->minburst = minburst; + opts->maxburst = maxburst; + opts->ns_per_byte = (u_int)nsPerByte; + opts->maxidle = (u_int)fabs(maxidle); + opts->minidle = (int)minidle; + opts->offtime = (u_int)fabs(offtime); + + return (0); +} + +static int +check_commit_cbq(int dev, int opts, struct pf_altq *pa) +{ + struct pf_altq *altq; + int root_class, default_class; + int error = 0; + + /* + * check if cbq has one root queue and one default queue + * for this interface + */ + root_class = default_class = 0; + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) + continue; + if (altq->qname[0] == 0) /* this is for interface */ + continue; + if (altq->pq_u.cbq_opts.flags & CBQCLF_ROOTCLASS) + root_class++; + if (altq->pq_u.cbq_opts.flags & CBQCLF_DEFCLASS) + default_class++; + } + if (root_class != 1) { + warnx("should have one root queue on %s", pa->ifname); + error++; + } + if (default_class != 1) { + warnx("should have one default queue on %s", pa->ifname); + error++; + } + return (error); +} + +static int +print_cbq_opts(const struct pf_altq *a) +{ + const struct cbq_opts *opts; + + opts = &a->pq_u.cbq_opts; + if (opts->flags) { + printf("cbq("); + if (opts->flags & CBQCLF_RED) + printf(" red"); + if (opts->flags & CBQCLF_ECN) + printf(" ecn"); + if (opts->flags & CBQCLF_RIO) + printf(" rio"); + if (opts->flags & CBQCLF_CODEL) + printf(" codel"); + if (opts->flags & CBQCLF_CLEARDSCP) + printf(" cleardscp"); + if (opts->flags & CBQCLF_FLOWVALVE) + printf(" flowvalve"); + if (opts->flags & CBQCLF_BORROW) + printf(" borrow"); + if (opts->flags & CBQCLF_WRR) + printf(" wrr"); + if (opts->flags & CBQCLF_EFFICIENT) + printf(" efficient"); + if (opts->flags & CBQCLF_ROOTCLASS) + printf(" root"); + if (opts->flags & CBQCLF_DEFCLASS) + printf(" default"); + printf(" ) "); + + return (1); + } else + return (0); +} + +/* + * PRIQ support functions + */ +static int +eval_pfqueue_priq(struct pfctl *pf, struct pf_altq *pa) +{ + struct pf_altq *altq; + + if (pa->priority >= PRIQ_MAXPRI) { + warnx("priority out of range: max %d", PRIQ_MAXPRI - 1); + return (-1); + } + /* the priority should be unique for the interface */ + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) == 0 && + altq->qname[0] != 0 && altq->priority == pa->priority) { + warnx("%s and %s have the same priority", + altq->qname, pa->qname); + return (-1); + } + } + + return (0); +} + +static int +check_commit_priq(int dev, int opts, struct pf_altq *pa) +{ + struct pf_altq *altq; + int default_class; + int error = 0; + + /* + * check if priq has one default class for this interface + */ + default_class = 0; + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) + continue; + if (altq->qname[0] == 0) /* this is for interface */ + continue; + if (altq->pq_u.priq_opts.flags & PRCF_DEFAULTCLASS) + default_class++; + } + if (default_class != 1) { + warnx("should have one default queue on %s", pa->ifname); + error++; + } + return (error); +} + +static int +print_priq_opts(const struct pf_altq *a) +{ + const struct priq_opts *opts; + + opts = &a->pq_u.priq_opts; + + if (opts->flags) { + printf("priq("); + if (opts->flags & PRCF_RED) + printf(" red"); + if (opts->flags & PRCF_ECN) + printf(" ecn"); + if (opts->flags & PRCF_RIO) + printf(" rio"); + if (opts->flags & PRCF_CODEL) + printf(" codel"); + if (opts->flags & PRCF_CLEARDSCP) + printf(" cleardscp"); + if (opts->flags & PRCF_DEFAULTCLASS) + printf(" default"); + printf(" ) "); + + return (1); + } else + return (0); +} + +/* + * HFSC support functions + */ +static int +eval_pfqueue_hfsc(struct pfctl *pf, struct pf_altq *pa) +{ + struct pf_altq *altq, *parent; + struct hfsc_opts *opts; + struct service_curve sc; + + opts = &pa->pq_u.hfsc_opts; + + if (pa->parent[0] == 0) { + /* root queue */ + opts->lssc_m1 = pa->ifbandwidth; + opts->lssc_m2 = pa->ifbandwidth; + opts->lssc_d = 0; + return (0); + } + + LIST_INIT(&rtsc); + LIST_INIT(&lssc); + + /* if link_share is not specified, use bandwidth */ + if (opts->lssc_m2 == 0) + opts->lssc_m2 = pa->bandwidth; + + if ((opts->rtsc_m1 > 0 && opts->rtsc_m2 == 0) || + (opts->lssc_m1 > 0 && opts->lssc_m2 == 0) || + (opts->ulsc_m1 > 0 && opts->ulsc_m2 == 0)) { + warnx("m2 is zero for %s", pa->qname); + return (-1); + } + + if ((opts->rtsc_m1 < opts->rtsc_m2 && opts->rtsc_m1 != 0) || + (opts->lssc_m1 < opts->lssc_m2 && opts->lssc_m1 != 0) || + (opts->ulsc_m1 < opts->ulsc_m2 && opts->ulsc_m1 != 0)) { + warnx("m1 must be zero for convex curve: %s", pa->qname); + return (-1); + } + + /* + * admission control: + * for the real-time service curve, the sum of the service curves + * should not exceed 80% of the interface bandwidth. 20% is reserved + * not to over-commit the actual interface bandwidth. + * for the linkshare service curve, the sum of the child service + * curve should not exceed the parent service curve. + * for the upper-limit service curve, the assigned bandwidth should + * be smaller than the interface bandwidth, and the upper-limit should + * be larger than the real-time service curve when both are defined. + */ + parent = qname_to_pfaltq(pa->parent, pa->ifname); + if (parent == NULL) + errx(1, "parent %s not found for %s", pa->parent, pa->qname); + + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) + continue; + if (altq->qname[0] == 0) /* this is for interface */ + continue; + + /* if the class has a real-time service curve, add it. */ + if (opts->rtsc_m2 != 0 && altq->pq_u.hfsc_opts.rtsc_m2 != 0) { + sc.m1 = altq->pq_u.hfsc_opts.rtsc_m1; + sc.d = altq->pq_u.hfsc_opts.rtsc_d; + sc.m2 = altq->pq_u.hfsc_opts.rtsc_m2; + gsc_add_sc(&rtsc, &sc); + } + + if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) + continue; + + /* if the class has a linkshare service curve, add it. */ + if (opts->lssc_m2 != 0 && altq->pq_u.hfsc_opts.lssc_m2 != 0) { + sc.m1 = altq->pq_u.hfsc_opts.lssc_m1; + sc.d = altq->pq_u.hfsc_opts.lssc_d; + sc.m2 = altq->pq_u.hfsc_opts.lssc_m2; + gsc_add_sc(&lssc, &sc); + } + } + + /* check the real-time service curve. reserve 20% of interface bw */ + if (opts->rtsc_m2 != 0) { + /* add this queue to the sum */ + sc.m1 = opts->rtsc_m1; + sc.d = opts->rtsc_d; + sc.m2 = opts->rtsc_m2; + gsc_add_sc(&rtsc, &sc); + /* compare the sum with 80% of the interface */ + sc.m1 = 0; + sc.d = 0; + sc.m2 = pa->ifbandwidth / 100 * 80; + if (!is_gsc_under_sc(&rtsc, &sc)) { + warnx("real-time sc exceeds 80%% of the interface " + "bandwidth (%s)", rate2str((double)sc.m2)); + goto err_ret; + } + } + + /* check the linkshare service curve. */ + if (opts->lssc_m2 != 0) { + /* add this queue to the child sum */ + sc.m1 = opts->lssc_m1; + sc.d = opts->lssc_d; + sc.m2 = opts->lssc_m2; + gsc_add_sc(&lssc, &sc); + /* compare the sum of the children with parent's sc */ + sc.m1 = parent->pq_u.hfsc_opts.lssc_m1; + sc.d = parent->pq_u.hfsc_opts.lssc_d; + sc.m2 = parent->pq_u.hfsc_opts.lssc_m2; + if (!is_gsc_under_sc(&lssc, &sc)) { + warnx("linkshare sc exceeds parent's sc"); + goto err_ret; + } + } + + /* check the upper-limit service curve. */ + if (opts->ulsc_m2 != 0) { + if (opts->ulsc_m1 > pa->ifbandwidth || + opts->ulsc_m2 > pa->ifbandwidth) { + warnx("upper-limit larger than interface bandwidth"); + goto err_ret; + } + if (opts->rtsc_m2 != 0 && opts->rtsc_m2 > opts->ulsc_m2) { + warnx("upper-limit sc smaller than real-time sc"); + goto err_ret; + } + } + + gsc_destroy(&rtsc); + gsc_destroy(&lssc); + + return (0); + +err_ret: + gsc_destroy(&rtsc); + gsc_destroy(&lssc); + return (-1); +} + +/* + * FAIRQ support functions + */ +static int +eval_pfqueue_fairq(struct pfctl *pf __unused, struct pf_altq *pa) +{ + struct pf_altq *altq, *parent; + struct fairq_opts *opts; + struct service_curve sc; + + opts = &pa->pq_u.fairq_opts; + + if (pa->parent[0] == 0) { + /* root queue */ + opts->lssc_m1 = pa->ifbandwidth; + opts->lssc_m2 = pa->ifbandwidth; + opts->lssc_d = 0; + return (0); + } + + LIST_INIT(&lssc); + + /* if link_share is not specified, use bandwidth */ + if (opts->lssc_m2 == 0) + opts->lssc_m2 = pa->bandwidth; + + /* + * admission control: + * for the real-time service curve, the sum of the service curves + * should not exceed 80% of the interface bandwidth. 20% is reserved + * not to over-commit the actual interface bandwidth. + * for the link-sharing service curve, the sum of the child service + * curve should not exceed the parent service curve. + * for the upper-limit service curve, the assigned bandwidth should + * be smaller than the interface bandwidth, and the upper-limit should + * be larger than the real-time service curve when both are defined. + */ + parent = qname_to_pfaltq(pa->parent, pa->ifname); + if (parent == NULL) + errx(1, "parent %s not found for %s", pa->parent, pa->qname); + + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) + continue; + if (altq->qname[0] == 0) /* this is for interface */ + continue; + + if (strncmp(altq->parent, pa->parent, PF_QNAME_SIZE) != 0) + continue; + + /* if the class has a link-sharing service curve, add it. */ + if (opts->lssc_m2 != 0 && altq->pq_u.fairq_opts.lssc_m2 != 0) { + sc.m1 = altq->pq_u.fairq_opts.lssc_m1; + sc.d = altq->pq_u.fairq_opts.lssc_d; + sc.m2 = altq->pq_u.fairq_opts.lssc_m2; + gsc_add_sc(&lssc, &sc); + } + } + + /* check the link-sharing service curve. */ + if (opts->lssc_m2 != 0) { + sc.m1 = parent->pq_u.fairq_opts.lssc_m1; + sc.d = parent->pq_u.fairq_opts.lssc_d; + sc.m2 = parent->pq_u.fairq_opts.lssc_m2; + if (!is_gsc_under_sc(&lssc, &sc)) { + warnx("link-sharing sc exceeds parent's sc"); + goto err_ret; + } + } + + gsc_destroy(&lssc); + + return (0); + +err_ret: + gsc_destroy(&lssc); + return (-1); +} + +static int +check_commit_hfsc(int dev, int opts, struct pf_altq *pa) +{ + struct pf_altq *altq, *def = NULL; + int default_class; + int error = 0; + + /* check if hfsc has one default queue for this interface */ + default_class = 0; + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) + continue; + if (altq->qname[0] == 0) /* this is for interface */ + continue; + if (altq->parent[0] == 0) /* dummy root */ + continue; + if (altq->pq_u.hfsc_opts.flags & HFCF_DEFAULTCLASS) { + default_class++; + def = altq; + } + } + if (default_class != 1) { + warnx("should have one default queue on %s", pa->ifname); + return (1); + } + /* make sure the default queue is a leaf */ + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) + continue; + if (altq->qname[0] == 0) /* this is for interface */ + continue; + if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { + warnx("default queue is not a leaf"); + error++; + } + } + return (error); +} + +static int +check_commit_fairq(int dev __unused, int opts __unused, struct pf_altq *pa) +{ + struct pf_altq *altq, *def = NULL; + int default_class; + int error = 0; + + /* check if fairq has one default queue for this interface */ + default_class = 0; + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) + continue; + if (altq->qname[0] == 0) /* this is for interface */ + continue; + if (altq->pq_u.fairq_opts.flags & FARF_DEFAULTCLASS) { + default_class++; + def = altq; + } + } + if (default_class != 1) { + warnx("should have one default queue on %s", pa->ifname); + return (1); + } + /* make sure the default queue is a leaf */ + TAILQ_FOREACH(altq, &altqs, entries) { + if (strncmp(altq->ifname, pa->ifname, IFNAMSIZ) != 0) + continue; + if (altq->qname[0] == 0) /* this is for interface */ + continue; + if (strncmp(altq->parent, def->qname, PF_QNAME_SIZE) == 0) { + warnx("default queue is not a leaf"); + error++; + } + } + return (error); +} + +static int +print_hfsc_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) +{ + const struct hfsc_opts *opts; + const struct node_hfsc_sc *rtsc, *lssc, *ulsc; + + opts = &a->pq_u.hfsc_opts; + if (qopts == NULL) + rtsc = lssc = ulsc = NULL; + else { + rtsc = &qopts->data.hfsc_opts.realtime; + lssc = &qopts->data.hfsc_opts.linkshare; + ulsc = &qopts->data.hfsc_opts.upperlimit; + } + + if (opts->flags || opts->rtsc_m2 != 0 || opts->ulsc_m2 != 0 || + (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || + opts->lssc_d != 0))) { + printf("hfsc("); + if (opts->flags & HFCF_RED) + printf(" red"); + if (opts->flags & HFCF_ECN) + printf(" ecn"); + if (opts->flags & HFCF_RIO) + printf(" rio"); + if (opts->flags & HFCF_CODEL) + printf(" codel"); + if (opts->flags & HFCF_CLEARDSCP) + printf(" cleardscp"); + if (opts->flags & HFCF_DEFAULTCLASS) + printf(" default"); + if (opts->rtsc_m2 != 0) + print_hfsc_sc("realtime", opts->rtsc_m1, opts->rtsc_d, + opts->rtsc_m2, rtsc); + if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || + opts->lssc_d != 0)) + print_hfsc_sc("linkshare", opts->lssc_m1, opts->lssc_d, + opts->lssc_m2, lssc); + if (opts->ulsc_m2 != 0) + print_hfsc_sc("upperlimit", opts->ulsc_m1, opts->ulsc_d, + opts->ulsc_m2, ulsc); + printf(" ) "); + + return (1); + } else + return (0); +} + +static int +print_codel_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) +{ + const struct codel_opts *opts; + + opts = &a->pq_u.codel_opts; + if (opts->target || opts->interval || opts->ecn) { + printf("codel("); + if (opts->target) + printf(" target %d", opts->target); + if (opts->interval) + printf(" interval %d", opts->interval); + if (opts->ecn) + printf("ecn"); + printf(" ) "); + + return (1); + } + + return (0); +} + +static int +print_fairq_opts(const struct pf_altq *a, const struct node_queue_opt *qopts) +{ + const struct fairq_opts *opts; + const struct node_fairq_sc *loc_lssc; + + opts = &a->pq_u.fairq_opts; + if (qopts == NULL) + loc_lssc = NULL; + else + loc_lssc = &qopts->data.fairq_opts.linkshare; + + if (opts->flags || + (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || + opts->lssc_d != 0))) { + printf("fairq("); + if (opts->flags & FARF_RED) + printf(" red"); + if (opts->flags & FARF_ECN) + printf(" ecn"); + if (opts->flags & FARF_RIO) + printf(" rio"); + if (opts->flags & FARF_CODEL) + printf(" codel"); + if (opts->flags & FARF_CLEARDSCP) + printf(" cleardscp"); + if (opts->flags & FARF_DEFAULTCLASS) + printf(" default"); + if (opts->lssc_m2 != 0 && (opts->lssc_m2 != a->bandwidth || + opts->lssc_d != 0)) + print_fairq_sc("linkshare", opts->lssc_m1, opts->lssc_d, + opts->lssc_m2, loc_lssc); + printf(" ) "); + + return (1); + } else + return (0); +} + +/* + * admission control using generalized service curve + */ + +/* add a new service curve to a generalized service curve */ +static void +gsc_add_sc(struct gen_sc *gsc, struct service_curve *sc) +{ + if (is_sc_null(sc)) + return; + if (sc->d != 0) + gsc_add_seg(gsc, 0.0, 0.0, (double)sc->d, (double)sc->m1); + gsc_add_seg(gsc, (double)sc->d, 0.0, INFINITY, (double)sc->m2); +} + +/* + * check whether all points of a generalized service curve have + * their y-coordinates no larger than a given two-piece linear + * service curve. + */ +static int +is_gsc_under_sc(struct gen_sc *gsc, struct service_curve *sc) +{ + struct segment *s, *last, *end; + double y; + + if (is_sc_null(sc)) { + if (LIST_EMPTY(gsc)) + return (1); + LIST_FOREACH(s, gsc, _next) { + if (s->m != 0) + return (0); + } + return (1); + } + /* + * gsc has a dummy entry at the end with x = INFINITY. + * loop through up to this dummy entry. + */ + end = gsc_getentry(gsc, INFINITY); + if (end == NULL) + return (1); + last = NULL; + for (s = LIST_FIRST(gsc); s != end; s = LIST_NEXT(s, _next)) { + if (s->y > sc_x2y(sc, s->x)) + return (0); + last = s; + } + /* last now holds the real last segment */ + if (last == NULL) + return (1); + if (last->m > sc->m2) + return (0); + if (last->x < sc->d && last->m > sc->m1) { + y = last->y + (sc->d - last->x) * last->m; + if (y > sc_x2y(sc, sc->d)) + return (0); + } + return (1); +} + +static void +gsc_destroy(struct gen_sc *gsc) +{ + struct segment *s; + + while ((s = LIST_FIRST(gsc)) != NULL) { + LIST_REMOVE(s, _next); + free(s); + } +} + +/* + * return a segment entry starting at x. + * if gsc has no entry starting at x, a new entry is created at x. + */ +static struct segment * +gsc_getentry(struct gen_sc *gsc, double x) +{ + struct segment *new, *prev, *s; + + prev = NULL; + LIST_FOREACH(s, gsc, _next) { + if (s->x == x) + return (s); /* matching entry found */ + else if (s->x < x) + prev = s; + else + break; + } + + /* we have to create a new entry */ + if ((new = calloc(1, sizeof(struct segment))) == NULL) + return (NULL); + + new->x = x; + if (x == INFINITY || s == NULL) + new->d = 0; + else if (s->x == INFINITY) + new->d = INFINITY; + else + new->d = s->x - x; + if (prev == NULL) { + /* insert the new entry at the head of the list */ + new->y = 0; + new->m = 0; + LIST_INSERT_HEAD(gsc, new, _next); + } else { + /* + * the start point intersects with the segment pointed by + * prev. divide prev into 2 segments + */ + if (x == INFINITY) { + prev->d = INFINITY; + if (prev->m == 0) + new->y = prev->y; + else + new->y = INFINITY; + } else { + prev->d = x - prev->x; + new->y = prev->d * prev->m + prev->y; + } + new->m = prev->m; + LIST_INSERT_AFTER(prev, new, _next); + } + return (new); +} + +/* add a segment to a generalized service curve */ +static int +gsc_add_seg(struct gen_sc *gsc, double x, double y, double d, double m) +{ + struct segment *start, *end, *s; + double x2; + + if (d == INFINITY) + x2 = INFINITY; + else + x2 = x + d; + start = gsc_getentry(gsc, x); + end = gsc_getentry(gsc, x2); + if (start == NULL || end == NULL) + return (-1); + + for (s = start; s != end; s = LIST_NEXT(s, _next)) { + s->m += m; + s->y += y + (s->x - x) * m; + } + + end = gsc_getentry(gsc, INFINITY); + for (; s != end; s = LIST_NEXT(s, _next)) { + s->y += m * d; + } + + return (0); +} + +/* get y-projection of a service curve */ +static double +sc_x2y(struct service_curve *sc, double x) +{ + double y; + + if (x <= (double)sc->d) + /* y belongs to the 1st segment */ + y = x * (double)sc->m1; + else + /* y belongs to the 2nd segment */ + y = (double)sc->d * (double)sc->m1 + + (x - (double)sc->d) * (double)sc->m2; + return (y); +} + +/* + * misc utilities + */ +#define R2S_BUFS 8 +#define RATESTR_MAX 16 + +#ifdef __rtems__ +static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */ +static int idx = 0; +#endif /* __rtems__ */ +char * +rate2str(double rate) +{ + char *buf; +#ifndef __rtems__ + static char r2sbuf[R2S_BUFS][RATESTR_MAX]; /* ring bufer */ + static int idx = 0; +#endif /* __rtems__ */ + int i; + static const char unit[] = " KMG"; + + buf = r2sbuf[idx++]; + if (idx == R2S_BUFS) + idx = 0; + + for (i = 0; rate >= 1000 && i <= 3; i++) + rate /= 1000; + + if ((int)(rate * 100) % 100) + snprintf(buf, RATESTR_MAX, "%.2f%cb", rate, unit[i]); + else + snprintf(buf, RATESTR_MAX, "%d%cb", (int)rate, unit[i]); + + return (buf); +} + +#ifdef __FreeBSD__ +/* + * XXX + * FreeBSD does not have SIOCGIFDATA. + * To emulate this, DIOCGIFSPEED ioctl added to pf. + */ +u_int32_t +getifspeed(int pfdev, char *ifname) +{ + struct pf_ifspeed io; + + bzero(&io, sizeof io); + if (strlcpy(io.ifname, ifname, IFNAMSIZ) >= + sizeof(io.ifname)) + errx(1, "getifspeed: strlcpy"); + if (ioctl(pfdev, DIOCGIFSPEED, &io) == -1) + err(1, "DIOCGIFSPEED"); + return ((u_int32_t)io.baudrate); +} +#else +u_int32_t +getifspeed(char *ifname) +{ + int s; + struct ifreq ifr; + struct if_data ifrdat; + + if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + bzero(&ifr, sizeof(ifr)); + if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= + sizeof(ifr.ifr_name)) + errx(1, "getifspeed: strlcpy"); + ifr.ifr_data = (caddr_t)&ifrdat; + if (ioctl(s, SIOCGIFDATA, (caddr_t)&ifr) == -1) + err(1, "SIOCGIFDATA"); + if (close(s)) + err(1, "close"); + return ((u_int32_t)ifrdat.ifi_baudrate); +} +#endif + +u_long +getifmtu(char *ifname) +{ + int s; + struct ifreq ifr; + + if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) < 0) + err(1, "socket"); + bzero(&ifr, sizeof(ifr)); + if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >= + sizeof(ifr.ifr_name)) + errx(1, "getifmtu: strlcpy"); + if (ioctl(s, SIOCGIFMTU, (caddr_t)&ifr) == -1) +#ifdef __FreeBSD__ + ifr.ifr_mtu = 1500; +#else + err(1, "SIOCGIFMTU"); +#endif + if (close(s)) + err(1, "close"); + if (ifr.ifr_mtu > 0) + return (ifr.ifr_mtu); + else { + warnx("could not get mtu for %s, assuming 1500", ifname); + return (1500); + } +} + +int +eval_queue_opts(struct pf_altq *pa, struct node_queue_opt *opts, + u_int32_t ref_bw) +{ + int errors = 0; + + switch (pa->scheduler) { + case ALTQT_CBQ: + pa->pq_u.cbq_opts = opts->data.cbq_opts; + break; + case ALTQT_PRIQ: + pa->pq_u.priq_opts = opts->data.priq_opts; + break; + case ALTQT_HFSC: + pa->pq_u.hfsc_opts.flags = opts->data.hfsc_opts.flags; + if (opts->data.hfsc_opts.linkshare.used) { + pa->pq_u.hfsc_opts.lssc_m1 = + eval_bwspec(&opts->data.hfsc_opts.linkshare.m1, + ref_bw); + pa->pq_u.hfsc_opts.lssc_m2 = + eval_bwspec(&opts->data.hfsc_opts.linkshare.m2, + ref_bw); + pa->pq_u.hfsc_opts.lssc_d = + opts->data.hfsc_opts.linkshare.d; + } + if (opts->data.hfsc_opts.realtime.used) { + pa->pq_u.hfsc_opts.rtsc_m1 = + eval_bwspec(&opts->data.hfsc_opts.realtime.m1, + ref_bw); + pa->pq_u.hfsc_opts.rtsc_m2 = + eval_bwspec(&opts->data.hfsc_opts.realtime.m2, + ref_bw); + pa->pq_u.hfsc_opts.rtsc_d = + opts->data.hfsc_opts.realtime.d; + } + if (opts->data.hfsc_opts.upperlimit.used) { + pa->pq_u.hfsc_opts.ulsc_m1 = + eval_bwspec(&opts->data.hfsc_opts.upperlimit.m1, + ref_bw); + pa->pq_u.hfsc_opts.ulsc_m2 = + eval_bwspec(&opts->data.hfsc_opts.upperlimit.m2, + ref_bw); + pa->pq_u.hfsc_opts.ulsc_d = + opts->data.hfsc_opts.upperlimit.d; + } + break; + case ALTQT_FAIRQ: + pa->pq_u.fairq_opts.flags = opts->data.fairq_opts.flags; + pa->pq_u.fairq_opts.nbuckets = opts->data.fairq_opts.nbuckets; + pa->pq_u.fairq_opts.hogs_m1 = + eval_bwspec(&opts->data.fairq_opts.hogs_bw, ref_bw); + + if (opts->data.fairq_opts.linkshare.used) { + pa->pq_u.fairq_opts.lssc_m1 = + eval_bwspec(&opts->data.fairq_opts.linkshare.m1, + ref_bw); + pa->pq_u.fairq_opts.lssc_m2 = + eval_bwspec(&opts->data.fairq_opts.linkshare.m2, + ref_bw); + pa->pq_u.fairq_opts.lssc_d = + opts->data.fairq_opts.linkshare.d; + } + break; + case ALTQT_CODEL: + pa->pq_u.codel_opts.target = opts->data.codel_opts.target; + pa->pq_u.codel_opts.interval = opts->data.codel_opts.interval; + pa->pq_u.codel_opts.ecn = opts->data.codel_opts.ecn; + break; + default: + warnx("eval_queue_opts: unknown scheduler type %u", + opts->qtype); + errors++; + break; + } + + return (errors); +} + +u_int32_t +eval_bwspec(struct node_queue_bw *bw, u_int32_t ref_bw) +{ + if (bw->bw_absolute > 0) + return (bw->bw_absolute); + + if (bw->bw_percent > 0) + return (ref_bw / 100 * bw->bw_percent); + + return (0); +} + +void +print_hfsc_sc(const char *scname, u_int m1, u_int d, u_int m2, + const struct node_hfsc_sc *sc) +{ + printf(" %s", scname); + + if (d != 0) { + printf("("); + if (sc != NULL && sc->m1.bw_percent > 0) + printf("%u%%", sc->m1.bw_percent); + else + printf("%s", rate2str((double)m1)); + printf(" %u", d); + } + + if (sc != NULL && sc->m2.bw_percent > 0) + printf(" %u%%", sc->m2.bw_percent); + else + printf(" %s", rate2str((double)m2)); + + if (d != 0) + printf(")"); +} + +void +print_fairq_sc(const char *scname, u_int m1, u_int d, u_int m2, + const struct node_fairq_sc *sc) +{ + printf(" %s", scname); + + if (d != 0) { + printf("("); + if (sc != NULL && sc->m1.bw_percent > 0) + printf("%u%%", sc->m1.bw_percent); + else + printf("%s", rate2str((double)m1)); + printf(" %u", d); + } + + if (sc != NULL && sc->m2.bw_percent > 0) + printf(" %u%%", sc->m2.bw_percent); + else + printf(" %s", rate2str((double)m2)); + + if (d != 0) + printf(")"); +} diff --git a/freebsd/sbin/pfctl/pfctl_optimize.c b/freebsd/sbin/pfctl/pfctl_optimize.c new file mode 100644 index 00000000..b8f44e8b --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl_optimize.c @@ -0,0 +1,1705 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ + +/* $OpenBSD: pfctl_optimize.c,v 1.17 2008/05/06 03:45:21 mpf Exp $ */ + +/* + * Copyright (c) 2004 Mike Frantzen <frantzen@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#define pf_find_or_create_ruleset _bsd_pf_find_or_create_ruleset +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/pfvar.h> + +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <assert.h> +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pfctl_parser.h" +#include "pfctl.h" +#ifdef __rtems__ +struct pf_rule_field { + const char *prf_name; + int prf_type; + size_t prf_offset; + size_t prf_size; +}; +#include "rtems-bsd-pfctl-pfctl_optimize-data.h" +#endif /* __rtems__ */ + +/* The size at which a table becomes faster than individual rules */ +#define TABLE_THRESHOLD 6 + + +/* #define OPT_DEBUG 1 */ +#ifdef OPT_DEBUG +# define DEBUG(str, v...) \ + printf("%s: " str "\n", __FUNCTION__ , ## v) +#else +# define DEBUG(str, v...) ((void)0) +#endif + + +/* + * A container that lets us sort a superblock to optimize the skip step jumps + */ +struct pf_skip_step { + int ps_count; /* number of items */ + TAILQ_HEAD( , pf_opt_rule) ps_rules; + TAILQ_ENTRY(pf_skip_step) ps_entry; +}; + + +/* + * A superblock is a block of adjacent rules of similar action. If there + * are five PASS rules in a row, they all become members of a superblock. + * Once we have a superblock, we are free to re-order any rules within it + * in order to improve performance; if a packet is passed, it doesn't matter + * who passed it. + */ +struct superblock { + TAILQ_HEAD( , pf_opt_rule) sb_rules; + TAILQ_ENTRY(superblock) sb_entry; + struct superblock *sb_profiled_block; + TAILQ_HEAD(skiplist, pf_skip_step) sb_skipsteps[PF_SKIP_COUNT]; +}; +TAILQ_HEAD(superblocks, superblock); + + +/* + * Description of the PF rule structure. + */ +enum { + BARRIER, /* the presence of the field puts the rule in it's own block */ + BREAK, /* the field may not differ between rules in a superblock */ + NOMERGE, /* the field may not differ between rules when combined */ + COMBINED, /* the field may itself be combined with other rules */ + DC, /* we just don't care about the field */ + NEVER}; /* we should never see this field set?!? */ +#ifndef __rtems__ +static struct pf_rule_field { + const char *prf_name; + int prf_type; + size_t prf_offset; + size_t prf_size; +} pf_rule_desc[] = { +#else /* __rtems__ */ +static struct pf_rule_field pf_rule_desc[] = { +#endif /* __rtems__ */ +#define PF_RULE_FIELD(field, ty) \ + {#field, \ + ty, \ + offsetof(struct pf_rule, field), \ + sizeof(((struct pf_rule *)0)->field)} + + + /* + * The presence of these fields in a rule put the rule in it's own + * superblock. Thus it will not be optimized. It also prevents the + * rule from being re-ordered at all. + */ + PF_RULE_FIELD(label, BARRIER), + PF_RULE_FIELD(prob, BARRIER), + PF_RULE_FIELD(max_states, BARRIER), + PF_RULE_FIELD(max_src_nodes, BARRIER), + PF_RULE_FIELD(max_src_states, BARRIER), + PF_RULE_FIELD(max_src_conn, BARRIER), + PF_RULE_FIELD(max_src_conn_rate, BARRIER), + PF_RULE_FIELD(anchor, BARRIER), /* for now */ + + /* + * These fields must be the same between all rules in the same superblock. + * These rules are allowed to be re-ordered but only among like rules. + * For instance we can re-order all 'tag "foo"' rules because they have the + * same tag. But we can not re-order between a 'tag "foo"' and a + * 'tag "bar"' since that would change the meaning of the ruleset. + */ + PF_RULE_FIELD(tagname, BREAK), + PF_RULE_FIELD(keep_state, BREAK), + PF_RULE_FIELD(qname, BREAK), + PF_RULE_FIELD(pqname, BREAK), + PF_RULE_FIELD(rt, BREAK), + PF_RULE_FIELD(allow_opts, BREAK), + PF_RULE_FIELD(rule_flag, BREAK), + PF_RULE_FIELD(action, BREAK), + PF_RULE_FIELD(log, BREAK), + PF_RULE_FIELD(quick, BREAK), + PF_RULE_FIELD(return_ttl, BREAK), + PF_RULE_FIELD(overload_tblname, BREAK), + PF_RULE_FIELD(flush, BREAK), + PF_RULE_FIELD(rpool, BREAK), + PF_RULE_FIELD(logif, BREAK), + + /* + * Any fields not listed in this structure act as BREAK fields + */ + + + /* + * These fields must not differ when we merge two rules together but + * their difference isn't enough to put the rules in different superblocks. + * There are no problems re-ordering any rules with these fields. + */ + PF_RULE_FIELD(af, NOMERGE), + PF_RULE_FIELD(ifnot, NOMERGE), + PF_RULE_FIELD(ifname, NOMERGE), /* hack for IF groups */ + PF_RULE_FIELD(match_tag_not, NOMERGE), + PF_RULE_FIELD(match_tagname, NOMERGE), + PF_RULE_FIELD(os_fingerprint, NOMERGE), + PF_RULE_FIELD(timeout, NOMERGE), + PF_RULE_FIELD(return_icmp, NOMERGE), + PF_RULE_FIELD(return_icmp6, NOMERGE), + PF_RULE_FIELD(uid, NOMERGE), + PF_RULE_FIELD(gid, NOMERGE), + PF_RULE_FIELD(direction, NOMERGE), + PF_RULE_FIELD(proto, NOMERGE), + PF_RULE_FIELD(type, NOMERGE), + PF_RULE_FIELD(code, NOMERGE), + PF_RULE_FIELD(flags, NOMERGE), + PF_RULE_FIELD(flagset, NOMERGE), + PF_RULE_FIELD(tos, NOMERGE), + PF_RULE_FIELD(src.port, NOMERGE), + PF_RULE_FIELD(dst.port, NOMERGE), + PF_RULE_FIELD(src.port_op, NOMERGE), + PF_RULE_FIELD(dst.port_op, NOMERGE), + PF_RULE_FIELD(src.neg, NOMERGE), + PF_RULE_FIELD(dst.neg, NOMERGE), + + /* These fields can be merged */ + PF_RULE_FIELD(src.addr, COMBINED), + PF_RULE_FIELD(dst.addr, COMBINED), + + /* We just don't care about these fields. They're set by the kernel */ + PF_RULE_FIELD(skip, DC), + PF_RULE_FIELD(evaluations, DC), + PF_RULE_FIELD(packets, DC), + PF_RULE_FIELD(bytes, DC), + PF_RULE_FIELD(kif, DC), + PF_RULE_FIELD(states_cur, DC), + PF_RULE_FIELD(states_tot, DC), + PF_RULE_FIELD(src_nodes, DC), + PF_RULE_FIELD(nr, DC), + PF_RULE_FIELD(entries, DC), + PF_RULE_FIELD(qid, DC), + PF_RULE_FIELD(pqid, DC), + PF_RULE_FIELD(anchor_relative, DC), + PF_RULE_FIELD(anchor_wildcard, DC), + PF_RULE_FIELD(tag, DC), + PF_RULE_FIELD(match_tag, DC), + PF_RULE_FIELD(overload_tbl, DC), + + /* These fields should never be set in a PASS/BLOCK rule */ + PF_RULE_FIELD(natpass, NEVER), + PF_RULE_FIELD(max_mss, NEVER), + PF_RULE_FIELD(min_ttl, NEVER), + PF_RULE_FIELD(set_tos, NEVER), +}; + + + +int add_opt_table(struct pfctl *, struct pf_opt_tbl **, sa_family_t, + struct pf_rule_addr *); +int addrs_combineable(struct pf_rule_addr *, struct pf_rule_addr *); +int addrs_equal(struct pf_rule_addr *, struct pf_rule_addr *); +int block_feedback(struct pfctl *, struct superblock *); +int combine_rules(struct pfctl *, struct superblock *); +void comparable_rule(struct pf_rule *, const struct pf_rule *, int); +int construct_superblocks(struct pfctl *, struct pf_opt_queue *, + struct superblocks *); +void exclude_supersets(struct pf_rule *, struct pf_rule *); +int interface_group(const char *); +int load_feedback_profile(struct pfctl *, struct superblocks *); +int optimize_superblock(struct pfctl *, struct superblock *); +int pf_opt_create_table(struct pfctl *, struct pf_opt_tbl *); +void remove_from_skipsteps(struct skiplist *, struct superblock *, + struct pf_opt_rule *, struct pf_skip_step *); +int remove_identical_rules(struct pfctl *, struct superblock *); +int reorder_rules(struct pfctl *, struct superblock *, int); +int rules_combineable(struct pf_rule *, struct pf_rule *); +void skip_append(struct superblock *, int, struct pf_skip_step *, + struct pf_opt_rule *); +int skip_compare(int, struct pf_skip_step *, struct pf_opt_rule *); +void skip_init(void); +int skip_cmp_af(struct pf_rule *, struct pf_rule *); +int skip_cmp_dir(struct pf_rule *, struct pf_rule *); +int skip_cmp_dst_addr(struct pf_rule *, struct pf_rule *); +int skip_cmp_dst_port(struct pf_rule *, struct pf_rule *); +int skip_cmp_ifp(struct pf_rule *, struct pf_rule *); +int skip_cmp_proto(struct pf_rule *, struct pf_rule *); +int skip_cmp_src_addr(struct pf_rule *, struct pf_rule *); +int skip_cmp_src_port(struct pf_rule *, struct pf_rule *); +int superblock_inclusive(struct superblock *, struct pf_opt_rule *); +void superblock_free(struct pfctl *, struct superblock *); + + +static int (*skip_comparitors[PF_SKIP_COUNT])(struct pf_rule *, + struct pf_rule *); +static const char *skip_comparitors_names[PF_SKIP_COUNT]; +#define PF_SKIP_COMPARITORS { \ + { "ifp", PF_SKIP_IFP, skip_cmp_ifp }, \ + { "dir", PF_SKIP_DIR, skip_cmp_dir }, \ + { "af", PF_SKIP_AF, skip_cmp_af }, \ + { "proto", PF_SKIP_PROTO, skip_cmp_proto }, \ + { "saddr", PF_SKIP_SRC_ADDR, skip_cmp_src_addr }, \ + { "sport", PF_SKIP_SRC_PORT, skip_cmp_src_port }, \ + { "daddr", PF_SKIP_DST_ADDR, skip_cmp_dst_addr }, \ + { "dport", PF_SKIP_DST_PORT, skip_cmp_dst_port } \ +} + +static struct pfr_buffer table_buffer; +static int table_identifier; + + +int +pfctl_optimize_ruleset(struct pfctl *pf, struct pf_ruleset *rs) +{ + struct superblocks superblocks; + struct pf_opt_queue opt_queue; + struct superblock *block; + struct pf_opt_rule *por; + struct pf_rule *r; + struct pf_rulequeue *old_rules; + + DEBUG("optimizing ruleset"); + memset(&table_buffer, 0, sizeof(table_buffer)); + skip_init(); + TAILQ_INIT(&opt_queue); + + old_rules = rs->rules[PF_RULESET_FILTER].active.ptr; + rs->rules[PF_RULESET_FILTER].active.ptr = + rs->rules[PF_RULESET_FILTER].inactive.ptr; + rs->rules[PF_RULESET_FILTER].inactive.ptr = old_rules; + + /* + * XXX expanding the pf_opt_rule format throughout pfctl might allow + * us to avoid all this copying. + */ + while ((r = TAILQ_FIRST(rs->rules[PF_RULESET_FILTER].inactive.ptr)) + != NULL) { + TAILQ_REMOVE(rs->rules[PF_RULESET_FILTER].inactive.ptr, r, + entries); + if ((por = calloc(1, sizeof(*por))) == NULL) + err(1, "calloc"); + memcpy(&por->por_rule, r, sizeof(*r)); + if (TAILQ_FIRST(&r->rpool.list) != NULL) { + TAILQ_INIT(&por->por_rule.rpool.list); + pfctl_move_pool(&r->rpool, &por->por_rule.rpool); + } else + bzero(&por->por_rule.rpool, + sizeof(por->por_rule.rpool)); + + + TAILQ_INSERT_TAIL(&opt_queue, por, por_entry); + } + + TAILQ_INIT(&superblocks); + if (construct_superblocks(pf, &opt_queue, &superblocks)) + goto error; + + if (pf->optimize & PF_OPTIMIZE_PROFILE) { + if (load_feedback_profile(pf, &superblocks)) + goto error; + } + + TAILQ_FOREACH(block, &superblocks, sb_entry) { + if (optimize_superblock(pf, block)) + goto error; + } + + rs->anchor->refcnt = 0; + while ((block = TAILQ_FIRST(&superblocks))) { + TAILQ_REMOVE(&superblocks, block, sb_entry); + + while ((por = TAILQ_FIRST(&block->sb_rules))) { + TAILQ_REMOVE(&block->sb_rules, por, por_entry); + por->por_rule.nr = rs->anchor->refcnt++; + if ((r = calloc(1, sizeof(*r))) == NULL) + err(1, "calloc"); + memcpy(r, &por->por_rule, sizeof(*r)); + TAILQ_INIT(&r->rpool.list); + pfctl_move_pool(&por->por_rule.rpool, &r->rpool); + TAILQ_INSERT_TAIL( + rs->rules[PF_RULESET_FILTER].active.ptr, + r, entries); + free(por); + } + free(block); + } + + return (0); + +error: + while ((por = TAILQ_FIRST(&opt_queue))) { + TAILQ_REMOVE(&opt_queue, por, por_entry); + if (por->por_src_tbl) { + pfr_buf_clear(por->por_src_tbl->pt_buf); + free(por->por_src_tbl->pt_buf); + free(por->por_src_tbl); + } + if (por->por_dst_tbl) { + pfr_buf_clear(por->por_dst_tbl->pt_buf); + free(por->por_dst_tbl->pt_buf); + free(por->por_dst_tbl); + } + free(por); + } + while ((block = TAILQ_FIRST(&superblocks))) { + TAILQ_REMOVE(&superblocks, block, sb_entry); + superblock_free(pf, block); + } + return (1); +} + + +/* + * Go ahead and optimize a superblock + */ +int +optimize_superblock(struct pfctl *pf, struct superblock *block) +{ +#ifdef OPT_DEBUG + struct pf_opt_rule *por; +#endif /* OPT_DEBUG */ + + /* We have a few optimization passes: + * 1) remove duplicate rules or rules that are a subset of other + * rules + * 2) combine otherwise identical rules with different IP addresses + * into a single rule and put the addresses in a table. + * 3) re-order the rules to improve kernel skip steps + * 4) re-order the 'quick' rules based on feedback from the + * active ruleset statistics + * + * XXX combine_rules() doesn't combine v4 and v6 rules. would just + * have to keep af in the table container, make af 'COMBINE' and + * twiddle the af on the merged rule + * XXX maybe add a weighting to the metric on skipsteps when doing + * reordering. sometimes two sequential tables will be better + * that four consecutive interfaces. + * XXX need to adjust the skipstep count of everything after PROTO, + * since they aren't actually checked on a proto mismatch in + * pf_test_{tcp, udp, icmp}() + * XXX should i treat proto=0, af=0 or dir=0 special in skepstep + * calculation since they are a DC? + * XXX keep last skiplist of last superblock to influence this + * superblock. '5 inet6 log' should make '3 inet6' come before '4 + * inet' in the next superblock. + * XXX would be useful to add tables for ports + * XXX we can also re-order some mutually exclusive superblocks to + * try merging superblocks before any of these optimization passes. + * for instance a single 'log in' rule in the middle of non-logging + * out rules. + */ + + /* shortcut. there will be a lot of 1-rule superblocks */ + if (!TAILQ_NEXT(TAILQ_FIRST(&block->sb_rules), por_entry)) + return (0); + +#ifdef OPT_DEBUG + printf("--- Superblock ---\n"); + TAILQ_FOREACH(por, &block->sb_rules, por_entry) { + printf(" "); + print_rule(&por->por_rule, por->por_rule.anchor ? + por->por_rule.anchor->name : "", 1, 0); + } +#endif /* OPT_DEBUG */ + + + if (remove_identical_rules(pf, block)) + return (1); + if (combine_rules(pf, block)) + return (1); + if ((pf->optimize & PF_OPTIMIZE_PROFILE) && + TAILQ_FIRST(&block->sb_rules)->por_rule.quick && + block->sb_profiled_block) { + if (block_feedback(pf, block)) + return (1); + } else if (reorder_rules(pf, block, 0)) { + return (1); + } + + /* + * Don't add any optimization passes below reorder_rules(). It will + * have divided superblocks into smaller blocks for further refinement + * and doesn't put them back together again. What once was a true + * superblock might have been split into multiple superblocks. + */ + +#ifdef OPT_DEBUG + printf("--- END Superblock ---\n"); +#endif /* OPT_DEBUG */ + return (0); +} + + +/* + * Optimization pass #1: remove identical rules + */ +int +remove_identical_rules(struct pfctl *pf, struct superblock *block) +{ + struct pf_opt_rule *por1, *por2, *por_next, *por2_next; + struct pf_rule a, a2, b, b2; + + for (por1 = TAILQ_FIRST(&block->sb_rules); por1; por1 = por_next) { + por_next = TAILQ_NEXT(por1, por_entry); + for (por2 = por_next; por2; por2 = por2_next) { + por2_next = TAILQ_NEXT(por2, por_entry); + comparable_rule(&a, &por1->por_rule, DC); + comparable_rule(&b, &por2->por_rule, DC); + memcpy(&a2, &a, sizeof(a2)); + memcpy(&b2, &b, sizeof(b2)); + + exclude_supersets(&a, &b); + exclude_supersets(&b2, &a2); + if (memcmp(&a, &b, sizeof(a)) == 0) { + DEBUG("removing identical rule nr%d = *nr%d*", + por1->por_rule.nr, por2->por_rule.nr); + TAILQ_REMOVE(&block->sb_rules, por2, por_entry); + if (por_next == por2) + por_next = TAILQ_NEXT(por1, por_entry); + free(por2); + } else if (memcmp(&a2, &b2, sizeof(a2)) == 0) { + DEBUG("removing identical rule *nr%d* = nr%d", + por1->por_rule.nr, por2->por_rule.nr); + TAILQ_REMOVE(&block->sb_rules, por1, por_entry); + free(por1); + break; + } + } + } + + return (0); +} + + +/* + * Optimization pass #2: combine similar rules with different addresses + * into a single rule and a table + */ +int +combine_rules(struct pfctl *pf, struct superblock *block) +{ + struct pf_opt_rule *p1, *p2, *por_next; + int src_eq, dst_eq; + + if ((pf->loadopt & PFCTL_FLAG_TABLE) == 0) { + warnx("Must enable table loading for optimizations"); + return (1); + } + + /* First we make a pass to combine the rules. O(n log n) */ + TAILQ_FOREACH(p1, &block->sb_rules, por_entry) { + for (p2 = TAILQ_NEXT(p1, por_entry); p2; p2 = por_next) { + por_next = TAILQ_NEXT(p2, por_entry); + + src_eq = addrs_equal(&p1->por_rule.src, + &p2->por_rule.src); + dst_eq = addrs_equal(&p1->por_rule.dst, + &p2->por_rule.dst); + + if (src_eq && !dst_eq && p1->por_src_tbl == NULL && + p2->por_dst_tbl == NULL && + p2->por_src_tbl == NULL && + rules_combineable(&p1->por_rule, &p2->por_rule) && + addrs_combineable(&p1->por_rule.dst, + &p2->por_rule.dst)) { + DEBUG("can combine rules nr%d = nr%d", + p1->por_rule.nr, p2->por_rule.nr); + if (p1->por_dst_tbl == NULL && + add_opt_table(pf, &p1->por_dst_tbl, + p1->por_rule.af, &p1->por_rule.dst)) + return (1); + if (add_opt_table(pf, &p1->por_dst_tbl, + p1->por_rule.af, &p2->por_rule.dst)) + return (1); + p2->por_dst_tbl = p1->por_dst_tbl; + if (p1->por_dst_tbl->pt_rulecount >= + TABLE_THRESHOLD) { + TAILQ_REMOVE(&block->sb_rules, p2, + por_entry); + free(p2); + } + } else if (!src_eq && dst_eq && p1->por_dst_tbl == NULL + && p2->por_src_tbl == NULL && + p2->por_dst_tbl == NULL && + rules_combineable(&p1->por_rule, &p2->por_rule) && + addrs_combineable(&p1->por_rule.src, + &p2->por_rule.src)) { + DEBUG("can combine rules nr%d = nr%d", + p1->por_rule.nr, p2->por_rule.nr); + if (p1->por_src_tbl == NULL && + add_opt_table(pf, &p1->por_src_tbl, + p1->por_rule.af, &p1->por_rule.src)) + return (1); + if (add_opt_table(pf, &p1->por_src_tbl, + p1->por_rule.af, &p2->por_rule.src)) + return (1); + p2->por_src_tbl = p1->por_src_tbl; + if (p1->por_src_tbl->pt_rulecount >= + TABLE_THRESHOLD) { + TAILQ_REMOVE(&block->sb_rules, p2, + por_entry); + free(p2); + } + } + } + } + + + /* + * Then we make a final pass to create a valid table name and + * insert the name into the rules. + */ + for (p1 = TAILQ_FIRST(&block->sb_rules); p1; p1 = por_next) { + por_next = TAILQ_NEXT(p1, por_entry); + assert(p1->por_src_tbl == NULL || p1->por_dst_tbl == NULL); + + if (p1->por_src_tbl && p1->por_src_tbl->pt_rulecount >= + TABLE_THRESHOLD) { + if (p1->por_src_tbl->pt_generated) { + /* This rule is included in a table */ + TAILQ_REMOVE(&block->sb_rules, p1, por_entry); + free(p1); + continue; + } + p1->por_src_tbl->pt_generated = 1; + + if ((pf->opts & PF_OPT_NOACTION) == 0 && + pf_opt_create_table(pf, p1->por_src_tbl)) + return (1); + + pf->tdirty = 1; + + if (pf->opts & PF_OPT_VERBOSE) + print_tabledef(p1->por_src_tbl->pt_name, + PFR_TFLAG_CONST, 1, + &p1->por_src_tbl->pt_nodes); + + memset(&p1->por_rule.src.addr, 0, + sizeof(p1->por_rule.src.addr)); + p1->por_rule.src.addr.type = PF_ADDR_TABLE; + strlcpy(p1->por_rule.src.addr.v.tblname, + p1->por_src_tbl->pt_name, + sizeof(p1->por_rule.src.addr.v.tblname)); + + pfr_buf_clear(p1->por_src_tbl->pt_buf); + free(p1->por_src_tbl->pt_buf); + p1->por_src_tbl->pt_buf = NULL; + } + if (p1->por_dst_tbl && p1->por_dst_tbl->pt_rulecount >= + TABLE_THRESHOLD) { + if (p1->por_dst_tbl->pt_generated) { + /* This rule is included in a table */ + TAILQ_REMOVE(&block->sb_rules, p1, por_entry); + free(p1); + continue; + } + p1->por_dst_tbl->pt_generated = 1; + + if ((pf->opts & PF_OPT_NOACTION) == 0 && + pf_opt_create_table(pf, p1->por_dst_tbl)) + return (1); + pf->tdirty = 1; + + if (pf->opts & PF_OPT_VERBOSE) + print_tabledef(p1->por_dst_tbl->pt_name, + PFR_TFLAG_CONST, 1, + &p1->por_dst_tbl->pt_nodes); + + memset(&p1->por_rule.dst.addr, 0, + sizeof(p1->por_rule.dst.addr)); + p1->por_rule.dst.addr.type = PF_ADDR_TABLE; + strlcpy(p1->por_rule.dst.addr.v.tblname, + p1->por_dst_tbl->pt_name, + sizeof(p1->por_rule.dst.addr.v.tblname)); + + pfr_buf_clear(p1->por_dst_tbl->pt_buf); + free(p1->por_dst_tbl->pt_buf); + p1->por_dst_tbl->pt_buf = NULL; + } + } + + return (0); +} + + +/* + * Optimization pass #3: re-order rules to improve skip steps + */ +int +reorder_rules(struct pfctl *pf, struct superblock *block, int depth) +{ + struct superblock *newblock; + struct pf_skip_step *skiplist; + struct pf_opt_rule *por; + int i, largest, largest_list, rule_count = 0; + TAILQ_HEAD( , pf_opt_rule) head; + + /* + * Calculate the best-case skip steps. We put each rule in a list + * of other rules with common fields + */ + for (i = 0; i < PF_SKIP_COUNT; i++) { + TAILQ_FOREACH(por, &block->sb_rules, por_entry) { + TAILQ_FOREACH(skiplist, &block->sb_skipsteps[i], + ps_entry) { + if (skip_compare(i, skiplist, por) == 0) + break; + } + if (skiplist == NULL) { + if ((skiplist = calloc(1, sizeof(*skiplist))) == + NULL) + err(1, "calloc"); + TAILQ_INIT(&skiplist->ps_rules); + TAILQ_INSERT_TAIL(&block->sb_skipsteps[i], + skiplist, ps_entry); + } + skip_append(block, i, skiplist, por); + } + } + + TAILQ_FOREACH(por, &block->sb_rules, por_entry) + rule_count++; + + /* + * Now we're going to ignore any fields that are identical between + * all of the rules in the superblock and those fields which differ + * between every rule in the superblock. + */ + largest = 0; + for (i = 0; i < PF_SKIP_COUNT; i++) { + skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]); + if (skiplist->ps_count == rule_count) { + DEBUG("(%d) original skipstep '%s' is all rules", + depth, skip_comparitors_names[i]); + skiplist->ps_count = 0; + } else if (skiplist->ps_count == 1) { + skiplist->ps_count = 0; + } else { + DEBUG("(%d) original skipstep '%s' largest jump is %d", + depth, skip_comparitors_names[i], + skiplist->ps_count); + if (skiplist->ps_count > largest) + largest = skiplist->ps_count; + } + } + if (largest == 0) { + /* Ugh. There is NO commonality in the superblock on which + * optimize the skipsteps optimization. + */ + goto done; + } + + /* + * Now we're going to empty the superblock rule list and re-create + * it based on a more optimal skipstep order. + */ + TAILQ_INIT(&head); + while ((por = TAILQ_FIRST(&block->sb_rules))) { + TAILQ_REMOVE(&block->sb_rules, por, por_entry); + TAILQ_INSERT_TAIL(&head, por, por_entry); + } + + + while (!TAILQ_EMPTY(&head)) { + largest = 1; + + /* + * Find the most useful skip steps remaining + */ + for (i = 0; i < PF_SKIP_COUNT; i++) { + skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]); + if (skiplist->ps_count > largest) { + largest = skiplist->ps_count; + largest_list = i; + } + } + + if (largest <= 1) { + /* + * Nothing useful left. Leave remaining rules in order. + */ + DEBUG("(%d) no more commonality for skip steps", depth); + while ((por = TAILQ_FIRST(&head))) { + TAILQ_REMOVE(&head, por, por_entry); + TAILQ_INSERT_TAIL(&block->sb_rules, por, + por_entry); + } + } else { + /* + * There is commonality. Extract those common rules + * and place them in the ruleset adjacent to each + * other. + */ + skiplist = TAILQ_FIRST(&block->sb_skipsteps[ + largest_list]); + DEBUG("(%d) skipstep '%s' largest jump is %d @ #%d", + depth, skip_comparitors_names[largest_list], + largest, TAILQ_FIRST(&TAILQ_FIRST(&block-> + sb_skipsteps [largest_list])->ps_rules)-> + por_rule.nr); + TAILQ_REMOVE(&block->sb_skipsteps[largest_list], + skiplist, ps_entry); + + + /* + * There may be further commonality inside these + * rules. So we'll split them off into they're own + * superblock and pass it back into the optimizer. + */ + if (skiplist->ps_count > 2) { + if ((newblock = calloc(1, sizeof(*newblock))) + == NULL) { + warn("calloc"); + return (1); + } + TAILQ_INIT(&newblock->sb_rules); + for (i = 0; i < PF_SKIP_COUNT; i++) + TAILQ_INIT(&newblock->sb_skipsteps[i]); + TAILQ_INSERT_BEFORE(block, newblock, sb_entry); + DEBUG("(%d) splitting off %d rules from superblock @ #%d", + depth, skiplist->ps_count, + TAILQ_FIRST(&skiplist->ps_rules)-> + por_rule.nr); + } else { + newblock = block; + } + + while ((por = TAILQ_FIRST(&skiplist->ps_rules))) { + TAILQ_REMOVE(&head, por, por_entry); + TAILQ_REMOVE(&skiplist->ps_rules, por, + por_skip_entry[largest_list]); + TAILQ_INSERT_TAIL(&newblock->sb_rules, por, + por_entry); + + /* Remove this rule from all other skiplists */ + remove_from_skipsteps(&block->sb_skipsteps[ + largest_list], block, por, skiplist); + } + free(skiplist); + if (newblock != block) + if (reorder_rules(pf, newblock, depth + 1)) + return (1); + } + } + +done: + for (i = 0; i < PF_SKIP_COUNT; i++) { + while ((skiplist = TAILQ_FIRST(&block->sb_skipsteps[i]))) { + TAILQ_REMOVE(&block->sb_skipsteps[i], skiplist, + ps_entry); + free(skiplist); + } + } + + return (0); +} + + +/* + * Optimization pass #4: re-order 'quick' rules based on feedback from the + * currently running ruleset + */ +int +block_feedback(struct pfctl *pf, struct superblock *block) +{ + TAILQ_HEAD( , pf_opt_rule) queue; + struct pf_opt_rule *por1, *por2; + u_int64_t total_count = 0; + struct pf_rule a, b; + + + /* + * Walk through all of the profiled superblock's rules and copy + * the counters onto our rules. + */ + TAILQ_FOREACH(por1, &block->sb_profiled_block->sb_rules, por_entry) { + comparable_rule(&a, &por1->por_rule, DC); + total_count += por1->por_rule.packets[0] + + por1->por_rule.packets[1]; + TAILQ_FOREACH(por2, &block->sb_rules, por_entry) { + if (por2->por_profile_count) + continue; + comparable_rule(&b, &por2->por_rule, DC); + if (memcmp(&a, &b, sizeof(a)) == 0) { + por2->por_profile_count = + por1->por_rule.packets[0] + + por1->por_rule.packets[1]; + break; + } + } + } + superblock_free(pf, block->sb_profiled_block); + block->sb_profiled_block = NULL; + + /* + * Now we pull all of the rules off the superblock and re-insert them + * in sorted order. + */ + + TAILQ_INIT(&queue); + while ((por1 = TAILQ_FIRST(&block->sb_rules)) != NULL) { + TAILQ_REMOVE(&block->sb_rules, por1, por_entry); + TAILQ_INSERT_TAIL(&queue, por1, por_entry); + } + + while ((por1 = TAILQ_FIRST(&queue)) != NULL) { + TAILQ_REMOVE(&queue, por1, por_entry); +/* XXX I should sort all of the unused rules based on skip steps */ + TAILQ_FOREACH(por2, &block->sb_rules, por_entry) { + if (por1->por_profile_count > por2->por_profile_count) { + TAILQ_INSERT_BEFORE(por2, por1, por_entry); + break; + } + } +#ifdef __FreeBSD__ + if (por2 == NULL) +#else + if (por2 == TAILQ_END(&block->sb_rules)) +#endif + TAILQ_INSERT_TAIL(&block->sb_rules, por1, por_entry); + } + + return (0); +} + + +/* + * Load the current ruleset from the kernel and try to associate them with + * the ruleset we're optimizing. + */ +int +load_feedback_profile(struct pfctl *pf, struct superblocks *superblocks) +{ + struct superblock *block, *blockcur; + struct superblocks prof_superblocks; + struct pf_opt_rule *por; + struct pf_opt_queue queue; + struct pfioc_rule pr; + struct pf_rule a, b; + int nr, mnr; + + TAILQ_INIT(&queue); + TAILQ_INIT(&prof_superblocks); + + memset(&pr, 0, sizeof(pr)); + pr.rule.action = PF_PASS; + if (ioctl(pf->dev, DIOCGETRULES, &pr)) { + warn("DIOCGETRULES"); + return (1); + } + mnr = pr.nr; + + DEBUG("Loading %d active rules for a feedback profile", mnr); + for (nr = 0; nr < mnr; ++nr) { + struct pf_ruleset *rs; + if ((por = calloc(1, sizeof(*por))) == NULL) { + warn("calloc"); + return (1); + } + pr.nr = nr; + if (ioctl(pf->dev, DIOCGETRULE, &pr)) { + warn("DIOCGETRULES"); + return (1); + } + memcpy(&por->por_rule, &pr.rule, sizeof(por->por_rule)); + rs = pf_find_or_create_ruleset(pr.anchor_call); + por->por_rule.anchor = rs->anchor; + if (TAILQ_EMPTY(&por->por_rule.rpool.list)) + memset(&por->por_rule.rpool, 0, + sizeof(por->por_rule.rpool)); + TAILQ_INSERT_TAIL(&queue, por, por_entry); + + /* XXX pfctl_get_pool(pf->dev, &pr.rule.rpool, nr, pr.ticket, + * PF_PASS, pf->anchor) ??? + * ... pfctl_clear_pool(&pr.rule.rpool) + */ + } + + if (construct_superblocks(pf, &queue, &prof_superblocks)) + return (1); + + + /* + * Now we try to associate the active ruleset's superblocks with + * the superblocks we're compiling. + */ + block = TAILQ_FIRST(superblocks); + blockcur = TAILQ_FIRST(&prof_superblocks); + while (block && blockcur) { + comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, + BREAK); + comparable_rule(&b, &TAILQ_FIRST(&blockcur->sb_rules)->por_rule, + BREAK); + if (memcmp(&a, &b, sizeof(a)) == 0) { + /* The two superblocks lined up */ + block->sb_profiled_block = blockcur; + } else { + DEBUG("superblocks don't line up between #%d and #%d", + TAILQ_FIRST(&block->sb_rules)->por_rule.nr, + TAILQ_FIRST(&blockcur->sb_rules)->por_rule.nr); + break; + } + block = TAILQ_NEXT(block, sb_entry); + blockcur = TAILQ_NEXT(blockcur, sb_entry); + } + + + + /* Free any superblocks we couldn't link */ + while (blockcur) { + block = TAILQ_NEXT(blockcur, sb_entry); + superblock_free(pf, blockcur); + blockcur = block; + } + return (0); +} + + +/* + * Compare a rule to a skiplist to see if the rule is a member + */ +int +skip_compare(int skipnum, struct pf_skip_step *skiplist, + struct pf_opt_rule *por) +{ + struct pf_rule *a, *b; + if (skipnum >= PF_SKIP_COUNT || skipnum < 0) + errx(1, "skip_compare() out of bounds"); + a = &por->por_rule; + b = &TAILQ_FIRST(&skiplist->ps_rules)->por_rule; + + return ((skip_comparitors[skipnum])(a, b)); +} + + +/* + * Add a rule to a skiplist + */ +void +skip_append(struct superblock *superblock, int skipnum, + struct pf_skip_step *skiplist, struct pf_opt_rule *por) +{ + struct pf_skip_step *prev; + + skiplist->ps_count++; + TAILQ_INSERT_TAIL(&skiplist->ps_rules, por, por_skip_entry[skipnum]); + + /* Keep the list of skiplists sorted by whichever is larger */ + while ((prev = TAILQ_PREV(skiplist, skiplist, ps_entry)) && + prev->ps_count < skiplist->ps_count) { + TAILQ_REMOVE(&superblock->sb_skipsteps[skipnum], + skiplist, ps_entry); + TAILQ_INSERT_BEFORE(prev, skiplist, ps_entry); + } +} + + +/* + * Remove a rule from the other skiplist calculations. + */ +void +remove_from_skipsteps(struct skiplist *head, struct superblock *block, + struct pf_opt_rule *por, struct pf_skip_step *active_list) +{ + struct pf_skip_step *sk, *next; + struct pf_opt_rule *p2; + int i, found; + + for (i = 0; i < PF_SKIP_COUNT; i++) { + sk = TAILQ_FIRST(&block->sb_skipsteps[i]); + if (sk == NULL || sk == active_list || sk->ps_count <= 1) + continue; + found = 0; + do { + TAILQ_FOREACH(p2, &sk->ps_rules, por_skip_entry[i]) + if (p2 == por) { + TAILQ_REMOVE(&sk->ps_rules, p2, + por_skip_entry[i]); + found = 1; + sk->ps_count--; + break; + } + } while (!found && (sk = TAILQ_NEXT(sk, ps_entry))); + if (found && sk) { + /* Does this change the sorting order? */ + while ((next = TAILQ_NEXT(sk, ps_entry)) && + next->ps_count > sk->ps_count) { + TAILQ_REMOVE(head, sk, ps_entry); + TAILQ_INSERT_AFTER(head, next, sk, ps_entry); + } +#ifdef OPT_DEBUG + next = TAILQ_NEXT(sk, ps_entry); + assert(next == NULL || next->ps_count <= sk->ps_count); +#endif /* OPT_DEBUG */ + } + } +} + + +/* Compare two rules AF field for skiplist construction */ +int +skip_cmp_af(struct pf_rule *a, struct pf_rule *b) +{ + if (a->af != b->af || a->af == 0) + return (1); + return (0); +} + +/* Compare two rules DIRECTION field for skiplist construction */ +int +skip_cmp_dir(struct pf_rule *a, struct pf_rule *b) +{ + if (a->direction == 0 || a->direction != b->direction) + return (1); + return (0); +} + +/* Compare two rules DST Address field for skiplist construction */ +int +skip_cmp_dst_addr(struct pf_rule *a, struct pf_rule *b) +{ + if (a->dst.neg != b->dst.neg || + a->dst.addr.type != b->dst.addr.type) + return (1); + /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 + * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || + * a->proto == IPPROTO_ICMP + * return (1); + */ + switch (a->dst.addr.type) { + case PF_ADDR_ADDRMASK: + if (memcmp(&a->dst.addr.v.a.addr, &b->dst.addr.v.a.addr, + sizeof(a->dst.addr.v.a.addr)) || + memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask, + sizeof(a->dst.addr.v.a.mask)) || + (a->dst.addr.v.a.addr.addr32[0] == 0 && + a->dst.addr.v.a.addr.addr32[1] == 0 && + a->dst.addr.v.a.addr.addr32[2] == 0 && + a->dst.addr.v.a.addr.addr32[3] == 0)) + return (1); + return (0); + case PF_ADDR_DYNIFTL: + if (strcmp(a->dst.addr.v.ifname, b->dst.addr.v.ifname) != 0 || + a->dst.addr.iflags != a->dst.addr.iflags || + memcmp(&a->dst.addr.v.a.mask, &b->dst.addr.v.a.mask, + sizeof(a->dst.addr.v.a.mask))) + return (1); + return (0); + case PF_ADDR_NOROUTE: + case PF_ADDR_URPFFAILED: + return (0); + case PF_ADDR_TABLE: + return (strcmp(a->dst.addr.v.tblname, b->dst.addr.v.tblname)); + } + return (1); +} + +/* Compare two rules DST port field for skiplist construction */ +int +skip_cmp_dst_port(struct pf_rule *a, struct pf_rule *b) +{ + /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 + * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || + * a->proto == IPPROTO_ICMP + * return (1); + */ + if (a->dst.port_op == PF_OP_NONE || a->dst.port_op != b->dst.port_op || + a->dst.port[0] != b->dst.port[0] || + a->dst.port[1] != b->dst.port[1]) + return (1); + return (0); +} + +/* Compare two rules IFP field for skiplist construction */ +int +skip_cmp_ifp(struct pf_rule *a, struct pf_rule *b) +{ + if (strcmp(a->ifname, b->ifname) || a->ifname[0] == '\0') + return (1); + return (a->ifnot != b->ifnot); +} + +/* Compare two rules PROTO field for skiplist construction */ +int +skip_cmp_proto(struct pf_rule *a, struct pf_rule *b) +{ + return (a->proto != b->proto || a->proto == 0); +} + +/* Compare two rules SRC addr field for skiplist construction */ +int +skip_cmp_src_addr(struct pf_rule *a, struct pf_rule *b) +{ + if (a->src.neg != b->src.neg || + a->src.addr.type != b->src.addr.type) + return (1); + /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 + * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || + * a->proto == IPPROTO_ICMP + * return (1); + */ + switch (a->src.addr.type) { + case PF_ADDR_ADDRMASK: + if (memcmp(&a->src.addr.v.a.addr, &b->src.addr.v.a.addr, + sizeof(a->src.addr.v.a.addr)) || + memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask, + sizeof(a->src.addr.v.a.mask)) || + (a->src.addr.v.a.addr.addr32[0] == 0 && + a->src.addr.v.a.addr.addr32[1] == 0 && + a->src.addr.v.a.addr.addr32[2] == 0 && + a->src.addr.v.a.addr.addr32[3] == 0)) + return (1); + return (0); + case PF_ADDR_DYNIFTL: + if (strcmp(a->src.addr.v.ifname, b->src.addr.v.ifname) != 0 || + a->src.addr.iflags != a->src.addr.iflags || + memcmp(&a->src.addr.v.a.mask, &b->src.addr.v.a.mask, + sizeof(a->src.addr.v.a.mask))) + return (1); + return (0); + case PF_ADDR_NOROUTE: + case PF_ADDR_URPFFAILED: + return (0); + case PF_ADDR_TABLE: + return (strcmp(a->src.addr.v.tblname, b->src.addr.v.tblname)); + } + return (1); +} + +/* Compare two rules SRC port field for skiplist construction */ +int +skip_cmp_src_port(struct pf_rule *a, struct pf_rule *b) +{ + if (a->src.port_op == PF_OP_NONE || a->src.port_op != b->src.port_op || + a->src.port[0] != b->src.port[0] || + a->src.port[1] != b->src.port[1]) + return (1); + /* XXX if (a->proto != b->proto && a->proto != 0 && b->proto != 0 + * && (a->proto == IPPROTO_TCP || a->proto == IPPROTO_UDP || + * a->proto == IPPROTO_ICMP + * return (1); + */ + return (0); +} + + +void +skip_init(void) +{ + struct { + char *name; + int skipnum; + int (*func)(struct pf_rule *, struct pf_rule *); + } comps[] = PF_SKIP_COMPARITORS; + int skipnum, i; + + for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++) { + for (i = 0; i < sizeof(comps)/sizeof(*comps); i++) + if (comps[i].skipnum == skipnum) { + skip_comparitors[skipnum] = comps[i].func; + skip_comparitors_names[skipnum] = comps[i].name; + } + } + for (skipnum = 0; skipnum < PF_SKIP_COUNT; skipnum++) + if (skip_comparitors[skipnum] == NULL) + errx(1, "Need to add skip step comparitor to pfctl?!"); +} + +/* + * Add a host/netmask to a table + */ +#ifdef __rtems__ +static int add_opt_tablenum = 0; +#endif /* __rtems__ */ +int +add_opt_table(struct pfctl *pf, struct pf_opt_tbl **tbl, sa_family_t af, + struct pf_rule_addr *addr) +{ +#ifdef OPT_DEBUG + char buf[128]; +#endif /* OPT_DEBUG */ +#ifndef __rtems__ + static int tablenum = 0; +#endif /* __rtems__ */ + struct node_host node_host; + + if (*tbl == NULL) { + if ((*tbl = calloc(1, sizeof(**tbl))) == NULL || + ((*tbl)->pt_buf = calloc(1, sizeof(*(*tbl)->pt_buf))) == + NULL) + err(1, "calloc"); + (*tbl)->pt_buf->pfrb_type = PFRB_ADDRS; + SIMPLEQ_INIT(&(*tbl)->pt_nodes); + + /* This is just a temporary table name */ + snprintf((*tbl)->pt_name, sizeof((*tbl)->pt_name), "%s%d", +#ifndef __rtems__ + PF_OPT_TABLE_PREFIX, tablenum++); +#else /* __rtems__ */ + PF_OPT_TABLE_PREFIX, add_opt_tablenum++); +#endif /* __rtems__ */ + DEBUG("creating table <%s>", (*tbl)->pt_name); + } + + memset(&node_host, 0, sizeof(node_host)); + node_host.af = af; + node_host.addr = addr->addr; + +#ifdef OPT_DEBUG + DEBUG("<%s> adding %s/%d", (*tbl)->pt_name, inet_ntop(af, + &node_host.addr.v.a.addr, buf, sizeof(buf)), + unmask(&node_host.addr.v.a.mask, af)); +#endif /* OPT_DEBUG */ + + if (append_addr_host((*tbl)->pt_buf, &node_host, 0, 0)) { + warn("failed to add host"); + return (1); + } + if (pf->opts & PF_OPT_VERBOSE) { + struct node_tinit *ti; + + if ((ti = calloc(1, sizeof(*ti))) == NULL) + err(1, "malloc"); + if ((ti->host = malloc(sizeof(*ti->host))) == NULL) + err(1, "malloc"); + memcpy(ti->host, &node_host, sizeof(*ti->host)); + SIMPLEQ_INSERT_TAIL(&(*tbl)->pt_nodes, ti, entries); + } + + (*tbl)->pt_rulecount++; + if ((*tbl)->pt_rulecount == TABLE_THRESHOLD) + DEBUG("table <%s> now faster than skip steps", (*tbl)->pt_name); + + return (0); +} + + +/* + * Do the dirty work of choosing an unused table name and creating it. + * (be careful with the table name, it might already be used in another anchor) + */ +#ifdef __rtems__ +static int pf_opt_create_tablenum; +#endif /* __rtems__ */ +int +pf_opt_create_table(struct pfctl *pf, struct pf_opt_tbl *tbl) +{ +#ifndef __rtems__ + static int tablenum; +#endif /* __rtems__ */ + struct pfr_table *t; + + if (table_buffer.pfrb_type == 0) { + /* Initialize the list of tables */ + table_buffer.pfrb_type = PFRB_TABLES; + for (;;) { + pfr_buf_grow(&table_buffer, table_buffer.pfrb_size); + table_buffer.pfrb_size = table_buffer.pfrb_msize; + if (pfr_get_tables(NULL, table_buffer.pfrb_caddr, + &table_buffer.pfrb_size, PFR_FLAG_ALLRSETS)) + err(1, "pfr_get_tables"); + if (table_buffer.pfrb_size <= table_buffer.pfrb_msize) + break; + } + table_identifier = arc4random(); + } + + /* XXX would be *really* nice to avoid duplicating identical tables */ + + /* Now we have to pick a table name that isn't used */ +again: + DEBUG("translating temporary table <%s> to <%s%x_%d>", tbl->pt_name, +#ifndef __rtems__ + PF_OPT_TABLE_PREFIX, table_identifier, tablenum); +#else /* __rtems__ */ + PF_OPT_TABLE_PREFIX, table_identifier, pf_opt_create_tablenum); +#endif /* __rtems__ */ + snprintf(tbl->pt_name, sizeof(tbl->pt_name), "%s%x_%d", +#ifndef __rtems__ + PF_OPT_TABLE_PREFIX, table_identifier, tablenum); +#else /* __rtems__ */ + PF_OPT_TABLE_PREFIX, table_identifier, pf_opt_create_tablenum); +#endif /* __rtems__ */ + PFRB_FOREACH(t, &table_buffer) { + if (strcasecmp(t->pfrt_name, tbl->pt_name) == 0) { + /* Collision. Try again */ + DEBUG("wow, table <%s> in use. trying again", + tbl->pt_name); + table_identifier = arc4random(); + goto again; + } + } +#ifndef __rtems__ + tablenum++; +#else /* __rtems__ */ + pf_opt_create_tablenum++; +#endif /* __rtems__ */ + + + if (pfctl_define_table(tbl->pt_name, PFR_TFLAG_CONST, 1, + pf->astack[0]->name, tbl->pt_buf, pf->astack[0]->ruleset.tticket)) { + warn("failed to create table %s in %s", + tbl->pt_name, pf->astack[0]->name); + return (1); + } + return (0); +} + +/* + * Partition the flat ruleset into a list of distinct superblocks + */ +int +construct_superblocks(struct pfctl *pf, struct pf_opt_queue *opt_queue, + struct superblocks *superblocks) +{ + struct superblock *block = NULL; + struct pf_opt_rule *por; + int i; + + while (!TAILQ_EMPTY(opt_queue)) { + por = TAILQ_FIRST(opt_queue); + TAILQ_REMOVE(opt_queue, por, por_entry); + if (block == NULL || !superblock_inclusive(block, por)) { + if ((block = calloc(1, sizeof(*block))) == NULL) { + warn("calloc"); + return (1); + } + TAILQ_INIT(&block->sb_rules); + for (i = 0; i < PF_SKIP_COUNT; i++) + TAILQ_INIT(&block->sb_skipsteps[i]); + TAILQ_INSERT_TAIL(superblocks, block, sb_entry); + } + TAILQ_INSERT_TAIL(&block->sb_rules, por, por_entry); + } + + return (0); +} + + +/* + * Compare two rule addresses + */ +int +addrs_equal(struct pf_rule_addr *a, struct pf_rule_addr *b) +{ + if (a->neg != b->neg) + return (0); + return (memcmp(&a->addr, &b->addr, sizeof(a->addr)) == 0); +} + + +/* + * The addresses are not equal, but can we combine them into one table? + */ +int +addrs_combineable(struct pf_rule_addr *a, struct pf_rule_addr *b) +{ + if (a->addr.type != PF_ADDR_ADDRMASK || + b->addr.type != PF_ADDR_ADDRMASK) + return (0); + if (a->neg != b->neg || a->port_op != b->port_op || + a->port[0] != b->port[0] || a->port[1] != b->port[1]) + return (0); + return (1); +} + + +/* + * Are we allowed to combine these two rules + */ +int +rules_combineable(struct pf_rule *p1, struct pf_rule *p2) +{ + struct pf_rule a, b; + + comparable_rule(&a, p1, COMBINED); + comparable_rule(&b, p2, COMBINED); + return (memcmp(&a, &b, sizeof(a)) == 0); +} + + +/* + * Can a rule be included inside a superblock + */ +int +superblock_inclusive(struct superblock *block, struct pf_opt_rule *por) +{ + struct pf_rule a, b; + int i, j; + + /* First check for hard breaks */ + for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++) { + if (pf_rule_desc[i].prf_type == BARRIER) { + for (j = 0; j < pf_rule_desc[i].prf_size; j++) + if (((char *)&por->por_rule)[j + + pf_rule_desc[i].prf_offset] != 0) + return (0); + } + } + + /* per-rule src-track is also a hard break */ + if (por->por_rule.rule_flag & PFRULE_RULESRCTRACK) + return (0); + + /* + * Have to handle interface groups separately. Consider the following + * rules: + * block on EXTIFS to any port 22 + * pass on em0 to any port 22 + * (where EXTIFS is an arbitrary interface group) + * The optimizer may decide to re-order the pass rule in front of the + * block rule. But what if EXTIFS includes em0??? Such a reordering + * would change the meaning of the ruleset. + * We can't just lookup the EXTIFS group and check if em0 is a member + * because the user is allowed to add interfaces to a group during + * runtime. + * Ergo interface groups become a defacto superblock break :-( + */ + if (interface_group(por->por_rule.ifname) || + interface_group(TAILQ_FIRST(&block->sb_rules)->por_rule.ifname)) { + if (strcasecmp(por->por_rule.ifname, + TAILQ_FIRST(&block->sb_rules)->por_rule.ifname) != 0) + return (0); + } + + comparable_rule(&a, &TAILQ_FIRST(&block->sb_rules)->por_rule, NOMERGE); + comparable_rule(&b, &por->por_rule, NOMERGE); + if (memcmp(&a, &b, sizeof(a)) == 0) + return (1); + +#ifdef OPT_DEBUG + for (i = 0; i < sizeof(por->por_rule); i++) { + int closest = -1; + if (((u_int8_t *)&a)[i] != ((u_int8_t *)&b)[i]) { + for (j = 0; j < sizeof(pf_rule_desc) / + sizeof(*pf_rule_desc); j++) { + if (i >= pf_rule_desc[j].prf_offset && + i < pf_rule_desc[j].prf_offset + + pf_rule_desc[j].prf_size) { + DEBUG("superblock break @ %d due to %s", + por->por_rule.nr, + pf_rule_desc[j].prf_name); + return (0); + } + if (i > pf_rule_desc[j].prf_offset) { + if (closest == -1 || + i-pf_rule_desc[j].prf_offset < + i-pf_rule_desc[closest].prf_offset) + closest = j; + } + } + + if (closest >= 0) + DEBUG("superblock break @ %d on %s+%xh", + por->por_rule.nr, + pf_rule_desc[closest].prf_name, + i - pf_rule_desc[closest].prf_offset - + pf_rule_desc[closest].prf_size); + else + DEBUG("superblock break @ %d on field @ %d", + por->por_rule.nr, i); + return (0); + } + } +#endif /* OPT_DEBUG */ + + return (0); +} + + +/* + * Figure out if an interface name is an actual interface or actually a + * group of interfaces. + */ +int +interface_group(const char *ifname) +{ + if (ifname == NULL || !ifname[0]) + return (0); + + /* Real interfaces must end in a number, interface groups do not */ + if (isdigit(ifname[strlen(ifname) - 1])) + return (0); + else + return (1); +} + + +/* + * Make a rule that can directly compared by memcmp() + */ +void +comparable_rule(struct pf_rule *dst, const struct pf_rule *src, int type) +{ + int i; + /* + * To simplify the comparison, we just zero out the fields that are + * allowed to be different and then do a simple memcmp() + */ + memcpy(dst, src, sizeof(*dst)); + for (i = 0; i < sizeof(pf_rule_desc)/sizeof(*pf_rule_desc); i++) + if (pf_rule_desc[i].prf_type >= type) { +#ifdef OPT_DEBUG + assert(pf_rule_desc[i].prf_type != NEVER || + *(((char *)dst) + pf_rule_desc[i].prf_offset) == 0); +#endif /* OPT_DEBUG */ + memset(((char *)dst) + pf_rule_desc[i].prf_offset, 0, + pf_rule_desc[i].prf_size); + } +} + + +/* + * Remove superset information from two rules so we can directly compare them + * with memcmp() + */ +void +exclude_supersets(struct pf_rule *super, struct pf_rule *sub) +{ + if (super->ifname[0] == '\0') + memset(sub->ifname, 0, sizeof(sub->ifname)); + if (super->direction == PF_INOUT) + sub->direction = PF_INOUT; + if ((super->proto == 0 || super->proto == sub->proto) && + super->flags == 0 && super->flagset == 0 && (sub->flags || + sub->flagset)) { + sub->flags = super->flags; + sub->flagset = super->flagset; + } + if (super->proto == 0) + sub->proto = 0; + + if (super->src.port_op == 0) { + sub->src.port_op = 0; + sub->src.port[0] = 0; + sub->src.port[1] = 0; + } + if (super->dst.port_op == 0) { + sub->dst.port_op = 0; + sub->dst.port[0] = 0; + sub->dst.port[1] = 0; + } + + if (super->src.addr.type == PF_ADDR_ADDRMASK && !super->src.neg && + !sub->src.neg && super->src.addr.v.a.mask.addr32[0] == 0 && + super->src.addr.v.a.mask.addr32[1] == 0 && + super->src.addr.v.a.mask.addr32[2] == 0 && + super->src.addr.v.a.mask.addr32[3] == 0) + memset(&sub->src.addr, 0, sizeof(sub->src.addr)); + else if (super->src.addr.type == PF_ADDR_ADDRMASK && + sub->src.addr.type == PF_ADDR_ADDRMASK && + super->src.neg == sub->src.neg && + super->af == sub->af && + unmask(&super->src.addr.v.a.mask, super->af) < + unmask(&sub->src.addr.v.a.mask, sub->af) && + super->src.addr.v.a.addr.addr32[0] == + (sub->src.addr.v.a.addr.addr32[0] & + super->src.addr.v.a.mask.addr32[0]) && + super->src.addr.v.a.addr.addr32[1] == + (sub->src.addr.v.a.addr.addr32[1] & + super->src.addr.v.a.mask.addr32[1]) && + super->src.addr.v.a.addr.addr32[2] == + (sub->src.addr.v.a.addr.addr32[2] & + super->src.addr.v.a.mask.addr32[2]) && + super->src.addr.v.a.addr.addr32[3] == + (sub->src.addr.v.a.addr.addr32[3] & + super->src.addr.v.a.mask.addr32[3])) { + /* sub->src.addr is a subset of super->src.addr/mask */ + memcpy(&sub->src.addr, &super->src.addr, sizeof(sub->src.addr)); + } + + if (super->dst.addr.type == PF_ADDR_ADDRMASK && !super->dst.neg && + !sub->dst.neg && super->dst.addr.v.a.mask.addr32[0] == 0 && + super->dst.addr.v.a.mask.addr32[1] == 0 && + super->dst.addr.v.a.mask.addr32[2] == 0 && + super->dst.addr.v.a.mask.addr32[3] == 0) + memset(&sub->dst.addr, 0, sizeof(sub->dst.addr)); + else if (super->dst.addr.type == PF_ADDR_ADDRMASK && + sub->dst.addr.type == PF_ADDR_ADDRMASK && + super->dst.neg == sub->dst.neg && + super->af == sub->af && + unmask(&super->dst.addr.v.a.mask, super->af) < + unmask(&sub->dst.addr.v.a.mask, sub->af) && + super->dst.addr.v.a.addr.addr32[0] == + (sub->dst.addr.v.a.addr.addr32[0] & + super->dst.addr.v.a.mask.addr32[0]) && + super->dst.addr.v.a.addr.addr32[1] == + (sub->dst.addr.v.a.addr.addr32[1] & + super->dst.addr.v.a.mask.addr32[1]) && + super->dst.addr.v.a.addr.addr32[2] == + (sub->dst.addr.v.a.addr.addr32[2] & + super->dst.addr.v.a.mask.addr32[2]) && + super->dst.addr.v.a.addr.addr32[3] == + (sub->dst.addr.v.a.addr.addr32[3] & + super->dst.addr.v.a.mask.addr32[3])) { + /* sub->dst.addr is a subset of super->dst.addr/mask */ + memcpy(&sub->dst.addr, &super->dst.addr, sizeof(sub->dst.addr)); + } + + if (super->af == 0) + sub->af = 0; +} + + +void +superblock_free(struct pfctl *pf, struct superblock *block) +{ + struct pf_opt_rule *por; + while ((por = TAILQ_FIRST(&block->sb_rules))) { + TAILQ_REMOVE(&block->sb_rules, por, por_entry); + if (por->por_src_tbl) { + if (por->por_src_tbl->pt_buf) { + pfr_buf_clear(por->por_src_tbl->pt_buf); + free(por->por_src_tbl->pt_buf); + } + free(por->por_src_tbl); + } + if (por->por_dst_tbl) { + if (por->por_dst_tbl->pt_buf) { + pfr_buf_clear(por->por_dst_tbl->pt_buf); + free(por->por_dst_tbl->pt_buf); + } + free(por->por_dst_tbl); + } + free(por); + } + if (block->sb_profiled_block) + superblock_free(pf, block->sb_profiled_block); + free(block); +} + diff --git a/freebsd/sbin/pfctl/pfctl_osfp.c b/freebsd/sbin/pfctl/pfctl_osfp.c new file mode 100644 index 00000000..dd672623 --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl_osfp.c @@ -0,0 +1,1123 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ + +/* $OpenBSD: pfctl_osfp.c,v 1.14 2006/04/08 02:13:14 ray Exp $ */ + +/* + * Copyright (c) 2003 Mike Frantzen <frantzen@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/pfvar.h> + +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "pfctl_parser.h" +#include "pfctl.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-pfctl_osfp-data.h" +#endif /* __rtems__ */ + +#ifndef MIN +# define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#endif /* MIN */ +#ifndef MAX +# define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif /* MAX */ + + +#if 0 +# define DEBUG(fp, str, v...) \ + fprintf(stderr, "%s:%s:%s " str "\n", (fp)->fp_os.fp_class_nm, \ + (fp)->fp_os.fp_version_nm, (fp)->fp_os.fp_subtype_nm , ## v); +#else +# define DEBUG(fp, str, v...) ((void)0) +#endif + + +struct name_entry; +LIST_HEAD(name_list, name_entry); +struct name_entry { + LIST_ENTRY(name_entry) nm_entry; + int nm_num; + char nm_name[PF_OSFP_LEN]; + + struct name_list nm_sublist; + int nm_sublist_num; +}; +static struct name_list classes = LIST_HEAD_INITIALIZER(&classes); +static int class_count; +static int fingerprint_count; + +void add_fingerprint(int, int, struct pf_osfp_ioctl *); +struct name_entry *fingerprint_name_entry(struct name_list *, char *); +void pfctl_flush_my_fingerprints(struct name_list *); +char *get_field(char **, size_t *, int *); +int get_int(char **, size_t *, int *, int *, const char *, + int, int, const char *, int); +int get_str(char **, size_t *, char **, const char *, int, + const char *, int); +int get_tcpopts(const char *, int, const char *, + pf_tcpopts_t *, int *, int *, int *, int *, int *, + int *); +void import_fingerprint(struct pf_osfp_ioctl *); +const char *print_ioctl(struct pf_osfp_ioctl *); +void print_name_list(int, struct name_list *, const char *); +void sort_name_list(int, struct name_list *); +struct name_entry *lookup_name_list(struct name_list *, const char *); + +/* Load fingerprints from a file */ +int +pfctl_file_fingerprints(int dev, int opts, const char *fp_filename) +{ + FILE *in; + char *line; + size_t len; + int i, lineno = 0; + int window, w_mod, ttl, df, psize, p_mod, mss, mss_mod, wscale, + wscale_mod, optcnt, ts0; + pf_tcpopts_t packed_tcpopts; + char *class, *version, *subtype, *desc, *tcpopts; + struct pf_osfp_ioctl fp; + + pfctl_flush_my_fingerprints(&classes); + + if ((in = pfctl_fopen(fp_filename, "r")) == NULL) { + warn("%s", fp_filename); + return (1); + } + class = version = subtype = desc = tcpopts = NULL; + + if ((opts & PF_OPT_NOACTION) == 0) + pfctl_clear_fingerprints(dev, opts); + + while ((line = fgetln(in, &len)) != NULL) { + lineno++; + if (class) + free(class); + if (version) + free(version); + if (subtype) + free(subtype); + if (desc) + free(desc); + if (tcpopts) + free(tcpopts); + class = version = subtype = desc = tcpopts = NULL; + memset(&fp, 0, sizeof(fp)); + + /* Chop off comment */ + for (i = 0; i < len; i++) + if (line[i] == '#') { + len = i; + break; + } + /* Chop off whitespace */ + while (len > 0 && isspace(line[len - 1])) + len--; + while (len > 0 && isspace(line[0])) { + len--; + line++; + } + if (len == 0) + continue; + +#define T_DC 0x01 /* Allow don't care */ +#define T_MSS 0x02 /* Allow MSS multiple */ +#define T_MTU 0x04 /* Allow MTU multiple */ +#define T_MOD 0x08 /* Allow modulus */ + +#define GET_INT(v, mod, n, ty, mx) \ + get_int(&line, &len, &v, mod, n, ty, mx, fp_filename, lineno) +#define GET_STR(v, n, mn) \ + get_str(&line, &len, &v, n, mn, fp_filename, lineno) + + if (GET_INT(window, &w_mod, "window size", T_DC|T_MSS|T_MTU| + T_MOD, 0xffff) || + GET_INT(ttl, NULL, "ttl", 0, 0xff) || + GET_INT(df, NULL, "don't fragment frag", 0, 1) || + GET_INT(psize, &p_mod, "overall packet size", T_MOD|T_DC, + 8192) || + GET_STR(tcpopts, "TCP Options", 1) || + GET_STR(class, "OS class", 1) || + GET_STR(version, "OS version", 0) || + GET_STR(subtype, "OS subtype", 0) || + GET_STR(desc, "OS description", 2)) + continue; + if (get_tcpopts(fp_filename, lineno, tcpopts, &packed_tcpopts, + &optcnt, &mss, &mss_mod, &wscale, &wscale_mod, &ts0)) + continue; + if (len != 0) { + fprintf(stderr, "%s:%d excess field\n", fp_filename, + lineno); + continue; + } + + fp.fp_ttl = ttl; + if (df) + fp.fp_flags |= PF_OSFP_DF; + switch (w_mod) { + case 0: + break; + case T_DC: + fp.fp_flags |= PF_OSFP_WSIZE_DC; + break; + case T_MSS: + fp.fp_flags |= PF_OSFP_WSIZE_MSS; + break; + case T_MTU: + fp.fp_flags |= PF_OSFP_WSIZE_MTU; + break; + case T_MOD: + fp.fp_flags |= PF_OSFP_WSIZE_MOD; + break; + } + fp.fp_wsize = window; + + switch (p_mod) { + case T_DC: + fp.fp_flags |= PF_OSFP_PSIZE_DC; + break; + case T_MOD: + fp.fp_flags |= PF_OSFP_PSIZE_MOD; + } + fp.fp_psize = psize; + + + switch (wscale_mod) { + case T_DC: + fp.fp_flags |= PF_OSFP_WSCALE_DC; + break; + case T_MOD: + fp.fp_flags |= PF_OSFP_WSCALE_MOD; + } + fp.fp_wscale = wscale; + + switch (mss_mod) { + case T_DC: + fp.fp_flags |= PF_OSFP_MSS_DC; + break; + case T_MOD: + fp.fp_flags |= PF_OSFP_MSS_MOD; + break; + } + fp.fp_mss = mss; + + fp.fp_tcpopts = packed_tcpopts; + fp.fp_optcnt = optcnt; + if (ts0) + fp.fp_flags |= PF_OSFP_TS0; + + if (class[0] == '@') + fp.fp_os.fp_enflags |= PF_OSFP_GENERIC; + if (class[0] == '*') + fp.fp_os.fp_enflags |= PF_OSFP_NODETAIL; + + if (class[0] == '@' || class[0] == '*') + strlcpy(fp.fp_os.fp_class_nm, class + 1, + sizeof(fp.fp_os.fp_class_nm)); + else + strlcpy(fp.fp_os.fp_class_nm, class, + sizeof(fp.fp_os.fp_class_nm)); + strlcpy(fp.fp_os.fp_version_nm, version, + sizeof(fp.fp_os.fp_version_nm)); + strlcpy(fp.fp_os.fp_subtype_nm, subtype, + sizeof(fp.fp_os.fp_subtype_nm)); + + add_fingerprint(dev, opts, &fp); + + fp.fp_flags |= (PF_OSFP_DF | PF_OSFP_INET6); + fp.fp_psize += sizeof(struct ip6_hdr) - sizeof(struct ip); + add_fingerprint(dev, opts, &fp); + } + + if (class) + free(class); + if (version) + free(version); + if (subtype) + free(subtype); + if (desc) + free(desc); + if (tcpopts) + free(tcpopts); + + fclose(in); + + if (opts & PF_OPT_VERBOSE2) + printf("Loaded %d passive OS fingerprints\n", + fingerprint_count); + return (0); +} + +/* flush the kernel's fingerprints */ +void +pfctl_clear_fingerprints(int dev, int opts) +{ + if (ioctl(dev, DIOCOSFPFLUSH)) + err(1, "DIOCOSFPFLUSH"); +} + +/* flush pfctl's view of the fingerprints */ +void +pfctl_flush_my_fingerprints(struct name_list *list) +{ + struct name_entry *nm; + + while ((nm = LIST_FIRST(list)) != NULL) { + LIST_REMOVE(nm, nm_entry); + pfctl_flush_my_fingerprints(&nm->nm_sublist); + free(nm); + } + fingerprint_count = 0; + class_count = 0; +} + +/* Fetch the active fingerprints from the kernel */ +int +pfctl_load_fingerprints(int dev, int opts) +{ + struct pf_osfp_ioctl io; + int i; + + pfctl_flush_my_fingerprints(&classes); + + for (i = 0; i >= 0; i++) { + memset(&io, 0, sizeof(io)); + io.fp_getnum = i; + if (ioctl(dev, DIOCOSFPGET, &io)) { + if (errno == EBUSY) + break; + warn("DIOCOSFPGET"); + return (1); + } + import_fingerprint(&io); + } + return (0); +} + +/* List the fingerprints */ +void +pfctl_show_fingerprints(int opts) +{ + if (LIST_FIRST(&classes) != NULL) { + if (opts & PF_OPT_SHOWALL) { + pfctl_print_title("OS FINGERPRINTS:"); + printf("%u fingerprints loaded\n", fingerprint_count); + } else { + printf("Class\tVersion\tSubtype(subversion)\n"); + printf("-----\t-------\t-------------------\n"); + sort_name_list(opts, &classes); + print_name_list(opts, &classes, ""); + } + } +} + +/* Lookup a fingerprint */ +pf_osfp_t +pfctl_get_fingerprint(const char *name) +{ + struct name_entry *nm, *class_nm, *version_nm, *subtype_nm; + pf_osfp_t ret = PF_OSFP_NOMATCH; + int class, version, subtype; + int unp_class, unp_version, unp_subtype; + int wr_len, version_len, subtype_len; + char *ptr, *wr_name; + + if (strcasecmp(name, "unknown") == 0) + return (PF_OSFP_UNKNOWN); + + /* Try most likely no version and no subtype */ + if ((nm = lookup_name_list(&classes, name))) { + class = nm->nm_num; + version = PF_OSFP_ANY; + subtype = PF_OSFP_ANY; + goto found; + } else { + + /* Chop it up into class/version/subtype */ + + if ((wr_name = strdup(name)) == NULL) + err(1, "malloc"); + if ((ptr = strchr(wr_name, ' ')) == NULL) { + free(wr_name); + return (PF_OSFP_NOMATCH); + } + *ptr++ = '\0'; + + /* The class is easy to find since it is delimited by a space */ + if ((class_nm = lookup_name_list(&classes, wr_name)) == NULL) { + free(wr_name); + return (PF_OSFP_NOMATCH); + } + class = class_nm->nm_num; + + /* Try no subtype */ + if ((version_nm = lookup_name_list(&class_nm->nm_sublist, ptr))) + { + version = version_nm->nm_num; + subtype = PF_OSFP_ANY; + free(wr_name); + goto found; + } + + + /* + * There must be a version and a subtype. + * We'll do some fuzzy matching to pick up things like: + * Linux 2.2.14 (version=2.2 subtype=14) + * FreeBSD 4.0-STABLE (version=4.0 subtype=STABLE) + * Windows 2000 SP2 (version=2000 subtype=SP2) + */ +#define CONNECTOR(x) ((x) == '.' || (x) == ' ' || (x) == '\t' || (x) == '-') + wr_len = strlen(ptr); + LIST_FOREACH(version_nm, &class_nm->nm_sublist, nm_entry) { + version_len = strlen(version_nm->nm_name); + if (wr_len < version_len + 2 || + !CONNECTOR(ptr[version_len])) + continue; + /* first part of the string must be version */ + if (strncasecmp(ptr, version_nm->nm_name, + version_len)) + continue; + + LIST_FOREACH(subtype_nm, &version_nm->nm_sublist, + nm_entry) { + subtype_len = strlen(subtype_nm->nm_name); + if (wr_len != version_len + subtype_len + 1) + continue; + + /* last part of the string must be subtype */ + if (strcasecmp(&ptr[version_len+1], + subtype_nm->nm_name) != 0) + continue; + + /* Found it!! */ + version = version_nm->nm_num; + subtype = subtype_nm->nm_num; + free(wr_name); + goto found; + } + } + + free(wr_name); + return (PF_OSFP_NOMATCH); + } + +found: + PF_OSFP_PACK(ret, class, version, subtype); + if (ret != PF_OSFP_NOMATCH) { + PF_OSFP_UNPACK(ret, unp_class, unp_version, unp_subtype); + if (class != unp_class) { + fprintf(stderr, "warning: fingerprint table overflowed " + "classes\n"); + return (PF_OSFP_NOMATCH); + } + if (version != unp_version) { + fprintf(stderr, "warning: fingerprint table overflowed " + "versions\n"); + return (PF_OSFP_NOMATCH); + } + if (subtype != unp_subtype) { + fprintf(stderr, "warning: fingerprint table overflowed " + "subtypes\n"); + return (PF_OSFP_NOMATCH); + } + } + if (ret == PF_OSFP_ANY) { + /* should never happen */ + fprintf(stderr, "warning: fingerprint packed to 'any'\n"); + return (PF_OSFP_NOMATCH); + } + + return (ret); +} + +/* Lookup a fingerprint name by ID */ +char * +pfctl_lookup_fingerprint(pf_osfp_t fp, char *buf, size_t len) +{ + int class, version, subtype; + struct name_list *list; + struct name_entry *nm; + + char *class_name, *version_name, *subtype_name; + class_name = version_name = subtype_name = NULL; + + if (fp == PF_OSFP_UNKNOWN) { + strlcpy(buf, "unknown", len); + return (buf); + } + if (fp == PF_OSFP_ANY) { + strlcpy(buf, "any", len); + return (buf); + } + + PF_OSFP_UNPACK(fp, class, version, subtype); + if (class >= (1 << _FP_CLASS_BITS) || + version >= (1 << _FP_VERSION_BITS) || + subtype >= (1 << _FP_SUBTYPE_BITS)) { + warnx("PF_OSFP_UNPACK(0x%x) failed!!", fp); + strlcpy(buf, "nomatch", len); + return (buf); + } + + LIST_FOREACH(nm, &classes, nm_entry) { + if (nm->nm_num == class) { + class_name = nm->nm_name; + if (version == PF_OSFP_ANY) + goto found; + list = &nm->nm_sublist; + LIST_FOREACH(nm, list, nm_entry) { + if (nm->nm_num == version) { + version_name = nm->nm_name; + if (subtype == PF_OSFP_ANY) + goto found; + list = &nm->nm_sublist; + LIST_FOREACH(nm, list, nm_entry) { + if (nm->nm_num == subtype) { + subtype_name = + nm->nm_name; + goto found; + } + } /* foreach subtype */ + strlcpy(buf, "nomatch", len); + return (buf); + } + } /* foreach version */ + strlcpy(buf, "nomatch", len); + return (buf); + } + } /* foreach class */ + + strlcpy(buf, "nomatch", len); + return (buf); + +found: + snprintf(buf, len, "%s", class_name); + if (version_name) { + strlcat(buf, " ", len); + strlcat(buf, version_name, len); + if (subtype_name) { + if (strchr(version_name, ' ')) + strlcat(buf, " ", len); + else if (strchr(version_name, '.') && + isdigit(*subtype_name)) + strlcat(buf, ".", len); + else + strlcat(buf, " ", len); + strlcat(buf, subtype_name, len); + } + } + return (buf); +} + +/* lookup a name in a list */ +struct name_entry * +lookup_name_list(struct name_list *list, const char *name) +{ + struct name_entry *nm; + LIST_FOREACH(nm, list, nm_entry) + if (strcasecmp(name, nm->nm_name) == 0) + return (nm); + + return (NULL); +} + + +void +add_fingerprint(int dev, int opts, struct pf_osfp_ioctl *fp) +{ + struct pf_osfp_ioctl fptmp; + struct name_entry *nm_class, *nm_version, *nm_subtype; + int class, version, subtype; + +/* We expand #-# or #.#-#.# version/subtypes into multiple fingerprints */ +#define EXPAND(field) do { \ + int _dot = -1, _start = -1, _end = -1, _i = 0; \ + /* pick major version out of #.# */ \ + if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.') { \ + _dot = fp->field[_i] - '0'; \ + _i += 2; \ + } \ + if (isdigit(fp->field[_i])) \ + _start = fp->field[_i++] - '0'; \ + else \ + break; \ + if (isdigit(fp->field[_i])) \ + _start = (_start * 10) + fp->field[_i++] - '0'; \ + if (fp->field[_i++] != '-') \ + break; \ + if (isdigit(fp->field[_i]) && fp->field[_i+1] == '.' && \ + fp->field[_i] - '0' == _dot) \ + _i += 2; \ + else if (_dot != -1) \ + break; \ + if (isdigit(fp->field[_i])) \ + _end = fp->field[_i++] - '0'; \ + else \ + break; \ + if (isdigit(fp->field[_i])) \ + _end = (_end * 10) + fp->field[_i++] - '0'; \ + if (isdigit(fp->field[_i])) \ + _end = (_end * 10) + fp->field[_i++] - '0'; \ + if (fp->field[_i] != '\0') \ + break; \ + memcpy(&fptmp, fp, sizeof(fptmp)); \ + for (;_start <= _end; _start++) { \ + memset(fptmp.field, 0, sizeof(fptmp.field)); \ + fptmp.fp_os.fp_enflags |= PF_OSFP_EXPANDED; \ + if (_dot == -1) \ + snprintf(fptmp.field, sizeof(fptmp.field), \ + "%d", _start); \ + else \ + snprintf(fptmp.field, sizeof(fptmp.field), \ + "%d.%d", _dot, _start); \ + add_fingerprint(dev, opts, &fptmp); \ + } \ +} while(0) + + /* We allow "#-#" as a version or subtype and we'll expand it */ + EXPAND(fp_os.fp_version_nm); + EXPAND(fp_os.fp_subtype_nm); + + if (strcasecmp(fp->fp_os.fp_class_nm, "nomatch") == 0) + errx(1, "fingerprint class \"nomatch\" is reserved"); + + version = PF_OSFP_ANY; + subtype = PF_OSFP_ANY; + + nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm); + if (nm_class->nm_num == 0) + nm_class->nm_num = ++class_count; + class = nm_class->nm_num; + + nm_version = fingerprint_name_entry(&nm_class->nm_sublist, + fp->fp_os.fp_version_nm); + if (nm_version) { + if (nm_version->nm_num == 0) + nm_version->nm_num = ++nm_class->nm_sublist_num; + version = nm_version->nm_num; + nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist, + fp->fp_os.fp_subtype_nm); + if (nm_subtype) { + if (nm_subtype->nm_num == 0) + nm_subtype->nm_num = + ++nm_version->nm_sublist_num; + subtype = nm_subtype->nm_num; + } + } + + + DEBUG(fp, "\tsignature %d:%d:%d %s", class, version, subtype, + print_ioctl(fp)); + + PF_OSFP_PACK(fp->fp_os.fp_os, class, version, subtype); + fingerprint_count++; + +#ifdef FAKE_PF_KERNEL + /* Linked to the sys/net/pf_osfp.c. Call pf_osfp_add() */ + if ((errno = pf_osfp_add(fp))) +#else + if ((opts & PF_OPT_NOACTION) == 0 && ioctl(dev, DIOCOSFPADD, fp)) +#endif /* FAKE_PF_KERNEL */ + { + if (errno == EEXIST) { + warn("Duplicate signature for %s %s %s", + fp->fp_os.fp_class_nm, + fp->fp_os.fp_version_nm, + fp->fp_os.fp_subtype_nm); + + } else { + err(1, "DIOCOSFPADD"); + } + } +} + +/* import a fingerprint from the kernel */ +void +import_fingerprint(struct pf_osfp_ioctl *fp) +{ + struct name_entry *nm_class, *nm_version, *nm_subtype; + int class, version, subtype; + + PF_OSFP_UNPACK(fp->fp_os.fp_os, class, version, subtype); + + nm_class = fingerprint_name_entry(&classes, fp->fp_os.fp_class_nm); + if (nm_class->nm_num == 0) { + nm_class->nm_num = class; + class_count = MAX(class_count, class); + } + + nm_version = fingerprint_name_entry(&nm_class->nm_sublist, + fp->fp_os.fp_version_nm); + if (nm_version) { + if (nm_version->nm_num == 0) { + nm_version->nm_num = version; + nm_class->nm_sublist_num = MAX(nm_class->nm_sublist_num, + version); + } + nm_subtype = fingerprint_name_entry(&nm_version->nm_sublist, + fp->fp_os.fp_subtype_nm); + if (nm_subtype) { + if (nm_subtype->nm_num == 0) { + nm_subtype->nm_num = subtype; + nm_version->nm_sublist_num = + MAX(nm_version->nm_sublist_num, subtype); + } + } + } + + + fingerprint_count++; + DEBUG(fp, "import signature %d:%d:%d", class, version, subtype); +} + +/* Find an entry for a fingerprints class/version/subtype */ +struct name_entry * +fingerprint_name_entry(struct name_list *list, char *name) +{ + struct name_entry *nm_entry; + + if (name == NULL || strlen(name) == 0) + return (NULL); + + LIST_FOREACH(nm_entry, list, nm_entry) { + if (strcasecmp(nm_entry->nm_name, name) == 0) { + /* We'll move this to the front of the list later */ + LIST_REMOVE(nm_entry, nm_entry); + break; + } + } + if (nm_entry == NULL) { + nm_entry = calloc(1, sizeof(*nm_entry)); + if (nm_entry == NULL) + err(1, "calloc"); + LIST_INIT(&nm_entry->nm_sublist); + strlcpy(nm_entry->nm_name, name, sizeof(nm_entry->nm_name)); + } + LIST_INSERT_HEAD(list, nm_entry, nm_entry); + return (nm_entry); +} + + +void +print_name_list(int opts, struct name_list *nml, const char *prefix) +{ + char newprefix[32]; + struct name_entry *nm; + + LIST_FOREACH(nm, nml, nm_entry) { + snprintf(newprefix, sizeof(newprefix), "%s%s\t", prefix, + nm->nm_name); + printf("%s\n", newprefix); + print_name_list(opts, &nm->nm_sublist, newprefix); + } +} + +void +sort_name_list(int opts, struct name_list *nml) +{ + struct name_list new; + struct name_entry *nm, *nmsearch, *nmlast; + + /* yes yes, it's a very slow sort. so sue me */ + + LIST_INIT(&new); + + while ((nm = LIST_FIRST(nml)) != NULL) { + LIST_REMOVE(nm, nm_entry); + nmlast = NULL; + LIST_FOREACH(nmsearch, &new, nm_entry) { + if (strcasecmp(nmsearch->nm_name, nm->nm_name) > 0) { + LIST_INSERT_BEFORE(nmsearch, nm, nm_entry); + break; + } + nmlast = nmsearch; + } + if (nmsearch == NULL) { + if (nmlast) + LIST_INSERT_AFTER(nmlast, nm, nm_entry); + else + LIST_INSERT_HEAD(&new, nm, nm_entry); + } + + sort_name_list(opts, &nm->nm_sublist); + } + nmlast = NULL; + while ((nm = LIST_FIRST(&new)) != NULL) { + LIST_REMOVE(nm, nm_entry); + if (nmlast == NULL) + LIST_INSERT_HEAD(nml, nm, nm_entry); + else + LIST_INSERT_AFTER(nmlast, nm, nm_entry); + nmlast = nm; + } +} + +/* parse the next integer in a formatted config file line */ +int +get_int(char **line, size_t *len, int *var, int *mod, + const char *name, int flags, int max, const char *filename, int lineno) +{ + int fieldlen, i; + char *field; + long val = 0; + + if (mod) + *mod = 0; + *var = 0; + + field = get_field(line, len, &fieldlen); + if (field == NULL) + return (1); + if (fieldlen == 0) { + fprintf(stderr, "%s:%d empty %s\n", filename, lineno, name); + return (1); + } + + i = 0; + if ((*field == '%' || *field == 'S' || *field == 'T' || *field == '*') + && fieldlen >= 1) { + switch (*field) { + case 'S': + if (mod && (flags & T_MSS)) + *mod = T_MSS; + if (fieldlen == 1) + return (0); + break; + case 'T': + if (mod && (flags & T_MTU)) + *mod = T_MTU; + if (fieldlen == 1) + return (0); + break; + case '*': + if (fieldlen != 1) { + fprintf(stderr, "%s:%d long '%c' %s\n", + filename, lineno, *field, name); + return (1); + } + if (mod && (flags & T_DC)) { + *mod = T_DC; + return (0); + } + case '%': + if (mod && (flags & T_MOD)) + *mod = T_MOD; + if (fieldlen == 1) { + fprintf(stderr, "%s:%d modulus %s must have a " + "value\n", filename, lineno, name); + return (1); + } + break; + } + if (mod == NULL || *mod == 0) { + fprintf(stderr, "%s:%d does not allow %c' %s\n", + filename, lineno, *field, name); + return (1); + } + i++; + } + + for (; i < fieldlen; i++) { + if (field[i] < '0' || field[i] > '9') { + fprintf(stderr, "%s:%d non-digit character in %s\n", + filename, lineno, name); + return (1); + } + val = val * 10 + field[i] - '0'; + if (val < 0) { + fprintf(stderr, "%s:%d %s overflowed\n", filename, + lineno, name); + return (1); + } + } + + if (val > max) { + fprintf(stderr, "%s:%d %s value %ld > %d\n", filename, lineno, + name, val, max); + return (1); + } + *var = (int)val; + + return (0); +} + +/* parse the next string in a formatted config file line */ +int +get_str(char **line, size_t *len, char **v, const char *name, int minlen, + const char *filename, int lineno) +{ + int fieldlen; + char *ptr; + + ptr = get_field(line, len, &fieldlen); + if (ptr == NULL) + return (1); + if (fieldlen < minlen) { + fprintf(stderr, "%s:%d too short %s\n", filename, lineno, name); + return (1); + } + if ((*v = malloc(fieldlen + 1)) == NULL) { + perror("malloc()"); + return (1); + } + memcpy(*v, ptr, fieldlen); + (*v)[fieldlen] = '\0'; + + return (0); +} + +/* Parse out the TCP opts */ +int +get_tcpopts(const char *filename, int lineno, const char *tcpopts, + pf_tcpopts_t *packed, int *optcnt, int *mss, int *mss_mod, int *wscale, + int *wscale_mod, int *ts0) +{ + int i, opt; + + *packed = 0; + *optcnt = 0; + *wscale = 0; + *wscale_mod = T_DC; + *mss = 0; + *mss_mod = T_DC; + *ts0 = 0; + if (strcmp(tcpopts, ".") == 0) + return (0); + + for (i = 0; tcpopts[i] && *optcnt < PF_OSFP_MAX_OPTS;) { + switch ((opt = toupper(tcpopts[i++]))) { + case 'N': /* FALLTHROUGH */ + case 'S': + *packed = (*packed << PF_OSFP_TCPOPT_BITS) | + (opt == 'N' ? PF_OSFP_TCPOPT_NOP : + PF_OSFP_TCPOPT_SACK); + break; + case 'W': /* FALLTHROUGH */ + case 'M': { + int *this_mod, *this; + + if (opt == 'W') { + this = wscale; + this_mod = wscale_mod; + } else { + this = mss; + this_mod = mss_mod; + } + *this = 0; + *this_mod = 0; + + *packed = (*packed << PF_OSFP_TCPOPT_BITS) | + (opt == 'W' ? PF_OSFP_TCPOPT_WSCALE : + PF_OSFP_TCPOPT_MSS); + if (tcpopts[i] == '*' && (tcpopts[i + 1] == '\0' || + tcpopts[i + 1] == ',')) { + *this_mod = T_DC; + i++; + break; + } + + if (tcpopts[i] == '%') { + *this_mod = T_MOD; + i++; + } + do { + if (!isdigit(tcpopts[i])) { + fprintf(stderr, "%s:%d unknown " + "character '%c' in %c TCP opt\n", + filename, lineno, tcpopts[i], opt); + return (1); + } + *this = (*this * 10) + tcpopts[i++] - '0'; + } while(tcpopts[i] != ',' && tcpopts[i] != '\0'); + break; + } + case 'T': + if (tcpopts[i] == '0') { + *ts0 = 1; + i++; + } + *packed = (*packed << PF_OSFP_TCPOPT_BITS) | + PF_OSFP_TCPOPT_TS; + break; + } + (*optcnt) ++; + if (tcpopts[i] == '\0') + break; + if (tcpopts[i] != ',') { + fprintf(stderr, "%s:%d unknown option to %c TCP opt\n", + filename, lineno, opt); + return (1); + } + i++; + } + + return (0); +} + +/* rip the next field ouf of a formatted config file line */ +char * +get_field(char **line, size_t *len, int *fieldlen) +{ + char *ret, *ptr = *line; + size_t plen = *len; + + + while (plen && isspace(*ptr)) { + plen--; + ptr++; + } + ret = ptr; + *fieldlen = 0; + + for (; plen > 0 && *ptr != ':'; plen--, ptr++) + (*fieldlen)++; + if (plen) { + *line = ptr + 1; + *len = plen - 1; + } else { + *len = 0; + } + while (*fieldlen && isspace(ret[*fieldlen - 1])) + (*fieldlen)--; + return (ret); +} + + +const char * +print_ioctl(struct pf_osfp_ioctl *fp) +{ + static char buf[1024]; + char tmp[32]; + int i, opt; + + *buf = '\0'; + if (fp->fp_flags & PF_OSFP_WSIZE_DC) + strlcat(buf, "*", sizeof(buf)); + else if (fp->fp_flags & PF_OSFP_WSIZE_MSS) + strlcat(buf, "S", sizeof(buf)); + else if (fp->fp_flags & PF_OSFP_WSIZE_MTU) + strlcat(buf, "T", sizeof(buf)); + else { + if (fp->fp_flags & PF_OSFP_WSIZE_MOD) + strlcat(buf, "%", sizeof(buf)); + snprintf(tmp, sizeof(tmp), "%d", fp->fp_wsize); + strlcat(buf, tmp, sizeof(buf)); + } + strlcat(buf, ":", sizeof(buf)); + + snprintf(tmp, sizeof(tmp), "%d", fp->fp_ttl); + strlcat(buf, tmp, sizeof(buf)); + strlcat(buf, ":", sizeof(buf)); + + if (fp->fp_flags & PF_OSFP_DF) + strlcat(buf, "1", sizeof(buf)); + else + strlcat(buf, "0", sizeof(buf)); + strlcat(buf, ":", sizeof(buf)); + + if (fp->fp_flags & PF_OSFP_PSIZE_DC) + strlcat(buf, "*", sizeof(buf)); + else { + if (fp->fp_flags & PF_OSFP_PSIZE_MOD) + strlcat(buf, "%", sizeof(buf)); + snprintf(tmp, sizeof(tmp), "%d", fp->fp_psize); + strlcat(buf, tmp, sizeof(buf)); + } + strlcat(buf, ":", sizeof(buf)); + + if (fp->fp_optcnt == 0) + strlcat(buf, ".", sizeof(buf)); + for (i = fp->fp_optcnt - 1; i >= 0; i--) { + opt = fp->fp_tcpopts >> (i * PF_OSFP_TCPOPT_BITS); + opt &= (1 << PF_OSFP_TCPOPT_BITS) - 1; + switch (opt) { + case PF_OSFP_TCPOPT_NOP: + strlcat(buf, "N", sizeof(buf)); + break; + case PF_OSFP_TCPOPT_SACK: + strlcat(buf, "S", sizeof(buf)); + break; + case PF_OSFP_TCPOPT_TS: + strlcat(buf, "T", sizeof(buf)); + if (fp->fp_flags & PF_OSFP_TS0) + strlcat(buf, "0", sizeof(buf)); + break; + case PF_OSFP_TCPOPT_MSS: + strlcat(buf, "M", sizeof(buf)); + if (fp->fp_flags & PF_OSFP_MSS_DC) + strlcat(buf, "*", sizeof(buf)); + else { + if (fp->fp_flags & PF_OSFP_MSS_MOD) + strlcat(buf, "%", sizeof(buf)); + snprintf(tmp, sizeof(tmp), "%d", fp->fp_mss); + strlcat(buf, tmp, sizeof(buf)); + } + break; + case PF_OSFP_TCPOPT_WSCALE: + strlcat(buf, "W", sizeof(buf)); + if (fp->fp_flags & PF_OSFP_WSCALE_DC) + strlcat(buf, "*", sizeof(buf)); + else { + if (fp->fp_flags & PF_OSFP_WSCALE_MOD) + strlcat(buf, "%", sizeof(buf)); + snprintf(tmp, sizeof(tmp), "%d", fp->fp_wscale); + strlcat(buf, tmp, sizeof(buf)); + } + break; + } + + if (i != 0) + strlcat(buf, ",", sizeof(buf)); + } + strlcat(buf, ":", sizeof(buf)); + + strlcat(buf, fp->fp_os.fp_class_nm, sizeof(buf)); + strlcat(buf, ":", sizeof(buf)); + strlcat(buf, fp->fp_os.fp_version_nm, sizeof(buf)); + strlcat(buf, ":", sizeof(buf)); + strlcat(buf, fp->fp_os.fp_subtype_nm, sizeof(buf)); + strlcat(buf, ":", sizeof(buf)); + + snprintf(tmp, sizeof(tmp), "TcpOpts %d 0x%llx", fp->fp_optcnt, + (long long int)fp->fp_tcpopts); + strlcat(buf, tmp, sizeof(buf)); + + return (buf); +} diff --git a/freebsd/sbin/pfctl/pfctl_parser.c b/freebsd/sbin/pfctl/pfctl_parser.c new file mode 100644 index 00000000..0ff7deec --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl_parser.c @@ -0,0 +1,1780 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ + +/* $OpenBSD: pfctl_parser.c,v 1.240 2008/06/10 20:55:02 mcbride Exp $ */ + +/* + * Copyright (c) 2001 Daniel Hartmeier + * Copyright (c) 2002,2003 Henning Brauer + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <rtems/bsd/sys/param.h> +#include <sys/proc.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <netinet/icmp6.h> +#include <net/pfvar.h> +#include <arpa/inet.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <netdb.h> +#include <stdarg.h> +#include <errno.h> +#include <err.h> +#include <ifaddrs.h> +#include <unistd.h> + +#include "pfctl_parser.h" +#include "pfctl.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-pfctl_parser-data.h" +#endif /* __rtems__ */ + +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_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); +void print_flags (u_int8_t); +void print_fromto(struct pf_rule_addr *, pf_osfp_t, + struct pf_rule_addr *, u_int8_t, u_int8_t, int, int); +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_v4(const char *, int); +struct node_host *host_v6(const char *, int); +struct node_host *host_dns(const char *, int, int); + +const char * const tcpflags = "FSRPAUEW"; + +static const struct icmptypeent icmp_type[] = { + { "echoreq", ICMP_ECHO }, + { "echorep", ICMP_ECHOREPLY }, + { "unreach", ICMP_UNREACH }, + { "squench", ICMP_SOURCEQUENCH }, + { "redir", ICMP_REDIRECT }, + { "althost", ICMP_ALTHOSTADDR }, + { "routeradv", ICMP_ROUTERADVERT }, + { "routersol", ICMP_ROUTERSOLICIT }, + { "timex", ICMP_TIMXCEED }, + { "paramprob", ICMP_PARAMPROB }, + { "timereq", ICMP_TSTAMP }, + { "timerep", ICMP_TSTAMPREPLY }, + { "inforeq", ICMP_IREQ }, + { "inforep", ICMP_IREQREPLY }, + { "maskreq", ICMP_MASKREQ }, + { "maskrep", ICMP_MASKREPLY }, + { "trace", ICMP_TRACEROUTE }, + { "dataconv", ICMP_DATACONVERR }, + { "mobredir", ICMP_MOBILE_REDIRECT }, + { "ipv6-where", ICMP_IPV6_WHEREAREYOU }, + { "ipv6-here", ICMP_IPV6_IAMHERE }, + { "mobregreq", ICMP_MOBILE_REGREQUEST }, + { "mobregrep", ICMP_MOBILE_REGREPLY }, + { "skip", ICMP_SKIP }, + { "photuris", ICMP_PHOTURIS } +}; + +static const struct icmptypeent icmp6_type[] = { + { "unreach", ICMP6_DST_UNREACH }, + { "toobig", ICMP6_PACKET_TOO_BIG }, + { "timex", ICMP6_TIME_EXCEEDED }, + { "paramprob", ICMP6_PARAM_PROB }, + { "echoreq", ICMP6_ECHO_REQUEST }, + { "echorep", ICMP6_ECHO_REPLY }, + { "groupqry", ICMP6_MEMBERSHIP_QUERY }, + { "listqry", MLD_LISTENER_QUERY }, + { "grouprep", ICMP6_MEMBERSHIP_REPORT }, + { "listenrep", MLD_LISTENER_REPORT }, + { "groupterm", ICMP6_MEMBERSHIP_REDUCTION }, + { "listendone", MLD_LISTENER_DONE }, + { "routersol", ND_ROUTER_SOLICIT }, + { "routeradv", ND_ROUTER_ADVERT }, + { "neighbrsol", ND_NEIGHBOR_SOLICIT }, + { "neighbradv", ND_NEIGHBOR_ADVERT }, + { "redir", ND_REDIRECT }, + { "routrrenum", ICMP6_ROUTER_RENUMBERING }, + { "wrureq", ICMP6_WRUREQUEST }, + { "wrurep", ICMP6_WRUREPLY }, + { "fqdnreq", ICMP6_FQDN_QUERY }, + { "fqdnrep", ICMP6_FQDN_REPLY }, + { "niqry", ICMP6_NI_QUERY }, + { "nirep", ICMP6_NI_REPLY }, + { "mtraceresp", MLD_MTRACE_RESP }, + { "mtrace", MLD_MTRACE } +}; + +static const struct icmpcodeent icmp_code[] = { + { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET }, + { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST }, + { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL }, + { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT }, + { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG }, + { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL }, + { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN }, + { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN }, + { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED }, + { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB }, + { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB }, + { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET }, + { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST }, + { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB }, + { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE }, + { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF }, + { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET }, + { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST }, + { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET }, + { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST }, + { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL }, + { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON }, + { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS }, + { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS }, + { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR }, + { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT }, + { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH }, + { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX }, + { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED }, + { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED } +}; + +static const struct icmpcodeent icmp6_code[] = { + { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN }, + { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE }, + { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR }, + { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE }, + { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR }, + { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT }, + { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT }, + { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY }, + { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER }, + { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER }, + { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK }, + { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER } +}; + +const struct pf_timeout pf_timeouts[] = { + { "tcp.first", PFTM_TCP_FIRST_PACKET }, + { "tcp.opening", PFTM_TCP_OPENING }, + { "tcp.established", PFTM_TCP_ESTABLISHED }, + { "tcp.closing", PFTM_TCP_CLOSING }, + { "tcp.finwait", PFTM_TCP_FIN_WAIT }, + { "tcp.closed", PFTM_TCP_CLOSED }, + { "tcp.tsdiff", PFTM_TS_DIFF }, + { "udp.first", PFTM_UDP_FIRST_PACKET }, + { "udp.single", PFTM_UDP_SINGLE }, + { "udp.multiple", PFTM_UDP_MULTIPLE }, + { "icmp.first", PFTM_ICMP_FIRST_PACKET }, + { "icmp.error", PFTM_ICMP_ERROR_REPLY }, + { "other.first", PFTM_OTHER_FIRST_PACKET }, + { "other.single", PFTM_OTHER_SINGLE }, + { "other.multiple", PFTM_OTHER_MULTIPLE }, + { "frag", PFTM_FRAG }, + { "interval", PFTM_INTERVAL }, + { "adaptive.start", PFTM_ADAPTIVE_START }, + { "adaptive.end", PFTM_ADAPTIVE_END }, + { "src.track", PFTM_SRC_NODE }, + { NULL, 0 } +}; + +const struct icmptypeent * +geticmptypebynumber(u_int8_t type, sa_family_t af) +{ + unsigned int i; + + if (af != AF_INET6) { + for (i=0; i < nitems(icmp_type); i++) { + if (type == icmp_type[i].type) + return (&icmp_type[i]); + } + } else { + for (i=0; i < nitems(icmp6_type); i++) { + if (type == icmp6_type[i].type) + return (&icmp6_type[i]); + } + } + return (NULL); +} + +const struct icmptypeent * +geticmptypebyname(char *w, sa_family_t af) +{ + unsigned int i; + + if (af != AF_INET6) { + for (i=0; i < nitems(icmp_type); i++) { + if (!strcmp(w, icmp_type[i].name)) + return (&icmp_type[i]); + } + } else { + for (i=0; i < nitems(icmp6_type); i++) { + if (!strcmp(w, icmp6_type[i].name)) + return (&icmp6_type[i]); + } + } + return (NULL); +} + +const struct icmpcodeent * +geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af) +{ + unsigned int i; + + if (af != AF_INET6) { + for (i=0; i < nitems(icmp_code); i++) { + if (type == icmp_code[i].type && + code == icmp_code[i].code) + return (&icmp_code[i]); + } + } else { + for (i=0; i < nitems(icmp6_code); i++) { + if (type == icmp6_code[i].type && + code == icmp6_code[i].code) + return (&icmp6_code[i]); + } + } + return (NULL); +} + +const struct icmpcodeent * +geticmpcodebyname(u_long type, char *w, sa_family_t af) +{ + unsigned int i; + + if (af != AF_INET6) { + for (i=0; i < nitems(icmp_code); i++) { + if (type == icmp_code[i].type && + !strcmp(w, icmp_code[i].name)) + return (&icmp_code[i]); + } + } else { + for (i=0; i < nitems(icmp6_code); i++) { + if (type == icmp6_code[i].type && + !strcmp(w, icmp6_code[i].name)) + return (&icmp6_code[i]); + } + } + return (NULL); +} + +void +print_op(u_int8_t op, const char *a1, const char *a2) +{ + if (op == PF_OP_IRG) + printf(" %s >< %s", a1, a2); + else if (op == PF_OP_XRG) + printf(" %s <> %s", a1, a2); + else if (op == PF_OP_EQ) + printf(" = %s", a1); + else if (op == PF_OP_NE) + printf(" != %s", a1); + else if (op == PF_OP_LT) + printf(" < %s", a1); + else if (op == PF_OP_LE) + printf(" <= %s", a1); + else if (op == PF_OP_GT) + printf(" > %s", a1); + else if (op == PF_OP_GE) + printf(" >= %s", a1); + else if (op == PF_OP_RRG) + printf(" %s:%s", a1, a2); +} + +void +print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numeric) +{ + char a1[6], a2[6]; + struct servent *s; + + if (!numeric) + s = getservbyport(p1, proto); + else + s = NULL; + p1 = ntohs(p1); + p2 = ntohs(p2); + snprintf(a1, sizeof(a1), "%u", p1); + snprintf(a2, sizeof(a2), "%u", p2); + printf(" port"); + if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE)) + print_op(op, s->s_name, a2); + else + print_op(op, a1, a2); +} + +void +print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax) +{ + char a1[11], a2[11]; + + snprintf(a1, sizeof(a1), "%u", u1); + snprintf(a2, sizeof(a2), "%u", u2); + printf(" %s", t); + if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) + print_op(op, "unknown", a2); + else + print_op(op, a1, a2); +} + +void +print_flags(u_int8_t f) +{ + int i; + + for (i = 0; tcpflags[i]; ++i) + if (f & (1 << i)) + printf("%c", tcpflags[i]); +} + +void +print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst, + sa_family_t af, u_int8_t proto, int verbose, int numeric) +{ + char buf[PF_OSFP_LEN*3]; + if (src->addr.type == PF_ADDR_ADDRMASK && + dst->addr.type == PF_ADDR_ADDRMASK && + PF_AZERO(&src->addr.v.a.addr, AF_INET6) && + PF_AZERO(&src->addr.v.a.mask, AF_INET6) && + PF_AZERO(&dst->addr.v.a.addr, AF_INET6) && + PF_AZERO(&dst->addr.v.a.mask, AF_INET6) && + !src->neg && !dst->neg && + !src->port_op && !dst->port_op && + osfp == PF_OSFP_ANY) + printf(" all"); + else { + printf(" from "); + if (src->neg) + printf("! "); + print_addr(&src->addr, af, verbose); + if (src->port_op) + print_port(src->port_op, src->port[0], + src->port[1], + proto == IPPROTO_TCP ? "tcp" : "udp", + numeric); + if (osfp != PF_OSFP_ANY) + printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf, + sizeof(buf))); + + printf(" to "); + if (dst->neg) + printf("! "); + print_addr(&dst->addr, af, verbose); + if (dst->port_op) + print_port(dst->port_op, dst->port[0], + dst->port[1], + proto == IPPROTO_TCP ? "tcp" : "udp", + numeric); + } +} + +void +print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, + sa_family_t af, int id) +{ + struct pf_pooladdr *pooladdr; + + if ((TAILQ_FIRST(&pool->list) != NULL) && + TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) + printf("{ "); + TAILQ_FOREACH(pooladdr, &pool->list, entries){ + switch (id) { + case PF_NAT: + case PF_RDR: + case PF_BINAT: + print_addr(&pooladdr->addr, af, 0); + break; + case PF_PASS: + if (PF_AZERO(&pooladdr->addr.v.a.addr, af)) + printf("%s", pooladdr->ifname); + else { + printf("(%s ", pooladdr->ifname); + print_addr(&pooladdr->addr, af, 0); + printf(")"); + } + break; + default: + break; + } + if (TAILQ_NEXT(pooladdr, entries) != NULL) + printf(", "); + else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) + printf(" }"); + } + switch (id) { + case PF_NAT: + if ((p1 != PF_NAT_PROXY_PORT_LOW || + p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) { + if (p1 == p2) + printf(" port %u", p1); + else + printf(" port %u:%u", p1, p2); + } + break; + case PF_RDR: + if (p1) { + printf(" port %u", p1); + if (p2 && (p2 != p1)) + printf(":%u", p2); + } + break; + default: + break; + } + switch (pool->opts & PF_POOL_TYPEMASK) { + case PF_POOL_NONE: + break; + case PF_POOL_BITMASK: + printf(" bitmask"); + break; + case PF_POOL_RANDOM: + printf(" random"); + break; + case PF_POOL_SRCHASH: + printf(" source-hash 0x%08x%08x%08x%08x", + pool->key.key32[0], pool->key.key32[1], + pool->key.key32[2], pool->key.key32[3]); + break; + case PF_POOL_ROUNDROBIN: + printf(" round-robin"); + break; + } + if (pool->opts & PF_POOL_STICKYADDR) + printf(" sticky-address"); + if (id == PF_NAT && p1 == 0 && p2 == 0) + printf(" static-port"); +} + +const char * const pf_reasons[PFRES_MAX+1] = PFRES_NAMES; +const char * const pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; +const char * const pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; +const char * const pf_scounters[FCNT_MAX+1] = FCNT_NAMES; + +void +print_status(struct pf_status *s, int opts) +{ + char statline[80], *running; + time_t runtime; + int i; + char buf[PF_MD5_DIGEST_LENGTH * 2 + 1]; + static const char hex[] = "0123456789abcdef"; + + runtime = time(NULL) - s->since; + running = s->running ? "Enabled" : "Disabled"; + + if (s->since) { + unsigned int sec, min, hrs, day = runtime; + + sec = day % 60; + day /= 60; + min = day % 60; + day /= 60; + hrs = day % 24; + day /= 24; + snprintf(statline, sizeof(statline), + "Status: %s for %u days %.2u:%.2u:%.2u", + running, day, hrs, min, sec); + } else + snprintf(statline, sizeof(statline), "Status: %s", running); + printf("%-44s", statline); + switch (s->debug) { + case PF_DEBUG_NONE: + printf("%15s\n\n", "Debug: None"); + break; + case PF_DEBUG_URGENT: + printf("%15s\n\n", "Debug: Urgent"); + break; + case PF_DEBUG_MISC: + printf("%15s\n\n", "Debug: Misc"); + break; + case PF_DEBUG_NOISY: + printf("%15s\n\n", "Debug: Loud"); + break; + } + + if (opts & PF_OPT_VERBOSE) { + printf("Hostid: 0x%08x\n", ntohl(s->hostid)); + + for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) { + buf[i + i] = hex[s->pf_chksum[i] >> 4]; + buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f]; + } + buf[i + i] = '\0'; + printf("Checksum: 0x%s\n\n", buf); + } + + if (s->ifname[0] != 0) { + printf("Interface Stats for %-16s %5s %16s\n", + s->ifname, "IPv4", "IPv6"); + printf(" %-25s %14llu %16llu\n", "Bytes In", + (unsigned long long)s->bcounters[0][0], + (unsigned long long)s->bcounters[1][0]); + printf(" %-25s %14llu %16llu\n", "Bytes Out", + (unsigned long long)s->bcounters[0][1], + (unsigned long long)s->bcounters[1][1]); + printf(" Packets In\n"); + printf(" %-23s %14llu %16llu\n", "Passed", + (unsigned long long)s->pcounters[0][0][PF_PASS], + (unsigned long long)s->pcounters[1][0][PF_PASS]); + printf(" %-23s %14llu %16llu\n", "Blocked", + (unsigned long long)s->pcounters[0][0][PF_DROP], + (unsigned long long)s->pcounters[1][0][PF_DROP]); + printf(" Packets Out\n"); + printf(" %-23s %14llu %16llu\n", "Passed", + (unsigned long long)s->pcounters[0][1][PF_PASS], + (unsigned long long)s->pcounters[1][1][PF_PASS]); + printf(" %-23s %14llu %16llu\n\n", "Blocked", + (unsigned long long)s->pcounters[0][1][PF_DROP], + (unsigned long long)s->pcounters[1][1][PF_DROP]); + } + printf("%-27s %14s %16s\n", "State Table", "Total", "Rate"); + printf(" %-25s %14u %14s\n", "current entries", s->states, ""); + for (i = 0; i < FCNT_MAX; i++) { + printf(" %-25s %14llu ", pf_fcounters[i], + (unsigned long long)s->fcounters[i]); + if (runtime > 0) + printf("%14.1f/s\n", + (double)s->fcounters[i] / (double)runtime); + else + printf("%14s\n", ""); + } + if (opts & PF_OPT_VERBOSE) { + printf("Source Tracking Table\n"); + printf(" %-25s %14u %14s\n", "current entries", + s->src_nodes, ""); + for (i = 0; i < SCNT_MAX; i++) { + printf(" %-25s %14lld ", pf_scounters[i], +#ifdef __FreeBSD__ + (long long)s->scounters[i]); +#else + s->scounters[i]); +#endif + if (runtime > 0) + printf("%14.1f/s\n", + (double)s->scounters[i] / (double)runtime); + else + printf("%14s\n", ""); + } + } + printf("Counters\n"); + for (i = 0; i < PFRES_MAX; i++) { + printf(" %-25s %14llu ", pf_reasons[i], + (unsigned long long)s->counters[i]); + if (runtime > 0) + printf("%14.1f/s\n", + (double)s->counters[i] / (double)runtime); + else + printf("%14s\n", ""); + } + if (opts & PF_OPT_VERBOSE) { + printf("Limit Counters\n"); + for (i = 0; i < LCNT_MAX; i++) { + printf(" %-25s %14lld ", pf_lcounters[i], +#ifdef __FreeBSD__ + (unsigned long long)s->lcounters[i]); +#else + s->lcounters[i]); +#endif + if (runtime > 0) + printf("%14.1f/s\n", + (double)s->lcounters[i] / (double)runtime); + else + printf("%14s\n", ""); + } + } +} + +void +print_src_node(struct pf_src_node *sn, int opts) +{ + struct pf_addr_wrap aw; + int min, sec; + + memset(&aw, 0, sizeof(aw)); + if (sn->af == AF_INET) + aw.v.a.mask.addr32[0] = 0xffffffff; + else + memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); + + aw.v.a.addr = sn->addr; + print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); + printf(" -> "); + aw.v.a.addr = sn->raddr; + print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); + printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states, + sn->conn, sn->conn_rate.count / 1000, + (sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds); + if (opts & PF_OPT_VERBOSE) { + sec = sn->creation % 60; + sn->creation /= 60; + min = sn->creation % 60; + sn->creation /= 60; + printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec); + if (sn->states == 0) { + sec = sn->expire % 60; + sn->expire /= 60; + min = sn->expire % 60; + sn->expire /= 60; + printf(", expires in %.2u:%.2u:%.2u", + sn->expire, min, sec); + } + printf(", %llu pkts, %llu bytes", +#ifdef __FreeBSD__ + (unsigned long long)(sn->packets[0] + sn->packets[1]), + (unsigned long long)(sn->bytes[0] + sn->bytes[1])); +#else + sn->packets[0] + sn->packets[1], + sn->bytes[0] + sn->bytes[1]); +#endif + switch (sn->ruletype) { + case PF_NAT: + if (sn->rule.nr != -1) + printf(", nat rule %u", sn->rule.nr); + break; + case PF_RDR: + if (sn->rule.nr != -1) + printf(", rdr rule %u", sn->rule.nr); + break; + case PF_PASS: + if (sn->rule.nr != -1) + printf(", filter rule %u", sn->rule.nr); + break; + } + printf("\n"); + } +} + +void +print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) +{ + static const char *actiontypes[] = { "pass", "block", "scrub", + "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr" }; + static const char *anchortypes[] = { "anchor", "anchor", "anchor", + "anchor", "nat-anchor", "nat-anchor", "binat-anchor", + "binat-anchor", "rdr-anchor", "rdr-anchor" }; + int i, opts; + + if (verbose) + printf("@%d ", r->nr); + if (r->action > PF_NORDR) + printf("action(%d)", r->action); + else if (anchor_call[0]) { + if (anchor_call[0] == '_') { + printf("%s", anchortypes[r->action]); + } else + printf("%s \"%s\"", anchortypes[r->action], + anchor_call); + } else { + printf("%s", actiontypes[r->action]); + if (r->natpass) + printf(" pass"); + } + if (r->action == PF_DROP) { + if (r->rule_flag & PFRULE_RETURN) + printf(" return"); + else if (r->rule_flag & PFRULE_RETURNRST) { + if (!r->return_ttl) + printf(" return-rst"); + else + printf(" return-rst(ttl %d)", r->return_ttl); + } else if (r->rule_flag & PFRULE_RETURNICMP) { + const struct icmpcodeent *ic, *ic6; + + ic = geticmpcodebynumber(r->return_icmp >> 8, + r->return_icmp & 255, AF_INET); + ic6 = geticmpcodebynumber(r->return_icmp6 >> 8, + r->return_icmp6 & 255, AF_INET6); + + switch (r->af) { + case AF_INET: + printf(" return-icmp"); + if (ic == NULL) + printf("(%u)", r->return_icmp & 255); + else + printf("(%s)", ic->name); + break; + case AF_INET6: + printf(" return-icmp6"); + if (ic6 == NULL) + printf("(%u)", r->return_icmp6 & 255); + else + printf("(%s)", ic6->name); + break; + default: + printf(" return-icmp"); + if (ic == NULL) + printf("(%u, ", r->return_icmp & 255); + else + printf("(%s, ", ic->name); + if (ic6 == NULL) + printf("%u)", r->return_icmp6 & 255); + else + printf("%s)", ic6->name); + break; + } + } else + printf(" drop"); + } + if (r->direction == PF_IN) + printf(" in"); + else if (r->direction == PF_OUT) + printf(" out"); + if (r->log) { + printf(" log"); + if (r->log & ~PF_LOG || r->logif) { + int count = 0; + + printf(" ("); + if (r->log & PF_LOG_ALL) + printf("%sall", count++ ? ", " : ""); + if (r->log & PF_LOG_SOCKET_LOOKUP) + printf("%suser", count++ ? ", " : ""); + if (r->logif) + printf("%sto pflog%u", count++ ? ", " : "", + r->logif); + printf(")"); + } + } + if (r->quick) + printf(" quick"); + if (r->ifname[0]) { + if (r->ifnot) + printf(" on ! %s", r->ifname); + else + printf(" on %s", r->ifname); + } + if (r->rt) { + if (r->rt == PF_ROUTETO) + printf(" route-to"); + else if (r->rt == PF_REPLYTO) + printf(" reply-to"); + else if (r->rt == PF_DUPTO) + printf(" dup-to"); + else if (r->rt == PF_FASTROUTE) + printf(" fastroute"); + if (r->rt != PF_FASTROUTE) { + printf(" "); + print_pool(&r->rpool, 0, 0, r->af, PF_PASS); + } + } + if (r->af) { + if (r->af == AF_INET) + printf(" inet"); + else + printf(" inet6"); + } + if (r->proto) { + struct protoent *p; + + if ((p = getprotobynumber(r->proto)) != NULL) + printf(" proto %s", p->p_name); + else + printf(" proto %u", r->proto); + } + print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto, + verbose, numeric); + if (r->uid.op) + print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user", + UID_MAX); + if (r->gid.op) + print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group", + GID_MAX); + if (r->flags || r->flagset) { + printf(" flags "); + print_flags(r->flags); + printf("/"); + print_flags(r->flagset); + } else if (r->action == PF_PASS && + (!r->proto || r->proto == IPPROTO_TCP) && + !(r->rule_flag & PFRULE_FRAGMENT) && + !anchor_call[0] && r->keep_state) + printf(" flags any"); + if (r->type) { + const struct icmptypeent *it; + + it = geticmptypebynumber(r->type-1, r->af); + if (r->af != AF_INET6) + printf(" icmp-type"); + else + printf(" icmp6-type"); + if (it != NULL) + printf(" %s", it->name); + else + printf(" %u", r->type-1); + if (r->code) { + const struct icmpcodeent *ic; + + ic = geticmpcodebynumber(r->type-1, r->code-1, r->af); + if (ic != NULL) + printf(" code %s", ic->name); + else + printf(" code %u", r->code-1); + } + } + if (r->tos) + printf(" tos 0x%2.2x", r->tos); + if (r->prio) + printf(" prio %u", r->prio == PF_PRIO_ZERO ? 0 : r->prio); + if (r->scrub_flags & PFSTATE_SETMASK) { + char *comma = ""; + printf(" set ("); + if (r->scrub_flags & PFSTATE_SETPRIO) { + if (r->set_prio[0] == r->set_prio[1]) + printf("%s prio %u", comma, r->set_prio[0]); + else + printf("%s prio(%u, %u)", comma, r->set_prio[0], + r->set_prio[1]); + comma = ","; + } + printf(" )"); + } + if (!r->keep_state && r->action == PF_PASS && !anchor_call[0]) + printf(" no state"); + else if (r->keep_state == PF_STATE_NORMAL) + printf(" keep state"); + else if (r->keep_state == PF_STATE_MODULATE) + printf(" modulate state"); + else if (r->keep_state == PF_STATE_SYNPROXY) + printf(" synproxy state"); + if (r->prob) { + char buf[20]; + + snprintf(buf, sizeof(buf), "%f", r->prob*100.0/(UINT_MAX+1.0)); + for (i = strlen(buf)-1; i > 0; i--) { + if (buf[i] == '0') + buf[i] = '\0'; + else { + if (buf[i] == '.') + buf[i] = '\0'; + break; + } + } + printf(" probability %s%%", buf); + } + opts = 0; + if (r->max_states || r->max_src_nodes || r->max_src_states) + opts = 1; + if (r->rule_flag & PFRULE_NOSYNC) + opts = 1; + if (r->rule_flag & PFRULE_SRCTRACK) + opts = 1; + if (r->rule_flag & PFRULE_IFBOUND) + opts = 1; + if (r->rule_flag & PFRULE_STATESLOPPY) + opts = 1; + for (i = 0; !opts && i < PFTM_MAX; ++i) + if (r->timeout[i]) + opts = 1; + if (opts) { + printf(" ("); + if (r->max_states) { + printf("max %u", r->max_states); + opts = 0; + } + if (r->rule_flag & PFRULE_NOSYNC) { + if (!opts) + printf(", "); + printf("no-sync"); + opts = 0; + } + if (r->rule_flag & PFRULE_SRCTRACK) { + if (!opts) + printf(", "); + printf("source-track"); + if (r->rule_flag & PFRULE_RULESRCTRACK) + printf(" rule"); + else + printf(" global"); + opts = 0; + } + if (r->max_src_states) { + if (!opts) + printf(", "); + printf("max-src-states %u", r->max_src_states); + opts = 0; + } + if (r->max_src_conn) { + if (!opts) + printf(", "); + printf("max-src-conn %u", r->max_src_conn); + opts = 0; + } + if (r->max_src_conn_rate.limit) { + if (!opts) + printf(", "); + printf("max-src-conn-rate %u/%u", + r->max_src_conn_rate.limit, + r->max_src_conn_rate.seconds); + opts = 0; + } + if (r->max_src_nodes) { + if (!opts) + printf(", "); + printf("max-src-nodes %u", r->max_src_nodes); + opts = 0; + } + if (r->overload_tblname[0]) { + if (!opts) + printf(", "); + printf("overload <%s>", r->overload_tblname); + if (r->flush) + printf(" flush"); + if (r->flush & PF_FLUSH_GLOBAL) + printf(" global"); + } + if (r->rule_flag & PFRULE_IFBOUND) { + if (!opts) + printf(", "); + printf("if-bound"); + opts = 0; + } + if (r->rule_flag & PFRULE_STATESLOPPY) { + if (!opts) + printf(", "); + printf("sloppy"); + opts = 0; + } + for (i = 0; i < PFTM_MAX; ++i) + if (r->timeout[i]) { + int j; + + if (!opts) + printf(", "); + opts = 0; + for (j = 0; pf_timeouts[j].name != NULL; + ++j) + if (pf_timeouts[j].timeout == i) + break; + printf("%s %u", pf_timeouts[j].name == NULL ? + "inv.timeout" : pf_timeouts[j].name, + r->timeout[i]); + } + printf(")"); + } + if (r->rule_flag & PFRULE_FRAGMENT) + printf(" fragment"); + if (r->rule_flag & PFRULE_NODF) + printf(" no-df"); + if (r->rule_flag & PFRULE_RANDOMID) + printf(" random-id"); + if (r->min_ttl) + printf(" min-ttl %d", r->min_ttl); + if (r->max_mss) + printf(" max-mss %d", r->max_mss); + if (r->rule_flag & PFRULE_SET_TOS) + printf(" set-tos 0x%2.2x", r->set_tos); + if (r->allow_opts) + printf(" allow-opts"); + if (r->action == PF_SCRUB) { + if (r->rule_flag & PFRULE_REASSEMBLE_TCP) + printf(" reassemble tcp"); + + printf(" fragment reassemble"); + } + if (r->label[0]) + printf(" label \"%s\"", r->label); + if (r->qname[0] && r->pqname[0]) + printf(" queue(%s, %s)", r->qname, r->pqname); + else if (r->qname[0]) + printf(" queue %s", r->qname); + if (r->tagname[0]) + printf(" tag %s", r->tagname); + if (r->match_tagname[0]) { + if (r->match_tag_not) + printf(" !"); + printf(" tagged %s", r->match_tagname); + } + if (r->rtableid != -1) + printf(" rtable %u", r->rtableid); + if (r->divert.port) { +#ifdef __FreeBSD__ + printf(" divert-to %u", ntohs(r->divert.port)); +#else + if (PF_AZERO(&r->divert.addr, r->af)) { + printf(" divert-reply"); + } else { + /* XXX cut&paste from print_addr */ + char buf[48]; + + printf(" divert-to "); + if (inet_ntop(r->af, &r->divert.addr, buf, + sizeof(buf)) == NULL) + printf("?"); + else + printf("%s", buf); + printf(" port %u", ntohs(r->divert.port)); + } +#endif + } + if (!anchor_call[0] && (r->action == PF_NAT || + r->action == PF_BINAT || r->action == PF_RDR)) { + printf(" -> "); + print_pool(&r->rpool, r->rpool.proxy_port[0], + r->rpool.proxy_port[1], r->af, r->action); + } +} + +void +print_tabledef(const char *name, int flags, int addrs, + struct node_tinithead *nodes) +{ + struct node_tinit *ti, *nti; + struct node_host *h; + + printf("table <%s>", name); + if (flags & PFR_TFLAG_CONST) + printf(" const"); + if (flags & PFR_TFLAG_PERSIST) + printf(" persist"); + if (flags & PFR_TFLAG_COUNTERS) + printf(" counters"); + SIMPLEQ_FOREACH(ti, nodes, entries) { + if (ti->file) { + printf(" file \"%s\"", ti->file); + continue; + } + printf(" {"); + for (;;) { + for (h = ti->host; h != NULL; h = h->next) { + printf(h->not ? " !" : " "); + print_addr(&h->addr, h->af, 0); + } + nti = SIMPLEQ_NEXT(ti, entries); + if (nti != NULL && nti->file == NULL) + ti = nti; /* merge lists */ + else + break; + } + printf(" }"); + } + if (addrs && SIMPLEQ_EMPTY(nodes)) + printf(" { }"); + printf("\n"); +} + +int +parse_flags(char *s) +{ + char *p, *q; + u_int8_t f = 0; + + for (p = s; *p; p++) { + if ((q = strchr(tcpflags, *p)) == NULL) + return -1; + else + f |= 1 << (q - tcpflags); + } + return (f ? f : PF_TH_ALL); +} + +void +set_ipmask(struct node_host *h, u_int8_t b) +{ + struct pf_addr *m, *n; + int i, j = 0; + + m = &h->addr.v.a.mask; + memset(m, 0, sizeof(*m)); + + while (b >= 32) { + m->addr32[j++] = 0xffffffff; + b -= 32; + } + for (i = 31; i > 31-b; --i) + m->addr32[j] |= (1 << i); + if (b) + m->addr32[j] = htonl(m->addr32[j]); + + /* Mask off bits of the address that will never be used. */ + n = &h->addr.v.a.addr; + if (h->addr.type == PF_ADDR_ADDRMASK) + for (i = 0; i < 4; i++) + n->addr32[i] = n->addr32[i] & m->addr32[i]; +} + +int +check_netmask(struct node_host *h, sa_family_t af) +{ + struct node_host *n = NULL; + struct pf_addr *m; + + for (n = h; n != NULL; n = n->next) { + if (h->addr.type == PF_ADDR_TABLE) + continue; + m = &h->addr.v.a.mask; + /* fix up netmask for dynaddr */ + if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL && + unmask(m, AF_INET6) > 32) + set_ipmask(n, 32); + /* netmasks > 32 bit are invalid on v4 */ + if (af == AF_INET && + (m->addr32[1] || m->addr32[2] || m->addr32[3])) { + fprintf(stderr, "netmask %u invalid for IPv4 address\n", + unmask(m, AF_INET6)); + return (1); + } + } + return (0); +} + +/* interface lookup routines */ + +static struct node_host *iftab; + +void +ifa_load(void) +{ + struct ifaddrs *ifap, *ifa; + struct node_host *n = NULL, *h = NULL; + + if (getifaddrs(&ifap) < 0) + err(1, "getifaddrs"); + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (!(ifa->ifa_addr->sa_family == AF_INET || + ifa->ifa_addr->sa_family == AF_INET6 || + ifa->ifa_addr->sa_family == AF_LINK)) + continue; + n = calloc(1, sizeof(struct node_host)); + if (n == NULL) + err(1, "address: calloc"); + n->af = ifa->ifa_addr->sa_family; + n->ifa_flags = ifa->ifa_flags; +#ifdef __KAME__ + if (n->af == AF_INET6 && + IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) + ifa->ifa_addr)->sin6_addr) && + ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == + 0) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | + sin6->sin6_addr.s6_addr[3]; + sin6->sin6_addr.s6_addr[2] = 0; + sin6->sin6_addr.s6_addr[3] = 0; + } +#endif + n->ifindex = 0; + if (n->af == AF_INET) { + memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *) + ifa->ifa_addr)->sin_addr.s_addr, + sizeof(struct in_addr)); + memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *) + ifa->ifa_netmask)->sin_addr.s_addr, + sizeof(struct in_addr)); + if (ifa->ifa_broadaddr != NULL) + memcpy(&n->bcast, &((struct sockaddr_in *) + ifa->ifa_broadaddr)->sin_addr.s_addr, + sizeof(struct in_addr)); + if (ifa->ifa_dstaddr != NULL) + memcpy(&n->peer, &((struct sockaddr_in *) + ifa->ifa_dstaddr)->sin_addr.s_addr, + sizeof(struct in_addr)); + } else if (n->af == AF_INET6) { + memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *) + ifa->ifa_addr)->sin6_addr.s6_addr, + sizeof(struct in6_addr)); + memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *) + ifa->ifa_netmask)->sin6_addr.s6_addr, + sizeof(struct in6_addr)); + if (ifa->ifa_broadaddr != NULL) + memcpy(&n->bcast, &((struct sockaddr_in6 *) + ifa->ifa_broadaddr)->sin6_addr.s6_addr, + sizeof(struct in6_addr)); + if (ifa->ifa_dstaddr != NULL) + memcpy(&n->peer, &((struct sockaddr_in6 *) + ifa->ifa_dstaddr)->sin6_addr.s6_addr, + sizeof(struct in6_addr)); + n->ifindex = ((struct sockaddr_in6 *) + ifa->ifa_addr)->sin6_scope_id; + } + if ((n->ifname = strdup(ifa->ifa_name)) == NULL) + err(1, "ifa_load: strdup"); + n->next = NULL; + n->tail = n; + if (h == NULL) + h = n; + else { + h->tail->next = n; + h->tail = n; + } + } + + iftab = h; + freeifaddrs(ifap); +} + +int +get_socket_domain(void) +{ + int sdom; + + sdom = AF_UNSPEC; +#ifdef WITH_INET6 + if (sdom == AF_UNSPEC && feature_present("inet6")) + sdom = AF_INET6; +#endif +#ifdef WITH_INET + if (sdom == AF_UNSPEC && feature_present("inet")) + sdom = AF_INET; +#endif + if (sdom == AF_UNSPEC) + sdom = AF_LINK; + + return (sdom); +} + +struct node_host * +ifa_exists(const char *ifa_name) +{ + struct node_host *n; + struct ifgroupreq ifgr; + int s; + + if (iftab == NULL) + ifa_load(); + + /* check wether this is a group */ + if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1) + err(1, "socket"); + 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 */ + if ((n = calloc(1, sizeof(*n))) == NULL) + err(1, "calloc"); + if ((n->ifname = strdup(ifa_name)) == NULL) + err(1, "strdup"); + close(s); + return (n); + } + close(s); + + for (n = iftab; n; n = n->next) { + if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) + return (n); + } + + return (NULL); +} + +struct node_host * +ifa_grouplookup(const char *ifa_name, int flags) +{ + struct ifg_req *ifg; + struct ifgroupreq ifgr; + int s, len; + struct node_host *n, *h = NULL; + + if ((s = socket(get_socket_domain(), SOCK_DGRAM, 0)) == -1) + err(1, "socket"); + bzero(&ifgr, sizeof(ifgr)); + 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) + err(1, "calloc"); + if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) + err(1, "SIOCGIFGMEMB"); + + for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); + ifg++) { + len -= sizeof(struct ifg_req); + if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL) + continue; + if (h == NULL) + h = n; + else { + h->tail->next = n; + h->tail = n->tail; + } + } + free(ifgr.ifgr_groups); + close(s); + + return (h); +} + +struct node_host * +ifa_lookup(const char *ifa_name, int flags) +{ + struct node_host *p = NULL, *h = NULL, *n = NULL; + int got4 = 0, got6 = 0; + const char *last_if = NULL; + + if ((h = ifa_grouplookup(ifa_name, flags)) != NULL) + return (h); + + if (!strncmp(ifa_name, "self", IFNAMSIZ)) + ifa_name = NULL; + + if (iftab == NULL) + ifa_load(); + + for (p = iftab; p; p = p->next) { + if (ifa_skip_if(ifa_name, p)) + continue; + if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET) + continue; + if ((flags & PFI_AFLAG_BROADCAST) && + !(p->ifa_flags & IFF_BROADCAST)) + continue; + if ((flags & PFI_AFLAG_PEER) && + !(p->ifa_flags & IFF_POINTOPOINT)) + continue; + if ((flags & PFI_AFLAG_NETWORK) && p->ifindex > 0) + continue; + if (last_if == NULL || strcmp(last_if, p->ifname)) + got4 = got6 = 0; + last_if = p->ifname; + if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET && got4) + continue; + if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET6 && got6) + continue; + if (p->af == AF_INET) + got4 = 1; + else + got6 = 1; + n = calloc(1, sizeof(struct node_host)); + if (n == NULL) + err(1, "address: calloc"); + n->af = p->af; + if (flags & PFI_AFLAG_BROADCAST) + memcpy(&n->addr.v.a.addr, &p->bcast, + sizeof(struct pf_addr)); + else if (flags & PFI_AFLAG_PEER) + memcpy(&n->addr.v.a.addr, &p->peer, + sizeof(struct pf_addr)); + else + memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr, + sizeof(struct pf_addr)); + if (flags & PFI_AFLAG_NETWORK) + set_ipmask(n, unmask(&p->addr.v.a.mask, n->af)); + else { + if (n->af == AF_INET) { + if (p->ifa_flags & IFF_LOOPBACK && + p->ifa_flags & IFF_LINK1) + memcpy(&n->addr.v.a.mask, + &p->addr.v.a.mask, + sizeof(struct pf_addr)); + else + set_ipmask(n, 32); + } else + set_ipmask(n, 128); + } + n->ifindex = p->ifindex; + + n->next = NULL; + n->tail = n; + if (h == NULL) + h = n; + else { + h->tail->next = n; + h->tail = n; + } + } + return (h); +} + +int +ifa_skip_if(const char *filter, struct node_host *p) +{ + int n; + + if (p->af != AF_INET && p->af != AF_INET6) + return (1); + if (filter == NULL || !*filter) + return (0); + if (!strcmp(p->ifname, filter)) + return (0); /* exact match */ + n = strlen(filter); + if (n < 1 || n >= IFNAMSIZ) + return (1); /* sanity check */ + if (filter[n-1] >= '0' && filter[n-1] <= '9') + return (1); /* only do exact match in that case */ + if (strncmp(p->ifname, filter, n)) + return (1); /* prefix doesn't match */ + return (p->ifname[n] < '0' || p->ifname[n] > '9'); +} + + +struct node_host * +host(const char *s) +{ + struct node_host *h = NULL; + int mask, v4mask, v6mask, cont = 1; + char *p, *q, *ps; + + if ((p = strrchr(s, '/')) != NULL) { + mask = strtol(p+1, &q, 0); + if (!q || *q || mask > 128 || q == (p+1)) { + fprintf(stderr, "invalid netmask '%s'\n", p); + return (NULL); + } + if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) + err(1, "host: malloc"); + strlcpy(ps, s, strlen(s) - strlen(p) + 1); + v4mask = v6mask = mask; + } else { + if ((ps = strdup(s)) == NULL) + err(1, "host: strdup"); + v4mask = 32; + v6mask = 128; + mask = -1; + } + + /* interface with this name exists? */ + if (cont && (h = host_if(ps, mask)) != NULL) + cont = 0; + + /* IPv4 address? */ + if (cont && (h = host_v4(s, mask)) != NULL) + cont = 0; + + /* IPv6 address? */ + if (cont && (h = host_v6(ps, v6mask)) != NULL) + cont = 0; + + /* dns lookup */ + if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL) + cont = 0; + free(ps); + + if (h == NULL || cont == 1) { + fprintf(stderr, "no IP address found for %s\n", s); + return (NULL); + } + return (h); +} + +struct node_host * +host_if(const char *s, int mask) +{ + struct node_host *n, *h = NULL; + char *p, *ps; + int flags = 0; + + if ((ps = strdup(s)) == NULL) + err(1, "host_if: strdup"); + while ((p = strrchr(ps, ':')) != NULL) { + if (!strcmp(p+1, "network")) + flags |= PFI_AFLAG_NETWORK; + else if (!strcmp(p+1, "broadcast")) + flags |= PFI_AFLAG_BROADCAST; + else if (!strcmp(p+1, "peer")) + flags |= PFI_AFLAG_PEER; + else if (!strcmp(p+1, "0")) + flags |= PFI_AFLAG_NOALIAS; + else { + free(ps); + return (NULL); + } + *p = '\0'; + } + if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */ + fprintf(stderr, "illegal combination of interface modifiers\n"); + free(ps); + return (NULL); + } + if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) { + fprintf(stderr, "network or broadcast lookup, but " + "extra netmask given\n"); + free(ps); + return (NULL); + } + if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { + /* interface with this name exists */ + h = ifa_lookup(ps, flags); + for (n = h; n != NULL && mask > -1; n = n->next) + set_ipmask(n, mask); + } + + free(ps); + return (h); +} + +struct node_host * +host_v4(const char *s, int mask) +{ + struct node_host *h = NULL; + struct in_addr ina; + int bits = 32; + + memset(&ina, 0, sizeof(struct in_addr)); + if (strrchr(s, '/') != NULL) { + if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) + return (NULL); + } else { + if (inet_pton(AF_INET, s, &ina) != 1) + return (NULL); + } + + h = calloc(1, sizeof(struct node_host)); + if (h == NULL) + err(1, "address: calloc"); + h->ifname = NULL; + h->af = AF_INET; + h->addr.v.a.addr.addr32[0] = ina.s_addr; + set_ipmask(h, bits); + h->next = NULL; + h->tail = h; + + return (h); +} + +struct node_host * +host_v6(const char *s, int mask) +{ + struct addrinfo hints, *res; + struct node_host *h = NULL; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(s, "0", &hints, &res) == 0) { + h = calloc(1, sizeof(struct node_host)); + if (h == NULL) + err(1, "address: calloc"); + h->ifname = NULL; + h->af = AF_INET6; + memcpy(&h->addr.v.a.addr, + &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, + sizeof(h->addr.v.a.addr)); + h->ifindex = + ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; + set_ipmask(h, mask); + freeaddrinfo(res); + h->next = NULL; + h->tail = h; + } + + return (h); +} + +struct node_host * +host_dns(const char *s, int v4mask, int v6mask) +{ + struct addrinfo hints, *res0, *res; + struct node_host *n, *h = NULL; + int error, noalias = 0; + int got4 = 0, got6 = 0; + char *p, *ps; + + if ((ps = strdup(s)) == NULL) + err(1, "host_dns: strdup"); + if ((p = strrchr(ps, ':')) != NULL && !strcmp(p, ":0")) { + noalias = 1; + *p = '\0'; + } + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; /* DUMMY */ + error = getaddrinfo(ps, NULL, &hints, &res0); + if (error) { + free(ps); + return (h); + } + + for (res = res0; res; res = res->ai_next) { + if (res->ai_family != AF_INET && + res->ai_family != AF_INET6) + continue; + if (noalias) { + if (res->ai_family == AF_INET) { + if (got4) + continue; + got4 = 1; + } else { + if (got6) + continue; + got6 = 1; + } + } + n = calloc(1, sizeof(struct node_host)); + if (n == NULL) + err(1, "host_dns: calloc"); + n->ifname = NULL; + n->af = res->ai_family; + if (res->ai_family == AF_INET) { + memcpy(&n->addr.v.a.addr, + &((struct sockaddr_in *) + res->ai_addr)->sin_addr.s_addr, + sizeof(struct in_addr)); + set_ipmask(n, v4mask); + } else { + memcpy(&n->addr.v.a.addr, + &((struct sockaddr_in6 *) + res->ai_addr)->sin6_addr.s6_addr, + sizeof(struct in6_addr)); + n->ifindex = + ((struct sockaddr_in6 *) + res->ai_addr)->sin6_scope_id; + set_ipmask(n, v6mask); + } + n->next = NULL; + n->tail = n; + if (h == NULL) + h = n; + else { + h->tail->next = n; + h->tail = n; + } + } + freeaddrinfo(res0); + free(ps); + + return (h); +} + +/* + * convert a hostname to a list of addresses and put them in the given buffer. + * test: + * if set to 1, only simple addresses are accepted (no netblock, no "!"). + */ +int +append_addr(struct pfr_buffer *b, char *s, int test) +{ + char *r; + struct node_host *h, *n; + int rv, not = 0; + + for (r = s; *r == '!'; r++) + not = !not; + if ((n = host(r)) == NULL) { + errno = 0; + return (-1); + } + rv = append_addr_host(b, n, test, not); + do { + h = n; + n = n->next; + free(h); + } while (n != NULL); + return (rv); +} + +/* + * same as previous function, but with a pre-parsed input and the ability + * to "negate" the result. Does not free the node_host list. + * not: + * setting it to 1 is equivalent to adding "!" in front of parameter s. + */ +int +append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not) +{ + int bits; + struct pfr_addr addr; + + do { + bzero(&addr, sizeof(addr)); + addr.pfra_not = n->not ^ not; + addr.pfra_af = n->af; + addr.pfra_net = unmask(&n->addr.v.a.mask, n->af); + switch (n->af) { + case AF_INET: + addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0]; + bits = 32; + break; + case AF_INET6: + memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6, + sizeof(struct in6_addr)); + bits = 128; + break; + default: + errno = EINVAL; + return (-1); + } + if ((test && (not || addr.pfra_net != bits)) || + addr.pfra_net > bits) { + errno = EINVAL; + return (-1); + } + if (pfr_buf_add(b, &addr)) + return (-1); + } while ((n = n->next) != NULL); + + return (0); +} + +int +pfctl_add_trans(struct pfr_buffer *buf, int rs_num, const char *anchor) +{ + struct pfioc_trans_e trans; + + bzero(&trans, sizeof(trans)); + trans.rs_num = rs_num; + if (strlcpy(trans.anchor, anchor, + sizeof(trans.anchor)) >= sizeof(trans.anchor)) + errx(1, "pfctl_add_trans: strlcpy"); + + return pfr_buf_add(buf, &trans); +} + +u_int32_t +pfctl_get_ticket(struct pfr_buffer *buf, int rs_num, const char *anchor) +{ + struct pfioc_trans_e *p; + + PFRB_FOREACH(p, buf) + if (rs_num == p->rs_num && !strcmp(anchor, p->anchor)) + return (p->ticket); + errx(1, "pfctl_get_ticket: assertion failed"); +} + +int +pfctl_trans(int dev, struct pfr_buffer *buf, u_long cmd, int from) +{ + struct pfioc_trans trans; + + bzero(&trans, sizeof(trans)); + trans.size = buf->pfrb_size - from; + trans.esize = sizeof(struct pfioc_trans_e); + trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from; + return ioctl(dev, cmd, &trans); +} diff --git a/freebsd/sbin/pfctl/pfctl_parser.h b/freebsd/sbin/pfctl/pfctl_parser.h new file mode 100644 index 00000000..2b7fea7b --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl_parser.h @@ -0,0 +1,322 @@ +/* $OpenBSD: pfctl_parser.h,v 1.86 2006/10/31 23:46:25 mcbride Exp $ */ + +/* + * Copyright (c) 2001 Daniel Hartmeier + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _PFCTL_PARSER_H_ +#define _PFCTL_PARSER_H_ + +#define PF_OSFP_FILE "/etc/pf.os" + +#define PF_OPT_DISABLE 0x0001 +#define PF_OPT_ENABLE 0x0002 +#define PF_OPT_VERBOSE 0x0004 +#define PF_OPT_NOACTION 0x0008 +#define PF_OPT_QUIET 0x0010 +#define PF_OPT_CLRRULECTRS 0x0020 +#define PF_OPT_USEDNS 0x0040 +#define PF_OPT_VERBOSE2 0x0080 +#define PF_OPT_DUMMYACTION 0x0100 +#define PF_OPT_DEBUG 0x0200 +#define PF_OPT_SHOWALL 0x0400 +#define PF_OPT_OPTIMIZE 0x0800 +#define PF_OPT_NUMERIC 0x1000 +#define PF_OPT_MERGE 0x2000 +#define PF_OPT_RECURSE 0x4000 + +#define PF_TH_ALL 0xFF + +#define PF_NAT_PROXY_PORT_LOW 50001 +#define PF_NAT_PROXY_PORT_HIGH 65535 + +#define PF_OPTIMIZE_BASIC 0x0001 +#define PF_OPTIMIZE_PROFILE 0x0002 + +#define FCNT_NAMES { \ + "searches", \ + "inserts", \ + "removals", \ + NULL \ +} + +struct pfr_buffer; /* forward definition */ + + +struct pfctl { + int dev; + int opts; + int optimize; + int loadopt; + int asd; /* anchor stack depth */ + int bn; /* brace number */ + int brace; + int tdirty; /* kernel dirty */ +#define PFCTL_ANCHOR_STACK_DEPTH 64 + struct pf_anchor *astack[PFCTL_ANCHOR_STACK_DEPTH]; + struct pfioc_pooladdr paddr; + struct pfioc_altq *paltq; + struct pfioc_queue *pqueue; + struct pfr_buffer *trans; + struct pf_anchor *anchor, *alast; + const char *ruleset; + + /* 'set foo' options */ + u_int32_t timeout[PFTM_MAX]; + u_int32_t limit[PF_LIMIT_MAX]; + u_int32_t debug; + u_int32_t hostid; + char *ifname; + + u_int8_t timeout_set[PFTM_MAX]; + u_int8_t limit_set[PF_LIMIT_MAX]; + u_int8_t debug_set; + u_int8_t hostid_set; + u_int8_t ifname_set; +}; + +struct node_if { + char ifname[IFNAMSIZ]; + u_int8_t not; + u_int8_t dynamic; /* antispoof */ + u_int ifa_flags; + struct node_if *next; + struct node_if *tail; +}; + +struct node_host { + struct pf_addr_wrap addr; + struct pf_addr bcast; + struct pf_addr peer; + sa_family_t af; + u_int8_t not; + u_int32_t ifindex; /* link-local IPv6 addrs */ + char *ifname; + u_int ifa_flags; + struct node_host *next; + struct node_host *tail; +}; + +struct node_os { + char *os; + pf_osfp_t fingerprint; + struct node_os *next; + struct node_os *tail; +}; + +struct node_queue_bw { + u_int32_t bw_absolute; + u_int16_t bw_percent; +}; + +struct node_hfsc_sc { + struct node_queue_bw m1; /* slope of 1st segment; bps */ + u_int d; /* x-projection of m1; msec */ + struct node_queue_bw m2; /* slope of 2nd segment; bps */ + u_int8_t used; +}; + +struct node_hfsc_opts { + struct node_hfsc_sc realtime; + struct node_hfsc_sc linkshare; + struct node_hfsc_sc upperlimit; + int flags; +}; + +struct node_fairq_sc { + struct node_queue_bw m1; /* slope of 1st segment; bps */ + u_int d; /* x-projection of m1; msec */ + struct node_queue_bw m2; /* slope of 2nd segment; bps */ + u_int8_t used; +}; + +struct node_fairq_opts { + struct node_fairq_sc linkshare; + struct node_queue_bw hogs_bw; + u_int nbuckets; + int flags; +}; + +struct node_queue_opt { + int qtype; + union { + struct cbq_opts cbq_opts; + struct codel_opts codel_opts; + struct priq_opts priq_opts; + struct node_hfsc_opts hfsc_opts; + struct node_fairq_opts fairq_opts; + } data; +}; + +#ifdef __FreeBSD__ +/* + * XXX + * Absolutely this is not correct location to define this. + * Should we use an another sperate header file? + */ +#define SIMPLEQ_HEAD STAILQ_HEAD +#define SIMPLEQ_HEAD_INITIALIZER STAILQ_HEAD_INITIALIZER +#define SIMPLEQ_ENTRY STAILQ_ENTRY +#define SIMPLEQ_FIRST STAILQ_FIRST +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY STAILQ_EMPTY +#define SIMPLEQ_NEXT STAILQ_NEXT +/*#define SIMPLEQ_FOREACH STAILQ_FOREACH*/ +#define SIMPLEQ_FOREACH(var, head, field) \ + for((var) = SIMPLEQ_FIRST(head); \ + (var) != SIMPLEQ_END(head); \ + (var) = SIMPLEQ_NEXT(var, field)) +#define SIMPLEQ_INIT STAILQ_INIT +#define SIMPLEQ_INSERT_HEAD STAILQ_INSERT_HEAD +#define SIMPLEQ_INSERT_TAIL STAILQ_INSERT_TAIL +#define SIMPLEQ_INSERT_AFTER STAILQ_INSERT_AFTER +#define SIMPLEQ_REMOVE_HEAD STAILQ_REMOVE_HEAD +#endif +SIMPLEQ_HEAD(node_tinithead, node_tinit); +struct node_tinit { /* table initializer */ + SIMPLEQ_ENTRY(node_tinit) entries; + struct node_host *host; + char *file; +}; + + +/* optimizer created tables */ +struct pf_opt_tbl { + char pt_name[PF_TABLE_NAME_SIZE]; + int pt_rulecount; + int pt_generated; + struct node_tinithead pt_nodes; + struct pfr_buffer *pt_buf; +}; +#define PF_OPT_TABLE_PREFIX "__automatic_" + +/* optimizer pf_rule container */ +struct pf_opt_rule { + struct pf_rule por_rule; + struct pf_opt_tbl *por_src_tbl; + struct pf_opt_tbl *por_dst_tbl; + u_int64_t por_profile_count; + TAILQ_ENTRY(pf_opt_rule) por_entry; + TAILQ_ENTRY(pf_opt_rule) por_skip_entry[PF_SKIP_COUNT]; +}; + +TAILQ_HEAD(pf_opt_queue, pf_opt_rule); + +int pfctl_rules(int, char *, int, int, char *, struct pfr_buffer *); +int pfctl_optimize_ruleset(struct pfctl *, struct pf_ruleset *); + +int pfctl_add_rule(struct pfctl *, struct pf_rule *, const char *); +int pfctl_add_altq(struct pfctl *, struct pf_altq *); +int pfctl_add_pool(struct pfctl *, struct pf_pool *, sa_family_t); +void pfctl_move_pool(struct pf_pool *, struct pf_pool *); +void pfctl_clear_pool(struct pf_pool *); + +int pfctl_set_timeout(struct pfctl *, const char *, int, int); +int pfctl_set_optimization(struct pfctl *, const char *); +int pfctl_set_limit(struct pfctl *, const char *, unsigned int); +int pfctl_set_logif(struct pfctl *, char *); +int pfctl_set_hostid(struct pfctl *, u_int32_t); +int pfctl_set_debug(struct pfctl *, char *); +int pfctl_set_interface_flags(struct pfctl *, char *, int, int); + +int parse_config(char *, struct pfctl *); +int parse_flags(char *); +int pfctl_load_anchors(int, struct pfctl *, struct pfr_buffer *); + +void print_pool(struct pf_pool *, u_int16_t, u_int16_t, sa_family_t, int); +void print_src_node(struct pf_src_node *, int); +void print_rule(struct pf_rule *, const char *, int, int); +void print_tabledef(const char *, int, int, struct node_tinithead *); +void print_status(struct pf_status *, int); + +int eval_pfaltq(struct pfctl *, struct pf_altq *, struct node_queue_bw *, + struct node_queue_opt *); +int eval_pfqueue(struct pfctl *, struct pf_altq *, struct node_queue_bw *, + struct node_queue_opt *); + +void print_altq(const struct pf_altq *, unsigned, struct node_queue_bw *, + struct node_queue_opt *); +void print_queue(const struct pf_altq *, unsigned, struct node_queue_bw *, + int, struct node_queue_opt *); + +int pfctl_define_table(char *, int, int, const char *, struct pfr_buffer *, + u_int32_t); + +void pfctl_clear_fingerprints(int, int); +int pfctl_file_fingerprints(int, int, const char *); +pf_osfp_t pfctl_get_fingerprint(const char *); +int pfctl_load_fingerprints(int, int); +char *pfctl_lookup_fingerprint(pf_osfp_t, char *, size_t); +void pfctl_show_fingerprints(int); + + +struct icmptypeent { + const char *name; + u_int8_t type; +}; + +struct icmpcodeent { + const char *name; + u_int8_t type; + u_int8_t code; +}; + +const struct icmptypeent *geticmptypebynumber(u_int8_t, u_int8_t); +const struct icmptypeent *geticmptypebyname(char *, u_int8_t); +const struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t, u_int8_t); +const struct icmpcodeent *geticmpcodebyname(u_long, char *, u_int8_t); + +struct pf_timeout { + const char *name; + int timeout; +}; + +#define PFCTL_FLAG_FILTER 0x02 +#define PFCTL_FLAG_NAT 0x04 +#define PFCTL_FLAG_OPTION 0x08 +#define PFCTL_FLAG_ALTQ 0x10 +#define PFCTL_FLAG_TABLE 0x20 + +extern const struct pf_timeout pf_timeouts[]; + +void set_ipmask(struct node_host *, u_int8_t); +int check_netmask(struct node_host *, sa_family_t); +int unmask(struct pf_addr *, sa_family_t); +void ifa_load(void); +int get_socket_domain(void); +struct node_host *ifa_exists(const char *); +struct node_host *ifa_lookup(const char *, int); +struct node_host *host(const char *); + +int append_addr(struct pfr_buffer *, char *, int); +int append_addr_host(struct pfr_buffer *, + struct node_host *, int, int); + +#endif /* _PFCTL_PARSER_H_ */ diff --git a/freebsd/sbin/pfctl/pfctl_qstats.c b/freebsd/sbin/pfctl/pfctl_qstats.c new file mode 100644 index 00000000..dda3a494 --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl_qstats.c @@ -0,0 +1,528 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ + +/* $OpenBSD: pfctl_qstats.c,v 1.30 2004/04/27 21:47:32 kjc Exp $ */ + +/* + * Copyright (c) Henning Brauer <henning@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <net/pfvar.h> +#include <arpa/inet.h> + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <net/altq/altq.h> +#include <net/altq/altq_cbq.h> +#include <net/altq/altq_codel.h> +#include <net/altq/altq_priq.h> +#include <net/altq/altq_hfsc.h> +#include <net/altq/altq_fairq.h> + +#include "pfctl.h" +#include "pfctl_parser.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-pfctl_qstats-data.h" +#endif /* __rtems__ */ + +union class_stats { + class_stats_t cbq_stats; + struct priq_classstats priq_stats; + struct hfsc_classstats hfsc_stats; + struct fairq_classstats fairq_stats; + struct codel_ifstats codel_stats; +}; + +#define AVGN_MAX 8 +#define STAT_INTERVAL 5 + +struct queue_stats { + union class_stats data; + int avgn; + double avg_bytes; + double avg_packets; + u_int64_t prev_bytes; + u_int64_t prev_packets; +}; + +struct pf_altq_node { + struct pf_altq altq; + struct pf_altq_node *next; + struct pf_altq_node *children; + struct queue_stats qstats; +}; + +int pfctl_update_qstats(int, struct pf_altq_node **); +void pfctl_insert_altq_node(struct pf_altq_node **, + const struct pf_altq, const struct queue_stats); +struct pf_altq_node *pfctl_find_altq_node(struct pf_altq_node *, + const char *, const char *); +void pfctl_print_altq_node(int, const struct pf_altq_node *, + unsigned, int); +void print_cbqstats(struct queue_stats); +void print_codelstats(struct queue_stats); +void print_priqstats(struct queue_stats); +void print_hfscstats(struct queue_stats); +void print_fairqstats(struct queue_stats); +void pfctl_free_altq_node(struct pf_altq_node *); +void pfctl_print_altq_nodestat(int, + const struct pf_altq_node *); + +void update_avg(struct pf_altq_node *); + +int +pfctl_show_altq(int dev, const char *iface, int opts, int verbose2) +{ + struct pf_altq_node *root = NULL, *node; + int nodes, dotitle = (opts & PF_OPT_SHOWALL); + +#ifdef __FreeBSD__ + if (!altqsupport) + return (-1); +#endif + + if ((nodes = pfctl_update_qstats(dev, &root)) < 0) + return (-1); + + if (nodes == 0) + printf("No queue in use\n"); + for (node = root; node != NULL; node = node->next) { + if (iface != NULL && strcmp(node->altq.ifname, iface)) + continue; + if (dotitle) { + pfctl_print_title("ALTQ:"); + dotitle = 0; + } + pfctl_print_altq_node(dev, node, 0, opts); + } + + while (verbose2 && nodes > 0) { + printf("\n"); + fflush(stdout); + sleep(STAT_INTERVAL); + if ((nodes = pfctl_update_qstats(dev, &root)) == -1) + return (-1); + for (node = root; node != NULL; node = node->next) { + if (iface != NULL && strcmp(node->altq.ifname, iface)) + continue; +#ifdef __FreeBSD__ + if (node->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) + continue; +#endif + pfctl_print_altq_node(dev, node, 0, opts); + } + } + pfctl_free_altq_node(root); + return (0); +} + +#ifdef __rtems__ +static u_int32_t last_ticket; +#endif /* __rtems__ */ +int +pfctl_update_qstats(int dev, struct pf_altq_node **root) +{ + struct pf_altq_node *node; + struct pfioc_altq pa; + struct pfioc_qstats pq; + u_int32_t mnr, nr; + struct queue_stats qstats; +#ifndef __rtems__ + static u_int32_t last_ticket; +#endif /* __rtems__ */ + + memset(&pa, 0, sizeof(pa)); + memset(&pq, 0, sizeof(pq)); + memset(&qstats, 0, sizeof(qstats)); + if (ioctl(dev, DIOCGETALTQS, &pa)) { + warn("DIOCGETALTQS"); + return (-1); + } + + /* if a new set is found, start over */ + if (pa.ticket != last_ticket && *root != NULL) { + pfctl_free_altq_node(*root); + *root = NULL; + } + last_ticket = pa.ticket; + + mnr = pa.nr; + for (nr = 0; nr < mnr; ++nr) { + pa.nr = nr; + if (ioctl(dev, DIOCGETALTQ, &pa)) { + warn("DIOCGETALTQ"); + return (-1); + } +#ifdef __FreeBSD__ + if ((pa.altq.qid > 0 || pa.altq.scheduler == ALTQT_CODEL) && + !(pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED)) { +#else + if (pa.altq.qid > 0) { +#endif + pq.nr = nr; + pq.ticket = pa.ticket; + pq.buf = &qstats.data; + pq.nbytes = sizeof(qstats.data); + if (ioctl(dev, DIOCGETQSTATS, &pq)) { + warn("DIOCGETQSTATS"); + return (-1); + } + if ((node = pfctl_find_altq_node(*root, pa.altq.qname, + pa.altq.ifname)) != NULL) { + memcpy(&node->qstats.data, &qstats.data, + sizeof(qstats.data)); + update_avg(node); + } else { + pfctl_insert_altq_node(root, pa.altq, qstats); + } + } +#ifdef __FreeBSD__ + else if (pa.altq.local_flags & PFALTQ_FLAG_IF_REMOVED) { + memset(&qstats.data, 0, sizeof(qstats.data)); + if ((node = pfctl_find_altq_node(*root, pa.altq.qname, + pa.altq.ifname)) != NULL) { + memcpy(&node->qstats.data, &qstats.data, + sizeof(qstats.data)); + update_avg(node); + } else { + pfctl_insert_altq_node(root, pa.altq, qstats); + } + } +#endif + } + return (mnr); +} + +void +pfctl_insert_altq_node(struct pf_altq_node **root, + const struct pf_altq altq, const struct queue_stats qstats) +{ + struct pf_altq_node *node; + + node = calloc(1, sizeof(struct pf_altq_node)); + if (node == NULL) + err(1, "pfctl_insert_altq_node: calloc"); + memcpy(&node->altq, &altq, sizeof(struct pf_altq)); + memcpy(&node->qstats, &qstats, sizeof(qstats)); + node->next = node->children = NULL; + + if (*root == NULL) + *root = node; + else if (!altq.parent[0]) { + struct pf_altq_node *prev = *root; + + while (prev->next != NULL) + prev = prev->next; + prev->next = node; + } else { + struct pf_altq_node *parent; + + parent = pfctl_find_altq_node(*root, altq.parent, altq.ifname); + if (parent == NULL) + errx(1, "parent %s not found", altq.parent); + if (parent->children == NULL) + parent->children = node; + else { + struct pf_altq_node *prev = parent->children; + + while (prev->next != NULL) + prev = prev->next; + prev->next = node; + } + } + update_avg(node); +} + +struct pf_altq_node * +pfctl_find_altq_node(struct pf_altq_node *root, const char *qname, + const char *ifname) +{ + struct pf_altq_node *node, *child; + + for (node = root; node != NULL; node = node->next) { + if (!strcmp(node->altq.qname, qname) + && !(strcmp(node->altq.ifname, ifname))) + return (node); + if (node->children != NULL) { + child = pfctl_find_altq_node(node->children, qname, + ifname); + if (child != NULL) + return (child); + } + } + return (NULL); +} + +void +pfctl_print_altq_node(int dev, const struct pf_altq_node *node, + unsigned int level, int opts) +{ + const struct pf_altq_node *child; + + if (node == NULL) + return; + + print_altq(&node->altq, level, NULL, NULL); + + if (node->children != NULL) { + printf("{"); + for (child = node->children; child != NULL; + child = child->next) { + printf("%s", child->altq.qname); + if (child->next != NULL) + printf(", "); + } + printf("}"); + } + printf("\n"); + + if (opts & PF_OPT_VERBOSE) + pfctl_print_altq_nodestat(dev, node); + + if (opts & PF_OPT_DEBUG) + printf(" [ qid=%u ifname=%s ifbandwidth=%s ]\n", + node->altq.qid, node->altq.ifname, + rate2str((double)(node->altq.ifbandwidth))); + + for (child = node->children; child != NULL; + child = child->next) + pfctl_print_altq_node(dev, child, level + 1, opts); +} + +void +pfctl_print_altq_nodestat(int dev, const struct pf_altq_node *a) +{ + if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL) + return; + +#ifdef __FreeBSD__ + if (a->altq.local_flags & PFALTQ_FLAG_IF_REMOVED) + return; +#endif + switch (a->altq.scheduler) { + case ALTQT_CBQ: + print_cbqstats(a->qstats); + break; + case ALTQT_PRIQ: + print_priqstats(a->qstats); + break; + case ALTQT_HFSC: + print_hfscstats(a->qstats); + break; + case ALTQT_FAIRQ: + print_fairqstats(a->qstats); + break; + case ALTQT_CODEL: + print_codelstats(a->qstats); + break; + } +} + +void +print_cbqstats(struct queue_stats cur) +{ + printf(" [ pkts: %10llu bytes: %10llu " + "dropped pkts: %6llu bytes: %6llu ]\n", + (unsigned long long)cur.data.cbq_stats.xmit_cnt.packets, + (unsigned long long)cur.data.cbq_stats.xmit_cnt.bytes, + (unsigned long long)cur.data.cbq_stats.drop_cnt.packets, + (unsigned long long)cur.data.cbq_stats.drop_cnt.bytes); + printf(" [ qlength: %3d/%3d borrows: %6u suspends: %6u ]\n", + cur.data.cbq_stats.qcnt, cur.data.cbq_stats.qmax, + cur.data.cbq_stats.borrows, cur.data.cbq_stats.delays); + + if (cur.avgn < 2) + return; + + printf(" [ measured: %7.1f packets/s, %s/s ]\n", + cur.avg_packets / STAT_INTERVAL, + rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); +} + +void +print_codelstats(struct queue_stats cur) +{ + printf(" [ pkts: %10llu bytes: %10llu " + "dropped pkts: %6llu bytes: %6llu ]\n", + (unsigned long long)cur.data.codel_stats.cl_xmitcnt.packets, + (unsigned long long)cur.data.codel_stats.cl_xmitcnt.bytes, + (unsigned long long)cur.data.codel_stats.cl_dropcnt.packets + + cur.data.codel_stats.stats.drop_cnt.packets, + (unsigned long long)cur.data.codel_stats.cl_dropcnt.bytes + + cur.data.codel_stats.stats.drop_cnt.bytes); + printf(" [ qlength: %3d/%3d ]\n", + cur.data.codel_stats.qlength, cur.data.codel_stats.qlimit); + + if (cur.avgn < 2) + return; + + printf(" [ measured: %7.1f packets/s, %s/s ]\n", + cur.avg_packets / STAT_INTERVAL, + rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); +} + +void +print_priqstats(struct queue_stats cur) +{ + printf(" [ pkts: %10llu bytes: %10llu " + "dropped pkts: %6llu bytes: %6llu ]\n", + (unsigned long long)cur.data.priq_stats.xmitcnt.packets, + (unsigned long long)cur.data.priq_stats.xmitcnt.bytes, + (unsigned long long)cur.data.priq_stats.dropcnt.packets, + (unsigned long long)cur.data.priq_stats.dropcnt.bytes); + printf(" [ qlength: %3d/%3d ]\n", + cur.data.priq_stats.qlength, cur.data.priq_stats.qlimit); + + if (cur.avgn < 2) + return; + + printf(" [ measured: %7.1f packets/s, %s/s ]\n", + cur.avg_packets / STAT_INTERVAL, + rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); +} + +void +print_hfscstats(struct queue_stats cur) +{ + printf(" [ pkts: %10llu bytes: %10llu " + "dropped pkts: %6llu bytes: %6llu ]\n", + (unsigned long long)cur.data.hfsc_stats.xmit_cnt.packets, + (unsigned long long)cur.data.hfsc_stats.xmit_cnt.bytes, + (unsigned long long)cur.data.hfsc_stats.drop_cnt.packets, + (unsigned long long)cur.data.hfsc_stats.drop_cnt.bytes); + printf(" [ qlength: %3d/%3d ]\n", + cur.data.hfsc_stats.qlength, cur.data.hfsc_stats.qlimit); + + if (cur.avgn < 2) + return; + + printf(" [ measured: %7.1f packets/s, %s/s ]\n", + cur.avg_packets / STAT_INTERVAL, + rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); +} + +void +print_fairqstats(struct queue_stats cur) +{ + printf(" [ pkts: %10llu bytes: %10llu " + "dropped pkts: %6llu bytes: %6llu ]\n", + (unsigned long long)cur.data.fairq_stats.xmit_cnt.packets, + (unsigned long long)cur.data.fairq_stats.xmit_cnt.bytes, + (unsigned long long)cur.data.fairq_stats.drop_cnt.packets, + (unsigned long long)cur.data.fairq_stats.drop_cnt.bytes); + printf(" [ qlength: %3d/%3d ]\n", + cur.data.fairq_stats.qlength, cur.data.fairq_stats.qlimit); + + if (cur.avgn < 2) + return; + + printf(" [ measured: %7.1f packets/s, %s/s ]\n", + cur.avg_packets / STAT_INTERVAL, + rate2str((8 * cur.avg_bytes) / STAT_INTERVAL)); +} + +void +pfctl_free_altq_node(struct pf_altq_node *node) +{ + while (node != NULL) { + struct pf_altq_node *prev; + + if (node->children != NULL) + pfctl_free_altq_node(node->children); + prev = node; + node = node->next; + free(prev); + } +} + +void +update_avg(struct pf_altq_node *a) +{ + struct queue_stats *qs; + u_int64_t b, p; + int n; + + if (a->altq.qid == 0 && a->altq.scheduler != ALTQT_CODEL) + return; + + qs = &a->qstats; + n = qs->avgn; + + switch (a->altq.scheduler) { + case ALTQT_CBQ: + b = qs->data.cbq_stats.xmit_cnt.bytes; + p = qs->data.cbq_stats.xmit_cnt.packets; + break; + case ALTQT_PRIQ: + b = qs->data.priq_stats.xmitcnt.bytes; + p = qs->data.priq_stats.xmitcnt.packets; + break; + case ALTQT_HFSC: + b = qs->data.hfsc_stats.xmit_cnt.bytes; + p = qs->data.hfsc_stats.xmit_cnt.packets; + break; + case ALTQT_FAIRQ: + b = qs->data.fairq_stats.xmit_cnt.bytes; + p = qs->data.fairq_stats.xmit_cnt.packets; + break; + case ALTQT_CODEL: + b = qs->data.codel_stats.cl_xmitcnt.bytes; + p = qs->data.codel_stats.cl_xmitcnt.packets; + break; + default: + b = 0; + p = 0; + break; + } + + if (n == 0) { + qs->prev_bytes = b; + qs->prev_packets = p; + qs->avgn++; + return; + } + + if (b >= qs->prev_bytes) + qs->avg_bytes = ((qs->avg_bytes * (n - 1)) + + (b - qs->prev_bytes)) / n; + + if (p >= qs->prev_packets) + qs->avg_packets = ((qs->avg_packets * (n - 1)) + + (p - qs->prev_packets)) / n; + + qs->prev_bytes = b; + qs->prev_packets = p; + if (n < AVGN_MAX) + qs->avgn++; +} diff --git a/freebsd/sbin/pfctl/pfctl_radix.c b/freebsd/sbin/pfctl/pfctl_radix.c new file mode 100644 index 00000000..c151f878 --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl_radix.c @@ -0,0 +1,597 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ + +/* $OpenBSD: pfctl_radix.c,v 1.27 2005/05/21 21:03:58 henning Exp $ */ + +/* + * Copyright (c) 2002 Cedric Berger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/pfvar.h> + +#include <errno.h> +#include <string.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <err.h> + +#include "pfctl.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-pfctl_radix-data.h" +#endif /* __rtems__ */ + +#define BUF_SIZE 256 + +extern int dev; + +static int pfr_next_token(char buf[], FILE *); + + +int +pfr_clr_tables(struct pfr_table *filter, int *ndel, int flags) +{ + struct pfioc_table io; + + bzero(&io, sizeof io); + io.pfrio_flags = flags; + if (filter != NULL) + io.pfrio_table = *filter; + if (ioctl(dev, DIOCRCLRTABLES, &io)) + return (-1); + if (ndel != NULL) + *ndel = io.pfrio_ndel; + return (0); +} + +int +pfr_add_tables(struct pfr_table *tbl, int size, int *nadd, int flags) +{ + struct pfioc_table io; + + if (size < 0 || (size && tbl == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_buffer = tbl; + io.pfrio_esize = sizeof(*tbl); + io.pfrio_size = size; + if (ioctl(dev, DIOCRADDTABLES, &io)) + return (-1); + if (nadd != NULL) + *nadd = io.pfrio_nadd; + return (0); +} + +int +pfr_del_tables(struct pfr_table *tbl, int size, int *ndel, int flags) +{ + struct pfioc_table io; + + if (size < 0 || (size && tbl == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_buffer = tbl; + io.pfrio_esize = sizeof(*tbl); + io.pfrio_size = size; + if (ioctl(dev, DIOCRDELTABLES, &io)) + return (-1); + if (ndel != NULL) + *ndel = io.pfrio_ndel; + return (0); +} + +int +pfr_get_tables(struct pfr_table *filter, struct pfr_table *tbl, int *size, + int flags) +{ + struct pfioc_table io; + + if (size == NULL || *size < 0 || (*size && tbl == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + if (filter != NULL) + io.pfrio_table = *filter; + io.pfrio_buffer = tbl; + io.pfrio_esize = sizeof(*tbl); + io.pfrio_size = *size; + if (ioctl(dev, DIOCRGETTABLES, &io)) + return (-1); + *size = io.pfrio_size; + return (0); +} + +int +pfr_get_tstats(struct pfr_table *filter, struct pfr_tstats *tbl, int *size, + int flags) +{ + struct pfioc_table io; + + if (size == NULL || *size < 0 || (*size && tbl == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + if (filter != NULL) + io.pfrio_table = *filter; + io.pfrio_buffer = tbl; + io.pfrio_esize = sizeof(*tbl); + io.pfrio_size = *size; + if (ioctl(dev, DIOCRGETTSTATS, &io)) + return (-1); + *size = io.pfrio_size; + return (0); +} + +int +pfr_clr_addrs(struct pfr_table *tbl, int *ndel, int flags) +{ + struct pfioc_table io; + + if (tbl == NULL) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_table = *tbl; + if (ioctl(dev, DIOCRCLRADDRS, &io)) + return (-1); + if (ndel != NULL) + *ndel = io.pfrio_ndel; + return (0); +} + +int +pfr_add_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, + int *nadd, int flags) +{ + struct pfioc_table io; + + if (tbl == NULL || size < 0 || (size && addr == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_table = *tbl; + io.pfrio_buffer = addr; + io.pfrio_esize = sizeof(*addr); + io.pfrio_size = size; + if (ioctl(dev, DIOCRADDADDRS, &io)) + return (-1); + if (nadd != NULL) + *nadd = io.pfrio_nadd; + return (0); +} + +int +pfr_del_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, + int *ndel, int flags) +{ + struct pfioc_table io; + + if (tbl == NULL || size < 0 || (size && addr == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_table = *tbl; + io.pfrio_buffer = addr; + io.pfrio_esize = sizeof(*addr); + io.pfrio_size = size; + if (ioctl(dev, DIOCRDELADDRS, &io)) + return (-1); + if (ndel != NULL) + *ndel = io.pfrio_ndel; + return (0); +} + +int +pfr_set_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, + int *size2, int *nadd, int *ndel, int *nchange, int flags) +{ + struct pfioc_table io; + + if (tbl == NULL || size < 0 || (size && addr == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_table = *tbl; + io.pfrio_buffer = addr; + io.pfrio_esize = sizeof(*addr); + io.pfrio_size = size; + io.pfrio_size2 = (size2 != NULL) ? *size2 : 0; + if (ioctl(dev, DIOCRSETADDRS, &io)) + return (-1); + if (nadd != NULL) + *nadd = io.pfrio_nadd; + if (ndel != NULL) + *ndel = io.pfrio_ndel; + if (nchange != NULL) + *nchange = io.pfrio_nchange; + if (size2 != NULL) + *size2 = io.pfrio_size2; + return (0); +} + +int +pfr_get_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int *size, + int flags) +{ + struct pfioc_table io; + + if (tbl == NULL || size == NULL || *size < 0 || + (*size && addr == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_table = *tbl; + io.pfrio_buffer = addr; + io.pfrio_esize = sizeof(*addr); + io.pfrio_size = *size; + if (ioctl(dev, DIOCRGETADDRS, &io)) + return (-1); + *size = io.pfrio_size; + return (0); +} + +int +pfr_get_astats(struct pfr_table *tbl, struct pfr_astats *addr, int *size, + int flags) +{ + struct pfioc_table io; + + if (tbl == NULL || size == NULL || *size < 0 || + (*size && addr == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_table = *tbl; + io.pfrio_buffer = addr; + io.pfrio_esize = sizeof(*addr); + io.pfrio_size = *size; + if (ioctl(dev, DIOCRGETASTATS, &io)) + return (-1); + *size = io.pfrio_size; + return (0); +} + +int +pfr_clr_tstats(struct pfr_table *tbl, int size, int *nzero, int flags) +{ + struct pfioc_table io; + + if (size < 0 || (size && !tbl)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_buffer = tbl; + io.pfrio_esize = sizeof(*tbl); + io.pfrio_size = size; + if (ioctl(dev, DIOCRCLRTSTATS, &io)) + return (-1); + if (nzero) + *nzero = io.pfrio_nzero; + return (0); +} + +int +pfr_tst_addrs(struct pfr_table *tbl, struct pfr_addr *addr, int size, + int *nmatch, int flags) +{ + struct pfioc_table io; + + if (tbl == NULL || size < 0 || (size && addr == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_table = *tbl; + io.pfrio_buffer = addr; + io.pfrio_esize = sizeof(*addr); + io.pfrio_size = size; + if (ioctl(dev, DIOCRTSTADDRS, &io)) + return (-1); + if (nmatch) + *nmatch = io.pfrio_nmatch; + return (0); +} + +int +pfr_ina_define(struct pfr_table *tbl, struct pfr_addr *addr, int size, + int *nadd, int *naddr, int ticket, int flags) +{ + struct pfioc_table io; + + if (tbl == NULL || size < 0 || (size && addr == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + io.pfrio_flags = flags; + io.pfrio_table = *tbl; + io.pfrio_buffer = addr; + io.pfrio_esize = sizeof(*addr); + io.pfrio_size = size; + io.pfrio_ticket = ticket; + if (ioctl(dev, DIOCRINADEFINE, &io)) + return (-1); + if (nadd != NULL) + *nadd = io.pfrio_nadd; + if (naddr != NULL) + *naddr = io.pfrio_naddr; + return (0); +} + +/* interface management code */ + +int +pfi_get_ifaces(const char *filter, struct pfi_kif *buf, int *size) +{ + struct pfioc_iface io; + + if (size == NULL || *size < 0 || (*size && buf == NULL)) { + errno = EINVAL; + return (-1); + } + bzero(&io, sizeof io); + if (filter != NULL) + if (strlcpy(io.pfiio_name, filter, sizeof(io.pfiio_name)) >= + sizeof(io.pfiio_name)) { + errno = EINVAL; + return (-1); + } + io.pfiio_buffer = buf; + io.pfiio_esize = sizeof(*buf); + io.pfiio_size = *size; + if (ioctl(dev, DIOCIGETIFACES, &io)) + return (-1); + *size = io.pfiio_size; + return (0); +} + +/* buffer management code */ + +const size_t buf_esize[PFRB_MAX] = { 0, + sizeof(struct pfr_table), sizeof(struct pfr_tstats), + sizeof(struct pfr_addr), sizeof(struct pfr_astats), + sizeof(struct pfi_kif), sizeof(struct pfioc_trans_e) +}; + +/* + * add one element to the buffer + */ +int +pfr_buf_add(struct pfr_buffer *b, const void *e) +{ + size_t bs; + + if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX || + e == NULL) { + errno = EINVAL; + return (-1); + } + bs = buf_esize[b->pfrb_type]; + if (b->pfrb_size == b->pfrb_msize) + if (pfr_buf_grow(b, 0)) + return (-1); + memcpy(((caddr_t)b->pfrb_caddr) + bs * b->pfrb_size, e, bs); + b->pfrb_size++; + return (0); +} + +/* + * return next element of the buffer (or first one if prev is NULL) + * see PFRB_FOREACH macro + */ +void * +pfr_buf_next(struct pfr_buffer *b, const void *prev) +{ + size_t bs; + + if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) + return (NULL); + if (b->pfrb_size == 0) + return (NULL); + if (prev == NULL) + return (b->pfrb_caddr); + bs = buf_esize[b->pfrb_type]; + if ((((caddr_t)prev)-((caddr_t)b->pfrb_caddr)) / bs >= b->pfrb_size-1) + return (NULL); + return (((caddr_t)prev) + bs); +} + +/* + * minsize: + * 0: make the buffer somewhat bigger + * n: make room for "n" entries in the buffer + */ +int +pfr_buf_grow(struct pfr_buffer *b, int minsize) +{ + caddr_t p; + size_t bs; + + if (b == NULL || b->pfrb_type <= 0 || b->pfrb_type >= PFRB_MAX) { + errno = EINVAL; + return (-1); + } + if (minsize != 0 && minsize <= b->pfrb_msize) + return (0); + bs = buf_esize[b->pfrb_type]; + if (!b->pfrb_msize) { + if (minsize < 64) + minsize = 64; + b->pfrb_caddr = calloc(bs, minsize); + if (b->pfrb_caddr == NULL) + return (-1); + b->pfrb_msize = minsize; + } else { + if (minsize == 0) + minsize = b->pfrb_msize * 2; + if (minsize < 0 || minsize >= SIZE_T_MAX / bs) { + /* msize overflow */ + errno = ENOMEM; + return (-1); + } + p = realloc(b->pfrb_caddr, minsize * bs); + if (p == NULL) + return (-1); + bzero(p + b->pfrb_msize * bs, (minsize - b->pfrb_msize) * bs); + b->pfrb_caddr = p; + b->pfrb_msize = minsize; + } + return (0); +} + +/* + * reset buffer and free memory. + */ +void +pfr_buf_clear(struct pfr_buffer *b) +{ + if (b == NULL) + return; + if (b->pfrb_caddr != NULL) + free(b->pfrb_caddr); + b->pfrb_caddr = NULL; + b->pfrb_size = b->pfrb_msize = 0; +} + +int +pfr_buf_load(struct pfr_buffer *b, char *file, int nonetwork, + int (*append_addr)(struct pfr_buffer *, char *, int)) +{ + FILE *fp; + char buf[BUF_SIZE]; + int rv; + + if (file == NULL) + return (0); + if (!strcmp(file, "-")) + fp = stdin; + else { + fp = pfctl_fopen(file, "r"); + if (fp == NULL) + return (-1); + } + while ((rv = pfr_next_token(buf, fp)) == 1) + if (append_addr(b, buf, nonetwork)) { + rv = -1; + break; + } + if (fp != stdin) + fclose(fp); + return (rv); +} + +int +pfr_next_token(char buf[BUF_SIZE], FILE *fp) +{ + static char next_ch = ' '; + int i = 0; + + for (;;) { + /* skip spaces */ + while (isspace(next_ch) && !feof(fp)) + next_ch = fgetc(fp); + /* remove from '#' until end of line */ + if (next_ch == '#') + while (!feof(fp)) { + next_ch = fgetc(fp); + if (next_ch == '\n') + break; + } + else + break; + } + if (feof(fp)) { + next_ch = ' '; + return (0); + } + do { + if (i < BUF_SIZE) + buf[i++] = next_ch; + next_ch = fgetc(fp); + } while (!feof(fp) && !isspace(next_ch)); + if (i >= BUF_SIZE) { + errno = EINVAL; + return (-1); + } + buf[i] = '\0'; + return (1); +} + +char * +pfr_strerror(int errnum) +{ + switch (errnum) { + case ESRCH: + return "Table does not exist"; + case ENOENT: + return "Anchor or Ruleset does not exist"; + default: + return strerror(errnum); + } +} diff --git a/freebsd/sbin/pfctl/pfctl_table.c b/freebsd/sbin/pfctl/pfctl_table.c new file mode 100644 index 00000000..4dfb0689 --- /dev/null +++ b/freebsd/sbin/pfctl/pfctl_table.c @@ -0,0 +1,650 @@ +#include <machine/rtems-bsd-user-space.h> + +#ifdef __rtems__ +#include "rtems-bsd-pfctl-namespace.h" +#endif /* __rtems__ */ + +/* $OpenBSD: pfctl_table.c,v 1.67 2008/06/10 20:55:02 mcbride Exp $ */ + +/* + * Copyright (c) 2002 Cedric Berger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#ifdef __rtems__ +#include <machine/rtems-bsd-program.h> +#endif /* __rtems__ */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> + +#include <net/if.h> +#include <net/pfvar.h> +#include <arpa/inet.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <netdb.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + +#include "pfctl_parser.h" +#include "pfctl.h" +#ifdef __rtems__ +#include "rtems-bsd-pfctl-pfctl_table-data.h" +#endif /* __rtems__ */ + +extern void usage(void); +static int pfctl_table(int, char *[], char *, const char *, char *, + const char *, int); +static void print_table(struct pfr_table *, int, int); +static void print_tstats(struct pfr_tstats *, int); +static int load_addr(struct pfr_buffer *, int, char *[], char *, int); +static void print_addrx(struct pfr_addr *, struct pfr_addr *, int); +static void print_astats(struct pfr_astats *, int); +static void radix_perror(void); +static void xprintf(int, const char *, ...); +static void print_iface(struct pfi_kif *, int); + +static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = { + { "In/Block:", "In/Pass:", "In/XPass:" }, + { "Out/Block:", "Out/Pass:", "Out/XPass:" } +}; + +static const char *istats_text[2][2][2] = { + { { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } }, + { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } } +}; + +#define RVTEST(fct) do { \ + if ((!(opts & PF_OPT_NOACTION) || \ + (opts & PF_OPT_DUMMYACTION)) && \ + (fct)) { \ + radix_perror(); \ + goto _error; \ + } \ + } while (0) + +#define CREATE_TABLE do { \ + table.pfrt_flags |= PFR_TFLAG_PERSIST; \ + if ((!(opts & PF_OPT_NOACTION) || \ + (opts & PF_OPT_DUMMYACTION)) && \ + (pfr_add_tables(&table, 1, &nadd, flags)) && \ + (errno != EPERM)) { \ + radix_perror(); \ + goto _error; \ + } \ + if (nadd) { \ + warn_namespace_collision(table.pfrt_name); \ + xprintf(opts, "%d table created", nadd); \ + if (opts & PF_OPT_NOACTION) \ + return (0); \ + } \ + table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \ + } while(0) + +int +pfctl_clear_tables(const char *anchor, int opts) +{ + return pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts); +} + +int +pfctl_show_tables(const char *anchor, int opts) +{ + return pfctl_table(0, NULL, NULL, "-s", NULL, anchor, opts); +} + +int +pfctl_command_tables(int argc, char *argv[], char *tname, + const char *command, char *file, const char *anchor, int opts) +{ + if (tname == NULL || command == NULL) + usage(); + return pfctl_table(argc, argv, tname, command, file, anchor, opts); +} + +int +pfctl_table(int argc, char *argv[], char *tname, const char *command, + char *file, const char *anchor, int opts) +{ + struct pfr_table table; + struct pfr_buffer b, b2; + struct pfr_addr *a, *a2; + int nadd = 0, ndel = 0, nchange = 0, nzero = 0; + int rv = 0, flags = 0, nmatch = 0; + void *p; + + if (command == NULL) + usage(); + if (opts & PF_OPT_NOACTION) + flags |= PFR_FLAG_DUMMY; + + bzero(&b, sizeof(b)); + bzero(&b2, sizeof(b2)); + bzero(&table, sizeof(table)); + if (tname != NULL) { + if (strlen(tname) >= PF_TABLE_NAME_SIZE) + usage(); + if (strlcpy(table.pfrt_name, tname, + sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name)) + errx(1, "pfctl_table: strlcpy"); + } + if (strlcpy(table.pfrt_anchor, anchor, + sizeof(table.pfrt_anchor)) >= sizeof(table.pfrt_anchor)) + errx(1, "pfctl_table: strlcpy"); + + if (!strcmp(command, "-F")) { + if (argc || file != NULL) + usage(); + RVTEST(pfr_clr_tables(&table, &ndel, flags)); + xprintf(opts, "%d tables deleted", ndel); + } else if (!strcmp(command, "-s")) { + b.pfrb_type = (opts & PF_OPT_VERBOSE2) ? + PFRB_TSTATS : PFRB_TABLES; + if (argc || file != NULL) + usage(); + for (;;) { + pfr_buf_grow(&b, b.pfrb_size); + b.pfrb_size = b.pfrb_msize; + if (opts & PF_OPT_VERBOSE2) + RVTEST(pfr_get_tstats(&table, + b.pfrb_caddr, &b.pfrb_size, flags)); + else + RVTEST(pfr_get_tables(&table, + b.pfrb_caddr, &b.pfrb_size, flags)); + if (b.pfrb_size <= b.pfrb_msize) + break; + } + + if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0) + pfctl_print_title("TABLES:"); + + PFRB_FOREACH(p, &b) + if (opts & PF_OPT_VERBOSE2) + print_tstats(p, opts & PF_OPT_DEBUG); + else + print_table(p, opts & PF_OPT_VERBOSE, + opts & PF_OPT_DEBUG); + } else if (!strcmp(command, "kill")) { + if (argc || file != NULL) + usage(); + RVTEST(pfr_del_tables(&table, 1, &ndel, flags)); + xprintf(opts, "%d table deleted", ndel); + } else if (!strcmp(command, "flush")) { + if (argc || file != NULL) + usage(); + RVTEST(pfr_clr_addrs(&table, &ndel, flags)); + xprintf(opts, "%d addresses deleted", ndel); + } else if (!strcmp(command, "add")) { + b.pfrb_type = PFRB_ADDRS; + if (load_addr(&b, argc, argv, file, 0)) + goto _error; + CREATE_TABLE; + if (opts & PF_OPT_VERBOSE) + flags |= PFR_FLAG_FEEDBACK; + RVTEST(pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size, + &nadd, flags)); + xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size); + if (opts & PF_OPT_VERBOSE) + PFRB_FOREACH(a, &b) + if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) + print_addrx(a, NULL, + opts & PF_OPT_USEDNS); + } else if (!strcmp(command, "delete")) { + b.pfrb_type = PFRB_ADDRS; + if (load_addr(&b, argc, argv, file, 0)) + goto _error; + if (opts & PF_OPT_VERBOSE) + flags |= PFR_FLAG_FEEDBACK; + RVTEST(pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size, + &ndel, flags)); + xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size); + if (opts & PF_OPT_VERBOSE) + PFRB_FOREACH(a, &b) + if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) + print_addrx(a, NULL, + opts & PF_OPT_USEDNS); + } else if (!strcmp(command, "replace")) { + b.pfrb_type = PFRB_ADDRS; + if (load_addr(&b, argc, argv, file, 0)) + goto _error; + CREATE_TABLE; + if (opts & PF_OPT_VERBOSE) + flags |= PFR_FLAG_FEEDBACK; + for (;;) { + int sz2 = b.pfrb_msize; + + RVTEST(pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size, + &sz2, &nadd, &ndel, &nchange, flags)); + if (sz2 <= b.pfrb_msize) { + b.pfrb_size = sz2; + break; + } else + pfr_buf_grow(&b, sz2); + } + if (nadd) + xprintf(opts, "%d addresses added", nadd); + if (ndel) + xprintf(opts, "%d addresses deleted", ndel); + if (nchange) + xprintf(opts, "%d addresses changed", nchange); + if (!nadd && !ndel && !nchange) + xprintf(opts, "no changes"); + if (opts & PF_OPT_VERBOSE) + PFRB_FOREACH(a, &b) + if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) + print_addrx(a, NULL, + opts & PF_OPT_USEDNS); + } else if (!strcmp(command, "expire")) { + const char *errstr; + u_int lifetime; + + b.pfrb_type = PFRB_ASTATS; + b2.pfrb_type = PFRB_ADDRS; + if (argc != 1 || file != NULL) + usage(); + lifetime = strtonum(*argv, 0, UINT_MAX, &errstr); + if (errstr) + errx(1, "expiry time: %s", errstr); + for (;;) { + pfr_buf_grow(&b, b.pfrb_size); + b.pfrb_size = b.pfrb_msize; + RVTEST(pfr_get_astats(&table, b.pfrb_caddr, + &b.pfrb_size, flags)); + if (b.pfrb_size <= b.pfrb_msize) + break; + } + PFRB_FOREACH(p, &b) { + ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0; + if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero > + lifetime) + if (pfr_buf_add(&b2, + &((struct pfr_astats *)p)->pfras_a)) + err(1, "duplicate buffer"); + } + + if (opts & PF_OPT_VERBOSE) + flags |= PFR_FLAG_FEEDBACK; + RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size, + &ndel, flags)); + xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size); + if (opts & PF_OPT_VERBOSE) + PFRB_FOREACH(a, &b2) + if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) + print_addrx(a, NULL, + opts & PF_OPT_USEDNS); + } else if (!strcmp(command, "show")) { + b.pfrb_type = (opts & PF_OPT_VERBOSE) ? + PFRB_ASTATS : PFRB_ADDRS; + if (argc || file != NULL) + usage(); + for (;;) { + pfr_buf_grow(&b, b.pfrb_size); + b.pfrb_size = b.pfrb_msize; + if (opts & PF_OPT_VERBOSE) + RVTEST(pfr_get_astats(&table, b.pfrb_caddr, + &b.pfrb_size, flags)); + else + RVTEST(pfr_get_addrs(&table, b.pfrb_caddr, + &b.pfrb_size, flags)); + if (b.pfrb_size <= b.pfrb_msize) + break; + } + PFRB_FOREACH(p, &b) + if (opts & PF_OPT_VERBOSE) + print_astats(p, opts & PF_OPT_USEDNS); + else + print_addrx(p, NULL, opts & PF_OPT_USEDNS); + } else if (!strcmp(command, "test")) { + b.pfrb_type = PFRB_ADDRS; + b2.pfrb_type = PFRB_ADDRS; + + if (load_addr(&b, argc, argv, file, 1)) + goto _error; + if (opts & PF_OPT_VERBOSE2) { + flags |= PFR_FLAG_REPLACE; + PFRB_FOREACH(a, &b) + if (pfr_buf_add(&b2, a)) + err(1, "duplicate buffer"); + } + RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size, + &nmatch, flags)); + xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size); + if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2)) + PFRB_FOREACH(a, &b) + if (a->pfra_fback == PFR_FB_MATCH) + print_addrx(a, NULL, + opts & PF_OPT_USEDNS); + if (opts & PF_OPT_VERBOSE2) { + a2 = NULL; + PFRB_FOREACH(a, &b) { + a2 = pfr_buf_next(&b2, a2); + print_addrx(a2, a, opts & PF_OPT_USEDNS); + } + } + if (nmatch < b.pfrb_size) + rv = 2; + } else if (!strcmp(command, "zero")) { + if (argc || file != NULL) + usage(); + flags |= PFR_FLAG_ADDRSTOO; + RVTEST(pfr_clr_tstats(&table, 1, &nzero, flags)); + xprintf(opts, "%d table/stats cleared", nzero); + } else + warnx("pfctl_table: unknown command '%s'", command); + goto _cleanup; + +_error: + rv = -1; +_cleanup: + pfr_buf_clear(&b); + pfr_buf_clear(&b2); + return (rv); +} + +void +print_table(struct pfr_table *ta, int verbose, int debug) +{ + if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE)) + return; + if (verbose) { + printf("%c%c%c%c%c%c%c\t%s", + (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-', + (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-', + (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-', + (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-', + (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-', + (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-', + (ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-', + ta->pfrt_name); + if (ta->pfrt_anchor[0]) + printf("\t%s", ta->pfrt_anchor); + puts(""); + } else + puts(ta->pfrt_name); +} + +void +print_tstats(struct pfr_tstats *ts, int debug) +{ + time_t time = ts->pfrts_tzero; + int dir, op; + + if (!debug && !(ts->pfrts_flags & PFR_TFLAG_ACTIVE)) + return; + print_table(&ts->pfrts_t, 1, debug); + printf("\tAddresses: %d\n", ts->pfrts_cnt); + printf("\tCleared: %s", ctime(&time)); + printf("\tReferences: [ Anchors: %-18d Rules: %-18d ]\n", + ts->pfrts_refcnt[PFR_REFCNT_ANCHOR], + ts->pfrts_refcnt[PFR_REFCNT_RULE]); + printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n", + (unsigned long long)ts->pfrts_nomatch, + (unsigned long long)ts->pfrts_match); + for (dir = 0; dir < PFR_DIR_MAX; dir++) + for (op = 0; op < PFR_OP_TABLE_MAX; op++) + printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", + stats_text[dir][op], + (unsigned long long)ts->pfrts_packets[dir][op], + (unsigned long long)ts->pfrts_bytes[dir][op]); +} + +int +load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file, + int nonetwork) +{ + while (argc--) + if (append_addr(b, *argv++, nonetwork)) { + if (errno) + warn("cannot decode %s", argv[-1]); + return (-1); + } + if (pfr_buf_load(b, file, nonetwork, append_addr)) { + warn("cannot load %s", file); + return (-1); + } + return (0); +} + +void +print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns) +{ + char ch, buf[256] = "{error}"; + char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' }; + unsigned int fback, hostnet; + + fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback; + ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?'; + hostnet = (ad->pfra_af == AF_INET6) ? 128 : 32; + inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf)); + printf("%c %c%s", ch, (ad->pfra_not?'!':' '), buf); + if (ad->pfra_net < hostnet) + printf("/%d", ad->pfra_net); + if (rad != NULL && fback != PFR_FB_NONE) { + if (strlcpy(buf, "{error}", sizeof(buf)) >= sizeof(buf)) + errx(1, "print_addrx: strlcpy"); + inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf)); + printf("\t%c%s", (rad->pfra_not?'!':' '), buf); + if (rad->pfra_net < hostnet) + printf("/%d", rad->pfra_net); + } + if (rad != NULL && fback == PFR_FB_NONE) + printf("\t nomatch"); + if (dns && ad->pfra_net == hostnet) { + char host[NI_MAXHOST]; + union sockaddr_union sa; + + strlcpy(host, "?", sizeof(host)); + bzero(&sa, sizeof(sa)); + sa.sa.sa_family = ad->pfra_af; + if (sa.sa.sa_family == AF_INET) { + sa.sa.sa_len = sizeof(sa.sin); + sa.sin.sin_addr = ad->pfra_ip4addr; + } else { + sa.sa.sa_len = sizeof(sa.sin6); + sa.sin6.sin6_addr = ad->pfra_ip6addr; + } + if (getnameinfo(&sa.sa, sa.sa.sa_len, host, sizeof(host), + NULL, 0, NI_NAMEREQD) == 0) + printf("\t(%s)", host); + } + printf("\n"); +} + +void +print_astats(struct pfr_astats *as, int dns) +{ + time_t time = as->pfras_tzero; + int dir, op; + + print_addrx(&as->pfras_a, NULL, dns); + printf("\tCleared: %s", ctime(&time)); + if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT) + return; + for (dir = 0; dir < PFR_DIR_MAX; dir++) + for (op = 0; op < PFR_OP_ADDR_MAX; op++) + printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", + stats_text[dir][op], + (unsigned long long)as->pfras_packets[dir][op], + (unsigned long long)as->pfras_bytes[dir][op]); +} + +void +radix_perror(void) +{ +#ifndef __rtems__ + extern char *__progname; +#else /* __rtems__ */ +#define __progname "pfctl" +#endif /* __rtems__ */ + fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno)); +} + +int +pfctl_define_table(char *name, int flags, int addrs, const char *anchor, + struct pfr_buffer *ab, u_int32_t ticket) +{ + struct pfr_table tbl; + + bzero(&tbl, sizeof(tbl)); + if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >= + sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor, + sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor)) + errx(1, "pfctl_define_table: strlcpy"); + tbl.pfrt_flags = flags; + + return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL, + NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0); +} + +void +warn_namespace_collision(const char *filter) +{ + struct pfr_buffer b; + struct pfr_table *t; + const char *name = NULL, *lastcoll; + int coll = 0; + + bzero(&b, sizeof(b)); + b.pfrb_type = PFRB_TABLES; + for (;;) { + pfr_buf_grow(&b, b.pfrb_size); + b.pfrb_size = b.pfrb_msize; + if (pfr_get_tables(NULL, b.pfrb_caddr, + &b.pfrb_size, PFR_FLAG_ALLRSETS)) + err(1, "pfr_get_tables"); + if (b.pfrb_size <= b.pfrb_msize) + break; + } + PFRB_FOREACH(t, &b) { + if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE)) + continue; + if (filter != NULL && strcmp(filter, t->pfrt_name)) + continue; + if (!t->pfrt_anchor[0]) + name = t->pfrt_name; + else if (name != NULL && !strcmp(name, t->pfrt_name)) { + coll++; + lastcoll = name; + name = NULL; + } + } + if (coll == 1) + warnx("warning: namespace collision with <%s> global table.", + lastcoll); + else if (coll > 1) + warnx("warning: namespace collisions with %d global tables.", + coll); + pfr_buf_clear(&b); +} + +void +xprintf(int opts, const char *fmt, ...) +{ + va_list args; + + if (opts & PF_OPT_QUIET) + return; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + + if (opts & PF_OPT_DUMMYACTION) + fprintf(stderr, " (dummy).\n"); + else if (opts & PF_OPT_NOACTION) + fprintf(stderr, " (syntax only).\n"); + else + fprintf(stderr, ".\n"); +} + + +/* interface stuff */ + +int +pfctl_show_ifaces(const char *filter, int opts) +{ + struct pfr_buffer b; + struct pfi_kif *p; + int i = 0; + + bzero(&b, sizeof(b)); + b.pfrb_type = PFRB_IFACES; + for (;;) { + pfr_buf_grow(&b, b.pfrb_size); + b.pfrb_size = b.pfrb_msize; + if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) { + radix_perror(); + return (1); + } + if (b.pfrb_size <= b.pfrb_msize) + break; + i++; + } + if (opts & PF_OPT_SHOWALL) + pfctl_print_title("INTERFACES:"); + PFRB_FOREACH(p, &b) + print_iface(p, opts); + return (0); +} + +void +print_iface(struct pfi_kif *p, int opts) +{ + time_t tzero = p->pfik_tzero; + int i, af, dir, act; + + printf("%s", p->pfik_name); + if (opts & PF_OPT_VERBOSE) { + if (p->pfik_flags & PFI_IFLAG_SKIP) + printf(" (skip)"); + } + printf("\n"); + + if (!(opts & PF_OPT_VERBOSE2)) + return; + printf("\tCleared: %s", ctime(&tzero)); + printf("\tReferences: %-18d\n", p->pfik_rulerefs); + for (i = 0; i < 8; i++) { + af = (i>>2) & 1; + dir = (i>>1) &1; + act = i & 1; + printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", + istats_text[af][dir][act], + (unsigned long long)p->pfik_packets[af][dir][act], + (unsigned long long)p->pfik_bytes[af][dir][act]); + } +} diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h new file mode 100644 index 00000000..3984522e --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-data.h @@ -0,0 +1,25 @@ +/* generated by userspace-header-gen.py */ +/* + * NOTE: MANUALLY CHANGED. + * YACC needs a special treatment for some variables. They are commented here. + */ +#include <rtems/linkersets.h> +/* parse.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlydebug); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlynerrs); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlyerrflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int pfctlychar); +/* RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlyval); */ +/* RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern YYSTYPE pfctlylval); */ +/* pfctl_altq.c */ +/* pfctl.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int loadopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int altqsupport); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, extern int dev); +/* pfctl_optimize.c */ +/* pfctl_osfp.c */ +/* pfctl_parser.c */ +/* pfctl_qstats.c */ +/* pfctl_radix.c */ +/* pfctl_table.c */ +/* pf_print_state.c */ diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h new file mode 100644 index 00000000..4e815fee --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-namespace.h @@ -0,0 +1,262 @@ +/* generated by userspace-header-gen.py */ +/* parse.c */ +#define pfctlydebug _bsd_pfctl_pfctlydebug +#define pfctlynerrs _bsd_pfctl_pfctlynerrs +#define pfctlyerrflag _bsd_pfctl_pfctlyerrflag +#define pfctlychar _bsd_pfctl_pfctlychar +#define pfctlyval _bsd_pfctl_pfctlyval +#define pfctlylval _bsd_pfctl_pfctlylval +#define pfctlyparse _bsd_pfctl_pfctlyparse +#define rt_tableid_max _bsd_pfctl_rt_tableid_max +#define pfctl_load_anchors _bsd_pfctl_pfctl_load_anchors +#define parseport _bsd_pfctl_parseport +#define parseicmpspec _bsd_pfctl_parseicmpspec +#define rule_label _bsd_pfctl_rule_label +#define getservice _bsd_pfctl_getservice +#define atoul _bsd_pfctl_atoul +#define invalid_redirect _bsd_pfctl_invalid_redirect +#define remove_invalid_hosts _bsd_pfctl_remove_invalid_hosts +#define decide_address_family _bsd_pfctl_decide_address_family +#define mv_rules _bsd_pfctl_mv_rules +#define symget _bsd_pfctl_symget +#define pfctl_cmdline_symset _bsd_pfctl_pfctl_cmdline_symset +#define symset _bsd_pfctl_symset +#define parse_config _bsd_pfctl_parse_config +#define popfile _bsd_pfctl_popfile +#define pushfile _bsd_pfctl_pushfile +#define check_file_secrecy _bsd_pfctl_check_file_secrecy +#define pfctlylex _bsd_pfctl_pfctlylex +#define findeol _bsd_pfctl_findeol +#define lungetc _bsd_pfctl_lungetc +#define lgetc _bsd_pfctl_lgetc +#define lookup _bsd_pfctl_lookup +#define kw_cmp _bsd_pfctl_kw_cmp +#define check_rulestate _bsd_pfctl_check_rulestate +#define expand_skip_interface _bsd_pfctl_expand_skip_interface +#define expand_rule _bsd_pfctl_expand_rule +#define expand_queue _bsd_pfctl_expand_queue +#define expand_altq _bsd_pfctl_expand_altq +#define expand_label _bsd_pfctl_expand_label +#define expand_label_nr _bsd_pfctl_expand_label_nr +#define expand_label_proto _bsd_pfctl_expand_label_proto +#define expand_label_port _bsd_pfctl_expand_label_port +#define expand_label_addr _bsd_pfctl_expand_label_addr +#define expand_label_if _bsd_pfctl_expand_label_if +#define expand_label_str _bsd_pfctl_expand_label_str +#define process_tabledef _bsd_pfctl_process_tabledef +#define rdr_consistent _bsd_pfctl_rdr_consistent +#define nat_consistent _bsd_pfctl_nat_consistent +#define filter_consistent _bsd_pfctl_filter_consistent +#define rule_consistent _bsd_pfctl_rule_consistent +#define disallow_alias _bsd_pfctl_disallow_alias +#define disallow_urpf_failed _bsd_pfctl_disallow_urpf_failed +#define disallow_table _bsd_pfctl_disallow_table +#define pfctlyerror _bsd_pfctl_pfctlyerror +/* pfctl_altq.c */ +#define print_fairq_sc _bsd_pfctl_print_fairq_sc +#define print_hfsc_sc _bsd_pfctl_print_hfsc_sc +#define eval_bwspec _bsd_pfctl_eval_bwspec +#define eval_queue_opts _bsd_pfctl_eval_queue_opts +#define getifmtu _bsd_pfctl_getifmtu +#define getifspeed _bsd_pfctl_getifspeed +#define rate2str _bsd_pfctl_rate2str +#define eval_pfqueue _bsd_pfctl_eval_pfqueue +#define check_commit_altq _bsd_pfctl_check_commit_altq +#define eval_pfaltq _bsd_pfctl_eval_pfaltq +#define print_queue _bsd_pfctl_print_queue +#define print_altq _bsd_pfctl_print_altq +#define qname_to_qid _bsd_pfctl_qname_to_qid +#define qname_to_pfaltq _bsd_pfctl_qname_to_pfaltq +#define pfaltq_lookup _bsd_pfctl_pfaltq_lookup +#define pfaltq_store _bsd_pfctl_pfaltq_store +/* pfctl.c */ +#define loadopt _bsd_pfctl_loadopt +#define altqsupport _bsd_pfctl_altqsupport +#define dev _bsd_pfctl_dev +#define pfctl_lookup_option _bsd_pfctl_pfctl_lookup_option +#define pfctl_show_anchors _bsd_pfctl_pfctl_show_anchors +#define pfctl_test_altqsupport _bsd_pfctl_pfctl_test_altqsupport +#define pfctl_debug _bsd_pfctl_pfctl_debug +#define pfctl_set_interface_flags _bsd_pfctl_pfctl_set_interface_flags +#define pfctl_load_debug _bsd_pfctl_pfctl_load_debug +#define pfctl_set_debug _bsd_pfctl_pfctl_set_debug +#define pfctl_load_hostid _bsd_pfctl_pfctl_load_hostid +#define pfctl_set_hostid _bsd_pfctl_pfctl_set_hostid +#define pfctl_load_logif _bsd_pfctl_pfctl_load_logif +#define pfctl_set_logif _bsd_pfctl_pfctl_set_logif +#define pfctl_set_optimization _bsd_pfctl_pfctl_set_optimization +#define pfctl_load_timeout _bsd_pfctl_pfctl_load_timeout +#define pfctl_set_timeout _bsd_pfctl_pfctl_set_timeout +#define pfctl_load_limit _bsd_pfctl_pfctl_load_limit +#define pfctl_set_limit _bsd_pfctl_pfctl_set_limit +#define pfctl_load_options _bsd_pfctl_pfctl_load_options +#define pfctl_init_options _bsd_pfctl_pfctl_init_options +#define pfctl_fopen _bsd_pfctl_pfctl_fopen +#define pfctl_rules _bsd_pfctl_pfctl_rules +#define pfctl_add_altq _bsd_pfctl_pfctl_add_altq +#define pfctl_load_rule _bsd_pfctl_pfctl_load_rule +#define pfctl_load_ruleset _bsd_pfctl_pfctl_load_ruleset +#define pfctl_ruleset_trans _bsd_pfctl_pfctl_ruleset_trans +#define pfctl_add_rule _bsd_pfctl_pfctl_add_rule +#define pfctl_add_pool _bsd_pfctl_pfctl_add_pool +#define pfctl_show_limits _bsd_pfctl_pfctl_show_limits +#define pfctl_show_timeouts _bsd_pfctl_pfctl_show_timeouts +#define pfctl_show_status _bsd_pfctl_pfctl_show_status +#define pfctl_show_states _bsd_pfctl_pfctl_show_states +#define pfctl_show_src_nodes _bsd_pfctl_pfctl_show_src_nodes +#define pfctl_show_nat _bsd_pfctl_pfctl_show_nat +#define pfctl_show_rules _bsd_pfctl_pfctl_show_rules +#define pfctl_print_title _bsd_pfctl_pfctl_print_title +#define pfctl_print_rule_counters _bsd_pfctl_pfctl_print_rule_counters +#define pfctl_clear_pool _bsd_pfctl_pfctl_clear_pool +#define pfctl_move_pool _bsd_pfctl_pfctl_move_pool +#define pfctl_get_pool _bsd_pfctl_pfctl_get_pool +#define pfctl_id_kill_states _bsd_pfctl_pfctl_id_kill_states +#define pfctl_label_kill_states _bsd_pfctl_pfctl_label_kill_states +#define pfctl_net_kill_states _bsd_pfctl_pfctl_net_kill_states +#define pfctl_kill_src_nodes _bsd_pfctl_pfctl_kill_src_nodes +#define pfctl_addrprefix _bsd_pfctl_pfctl_addrprefix +#define pfctl_clear_states _bsd_pfctl_pfctl_clear_states +#define pfctl_clear_src_nodes _bsd_pfctl_pfctl_clear_src_nodes +#define pfctl_clear_altq _bsd_pfctl_pfctl_clear_altq +#define pfctl_clear_nat _bsd_pfctl_pfctl_clear_nat +#define pfctl_clear_rules _bsd_pfctl_pfctl_clear_rules +#define pfctl_clear_interface_flags _bsd_pfctl_pfctl_clear_interface_flags +#define pfctl_clear_stats _bsd_pfctl_pfctl_clear_stats +#define pfctl_disable _bsd_pfctl_pfctl_disable +#define pfctl_enable _bsd_pfctl_pfctl_enable +#define usage _bsd_pfctl_usage +/* pfctl_optimize.c */ +#define superblock_free _bsd_pfctl_superblock_free +#define exclude_supersets _bsd_pfctl_exclude_supersets +#define comparable_rule _bsd_pfctl_comparable_rule +#define interface_group _bsd_pfctl_interface_group +#define superblock_inclusive _bsd_pfctl_superblock_inclusive +#define rules_combineable _bsd_pfctl_rules_combineable +#define addrs_combineable _bsd_pfctl_addrs_combineable +#define addrs_equal _bsd_pfctl_addrs_equal +#define construct_superblocks _bsd_pfctl_construct_superblocks +#define pf_opt_create_table _bsd_pfctl_pf_opt_create_table +#define add_opt_table _bsd_pfctl_add_opt_table +#define skip_init _bsd_pfctl_skip_init +#define skip_cmp_src_port _bsd_pfctl_skip_cmp_src_port +#define skip_cmp_src_addr _bsd_pfctl_skip_cmp_src_addr +#define skip_cmp_proto _bsd_pfctl_skip_cmp_proto +#define skip_cmp_ifp _bsd_pfctl_skip_cmp_ifp +#define skip_cmp_dst_port _bsd_pfctl_skip_cmp_dst_port +#define skip_cmp_dst_addr _bsd_pfctl_skip_cmp_dst_addr +#define skip_cmp_dir _bsd_pfctl_skip_cmp_dir +#define skip_cmp_af _bsd_pfctl_skip_cmp_af +#define remove_from_skipsteps _bsd_pfctl_remove_from_skipsteps +#define skip_append _bsd_pfctl_skip_append +#define skip_compare _bsd_pfctl_skip_compare +#define load_feedback_profile _bsd_pfctl_load_feedback_profile +#define block_feedback _bsd_pfctl_block_feedback +#define reorder_rules _bsd_pfctl_reorder_rules +#define combine_rules _bsd_pfctl_combine_rules +#define remove_identical_rules _bsd_pfctl_remove_identical_rules +#define optimize_superblock _bsd_pfctl_optimize_superblock +#define pfctl_optimize_ruleset _bsd_pfctl_pfctl_optimize_ruleset +/* pfctl_osfp.c */ +#define print_ioctl _bsd_pfctl_print_ioctl +#define get_field _bsd_pfctl_get_field +#define get_tcpopts _bsd_pfctl_get_tcpopts +#define get_str _bsd_pfctl_get_str +#define get_int _bsd_pfctl_get_int +#define sort_name_list _bsd_pfctl_sort_name_list +#define print_name_list _bsd_pfctl_print_name_list +#define fingerprint_name_entry _bsd_pfctl_fingerprint_name_entry +#define import_fingerprint _bsd_pfctl_import_fingerprint +#define add_fingerprint _bsd_pfctl_add_fingerprint +#define lookup_name_list _bsd_pfctl_lookup_name_list +#define pfctl_lookup_fingerprint _bsd_pfctl_pfctl_lookup_fingerprint +#define pfctl_get_fingerprint _bsd_pfctl_pfctl_get_fingerprint +#define pfctl_show_fingerprints _bsd_pfctl_pfctl_show_fingerprints +#define pfctl_load_fingerprints _bsd_pfctl_pfctl_load_fingerprints +#define pfctl_flush_my_fingerprints _bsd_pfctl_pfctl_flush_my_fingerprints +#define pfctl_clear_fingerprints _bsd_pfctl_pfctl_clear_fingerprints +#define pfctl_file_fingerprints _bsd_pfctl_pfctl_file_fingerprints +/* pfctl_parser.c */ +#define pfctl_trans _bsd_pfctl_pfctl_trans +#define pfctl_get_ticket _bsd_pfctl_pfctl_get_ticket +#define pfctl_add_trans _bsd_pfctl_pfctl_add_trans +#define append_addr_host _bsd_pfctl_append_addr_host +#define append_addr _bsd_pfctl_append_addr +#define host_dns _bsd_pfctl_host_dns +#define host_v6 _bsd_pfctl_host_v6 +#define host_v4 _bsd_pfctl_host_v4 +#define host_if _bsd_pfctl_host_if +#define host _bsd_pfctl_host +#define ifa_skip_if _bsd_pfctl_ifa_skip_if +#define ifa_lookup _bsd_pfctl_ifa_lookup +#define ifa_grouplookup _bsd_pfctl_ifa_grouplookup +#define ifa_exists _bsd_pfctl_ifa_exists +#define get_socket_domain _bsd_pfctl_get_socket_domain +#define ifa_load _bsd_pfctl_ifa_load +#define check_netmask _bsd_pfctl_check_netmask +#define set_ipmask _bsd_pfctl_set_ipmask +#define parse_flags _bsd_pfctl_parse_flags +#define print_tabledef _bsd_pfctl_print_tabledef +#define print_rule _bsd_pfctl_print_rule +#define print_src_node _bsd_pfctl_print_src_node +#define print_status _bsd_pfctl_print_status +#define print_pool _bsd_pfctl_print_pool +#define print_fromto _bsd_pfctl_print_fromto +#define print_flags _bsd_pfctl_print_flags +#define print_ugid _bsd_pfctl_print_ugid +#define print_port _bsd_pfctl_print_port +#define print_op _bsd_pfctl_print_op +#define geticmpcodebyname _bsd_pfctl_geticmpcodebyname +#define geticmpcodebynumber _bsd_pfctl_geticmpcodebynumber +#define geticmptypebyname _bsd_pfctl_geticmptypebyname +#define geticmptypebynumber _bsd_pfctl_geticmptypebynumber +/* pfctl_qstats.c */ +#define update_avg _bsd_pfctl_update_avg +#define pfctl_free_altq_node _bsd_pfctl_pfctl_free_altq_node +#define print_fairqstats _bsd_pfctl_print_fairqstats +#define print_hfscstats _bsd_pfctl_print_hfscstats +#define print_priqstats _bsd_pfctl_print_priqstats +#define print_codelstats _bsd_pfctl_print_codelstats +#define print_cbqstats _bsd_pfctl_print_cbqstats +#define pfctl_print_altq_nodestat _bsd_pfctl_pfctl_print_altq_nodestat +#define pfctl_print_altq_node _bsd_pfctl_pfctl_print_altq_node +#define pfctl_find_altq_node _bsd_pfctl_pfctl_find_altq_node +#define pfctl_insert_altq_node _bsd_pfctl_pfctl_insert_altq_node +#define pfctl_update_qstats _bsd_pfctl_pfctl_update_qstats +#define pfctl_show_altq _bsd_pfctl_pfctl_show_altq +/* pfctl_radix.c */ +#define pfr_strerror _bsd_pfctl_pfr_strerror +#define pfr_buf_load _bsd_pfctl_pfr_buf_load +#define pfr_buf_clear _bsd_pfctl_pfr_buf_clear +#define pfr_buf_grow _bsd_pfctl_pfr_buf_grow +#define pfr_buf_next _bsd_pfctl_pfr_buf_next +#define pfr_buf_add _bsd_pfctl_pfr_buf_add +#define pfi_get_ifaces _bsd_pfctl_pfi_get_ifaces +#define pfr_ina_define _bsd_pfctl_pfr_ina_define +#define pfr_tst_addrs _bsd_pfctl_pfr_tst_addrs +#define pfr_clr_tstats _bsd_pfctl_pfr_clr_tstats +#define pfr_get_astats _bsd_pfctl_pfr_get_astats +#define pfr_get_addrs _bsd_pfctl_pfr_get_addrs +#define pfr_set_addrs _bsd_pfctl_pfr_set_addrs +#define pfr_del_addrs _bsd_pfctl_pfr_del_addrs +#define pfr_add_addrs _bsd_pfctl_pfr_add_addrs +#define pfr_clr_addrs _bsd_pfctl_pfr_clr_addrs +#define pfr_get_tstats _bsd_pfctl_pfr_get_tstats +#define pfr_get_tables _bsd_pfctl_pfr_get_tables +#define pfr_del_tables _bsd_pfctl_pfr_del_tables +#define pfr_add_tables _bsd_pfctl_pfr_add_tables +#define pfr_clr_tables _bsd_pfctl_pfr_clr_tables +/* pfctl_table.c */ +#define pfctl_show_ifaces _bsd_pfctl_pfctl_show_ifaces +#define warn_namespace_collision _bsd_pfctl_warn_namespace_collision +#define pfctl_define_table _bsd_pfctl_pfctl_define_table +#define pfctl_command_tables _bsd_pfctl_pfctl_command_tables +#define pfctl_show_tables _bsd_pfctl_pfctl_show_tables +#define pfctl_clear_tables _bsd_pfctl_pfctl_clear_tables +/* pf_print_state.c */ +#define unmask _bsd_pfctl_unmask +#define print_state _bsd_pfctl_print_state +#define print_seq _bsd_pfctl_print_seq +#define print_host _bsd_pfctl_print_host +#define print_name _bsd_pfctl_print_name +#define print_addr _bsd_pfctl_print_addr diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h new file mode 100644 index 00000000..ed13a43a --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-parse-data.h @@ -0,0 +1,36 @@ +/* generated by userspace-header-gen.py */ +/* + * NOTE: MANUALLY CHANGED. + * YACC needs a special treatment for some variables. They are commented here. + */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* parse.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pfctl *pf); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int debug); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int rulestate); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int16_t returnicmpdefault); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int16_t returnicmp6default); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int blockpolicy); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int require_order); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int default_statelock); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct files files); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct file *file); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct symhead symhead); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_queue *queues); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct filter_opts filter_opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct antispoof_opts antispoof_opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct scrub_opts scrub_opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct queue_opts queue_opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct table_opts table_opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pool_opts pool_opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct codel_opts codel_opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_hfsc_opts hfsc_opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_fairq_opts fairq_opts); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_state_opt *keep_state_defaults); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct loadanchorshead loadanchorshead); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *parsebuf); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int parseindex); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pushback_index); +/* RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static YYSTACKDATA yystack); */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char pushback_buffer[]); diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h new file mode 100644 index 00000000..33366e0d --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pf_print_state-data.h @@ -0,0 +1,4 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* pf_print_state.c */ diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h new file mode 100644 index 00000000..65956d58 --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl-data.h @@ -0,0 +1,22 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* pfctl.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pf_anchor_global pf_anchors); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pf_anchor pf_main_anchor); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *clearopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *rulesopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *showopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *debugopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *anchoropt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *optiopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *pf_device); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *ifaceopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *tableopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *tblcmdopt); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int src_node_killers); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int state_killers); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int first_title); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int labels); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *src_node_kill[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char *state_kill[]); diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h new file mode 100644 index 00000000..6a032132 --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_altq-data.h @@ -0,0 +1,9 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* pfctl_altq.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct altqs altqs); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc rtsc); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct gen_sc lssc); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char r2sbuf[8][16]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int idx); diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h new file mode 100644 index 00000000..09598a79 --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_optimize-data.h @@ -0,0 +1,11 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* pfctl_optimize.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pf_rule_field pf_rule_desc[70]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int (*skip_comparitors[8])(struct pf_rule *, struct pf_rule *)); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *skip_comparitors_names[8]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct pfr_buffer table_buffer); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int table_identifier); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int add_opt_tablenum); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int pf_opt_create_tablenum); diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h new file mode 100644 index 00000000..53bf09c4 --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_osfp-data.h @@ -0,0 +1,7 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* pfctl_osfp.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct name_list classes); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int class_count); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static int fingerprint_count); diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h new file mode 100644 index 00000000..bb8832ac --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_parser-data.h @@ -0,0 +1,5 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* pfctl_parser.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static struct node_host *iftab); diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h new file mode 100644 index 00000000..0ee02a9e --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_qstats-data.h @@ -0,0 +1,5 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* pfctl_qstats.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static u_int32_t last_ticket); diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h new file mode 100644 index 00000000..b2a7340e --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_radix-data.h @@ -0,0 +1,4 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* pfctl_radix.c */ diff --git a/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h new file mode 100644 index 00000000..db4e915b --- /dev/null +++ b/freebsd/sbin/pfctl/rtems-bsd-pfctl-pfctl_table-data.h @@ -0,0 +1,6 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-pfctl-data.h" +/* pfctl_table.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *stats_text[2][3]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_pfctl, static char const *istats_text[2][2][2]); diff --git a/freebsd/sbin/ping/ping.c b/freebsd/sbin/ping/ping.c index ad5515ab..f0d1f7ce 100644 --- a/freebsd/sbin/ping/ping.c +++ b/freebsd/sbin/ping/ping.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ping-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -43,21 +47,6 @@ static const char copyright[] = static char sccsid[] = "@(#)ping.c 8.1 (Berkeley) 6/5/93"; #endif /* not lint */ #endif -#ifdef __rtems__ -#define __need_getopt_newlib -#include <getopt.h> -#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP -#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP -#include <machine/rtems-bsd-program.h> -#include <machine/rtems-bsd-commands.h> -#endif /* __rtems__ */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -79,7 +68,14 @@ __FBSDID("$FreeBSD$"); * This program has to run SUID to ROOT to access the ICMP socket. */ +#ifdef __rtems__ +#define __need_getopt_newlib +#include <getopt.h> +#include <machine/rtems-bsd-program.h> +#include <machine/rtems-bsd-commands.h> +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> /* NB: we rely on this for <sys/types.h> */ +#include <sys/capsicum.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <sys/time.h> @@ -92,6 +88,11 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip_var.h> #include <arpa/inet.h> +#ifdef HAVE_LIBCASPER +#include <libcasper.h> +#include <casper/cap_dns.h> +#endif + #ifdef IPSEC #include <netipsec/ipsec.h> #endif /*IPSEC*/ @@ -107,6 +108,9 @@ __FBSDID("$FreeBSD$"); #include <string.h> #include <sysexits.h> #include <unistd.h> +#ifdef __rtems__ +#include "rtems-bsd-ping-ping-data.h" +#endif /* __rtems__ */ #define INADDR_LEN ((int)sizeof(in_addr_t)) #define TIMEVAL_LEN ((int)sizeof(struct tv32)) @@ -168,20 +172,20 @@ static int options; * to 8192 for complete accuracy... */ #define MAX_DUP_CHK (8 * 128) -static const int mx_dup_ck = MAX_DUP_CHK; static char rcvd_tbl[MAX_DUP_CHK / 8]; static struct sockaddr_in whereto; /* who to ping */ static int datalen = DEFDATALEN; static int maxpayload; -static int s; /* socket file descriptor */ +static int ssend; /* send socket file descriptor */ +static int srecv; /* receive socket file descriptor */ static u_char outpackhdr[IP_MAXPACKET], *outpack; -static const char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */ -static const char BSPACE = '\b'; /* characters written for flood */ +static const char BBELL = '\a'; /* characters written for MISSED and AUDIBLE */ +static const char BSPACE = '\b'; /* characters written for flood */ static const char DOT = '.'; static char *hostname; static char *shostname; -static int ident; /* process id to identify our packets */ +static int ident; /* process id to identify our packets */ static int uid; /* cached uid for micro-optimization */ static u_char icmp_type = ICMP_ECHO; static u_char icmp_type_rsp = ICMP_ECHOREPLY; @@ -190,31 +194,49 @@ static int send_len; /* counters */ static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ -static long npackets; /* max packets to transmit */ -static long nreceived; /* # of packets we got back */ -static long nrepeats; /* number of duplicates */ -static long ntransmitted; /* sequence # for outbound packets = #sent */ +#ifndef __rtems__ +static long npackets; /* max packets to transmit */ +#else /* __rtems__ */ +static long npackets = 3; /* max packets to transmit */ +#endif /* __rtems__ */ +static long nreceived; /* # of packets we got back */ +static long nrepeats; /* number of duplicates */ +static long ntransmitted; /* sequence # for outbound packets = #sent */ static long snpackets; /* max packets to transmit in one sweep */ -static long sntransmitted; /* # of packets we sent in this sweep */ -static int sweepmax; /* max value of payload in sweep */ -static int sweepmin = 0; /* start value of payload in sweep */ -static int sweepincr = 1; /* payload increment in sweep */ -static int interval = 1000; /* interval between packets, ms */ -static int waittime = MAXWAIT; /* timeout for each packet */ -static long nrcvtimeout = 0; /* # of packets we got back after waittime */ +static long sntransmitted; /* # of packets we sent in this sweep */ +static int sweepmax; /* max value of payload in sweep */ +static int sweepmin = 0; /* start value of payload in sweep */ +static int sweepincr = 1; /* payload increment in sweep */ +static int interval = 1000; /* interval between packets, ms */ +static int waittime = MAXWAIT; /* timeout for each packet */ +static long nrcvtimeout = 0; /* # of packets we got back after waittime */ /* timing */ -static int timing; /* flag to do timing */ +static int timing; /* flag to do timing */ static double tmin = 999999999.0; /* minimum round trip time */ -static double tmax = 0.0; /* maximum round trip time */ -static double tsum = 0.0; /* sum of all times, for doing average */ -static double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ +static double tmax = 0.0; /* maximum round trip time */ +static double tsum = 0.0; /* sum of all times, for doing average */ +static double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ -static volatile sig_atomic_t finish_up; /* nonzero if we've been told to finish up */ +/* nonzero if we've been told to finish up */ +static volatile sig_atomic_t finish_up; +#ifndef __rtems__ static volatile sig_atomic_t siginfo_p; +#endif /* __rtems__ */ + +#ifdef HAVE_LIBCASPER +static cap_channel_t *capdns; +#endif +#ifdef __rtems__ +static u_char packet[IP_MAXPACKET] __aligned(4); +static char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN]; +#endif /* __rtems__ */ static void fill(char *, char *); static u_short in_cksum(u_short *, int); +#ifdef HAVE_LIBCASPER +static cap_channel_t *capdns_setup(void); +#endif static void check_status(void); static void finish(void) __dead2; static void pinger(void); @@ -232,55 +254,32 @@ static void tvsub(struct timeval *, const struct timeval *); static void usage(void) __dead2; #ifdef __rtems__ -static int main(int argc, char **argv); +static int main(int argc, char *argv[]); + +RTEMS_LINKER_RWSET(bsd_prog_ping, char); -int rtems_bsd_command_ping(int argc, char *argv[]) +int +rtems_bsd_command_ping(int argc, char *argv[]) { int exit_code; + void *data_begin; + size_t data_size; - rtems_bsd_program_lock(); - - memset(&rcvd_tbl[0], 0, sizeof(rcvd_tbl)); - s = -1; - memset(&outpackhdr[0], 0, sizeof(outpackhdr)); - icmp_type = ICMP_ECHO; - icmp_type_rsp = ICMP_ECHOREPLY; - phdr_len = 0; - nmissedmax = 0; - npackets = 3; - nreceived = 0; - nrepeats = 0; - ntransmitted = 0; - snpackets = 0; - sntransmitted = 0; - sweepmax = 0; - sweepmin = 0; - sweepincr = 1; - interval = 1000; - waittime = MAXWAIT; - nrcvtimeout = 0; - timing = 0; - tmin = 999999999.0; - tmax = 0.0; - tsum = 0.0; - tsumsq = 0.0; - finish_up = 0; - siginfo_p = 0; - - exit_code = rtems_bsd_program_call_main("ping", main, argc, argv); + data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_ping); + data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_ping); + rtems_bsd_program_lock(); + exit_code = rtems_bsd_program_call_main_with_data_restore("ping", + main, argc, argv, data_begin, data_size); rtems_bsd_program_unlock(); - close(s); - return exit_code; } -#endif /* __rtems__ */ int -#ifndef __rtems__ -main(int argc, char *const *argv) -#else /* __rtems__ */ main(int argc, char **argv) +#else /* __rtems__ */ +int +main(int argc, char *const *argv) #endif /* __rtems__ */ { struct sockaddr_in from, sock_in; @@ -289,13 +288,14 @@ main(int argc, char **argv) struct iovec iov; struct ip *ip; struct msghdr msg; +#ifndef __rtems__ struct sigaction si_sa; +#endif /* __rtems__ */ size_t sz; #ifndef __rtems__ u_char *datap, packet[IP_MAXPACKET] __aligned(4); #else /* __rtems__ */ u_char *datap; - static u_char packet[IP_MAXPACKET] __aligned(4); #endif /* __rtems__ */ char *ep, *source, *target, *payload; struct hostent *hp; @@ -305,19 +305,23 @@ main(int argc, char **argv) struct sockaddr_in *to; double t; u_long alarmtimeout, ultmp; - int almost_done, ch, df, hold, i, icmp_len, mib[4], preload, sockerrno, - tos, ttl; + int almost_done, ch, df, hold, i, icmp_len, mib[4], preload; + int ssend_errno, srecv_errno, tos, ttl; char ctrl[CMSG_SPACE(sizeof(struct timeval))]; #ifndef __rtems__ char hnamebuf[MAXHOSTNAMELEN], snamebuf[MAXHOSTNAMELEN]; -#else /* __rtems__ */ - static char hnamebuf[MAXHOSTNAMELEN]; - static char snamebuf[MAXHOSTNAMELEN]; #endif /* __rtems__ */ #ifdef IP_OPTIONS char rspace[MAX_IPOPTLEN]; /* record route space */ #endif unsigned char loop, mttl; + + payload = source = NULL; +#ifdef IPSEC_POLICY_IPSEC + policy_in = policy_out = NULL; +#endif + cap_rights_t rights; + bool cansandbox; #ifdef __rtems__ struct getopt_data getopt_data; memset(&getopt_data, 0, sizeof(getopt_data)); @@ -328,22 +332,38 @@ main(int argc, char **argv) #define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data) #endif /* __rtems__ */ - payload = source = NULL; -#ifdef IPSEC_POLICY_IPSEC - policy_in = policy_out = NULL; -#endif - /* * Do the stuff that we need root priv's for *first*, and * then drop our setuid bit. Save error reporting for * after arg parsing. + * + * Historicaly ping was using one socket 's' for sending and for + * receiving. After capsicum(4) related changes we use two + * sockets. It was done for special ping use case - when user + * issue ping on multicast or broadcast address replies come + * from different addresses, not from the address we + * connect(2)'ed to, and send socket do not receive those + * packets. */ - s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); - sockerrno = errno; + ssend = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + ssend_errno = errno; + srecv = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + srecv_errno = errno; - setuid(getuid()); + if (setuid(getuid()) != 0) + err(EX_NOPERM, "setuid() failed"); uid = getuid(); + if (ssend < 0) { + errno = ssend_errno; + err(EX_OSERR, "ssend socket"); + } + + if (srecv < 0) { + errno = srecv_errno; + err(EX_OSERR, "srecv socket"); + } + alarmtimeout = df = preload = tos = 0; outpack = outpackhdr + sizeof(struct ip); @@ -612,13 +632,22 @@ main(int argc, char **argv) if (options & F_PINGFILLED) { fill((char *)datap, payload); } +#ifdef HAVE_LIBCASPER + capdns = capdns_setup(); +#endif if (source) { bzero((char *)&sock_in, sizeof(sock_in)); sock_in.sin_family = AF_INET; if (inet_aton(source, &sock_in.sin_addr) != 0) { shostname = source; } else { - hp = gethostbyname2(source, AF_INET); +#ifdef HAVE_LIBCASPER + if (capdns != NULL) + hp = cap_gethostbyname2(capdns, source, + AF_INET); + else +#endif + hp = gethostbyname2(source, AF_INET); if (!hp) errx(EX_NOHOST, "cannot resolve %s: %s", source, hstrerror(h_errno)); @@ -634,7 +663,8 @@ main(int argc, char **argv) snamebuf[sizeof(snamebuf) - 1] = '\0'; shostname = snamebuf; } - if (bind(s, (struct sockaddr *)&sock_in, sizeof sock_in) == -1) + if (bind(ssend, (struct sockaddr *)&sock_in, sizeof sock_in) == + -1) err(1, "bind"); } @@ -645,7 +675,12 @@ main(int argc, char **argv) if (inet_aton(target, &to->sin_addr) != 0) { hostname = target; } else { - hp = gethostbyname2(target, AF_INET); +#ifdef HAVE_LIBCASPER + if (capdns != NULL) + hp = cap_gethostbyname2(capdns, target, AF_INET); + else +#endif + hp = gethostbyname2(target, AF_INET); if (!hp) errx(EX_NOHOST, "cannot resolve %s: %s", target, hstrerror(h_errno)); @@ -658,6 +693,20 @@ main(int argc, char **argv) hostname = hnamebuf; } +#ifdef HAVE_LIBCASPER + /* From now on we will use only reverse DNS lookups. */ + if (capdns != NULL) { + const char *types[1]; + + types[0] = "ADDR"; + if (cap_dns_type_limit(capdns, types, 1) < 0) + err(1, "unable to limit access to system.dns service"); + } +#endif + + if (connect(ssend, (struct sockaddr *)&whereto, sizeof(whereto)) != 0) + err(1, "connect"); + if (options & F_FLOOD && options & F_INTERVAL) errx(EX_USAGE, "-f and -i: incompatible options"); @@ -678,16 +727,15 @@ main(int argc, char **argv) ident = getpid() & 0xFFFF; - if (s < 0) { - errno = sockerrno; - err(EX_OSERR, "socket"); - } hold = 1; - if (options & F_SO_DEBUG) - (void)setsockopt(s, SOL_SOCKET, SO_DEBUG, (char *)&hold, + if (options & F_SO_DEBUG) { + (void)setsockopt(ssend, SOL_SOCKET, SO_DEBUG, (char *)&hold, sizeof(hold)); + (void)setsockopt(srecv, SOL_SOCKET, SO_DEBUG, (char *)&hold, + sizeof(hold)); + } if (options & F_SO_DONTROUTE) - (void)setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, + (void)setsockopt(ssend, SOL_SOCKET, SO_DONTROUTE, (char *)&hold, sizeof(hold)); #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC @@ -697,7 +745,7 @@ main(int argc, char **argv) buf = ipsec_set_policy(policy_in, strlen(policy_in)); if (buf == NULL) errx(EX_CONFIG, "%s", ipsec_strerror()); - if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, + if (setsockopt(srecv, IPPROTO_IP, IP_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) err(EX_CONFIG, "ipsec policy cannot be configured"); @@ -708,7 +756,7 @@ main(int argc, char **argv) buf = ipsec_set_policy(policy_out, strlen(policy_out)); if (buf == NULL) errx(EX_CONFIG, "%s", ipsec_strerror()); - if (setsockopt(s, IPPROTO_IP, IP_IPSEC_POLICY, + if (setsockopt(ssend, IPPROTO_IP, IP_IPSEC_POLICY, buf, ipsec_get_policylen(buf)) < 0) err(EX_CONFIG, "ipsec policy cannot be configured"); @@ -729,17 +777,43 @@ main(int argc, char **argv) if (sysctl(mib, 4, &ttl, &sz, NULL, 0) == -1) err(1, "sysctl(net.inet.ip.ttl)"); } - setsockopt(s, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); + setsockopt(ssend, IPPROTO_IP, IP_HDRINCL, &hold, sizeof(hold)); ip->ip_v = IPVERSION; ip->ip_hl = sizeof(struct ip) >> 2; ip->ip_tos = tos; ip->ip_id = 0; - ip->ip_off = df ? IP_DF : 0; + ip->ip_off = htons(df ? IP_DF : 0); ip->ip_ttl = ttl; ip->ip_p = IPPROTO_ICMP; ip->ip_src.s_addr = source ? sock_in.sin_addr.s_addr : INADDR_ANY; ip->ip_dst = to->sin_addr; } + + if (options & F_NUMERIC) + cansandbox = true; +#ifdef HAVE_LIBCASPER + else if (capdns != NULL) + cansandbox = true; +#endif + else + cansandbox = false; + + /* + * Here we enter capability mode. Further down access to global + * namespaces (e.g filesystem) is restricted (see capsicum(4)). + * We must connect(2) our socket before this point. + */ + if (cansandbox && cap_enter() < 0 && errno != ENOSYS) + err(1, "cap_enter"); + + cap_rights_init(&rights, CAP_RECV, CAP_EVENT, CAP_SETSOCKOPT); + if (cap_rights_limit(srecv, &rights) < 0 && errno != ENOSYS) + err(1, "cap_rights_limit srecv"); + + cap_rights_init(&rights, CAP_SEND, CAP_SETSOCKOPT); + if (cap_rights_limit(ssend, &rights) < 0 && errno != ENOSYS) + err(1, "cap_rights_limit ssend"); + /* record route option */ if (options & F_RROUTE) { #ifdef IP_OPTIONS @@ -748,7 +822,7 @@ main(int argc, char **argv) rspace[IPOPT_OLEN] = sizeof(rspace) - 1; rspace[IPOPT_OFFSET] = IPOPT_MINOFF; rspace[sizeof(rspace) - 1] = IPOPT_EOL; - if (setsockopt(s, IPPROTO_IP, IP_OPTIONS, rspace, + if (setsockopt(ssend, IPPROTO_IP, IP_OPTIONS, rspace, sizeof(rspace)) < 0) err(EX_OSERR, "setsockopt IP_OPTIONS"); #else @@ -758,38 +832,38 @@ main(int argc, char **argv) } if (options & F_TTL) { - if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, + if (setsockopt(ssend, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) { err(EX_OSERR, "setsockopt IP_TTL"); } } if (options & F_NOLOOP) { - if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, + if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { err(EX_OSERR, "setsockopt IP_MULTICAST_LOOP"); } } if (options & F_MTTL) { - if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &mttl, + if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_TTL, &mttl, sizeof(mttl)) < 0) { err(EX_OSERR, "setsockopt IP_MULTICAST_TTL"); } } if (options & F_MIF) { - if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, + if (setsockopt(ssend, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, sizeof(ifaddr)) < 0) { err(EX_OSERR, "setsockopt IP_MULTICAST_IF"); } } #ifdef SO_TIMESTAMP { int on = 1; - if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0) + if (setsockopt(srecv, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)) < 0) err(EX_OSERR, "setsockopt SO_TIMESTAMP"); } #endif if (sweepmax) { - if (sweepmin >= sweepmax) - errx(EX_USAGE, "Maximum packet size must be greater than the minimum packet size"); + if (sweepmin > sweepmax) + errx(EX_USAGE, "Maximum packet size must be no less than the minimum packet size"); if (datalen != DEFDATALEN) errx(EX_USAGE, "Packet size and ping sweep are mutually exclusive"); @@ -802,7 +876,7 @@ main(int argc, char **argv) datalen = sweepmin; send_len = icmp_len + sweepmin; } - if (options & F_SWEEP && !sweepmax) + if (options & F_SWEEP && !sweepmax) errx(EX_USAGE, "Maximum sweep size must be specified"); /* @@ -818,11 +892,19 @@ main(int argc, char **argv) * as well. */ hold = IP_MAXPACKET + 128; - (void)setsockopt(s, SOL_SOCKET, SO_RCVBUF, (char *)&hold, + (void)setsockopt(srecv, SOL_SOCKET, SO_RCVBUF, (char *)&hold, sizeof(hold)); + /* CAP_SETSOCKOPT removed */ + cap_rights_init(&rights, CAP_RECV, CAP_EVENT); + if (cap_rights_limit(srecv, &rights) < 0 && errno != ENOSYS) + err(1, "cap_rights_limit srecv setsockopt"); if (uid == 0) - (void)setsockopt(s, SOL_SOCKET, SO_SNDBUF, (char *)&hold, + (void)setsockopt(ssend, SOL_SOCKET, SO_SNDBUF, (char *)&hold, sizeof(hold)); + /* CAP_SETSOCKOPT removed */ + cap_rights_init(&rights, CAP_SEND); + if (cap_rights_limit(ssend, &rights) < 0 && errno != ENOSYS) + err(1, "cap_rights_limit ssend setsockopt"); if (to->sin_family == AF_INET) { (void)printf("PING %s (%s)", hostname, @@ -832,9 +914,9 @@ main(int argc, char **argv) if (sweepmax) (void)printf(": (%d ... %d) data bytes\n", sweepmin, sweepmax); - else + else (void)printf(": %d data bytes\n", datalen); - + } else { if (sweepmax) (void)printf("PING %s: (%d ... %d) data bytes\n", @@ -867,8 +949,6 @@ main(int argc, char **argv) if (sigaction(SIGALRM, &si_sa, 0) == -1) err(EX_OSERR, "sigaction SIGALRM"); } -#else /* __rtems__ */ - (void) si_sa; #endif /* __rtems__ */ bzero(&msg, sizeof(msg)); @@ -906,10 +986,10 @@ main(int argc, char **argv) int cc, n; check_status(); - if ((unsigned)s >= FD_SETSIZE) + if ((unsigned)srecv >= FD_SETSIZE) errx(EX_OSERR, "descriptor too large"); FD_ZERO(&rfds); - FD_SET(s, &rfds); + FD_SET(srecv, &rfds); (void)gettimeofday(&now, NULL); timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; @@ -922,8 +1002,8 @@ main(int argc, char **argv) timeout.tv_sec++; } if (timeout.tv_sec < 0) - timeout.tv_sec = timeout.tv_usec = 0; - n = select(s + 1, &rfds, NULL, NULL, &timeout); + timerclear(&timeout); + n = select(srecv + 1, &rfds, NULL, NULL, &timeout); if (n < 0) continue; /* Must be EINTR. */ if (n == 1) { @@ -934,7 +1014,7 @@ main(int argc, char **argv) msg.msg_controllen = sizeof(ctrl); #endif msg.msg_namelen = sizeof(from); - if ((cc = recvmsg(s, &msg, 0)) < 0) { + if ((cc = recvmsg(srecv, &msg, 0)) < 0) { if (errno == EINTR) continue; warn("recvmsg"); @@ -960,14 +1040,14 @@ main(int argc, char **argv) } if (n == 0 || options & F_FLOOD) { if (sweepmax && sntransmitted == snpackets) { - for (i = 0; i < sweepincr ; ++i) + for (i = 0; i < sweepincr ; ++i) *datap++ = i; datalen += sweepincr; if (datalen > sweepmax) break; send_len = icmp_len + datalen; sntransmitted = 0; - } + } if (!npackets || ntransmitted < npackets) pinger(); else { @@ -1044,7 +1124,7 @@ pinger(void) icp->icmp_seq = htons(ntransmitted); icp->icmp_id = ident; /* ID */ - CLR(ntransmitted % mx_dup_ck); + CLR(ntransmitted % MAX_DUP_CHK); if ((options & F_TIME) || timing) { (void)gettimeofday(&now, NULL); @@ -1068,13 +1148,11 @@ pinger(void) if (options & F_HDRINCL) { cc += sizeof(struct ip); ip = (struct ip *)outpackhdr; - ip->ip_len = cc; + ip->ip_len = htons(cc); ip->ip_sum = in_cksum((u_short *)outpackhdr, cc); packet = outpackhdr; } - i = sendto(s, (char *)packet, cc, 0, (struct sockaddr *)&whereto, - sizeof(whereto)); - + i = send(ssend, (char *)packet, cc, 0); if (i < 0 || i != cc) { if (i < 0) { if (options & F_FLOOD && errno == ENOBUFS) { @@ -1142,7 +1220,8 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv) #endif tp = (const char *)tp + phdr_len; - if (cc - ICMP_MINLEN - phdr_len >= sizeof(tv1)) { + if ((size_t)(cc - ICMP_MINLEN - phdr_len) >= + sizeof(tv1)) { /* Copy to avoid alignment problems: */ memcpy(&tv32, tp, sizeof(tv32)); tv1.tv_sec = ntohl(tv32.tv32_sec); @@ -1162,18 +1241,18 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv) seq = ntohs(icp->icmp_seq); - if (TST(seq % mx_dup_ck)) { + if (TST(seq % MAX_DUP_CHK)) { ++nrepeats; --nreceived; dupflag = 1; } else { - SET(seq % mx_dup_ck); + SET(seq % MAX_DUP_CHK); dupflag = 0; } if (options & F_QUIET) return; - + if (options & F_WAITTIME && triptime > waittime) { ++nrcvtimeout; return; @@ -1195,7 +1274,7 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from, struct timeval *tv) if (options & F_MASK) { /* Just prentend this cast isn't ugly */ (void)printf(" mask=%s", - pr_addr(*(struct in_addr *)&(icp->icmp_mask))); + inet_ntoa(*(struct in_addr *)&(icp->icmp_mask))); } if (options & F_TIME) { (void)printf(" tso=%s", pr_ntime(icp->icmp_otime)); @@ -1437,6 +1516,7 @@ static void check_status(void) { +#ifndef __rtems__ if (siginfo_p) { siginfo_p = 0; (void)fprintf(stderr, "\r%ld/%ld packets received (%.1f%%)", @@ -1447,6 +1527,7 @@ check_status(void) tmin, tsum / (nreceived + nrepeats), tmax); (void)fprintf(stderr, "\n"); } +#endif /* __rtems__ */ } /* @@ -1697,12 +1778,21 @@ pr_addr(struct in_addr ina) struct hostent *hp; static char buf[16 + 3 + MAXHOSTNAMELEN]; - if ((options & F_NUMERIC) || - !(hp = gethostbyaddr((char *)&ina, 4, AF_INET))) + if (options & F_NUMERIC) return inet_ntoa(ina); + +#ifdef HAVE_LIBCASPER + if (capdns != NULL) + hp = cap_gethostbyaddr(capdns, (char *)&ina, 4, AF_INET); else - (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, - inet_ntoa(ina)); +#endif + hp = gethostbyaddr((char *)&ina, 4, AF_INET); + + if (hp == NULL) + return inet_ntoa(ina); + + (void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name, + inet_ntoa(ina)); return(buf); } @@ -1752,7 +1842,7 @@ fill(char *bp, char *patp) u_int ii, jj, kk; for (cp = patp; *cp; cp++) { - if (!isxdigit((unsigned char) *cp)) + if (!isxdigit((unsigned char)*cp)) errx(EX_USAGE, "patterns must be specified as hex digits"); @@ -1775,6 +1865,34 @@ fill(char *bp, char *patp) } } +#ifdef HAVE_LIBCASPER +static cap_channel_t * +capdns_setup(void) +{ + cap_channel_t *capcas, *capdnsloc; + const char *types[2]; + int families[1]; + + capcas = cap_init(); + if (capcas == NULL) + err(1, "unable to create casper process"); + capdnsloc = cap_service_open(capcas, "system.dns"); + /* Casper capability no longer needed. */ + cap_close(capcas); + if (capdnsloc == NULL) + err(1, "unable to open system.dns service"); + types[0] = "NAME"; + types[1] = "ADDR"; + if (cap_dns_type_limit(capdnsloc, types, 2) < 0) + err(1, "unable to limit access to system.dns service"); + families[0] = AF_INET; + if (cap_dns_family_limit(capdnsloc, families, 1) < 0) + err(1, "unable to limit access to system.dns service"); + + return (capdnsloc); +} +#endif /* HAVE_LIBCASPER */ + #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) #define SECOPT " [-P policy]" #else diff --git a/freebsd/sbin/ping/rtems-bsd-ping-data.h b/freebsd/sbin/ping/rtems-bsd-ping-data.h new file mode 100644 index 00000000..b89b2282 --- /dev/null +++ b/freebsd/sbin/ping/rtems-bsd-ping-data.h @@ -0,0 +1,3 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +/* ping.c */ diff --git a/freebsd/sbin/ping/rtems-bsd-ping-namespace.h b/freebsd/sbin/ping/rtems-bsd-ping-namespace.h new file mode 100644 index 00000000..a46682da --- /dev/null +++ b/freebsd/sbin/ping/rtems-bsd-ping-namespace.h @@ -0,0 +1,2 @@ +/* generated by userspace-header-gen.py */ +/* ping.c */ diff --git a/freebsd/sbin/ping/rtems-bsd-ping-ping-data.h b/freebsd/sbin/ping/rtems-bsd-ping-ping-data.h new file mode 100644 index 00000000..46bada6b --- /dev/null +++ b/freebsd/sbin/ping/rtems-bsd-ping-ping-data.h @@ -0,0 +1,43 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ping-data.h" +/* ping.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int options); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static struct sockaddr_in whereto); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int datalen); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int maxpayload); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int ssend); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int srecv); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char *outpack); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char *hostname); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char *shostname); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int ident); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int uid); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char icmp_type); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char icmp_type_rsp); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int phdr_len); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int send_len); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int nmissedmax); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int npackets); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int nreceived); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int nrepeats); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int ntransmitted); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int snpackets); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int sntransmitted); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int sweepmax); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int sweepmin); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int sweepincr); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int interval); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int waittime); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static long int nrcvtimeout); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static int timing); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static double tmin); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static double tmax); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static double tsum); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static double tsumsq); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static sig_atomic_t volatile finish_up); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char rcvd_tbl[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char outpackhdr[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static u_char packet[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char hnamebuf[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping, static char snamebuf[]); diff --git a/freebsd/sbin/ping6/ping6.c b/freebsd/sbin/ping6/ping6.c index 054cebf2..b8f565c6 100644 --- a/freebsd/sbin/ping6/ping6.c +++ b/freebsd/sbin/ping6/ping6.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-ping6-namespace.h" +#endif /* __rtems__ */ + /* $KAME: ping6.c,v 1.169 2003/07/25 06:01:47 itojun Exp $ */ /* @@ -106,20 +110,8 @@ __FBSDID("$FreeBSD$"); #ifdef __rtems__ #define __need_getopt_newlib #include <getopt.h> -#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP -#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP #include <machine/rtems-bsd-program.h> #include <machine/rtems-bsd-commands.h> - -#define USE_RFC2292BIS -#define HAVE_POLL_H #endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/uio.h> @@ -145,10 +137,8 @@ __FBSDID("$FreeBSD$"); #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sysexits.h> #include <unistd.h> -#ifdef HAVE_POLL_H -#include <poll.h> -#endif #ifdef IPSEC #include <netipsec/ah.h> @@ -156,6 +146,9 @@ __FBSDID("$FreeBSD$"); #endif #include <md5.h> +#ifdef __rtems__ +#include "rtems-bsd-ping6-ping6-data.h" +#endif /* __rtems__ */ struct tv32 { u_int32_t tv32_sec; @@ -174,6 +167,8 @@ struct tv32 { #define DEFDATALEN ICMP6ECHOTMLEN #define MAXDATALEN MAXPACKETLEN - IP6LEN - ICMP6ECHOLEN #define NROUTES 9 /* number of record route slots */ +#define MAXWAIT 10000 /* max ms to wait for response */ +#define MAXALARM (60 * 60) /* max seconds for alarm timeout */ #define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ #define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ @@ -210,7 +205,8 @@ struct tv32 { #define F_MISSED 0x800000 #define F_DONTFRAG 0x1000000 #define F_NOUSERDATA (F_NODEADDR | F_FQDN | F_FQDNOLD | F_SUPTYPES) -static u_int options; +#define F_WAITTIME 0x2000000 +u_int options; #define IN6LEN sizeof(struct in6_addr) #define SA6LEN sizeof(struct sockaddr_in6) @@ -224,45 +220,40 @@ static u_int options; * to 8192 for complete accuracy... */ #define MAX_DUP_CHK (8 * 8192) -static const int mx_dup_ck = MAX_DUP_CHK; +static int mx_dup_ck = MAX_DUP_CHK; static char rcvd_tbl[MAX_DUP_CHK / 8]; -static struct addrinfo *res; static struct sockaddr_in6 dst; /* who to ping6 */ static struct sockaddr_in6 src; /* src addr of this packet */ static socklen_t srclen; -static int datalen; -static int s; /* socket file descriptor */ +static size_t datalen = DEFDATALEN; +static int s; /* socket file descriptor */ static u_char outpack[MAXPACKETLEN]; -static const char BSPACE = '\b'; /* characters written for flood */ -static const char BBELL = '\a'; /* characters written for AUDIBLE */ -static const char DOT = '.'; +static char BSPACE = '\b'; /* characters written for flood */ +static char BBELL = '\a'; /* characters written for AUDIBLE */ +static char DOT = '.'; static char *hostname; -static int ident; /* process id to identify our packets */ -static u_int8_t nonce[8]; /* nonce field for node information */ -static int hoplimit; /* hoplimit */ -static u_char *packet; -#ifdef HAVE_POLL_H -static struct pollfd fdmaskp[1]; -#else -static fd_set *fdmaskp = NULL; -static int fdmasks; -#endif +static int ident; /* process id to identify our packets */ +static u_int8_t nonce[8]; /* nonce field for node information */ +static int hoplimit = -1; /* hoplimit */ +static u_char *packet = NULL; /* counters */ static long nmissedmax; /* max value of ntransmitted - nreceived - 1 */ -static long npackets; /* max packets to transmit */ -static long nreceived; /* # of packets we got back */ -static long nrepeats; /* number of duplicates */ -static long ntransmitted; /* sequence # for outbound packets = #sent */ -static struct timeval interval; /* interval between packets */ +static long npackets; /* max packets to transmit */ +static long nreceived; /* # of packets we got back */ +static long nrepeats; /* number of duplicates */ +static long ntransmitted; /* sequence # for outbound packets = #sent */ +static int interval = 1000; /* interval between packets in ms */ +static int waittime = MAXWAIT; /* timeout for each packet */ +static long nrcvtimeout = 0; /* # of packets we got back after waittime */ /* timing */ -static int timing; /* flag to do timing */ -static double tmin; /* minimum round trip time */ -static double tmax; /* maximum round trip time */ -static double tsum; /* sum of all times, for doing average */ -static double tsumsq; /* sum of all times squared, for std. dev. */ +static int timing; /* flag to do timing */ +static double tmin = 999999999.0; /* minimum round trip time */ +static double tmax = 0.0; /* maximum round trip time */ +static double tsum = 0.0; /* sum of all times, for doing average */ +static double tsumsq = 0.0; /* sum of all times squared, for std. dev. */ /* for node addresses */ static u_short naflags; @@ -272,22 +263,19 @@ static struct msghdr smsghdr; static struct iovec smsgiov; static char *scmsg = 0; -static volatile sig_atomic_t seenalrm; static volatile sig_atomic_t seenint; #ifdef SIGINFO static volatile sig_atomic_t seeninfo; #endif -/* For control (ancillary) data received from recvmsg() */ -static struct cmsghdr cm[CONTROLLEN]; - -static int main(int, char *[]); +#ifndef __rtems__ +int main(int, char *[]); +#endif /* __rtems__ */ static void fill(char *, char *); static int get_hoplim(struct msghdr *); static int get_pathmtu(struct msghdr *); static struct in6_pktinfo *get_rcvpktinfo(struct msghdr *); static void onsignal(int); -static void retransmit(void); static void onint(int); static size_t pingerlen(void); static int pinger(void); @@ -299,7 +287,7 @@ static void pr_nodeaddr(struct icmp6_nodeinfo *, int); static int myechoreply(const struct icmp6_hdr *); static int mynireply(const struct icmp6_nodeinfo *); static char *dnsdecode(const u_char **, const u_char *, const u_char *, - char *, size_t); + char *, size_t); static void pr_pack(u_char *, int, struct msghdr *); static void pr_exthdrs(struct msghdr *); static void pr_ip6opt(void *, size_t); @@ -308,85 +296,56 @@ static int pr_bitrange(u_int32_t, int, int); static void pr_retip(struct ip6_hdr *, u_char *); static void summary(void); static void tvsub(struct timeval *, struct timeval *); -#ifdef IPSEC -#ifdef IPSEC_POLICY_IPSEC static int setpolicy(int, char *); -#endif -#endif static char *nigroup(char *, int); static void usage(void); #ifdef __rtems__ -int rtems_bsd_command_ping6(int argc, char **argv) -{ - int exit_code; +#define USE_RFC2292BIS +#endif /* __rtems__ */ +#ifdef __rtems__ +static int main(int argc, char *argv[]); - rtems_bsd_program_lock(); +RTEMS_LINKER_RWSET(bsd_prog_ping6, char); - memset(&rcvd_tbl[0], 0, sizeof(rcvd_tbl)); - res = NULL; - srclen = 0; - datalen = DEFDATALEN; - s = -1; - memset(&outpack[0], 0, sizeof(outpack)); - hoplimit = -1; - nmissedmax = 0; - npackets = 0; - nreceived = 0; - nrepeats = 0; - ntransmitted = 0; - interval.tv_sec = 1; - interval.tv_usec = 0; - timing = 0; - tmin = 999999999.0; - tmax = 0.0; - tsum = 0.0; - tsumsq = 0.0; - naflags = 0; - scmsg = NULL; - seenalrm = 0; - seenint = 0; -#ifdef SIGINFO - seeninfo = 0; -#endif - packet = NULL; +int +rtems_bsd_command_ping6(int argc, char *argv[]) +{ + int exit_code; + void *data_begin; + size_t data_size; - exit_code = rtems_bsd_program_call_main("ping6", main, argc, argv); + data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_ping6); + data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_ping6); + rtems_bsd_program_lock(); + exit_code = rtems_bsd_program_call_main_with_data_restore("ping6", + main, argc, argv, data_begin, data_size); rtems_bsd_program_unlock(); - close(s); - free(scmsg); - free(packet); - - if (res != NULL) { - freeaddrinfo(res); - } - return exit_code; } #endif /* __rtems__ */ int main(int argc, char *argv[]) { - struct itimerval itimer; - struct sockaddr_in6 from; -#ifndef HAVE_ARC4RANDOM - struct timeval seed; -#endif -#ifdef HAVE_POLL_H - int timeout; -#else - struct timeval timeout, *tv; -#endif - struct addrinfo hints; + struct timeval last, intvl; + struct sockaddr_in6 from, *sin6; + struct addrinfo hints, *res; + struct sigaction si_sa; int cc, i; - int ch, hold, packlen, preload, optval, ret_ga; + int almost_done, ch, hold, packlen, preload, optval, error; int nig_oldmcprefix = -1; u_char *datap; char *e, *target, *ifname = NULL, *gateway = NULL; int ip6optlen = 0; struct cmsghdr *scmsgp = NULL; + /* For control (ancillary) data received from recvmsg() */ +#ifndef __rtems__ + struct cmsghdr cm[CONTROLLEN]; +#else /* __rtems__ */ + static struct cmsghdr cm[CONTROLLEN]; +#endif /* __rtems__ */ #if defined(SO_SNDBUF) && defined(SO_RCVBUF) u_long lsockbufsize; int sockbufsize = 0; @@ -400,7 +359,8 @@ main(int argc, char *argv[]) char *policy_in = NULL; char *policy_out = NULL; #endif - double intval; + double t; + u_long alarmtimeout; size_t rthlen; #ifdef IPV6_USE_MIN_MTU int mflag = 0; @@ -419,7 +379,7 @@ main(int argc, char *argv[]) memset(&smsghdr, 0, sizeof(smsghdr)); memset(&smsgiov, 0, sizeof(smsgiov)); - preload = 0; + alarmtimeout = preload = 0; datap = &outpack[ICMP6ECHOLEN + ICMP6ECHOTMLEN]; #ifndef IPSEC #define ADDOPTS @@ -431,7 +391,7 @@ main(int argc, char *argv[]) #endif /*IPSEC_POLICY_IPSEC*/ #endif while ((ch = getopt(argc, argv, - "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwW" ADDOPTS)) != -1) { + "a:b:c:DdfHg:h:I:i:l:mnNop:qrRS:s:tvwWx:X:" ADDOPTS)) != -1) { #undef ADDOPTS switch (ch) { case 'a': @@ -482,9 +442,9 @@ main(int argc, char *argv[]) errno = 0; e = NULL; lsockbufsize = strtoul(optarg, &e, 10); - sockbufsize = lsockbufsize; + sockbufsize = (int)lsockbufsize; if (errno || !*optarg || *e || - sockbufsize != lsockbufsize) + lsockbufsize > INT_MAX) errx(1, "invalid socket buffer size"); #else errx(1, @@ -533,22 +493,22 @@ main(int argc, char *argv[]) #endif break; case 'i': /* wait between sending packets */ - intval = strtod(optarg, &e); + t = strtod(optarg, &e); if (*optarg == '\0' || *e != '\0') errx(1, "illegal timing interval %s", optarg); - if (intval < 1 && getuid()) { + if (t < 1 && getuid()) { errx(1, "%s: only root may use interval < 1s", strerror(EPERM)); } - interval.tv_sec = (long)intval; - interval.tv_usec = - (long)((intval - interval.tv_sec) * 1000000); - if (interval.tv_sec < 0) + intvl.tv_sec = (long)t; + intvl.tv_usec = + (long)((t - intvl.tv_sec) * 1000000); + if (intvl.tv_sec < 0) errx(1, "illegal timing interval %s", optarg); /* less than 1/hz does not make sense */ - if (interval.tv_sec == 0 && interval.tv_usec < 1) { + if (intvl.tv_sec == 0 && intvl.tv_usec < 1) { warnx("too small interval, raised to .000001"); - interval.tv_usec = 1; + intvl.tv_usec = 1; } options |= F_INTERVAL; break; @@ -599,10 +559,10 @@ main(int argc, char *argv[]) hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; - ret_ga = getaddrinfo(optarg, NULL, &hints, &res); - if (ret_ga) { + error = getaddrinfo(optarg, NULL, &hints, &res); + if (error) { errx(1, "invalid source address: %s", - gai_strerror(ret_ga)); + gai_strerror(error)); } /* * res->ai_family must be AF_INET6 and res->ai_addrlen @@ -611,7 +571,6 @@ main(int argc, char *argv[]) memcpy(&src, res->ai_addr, res->ai_addrlen); srclen = res->ai_addrlen; freeaddrinfo(res); - res = NULL; options |= F_SRCADDR; break; case 's': /* size of packet to send */ @@ -639,6 +598,24 @@ main(int argc, char *argv[]) options &= ~F_NOUSERDATA; options |= F_FQDNOLD; break; + case 'x': + t = strtod(optarg, &e); + if (*e || e == optarg || t > (double)INT_MAX) + err(EX_USAGE, "invalid timing interval: `%s'", + optarg); + options |= F_WAITTIME; + waittime = (int)t; + break; + case 'X': + alarmtimeout = strtoul(optarg, &e, 0); + if ((alarmtimeout < 1) || (alarmtimeout == ULONG_MAX)) + errx(EX_USAGE, "invalid timeout: `%s'", + optarg); + if (alarmtimeout > MAXALARM) + errx(EX_USAGE, "invalid timeout: `%s' > %d", + optarg, MAXALARM); + alarm((int)alarmtimeout); + break; #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC case 'P': @@ -705,11 +682,11 @@ main(int argc, char *argv[]) hints.ai_socktype = SOCK_RAW; hints.ai_protocol = IPPROTO_ICMPV6; - ret_ga = getaddrinfo(target, NULL, &hints, &res); - if (ret_ga) - errx(1, "%s", gai_strerror(ret_ga)); + error = getaddrinfo(target, NULL, &hints, &res); + if (error) + errx(1, "%s", gai_strerror(error)); if (res->ai_canonname) - hostname = res->ai_canonname; + hostname = strdup(res->ai_canonname); else hostname = target; @@ -721,40 +698,44 @@ main(int argc, char *argv[]) if ((s = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) err(1, "socket"); + freeaddrinfo(res); /* set the source address if specified. */ - if ((options & F_SRCADDR) && - bind(s, (struct sockaddr *)&src, srclen) != 0) { - err(1, "bind"); + if ((options & F_SRCADDR) != 0) { + /* properly fill sin6_scope_id */ + if (IN6_IS_ADDR_LINKLOCAL(&src.sin6_addr) && ( + IN6_IS_ADDR_LINKLOCAL(&dst.sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&dst.sin6_addr) || + IN6_IS_ADDR_MC_NODELOCAL(&dst.sin6_addr))) { + if (src.sin6_scope_id == 0) + src.sin6_scope_id = dst.sin6_scope_id; + if (dst.sin6_scope_id == 0) + dst.sin6_scope_id = src.sin6_scope_id; + } + if (bind(s, (struct sockaddr *)&src, srclen) != 0) + err(1, "bind"); } - /* set the gateway (next hop) if specified */ if (gateway) { - struct addrinfo ghints, *gres; - int error; - - memset(&ghints, 0, sizeof(ghints)); - ghints.ai_family = AF_INET6; - ghints.ai_socktype = SOCK_RAW; - ghints.ai_protocol = IPPROTO_ICMPV6; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_RAW; + hints.ai_protocol = IPPROTO_ICMPV6; - error = getaddrinfo(gateway, NULL, &hints, &gres); + error = getaddrinfo(gateway, NULL, &hints, &res); if (error) { - freeaddrinfo(gres); errx(1, "getaddrinfo for the gateway %s: %s", gateway, gai_strerror(error)); } - if (gres->ai_next && (options & F_VERBOSE)) - freeaddrinfo(gres); + if (res->ai_next && (options & F_VERBOSE)) warnx("gateway resolves to multiple addresses"); if (setsockopt(s, IPPROTO_IPV6, IPV6_NEXTHOP, - gres->ai_addr, gres->ai_addrlen)) { - freeaddrinfo(gres); + res->ai_addr, res->ai_addrlen)) { err(1, "setsockopt(IPV6_NEXTHOP)"); } - freeaddrinfo(gres); + freeaddrinfo(res); } /* @@ -790,8 +771,10 @@ main(int argc, char *argv[]) } /* revoke root privilege */ - seteuid(getuid()); - setuid(getuid()); + if (seteuid(getuid()) != 0) + err(1, "seteuid() failed"); + if (setuid(getuid()) != 0) + err(1, "setuid() failed"); if ((options & F_FLOOD) && (options & F_INTERVAL)) errx(1, "-f and -i incompatible options"); @@ -821,17 +804,7 @@ main(int argc, char *argv[]) *datap++ = i; ident = getpid() & 0xFFFF; -#ifndef HAVE_ARC4RANDOM - gettimeofday(&seed, NULL); - srand((unsigned int)(seed.tv_sec ^ seed.tv_usec ^ (long)ident)); - memset(nonce, 0, sizeof(nonce)); - for (i = 0; i < sizeof(nonce); i += sizeof(int)) - *((int *)&nonce[i]) = rand(); -#else - memset(nonce, 0, sizeof(nonce)); - for (i = 0; i < sizeof(nonce); i += sizeof(u_int32_t)) - *((u_int32_t *)&nonce[i]) = arc4random(); -#endif + arc4random_buf(nonce, sizeof(nonce)); optval = 1; if (options & F_DONTFRAG) if (setsockopt(s, IPPROTO_IPV6, IPV6_DONTFRAG, @@ -946,7 +919,7 @@ main(int argc, char *argv[]) /* set IP6 packet options */ if (ip6optlen) { - if ((scmsg = (char *)malloc(ip6optlen)) == 0) + if ((scmsg = (char *)malloc(ip6optlen)) == NULL) errx(1, "can't allocate enough memory"); smsghdr.msg_control = (caddr_t)scmsg; smsghdr.msg_controllen = ip6optlen; @@ -982,7 +955,7 @@ main(int argc, char *argv[]) } if (argc > 1) { /* some intermediate addrs are specified */ - int hops, error; + int hops; #ifdef USE_RFC2292BIS int rthdrlen; #endif @@ -999,31 +972,30 @@ main(int argc, char *argv[]) errx(1, "can't initialize rthdr"); #else /* old advanced API */ if ((scmsgp = (struct cmsghdr *)inet6_rthdr_init(scmsgp, - IPV6_RTHDR_TYPE_0)) == 0) + IPV6_RTHDR_TYPE_0)) == NULL) errx(1, "can't initialize rthdr"); #endif /* USE_RFC2292BIS */ for (hops = 0; hops < argc - 1; hops++) { - struct addrinfo *iaip; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; if ((error = getaddrinfo(argv[hops], NULL, &hints, - &iaip))) + &res))) errx(1, "%s", gai_strerror(error)); - if (SIN6(iaip->ai_addr)->sin6_family != AF_INET6) + if (res->ai_addr->sa_family != AF_INET6) errx(1, "bad addr family of an intermediate addr"); - + sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr; #ifdef USE_RFC2292BIS - if (inet6_rth_add(rthdr, - &(SIN6(iaip->ai_addr))->sin6_addr)) + if (inet6_rth_add(rthdr, &sin6->sin6_addr)) errx(1, "can't add an intermediate node"); #else /* old advanced API */ - if (inet6_rthdr_add(scmsgp, - &(SIN6(iaip->ai_addr))->sin6_addr, + if (inet6_rthdr_add(scmsg, &sin6->sin6_addr, IPV6_RTHDR_LOOSE)) errx(1, "can't add an intermediate node"); #endif /* USE_RFC2292BIS */ - freeaddrinfo(iaip); + freeaddrinfo(res); } #ifndef USE_RFC2292BIS @@ -1088,7 +1060,7 @@ main(int argc, char *argv[]) #if defined(SO_SNDBUF) && defined(SO_RCVBUF) if (sockbufsize) { - if (datalen > sockbufsize) + if (datalen > (size_t)sockbufsize) warnx("you need -b to increase socket buffer size"); if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof(sockbufsize)) < 0) @@ -1139,58 +1111,50 @@ main(int argc, char *argv[]) printf("%s --> ", pr_addr((struct sockaddr *)&src, sizeof(src))); printf("%s\n", pr_addr((struct sockaddr *)&dst, sizeof(dst))); - while (preload--) /* Fire off them quickies. */ - (void)pinger(); - - (void)signal(SIGINT, onsignal); -#ifdef SIGINFO - (void)signal(SIGINFO, onsignal); -#endif - - if ((options & F_FLOOD) == 0) { - (void)signal(SIGALRM, onsignal); - itimer.it_interval = interval; - itimer.it_value = interval; - (void)setitimer(ITIMER_REAL, &itimer, NULL); - if (ntransmitted == 0) - retransmit(); + if (preload == 0) + pinger(); + else { + if (npackets != 0 && preload > npackets) + preload = npackets; + while (preload--) + pinger(); } + gettimeofday(&last, NULL); -#ifndef HAVE_POLL_H - fdmasks = howmany(s + 1, NFDBITS) * sizeof(fd_mask); - if ((fdmaskp = malloc(fdmasks)) == NULL) - err(1, "malloc"); -#endif - - seenalrm = seenint = 0; + sigemptyset(&si_sa.sa_mask); + si_sa.sa_flags = 0; + si_sa.sa_handler = onsignal; + if (sigaction(SIGINT, &si_sa, 0) == -1) + err(EX_OSERR, "sigaction SIGINT"); + seenint = 0; #ifdef SIGINFO + if (sigaction(SIGINFO, &si_sa, 0) == -1) + err(EX_OSERR, "sigaction SIGINFO"); seeninfo = 0; #endif + if (alarmtimeout > 0) { + if (sigaction(SIGALRM, &si_sa, 0) == -1) + err(EX_OSERR, "sigaction SIGALRM"); + } + if (options & F_FLOOD) { + intvl.tv_sec = 0; + intvl.tv_usec = 10000; + } else if ((options & F_INTERVAL) == 0) { + intvl.tv_sec = interval / 1000; + intvl.tv_usec = interval % 1000 * 1000; + } - for (;;) { + almost_done = 0; + while (seenint == 0) { + struct timeval now, timeout; struct msghdr m; struct iovec iov[2]; + fd_set rfds; + int n; /* signal handling */ - if (seenalrm) { - /* last packet sent, timeout reached? */ - if (npackets && ntransmitted >= npackets) { - struct timeval zerotime = {0, 0}; - itimer.it_value = zerotime; - itimer.it_interval = zerotime; - (void)setitimer(ITIMER_REAL, &itimer, NULL); - seenalrm = 0; /* clear flag */ - continue; - } - retransmit(); - seenalrm = 0; - continue; - } - if (seenint) { + if (seenint) onint(SIGINT); - seenint = 0; - continue; - } #ifdef SIGINFO if (seeninfo) { summary(); @@ -1198,122 +1162,121 @@ main(int argc, char *argv[]) continue; } #endif - - if (options & F_FLOOD) { - (void)pinger(); -#ifdef HAVE_POLL_H - timeout = 10; -#else - timeout.tv_sec = 0; - timeout.tv_usec = 10000; - tv = &timeout; -#endif - } else { -#ifdef HAVE_POLL_H - timeout = INFTIM; -#else - tv = NULL; -#endif + FD_ZERO(&rfds); + FD_SET(s, &rfds); + gettimeofday(&now, NULL); + timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec; + timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec; + while (timeout.tv_usec < 0) { + timeout.tv_usec += 1000000; + timeout.tv_sec--; } -#ifdef HAVE_POLL_H - fdmaskp[0].fd = s; - fdmaskp[0].events = POLLIN; - cc = poll(fdmaskp, 1, timeout); -#else - memset(fdmaskp, 0, fdmasks); - FD_SET(s, fdmaskp); - cc = select(s + 1, fdmaskp, NULL, NULL, tv); -#endif - if (cc < 0) { - if (errno != EINTR) { -#ifdef HAVE_POLL_H - warn("poll"); -#else - warn("select"); -#endif - sleep(1); - } - continue; - } else if (cc == 0) - continue; + while (timeout.tv_usec > 1000000) { + timeout.tv_usec -= 1000000; + timeout.tv_sec++; + } + if (timeout.tv_sec < 0) + timeout.tv_sec = timeout.tv_usec = 0; + + n = select(s + 1, &rfds, NULL, NULL, &timeout); + if (n < 0) + continue; /* EINTR */ + if (n == 1) { + m.msg_name = (caddr_t)&from; + m.msg_namelen = sizeof(from); + memset(&iov, 0, sizeof(iov)); + iov[0].iov_base = (caddr_t)packet; + iov[0].iov_len = packlen; + m.msg_iov = iov; + m.msg_iovlen = 1; + memset(cm, 0, CONTROLLEN); + m.msg_control = (void *)cm; + m.msg_controllen = CONTROLLEN; + + cc = recvmsg(s, &m, 0); + if (cc < 0) { + if (errno != EINTR) { + warn("recvmsg"); + sleep(1); + } + continue; + } else if (cc == 0) { + int mtu; - m.msg_name = (caddr_t)&from; - m.msg_namelen = sizeof(from); - memset(&iov, 0, sizeof(iov)); - iov[0].iov_base = (caddr_t)packet; - iov[0].iov_len = packlen; - m.msg_iov = iov; - m.msg_iovlen = 1; - memset(cm, 0, CONTROLLEN); - m.msg_control = (void *)cm; - m.msg_controllen = CONTROLLEN; - - cc = recvmsg(s, &m, 0); - if (cc < 0) { - if (errno != EINTR) { - warn("recvmsg"); - sleep(1); + /* + * receive control messages only. Process the + * exceptions (currently the only possibility is + * a path MTU notification.) + */ + if ((mtu = get_pathmtu(&m)) > 0) { + if ((options & F_VERBOSE) != 0) { + printf("new path MTU (%d) is " + "notified\n", mtu); + } + } + continue; + } else { + /* + * an ICMPv6 message (probably an echoreply) + * arrived. + */ + pr_pack(packet, cc, &m); } - continue; - } else if (cc == 0) { - int mtu; - + if (((options & F_ONCE) != 0 && nreceived > 0) || + (npackets > 0 && nreceived >= npackets)) + break; + } + if (n == 0 || (options & F_FLOOD)) { + if (npackets == 0 || ntransmitted < npackets) + pinger(); + else { + if (almost_done) + break; + almost_done = 1; /* - * receive control messages only. Process the - * exceptions (currently the only possiblity is - * a path MTU notification.) + * If we're not transmitting any more packets, + * change the timer to wait two round-trip times + * if we've received any packets or (waittime) + * milliseconds if we haven't. */ - if ((mtu = get_pathmtu(&m)) > 0) { - if ((options & F_VERBOSE) != 0) { - printf("new path MTU (%d) is " - "notified\n", mtu); + intvl.tv_usec = 0; + if (nreceived) { + intvl.tv_sec = 2 * tmax / 1000; + if (intvl.tv_sec == 0) + intvl.tv_sec = 1; + } else { + intvl.tv_sec = waittime / 1000; + intvl.tv_usec = waittime % 1000 * 1000; } } - continue; - } else { - /* - * an ICMPv6 message (probably an echoreply) arrived. - */ - pr_pack(packet, cc, &m); - } - if (((options & F_ONCE) != 0 && nreceived > 0) || - (npackets > 0 && nreceived >= npackets)) - break; - if (ntransmitted - nreceived - 1 > nmissedmax) { - nmissedmax = ntransmitted - nreceived - 1; - if (options & F_MISSED) - (void)write(STDOUT_FILENO, &BBELL, 1); + gettimeofday(&last, NULL); + if (ntransmitted - nreceived - 1 > nmissedmax) { + nmissedmax = ntransmitted - nreceived - 1; + if (options & F_MISSED) + (void)write(STDOUT_FILENO, &BBELL, 1); + } } } + sigemptyset(&si_sa.sa_mask); + si_sa.sa_flags = 0; + si_sa.sa_handler = SIG_IGN; + sigaction(SIGINT, &si_sa, 0); + sigaction(SIGALRM, &si_sa, 0); summary(); - if (res != NULL) { - freeaddrinfo(res); - res = NULL; - } - - if(packet != NULL) { + if(packet != NULL) free(packet); - packet = NULL; - } - -#ifndef HAVE_POLL_H - if(fdmaskp != NULL) - free(fdmaskp); -#endif exit(nreceived == 0 ? 2 : 0); } -void +static void onsignal(int sig) { switch (sig) { - case SIGALRM: - seenalrm++; - break; case SIGINT: + case SIGALRM: seenint++; break; #ifdef SIGINFO @@ -1325,38 +1288,6 @@ onsignal(int sig) } /* - * retransmit -- - * This routine transmits another ping6. - */ -void -retransmit(void) -{ - struct itimerval itimer; - - if (pinger() == 0) - return; - - /* - * If we're not transmitting any more packets, change the timer - * to wait two round-trip times if we've received any packets or - * ten seconds if we haven't. - */ -#define MAXWAIT 10 - if (nreceived) { - itimer.it_value.tv_sec = 2 * tmax / 1000; - if (itimer.it_value.tv_sec == 0) - itimer.it_value.tv_sec = 1; - } else - itimer.it_value.tv_sec = MAXWAIT; - itimer.it_interval.tv_sec = 0; - itimer.it_interval.tv_usec = 0; - itimer.it_value.tv_usec = 0; - - (void)signal(SIGALRM, onsignal); - (void)setitimer(ITIMER_REAL, &itimer, NULL); -} - -/* * pinger -- * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet * will be added on by the kernel. The ID field is our UNIX process ID, @@ -1364,7 +1295,7 @@ retransmit(void) * of the data portion are used to hold a UNIX "timeval" struct in VAX * byte-order, to compute the round-trip time. */ -size_t +static size_t pingerlen(void) { size_t l; @@ -1383,7 +1314,7 @@ pingerlen(void) return l; } -int +static int pinger(void) { struct icmp6_hdr *icp; @@ -1498,7 +1429,7 @@ pinger(void) return(0); } -int +static int myechoreply(const struct icmp6_hdr *icp) { if (ntohs(icp->icmp6_id) == ident) @@ -1507,7 +1438,7 @@ myechoreply(const struct icmp6_hdr *icp) return 0; } -int +static int mynireply(const struct icmp6_nodeinfo *nip) { if (memcmp(nip->icmp6_ni_nonce + sizeof(u_int16_t), @@ -1518,7 +1449,7 @@ mynireply(const struct icmp6_nodeinfo *nip) return 0; } -char * +static char * dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf, size_t bufsiz) /*base for compressed name*/ @@ -1562,7 +1493,7 @@ dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf, while (i-- > 0 && cp < ep) { l = snprintf(cresult, sizeof(cresult), isprint(*cp) ? "%c" : "\\%03o", *cp & 0xff); - if (l >= sizeof(cresult) || l < 0) + if ((size_t)l >= sizeof(cresult) || l < 0) return NULL; if (strlcat(buf, cresult, bufsiz) >= bufsiz) return NULL; /*result overrun*/ @@ -1585,7 +1516,7 @@ dnsdecode(const u_char **sp, const u_char *ep, const u_char *base, char *buf, * which arrive ('tis only fair). This permits multiple copies of this * program to be run without having intermingled output (or statistics!). */ -void +static void pr_pack(u_char *buf, int cc, struct msghdr *mhdr) { #define safeputc(c) printf((isprint((c)) ? "%c" : "\\%03o"), c) @@ -1617,7 +1548,7 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr) } from = (struct sockaddr *)mhdr->msg_name; fromlen = mhdr->msg_namelen; - if (cc < sizeof(struct icmp6_hdr)) { + if (cc < (int)sizeof(struct icmp6_hdr)) { if (options & F_VERBOSE) warnx("packet too short (%d bytes) from %s", cc, pr_addr(from, fromlen)); @@ -1669,6 +1600,11 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr) if (options & F_QUIET) return; + if (options & F_WAITTIME && triptime > waittime) { + ++nrcvtimeout; + return; + } + if (options & F_FLOOD) (void)write(STDOUT_FILENO, &BSPACE, 1); else { @@ -1866,7 +1802,7 @@ pr_pack(u_char *buf, int cc, struct msghdr *mhdr) #undef safeputc } -void +static void pr_exthdrs(struct msghdr *mhdr) { ssize_t bufsize; @@ -1904,7 +1840,7 @@ pr_exthdrs(struct msghdr *mhdr) } #ifdef USE_RFC2292BIS -void +static void pr_ip6opt(void *extbuf, size_t bufsize) { struct ip6_hbh *ext; @@ -1967,7 +1903,7 @@ pr_ip6opt(void *extbuf, size_t bufsize) } #else /* !USE_RFC2292BIS */ /* ARGSUSED */ -void +static void pr_ip6opt(void *extbuf, size_t bufsize __unused) { putchar('\n'); @@ -1976,7 +1912,7 @@ pr_ip6opt(void *extbuf, size_t bufsize __unused) #endif /* USE_RFC2292BIS */ #ifdef USE_RFC2292BIS -void +static void pr_rthdr(void *extbuf, size_t bufsize) { struct in6_addr *in6; @@ -2033,7 +1969,7 @@ pr_rthdr(void *extbuf, size_t bufsize) #else /* !USE_RFC2292BIS */ /* ARGSUSED */ -void +static void pr_rthdr(void *extbuf, size_t bufsize __unused) { putchar('\n'); @@ -2041,7 +1977,7 @@ pr_rthdr(void *extbuf, size_t bufsize __unused) } #endif /* USE_RFC2292BIS */ -int +static int pr_bitrange(u_int32_t v, int soff, int ii) { int off; @@ -2087,7 +2023,7 @@ pr_bitrange(u_int32_t v, int soff, int ii) return ii; } -void +static void pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen) /* ni->qtype must be SUPTYPES */ { @@ -2153,7 +2089,7 @@ pr_suptypes(struct icmp6_nodeinfo *ni, size_t nilen) } } -void +static void pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen) /* ni->qtype must be NODEADDR */ { @@ -2219,7 +2155,7 @@ pr_nodeaddr(struct icmp6_nodeinfo *ni, int nilen) } } -int +static int get_hoplim(struct msghdr *mhdr) { struct cmsghdr *cm; @@ -2238,7 +2174,7 @@ get_hoplim(struct msghdr *mhdr) return(-1); } -struct in6_pktinfo * +static struct in6_pktinfo * get_rcvpktinfo(struct msghdr *mhdr) { struct cmsghdr *cm; @@ -2257,7 +2193,7 @@ get_rcvpktinfo(struct msghdr *mhdr) return(NULL); } -int +static int get_pathmtu(struct msghdr *mhdr) { #ifdef IPV6_RECVPATHMTU @@ -2317,7 +2253,7 @@ get_pathmtu(struct msghdr *mhdr) * Subtract 2 timeval structs: out = out - in. Out is assumed to * be >= in. */ -void +static void tvsub(struct timeval *out, struct timeval *in) { if ((out->tv_usec -= in->tv_usec) < 0) { @@ -2332,34 +2268,22 @@ tvsub(struct timeval *out, struct timeval *in) * SIGINT handler. */ /* ARGSUSED */ -void +static void onint(int notused __unused) { - summary(); - - if (res != NULL) - freeaddrinfo(res); - - if(packet != NULL) - free(packet); - -#ifndef HAVE_POLL_H - if(fdmaskp != NULL) - free(fdmaskp); -#endif - - (void)signal(SIGINT, SIG_DFL); - (void)kill(getpid(), SIGINT); - - /* NOTREACHED */ - exit(1); + /* + * When doing reverse DNS lookups, the seenint flag might not + * be noticed for a while. Just exit if we get a second SIGINT. + */ + if ((options & F_HOSTNAME) && seenint != 0) + _exit(nreceived ? 0 : 2); } /* * summary -- * Print out statistics. */ -void +static void summary(void) { @@ -2376,6 +2300,8 @@ summary(void) ((((double)ntransmitted - nreceived) * 100.0) / ntransmitted)); } + if (nrcvtimeout) + printf(", %ld packets out of wait time", nrcvtimeout); (void)putchar('\n'); if (nreceived && timing) { /* Only display average to microseconds */ @@ -2407,7 +2333,7 @@ static const char *nircode[] = { * pr_icmph -- * Print a descriptive string about an ICMP header. */ -void +static void pr_icmph(struct icmp6_hdr *icp, u_char *end) { char ntop_buf[INET6_ADDRSTRLEN]; @@ -2622,7 +2548,7 @@ pr_icmph(struct icmp6_hdr *icp, u_char *end) break; } if (options & F_VERBOSE) { - if (ni->ni_code > sizeof(nircode) / sizeof(nircode[0])) + if (ni->ni_code > nitems(nircode)) printf(", invalid"); else printf(", %s", nircode[ni->ni_code]); @@ -2637,7 +2563,7 @@ pr_icmph(struct icmp6_hdr *icp, u_char *end) * pr_iph -- * Print an IP6 header. */ -void +static void pr_iph(struct ip6_hdr *ip6) { u_int32_t flow = ip6->ip6_flow & IPV6_FLOWLABEL_MASK; @@ -2665,7 +2591,7 @@ pr_iph(struct ip6_hdr *ip6) * Return an ascii host address as a dotted quad and optionally with * a hostname. */ -const char * +static const char * pr_addr(struct sockaddr *addr, int addrlen) { static char buf[NI_MAXHOST]; @@ -2684,13 +2610,13 @@ pr_addr(struct sockaddr *addr, int addrlen) * pr_retip -- * Dump some info on a returned (via ICMPv6) IPv6 packet. */ -void +static void pr_retip(struct ip6_hdr *ip6, u_char *end) { u_char *cp = (u_char *)ip6, nh; int hlen; - if (end - (u_char *)ip6 < sizeof(*ip6)) { + if ((size_t)(end - (u_char *)ip6) < sizeof(*ip6)) { printf("IP6"); goto trunc; } @@ -2764,7 +2690,7 @@ pr_retip(struct ip6_hdr *ip6, u_char *end) return; } -void +static void fill(char *bp, char *patp) { int ii, jj, kk; @@ -2772,7 +2698,11 @@ fill(char *bp, char *patp) char *cp; for (cp = patp; *cp; cp++) - if (!isxdigit((unsigned char) *cp)) +#ifndef __rtems__ + if (!isxdigit(*cp)) +#else /* __rtems__ */ + if (!isxdigit((unsigned char)*cp)) +#endif /* __rtems__ */ errx(1, "patterns must be specified as hex digits"); ii = sscanf(patp, "%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x", @@ -2783,7 +2713,7 @@ fill(char *bp, char *patp) /* xxx */ if (ii > 0) for (kk = 0; - kk <= MAXDATALEN - (8 + sizeof(struct tv32) + ii); + (size_t)kk <= MAXDATALEN - 8 + sizeof(struct tv32) + ii; kk += ii) for (jj = 0; jj < ii; ++jj) bp[jj + kk] = pat[jj]; @@ -2797,7 +2727,7 @@ fill(char *bp, char *patp) #ifdef IPSEC #ifdef IPSEC_POLICY_IPSEC -int +static int setpolicy(int so __unused, char *policy) { char *buf; @@ -2818,7 +2748,7 @@ setpolicy(int so __unused, char *policy) #endif #endif -char * +static char * nigroup(char *name, int nig_oldmcprefix) { char *p; @@ -2877,7 +2807,7 @@ nigroup(char *name, int nig_oldmcprefix) return strdup(hbuf); } -void +static void usage(void) { (void)fprintf(stderr, @@ -2901,6 +2831,7 @@ usage(void) #endif "\n" " [-p pattern] [-S sourceaddr] [-s packetsize] " - "[hops ...] host\n"); + "[-x waittime]\n" + " [-X timeout] [hops ...] host\n"); exit(1); } diff --git a/freebsd/sbin/ping6/rtems-bsd-ping6-data.h b/freebsd/sbin/ping6/rtems-bsd-ping6-data.h new file mode 100644 index 00000000..40e781b8 --- /dev/null +++ b/freebsd/sbin/ping6/rtems-bsd-ping6-data.h @@ -0,0 +1,4 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +/* ping6.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, extern u_int options); diff --git a/freebsd/sbin/ping6/rtems-bsd-ping6-namespace.h b/freebsd/sbin/ping6/rtems-bsd-ping6-namespace.h new file mode 100644 index 00000000..8b875692 --- /dev/null +++ b/freebsd/sbin/ping6/rtems-bsd-ping6-namespace.h @@ -0,0 +1,3 @@ +/* generated by userspace-header-gen.py */ +/* ping6.c */ +#define options _bsd_ping6_options diff --git a/freebsd/sbin/ping6/rtems-bsd-ping6-ping6-data.h b/freebsd/sbin/ping6/rtems-bsd-ping6-ping6-data.h new file mode 100644 index 00000000..54444845 --- /dev/null +++ b/freebsd/sbin/ping6/rtems-bsd-ping6-ping6-data.h @@ -0,0 +1,40 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-ping6-data.h" +/* ping6.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int mx_dup_ck); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static struct sockaddr_in6 dst); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static struct sockaddr_in6 src); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static socklen_t srclen); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static size_t datalen); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int s); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char BSPACE); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char BBELL); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char DOT); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char *hostname); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int ident); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int hoplimit); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static u_char *packet); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int nmissedmax); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int npackets); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int nreceived); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int nrepeats); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int ntransmitted); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int interval); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int waittime); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static long int nrcvtimeout); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static int timing); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static double tmin); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static double tmax); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static double tsum); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static double tsumsq); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static u_short naflags); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static struct msghdr smsghdr); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static struct iovec smsgiov); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char *scmsg); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static sig_atomic_t volatile seenint); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char rcvd_tbl[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static u_char outpack[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static u_int8_t nonce[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char const *niqcode[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_ping6, static char const *nircode[]); diff --git a/freebsd/sbin/route/keywords b/freebsd/sbin/route/keywords index 676f781d..82edc466 100644 --- a/freebsd/sbin/route/keywords +++ b/freebsd/sbin/route/keywords @@ -4,7 +4,6 @@ 4 6 add -atalk blackhole change cloning diff --git a/freebsd/sbin/route/route.c b/freebsd/sbin/route/route.c index f2d73587..76c609af 100644 --- a/freebsd/sbin/route/route.c +++ b/freebsd/sbin/route/route.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-route-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 1983, 1989, 1991, 1993 * The Regents of the University of California. All rights reserved. @@ -41,24 +45,15 @@ static char sccsid[] = "@(#)route.c 8.6 (Berkeley) 4/28/95"; #endif #endif /* not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + #ifdef __rtems__ #define __need_getopt_newlib #include <getopt.h> -#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP -#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP #include <machine/rtems-bsd-program.h> #include <machine/rtems-bsd-commands.h> -#endif -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - +#endif /* __rtems__ */ #include <rtems/bsd/sys/param.h> #include <sys/file.h> #include <sys/socket.h> @@ -79,20 +74,18 @@ __FBSDID("$FreeBSD$"); #include <err.h> #include <errno.h> #include <paths.h> +#include <signal.h> +#include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sysexits.h> +#include <time.h> #include <unistd.h> #include <ifaddrs.h> - -static const struct keytab { - const char *kt_cp; - int kt_i; -} keywords[] = { -#include "keywords.h" - {0, 0} -}; +#ifdef __rtems__ +#include "rtems-bsd-route-route-data.h" +#endif /* __rtems__ */ struct fibl { TAILQ_ENTRY(fibl) fl_next; @@ -102,152 +95,120 @@ struct fibl { int fl_errno; }; -struct rt_ctx { - union sockunion { - struct sockaddr sa; - struct sockaddr_in sin; -#ifdef INET6 - struct sockaddr_in6 sin6; -#endif - struct sockaddr_dl sdl; - struct sockaddr_inarp sinarp; - struct sockaddr_storage ss; /* added to avoid memory overrun */ - } so_dst, so_gate, so_mask, so_genmask, so_ifa, so_ifp; - - int pid, rtm_addrs; - int s; - int forcehost, forcenet, nflag, af, qflag, tflag; - int verbose, aflen; - int locking, lockrest, debugonly; - struct rt_metrics rt_metrics; - u_long rtm_inits; - uid_t uid; - int defaultfib; - int numfibs; - char domain[MAXHOSTNAMELEN + 1]; - int domain_initialized; - int rtm_seq; - char rt_line[MAXHOSTNAMELEN + 1]; - char net_line[MAXHOSTNAMELEN + 1]; - struct { - struct rt_msghdr m_rtm; - char m_space[512]; - } m_rtmsg; - TAILQ_HEAD(fibl_head_t, fibl) fibl_head; +static struct keytab { + const char *kt_cp; + int kt_i; +} const keywords[] = { +#include "keywords.h" + {0, 0} }; +static struct sockaddr_storage so[RTAX_MAX]; +static int pid, rtm_addrs; +static int s; +static int nflag, af, qflag, tflag; +static int verbose, aflen; +static int locking, lockrest, debugonly; +static struct rt_metrics rt_metrics; +static u_long rtm_inits; +static uid_t uid; +static int defaultfib; +static int numfibs; +static char domain[MAXHOSTNAMELEN + 1]; +static bool domain_initialized; +static int rtm_seq; +static char rt_line[NI_MAXHOST]; +static char net_line[MAXHOSTNAMELEN + 1]; + #ifndef __rtems__ -struct rt_ctx rt_ctx; +static struct { +#else /* __rtems__ */ +static struct m_rtmsg { #endif /* __rtems__ */ + struct rt_msghdr m_rtm; + char m_space[512]; +} m_rtmsg; -typedef union sockunion *sup; +static TAILQ_HEAD(fibl_head_t, fibl) fibl_head; -static void bprintf(FILE *, int, const char *); -static void flushroutes(struct rt_ctx *, int argc, char *argv[]); -static int flushroutes_fib(struct rt_ctx *, int); -static int getaddr(struct rt_ctx *, int, char *, struct hostent **, int); +static void printb(int, const char *); +static void flushroutes(int argc, char *argv[]); +static int flushroutes_fib(int); +static int getaddr(int, char *, struct hostent **, int); static int keyword(const char *); -static void inet_makenetandmask(struct rt_ctx *, u_long, struct sockaddr_in *, u_long); +#ifdef INET +static void inet_makenetandmask(u_long, struct sockaddr_in *, + struct sockaddr_in *, u_long); +#endif #ifdef INET6 -static int inet6_makenetandmask(struct rt_ctx *, struct sockaddr_in6 *, const char *); +static int inet6_makenetandmask(struct sockaddr_in6 *, const char *); #endif -static void interfaces(struct rt_ctx *); -static void mask_addr(struct rt_ctx *); -static void monitor(struct rt_ctx *, int, char *[]); -static const char *netname(struct rt_ctx *, struct sockaddr *); -static void newroute(struct rt_ctx *, int, char **); -static int newroute_fib(struct rt_ctx *, int, char *, int); -static void pmsg_addrs(struct rt_ctx *, char *, int, size_t); -static void pmsg_common(struct rt_ctx *, struct rt_msghdr *, size_t); -static int prefixlen(struct rt_ctx *, const char *); -static void print_getmsg(struct rt_ctx *, struct rt_msghdr *, int, int); -static void print_rtmsg(struct rt_ctx *, struct rt_msghdr *, size_t); -static const char *routename(struct rt_ctx *, struct sockaddr *); -static int rtmsg(struct rt_ctx *, int, int, int); -static void set_metric(struct rt_ctx *, char *, int); -static int set_sofib(struct rt_ctx *, int); -static int set_procfib(int); -static void sockaddr(char *, struct sockaddr *); -static void sodump(sup, const char *); -extern char *iso_ntoa(void); - -static int fiboptlist_csv(struct rt_ctx *, const char *, struct fibl_head_t *); -static int fiboptlist_range(struct rt_ctx *, const char *, struct fibl_head_t *); +static void interfaces(void); +static void monitor(int, char*[]); +static const char *netname(struct sockaddr *); +static void newroute(int, char **); +static int newroute_fib(int, char *, int); +static void pmsg_addrs(char *, int, size_t); +static void pmsg_common(struct rt_msghdr *, size_t); +static int prefixlen(const char *); +static void print_getmsg(struct rt_msghdr *, int, int); +static void print_rtmsg(struct rt_msghdr *, size_t); +static const char *routename(struct sockaddr *); +static int rtmsg(int, int, int); +static void set_metric(char *, int); +static int set_sofib(int); +static void sockaddr(char *, struct sockaddr *, size_t); +static void sodump(struct sockaddr *, const char *); +static int fiboptlist_csv(const char *, struct fibl_head_t *); +static int fiboptlist_range(const char *, struct fibl_head_t *); static void usage(const char *) __dead2; -void +#define READ_TIMEOUT 10 +static volatile sig_atomic_t stop_read; + +static void +stopit(int sig __unused) +{ + + stop_read = 1; +} + +static void usage(const char *cp) { if (cp != NULL) warnx("bad keyword: %s", cp); - (void) fprintf(stderr, - "usage: route [-46dnqtv] command [[modifiers] args]\n"); - exit(EX_USAGE); + errx(EX_USAGE, "usage: route [-46dnqtv] command [[modifiers] args]"); /* NOTREACHED */ } #ifdef __rtems__ -static int main(int argc, char **argv, struct rt_ctx *c); +static int main(int argc, char *argv[]); -struct main_ctx { - int argc; - char **argv; - struct rt_ctx *c; -}; +RTEMS_LINKER_RWSET(bsd_prog_route, char); -static int -call_main(void *ctx) -{ - const struct main_ctx *mc = ctx; - - return main(mc->argc, mc->argv, mc->c); -} - -int rtems_bsd_command_route(int argc, char *argv[]) +int +rtems_bsd_command_route(int argc, char *argv[]) { - struct rt_ctx *c; int exit_code; + void *data_begin; + size_t data_size; - c = calloc(1, sizeof(*c)); - if (c != NULL) { - struct main_ctx mc; - struct fibl *fl; - struct fibl *tfl; - - mc.argc = argc; - mc.argv = argv; - mc.c = c; - - c->s = -1; - c->aflen = sizeof(struct sockaddr_in); - TAILQ_INIT(&c->fibl_head); + data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_route); + data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_route); - exit_code = rtems_bsd_program_call("route", call_main, &mc); - - close(c->s); - - TAILQ_FOREACH_SAFE(fl, &c->fibl_head, fl_next, tfl) { - free(fl); - } - - free(c); - } else { - exit_code = EXIT_FAILURE; - } + rtems_bsd_program_lock(); + exit_code = rtems_bsd_program_call_main_with_data_restore("route", + main, argc, argv, data_begin, data_size); + rtems_bsd_program_unlock(); return exit_code; } - -int -main(int argc, char **argv, struct rt_ctx *c) -{ -#else /* __rtems__ */ +#endif /* __rtems__ */ int main(int argc, char **argv) { - struct rt_ctx *c; -#endif /* __rtems__ */ int ch; size_t len; #ifdef __rtems__ @@ -260,11 +221,6 @@ main(int argc, char **argv) #define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data) #endif /* __rtems__ */ -#ifndef __rtems__ - c = &rt_ctx; - c->aflen = sizeof (struct sockaddr_in); -#endif /* __rtems__ */ - if (argc < 2) usage(NULL); @@ -272,34 +228,34 @@ main(int argc, char **argv) switch(ch) { case '4': #ifdef INET - c->af = AF_INET; - c->aflen = sizeof(struct sockaddr_in); + af = AF_INET; + aflen = sizeof(struct sockaddr_in); #else errx(1, "IPv4 support is not compiled in"); #endif break; case '6': #ifdef INET6 - c->af = AF_INET6; - c->aflen = sizeof(struct sockaddr_in6); + af = AF_INET6; + aflen = sizeof(struct sockaddr_in6); #else errx(1, "IPv6 support is not compiled in"); #endif break; case 'n': - c->nflag = 1; + nflag = 1; break; case 'q': - c->qflag = 1; + qflag = 1; break; case 'v': - c->verbose = 1; + verbose = 1; break; case 't': - c->tflag = 1; + tflag = 1; break; case 'd': - c->debugonly = 1; + debugonly = 1; break; case '?': default: @@ -308,45 +264,45 @@ main(int argc, char **argv) argc -= optind; argv += optind; - c->pid = getpid(); - c->uid = geteuid(); - if (c->tflag) - c->s = open(_PATH_DEVNULL, O_WRONLY, 0); + pid = getpid(); + uid = geteuid(); + if (tflag) + s = open(_PATH_DEVNULL, O_WRONLY, 0); else - c->s = socket(PF_ROUTE, SOCK_RAW, 0); - if (c->s < 0) + s = socket(PF_ROUTE, SOCK_RAW, 0); + if (s < 0) err(EX_OSERR, "socket"); - len = sizeof(c->numfibs); - if (sysctlbyname("net.fibs", (void *)&c->numfibs, &len, NULL, 0) == -1) - c->numfibs = -1; + len = sizeof(numfibs); + if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1) + numfibs = -1; - len = sizeof(c->defaultfib); - if (c->numfibs != -1 && - sysctlbyname("net.my_fibnum", (void *)&c->defaultfib, &len, NULL, + len = sizeof(defaultfib); + if (numfibs != -1 && + sysctlbyname("net.my_fibnum", (void *)&defaultfib, &len, NULL, 0) == -1) - c->defaultfib = -1; + defaultfib = -1; if (*argv != NULL) switch (keyword(*argv)) { case K_GET: case K_SHOW: - c->uid = 0; + uid = 0; /* FALLTHROUGH */ case K_CHANGE: case K_ADD: case K_DEL: case K_DELETE: - newroute(c, argc, argv); + newroute(argc, argv); /* NOTREACHED */ case K_MONITOR: - monitor(c, argc, argv); + monitor(argc, argv); /* NOTREACHED */ case K_FLUSH: - flushroutes(c, argc, argv); + flushroutes(argc, argv); exit(0); /* NOTREACHED */ } @@ -355,26 +311,17 @@ main(int argc, char **argv) } static int -set_sofib(struct rt_ctx *c, int fib) +set_sofib(int fib) { if (fib < 0) return (0); - return (setsockopt(c->s, SOL_SOCKET, SO_SETFIB, (void *)&fib, + return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib, sizeof(fib))); } static int -set_procfib(int fib) -{ - - if (fib < 0) - return (0); - return (setfib(fib)); -} - -static int -fiboptlist_range(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh) +fiboptlist_range(const char *arg, struct fibl_head_t *flh) { struct fibl *fl; char *str0, *str, *token, *endptr; @@ -392,7 +339,7 @@ fiboptlist_range(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh) if (errno == 0) { if (*endptr != '\0' || fib[i] < 0 || - (c->numfibs != -1 && fib[i] > c->numfibs - 1)) + (numfibs != -1 && fib[i] > numfibs - 1)) errno = EINVAL; } if (errno) @@ -425,20 +372,21 @@ fiboptlist_range_ret: #define ALLSTRLEN 64 static int -fiboptlist_csv(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh) +fiboptlist_csv(const char *arg, struct fibl_head_t *flh) { struct fibl *fl; char *str0, *str, *token, *endptr; int fib, error; + str0 = str = NULL; if (strcmp("all", arg) == 0) { - str0 = str = calloc(1, ALLSTRLEN); + str = calloc(1, ALLSTRLEN); if (str == NULL) { error = 1; goto fiboptlist_csv_ret; } - if (c->numfibs > 1) - snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, c->numfibs - 1); + if (numfibs > 1) + snprintf(str, ALLSTRLEN - 1, "%d-%d", 0, numfibs - 1); else snprintf(str, ALLSTRLEN - 1, "%d", 0); } else if (strcmp("default", arg) == 0) { @@ -447,14 +395,14 @@ fiboptlist_csv(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh) error = 1; goto fiboptlist_csv_ret; } - snprintf(str, ALLSTRLEN - 1, "%d", c->defaultfib); + snprintf(str, ALLSTRLEN - 1, "%d", defaultfib); } else str0 = str = strdup(arg); error = 0; while ((token = strsep(&str, ",")) != NULL) { if (*token != '-' && strchr(token, '-') != NULL) { - error = fiboptlist_range(c, token, flh); + error = fiboptlist_range(token, flh); if (error) goto fiboptlist_csv_ret; } else { @@ -463,7 +411,7 @@ fiboptlist_csv(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh) if (errno == 0) { if (*endptr != '\0' || fib < 0 || - (c->numfibs != -1 && fib > c->numfibs - 1)) + (numfibs != -1 && fib > numfibs - 1)) errno = EINVAL; } if (errno) { @@ -480,7 +428,8 @@ fiboptlist_csv(struct rt_ctx *c, const char *arg, struct fibl_head_t *flh) } } fiboptlist_csv_ret: - free(str0); + if (str0 != NULL) + free(str0); return (error); } @@ -489,43 +438,41 @@ fiboptlist_csv_ret: * associated with network interfaces. */ static void -flushroutes(struct rt_ctx *c, int argc, char *argv[]) +flushroutes(int argc, char *argv[]) { struct fibl *fl; int error; - if (c->uid != 0 && !c->debugonly) { + if (uid != 0 && !debugonly && !tflag) errx(EX_NOPERM, "must be root to alter routing table"); - } - shutdown(c->s, SHUT_RD); /* Don't want to read back our messages */ + shutdown(s, SHUT_RD); /* Don't want to read back our messages */ - TAILQ_INIT(&c->fibl_head); + TAILQ_INIT(&fibl_head); while (argc > 1) { argc--; argv++; if (**argv != '-') usage(*argv); switch (keyword(*argv + 1)) { +#ifdef INET case K_4: case K_INET: - c->af = AF_INET; + af = AF_INET; break; +#endif #ifdef INET6 case K_6: case K_INET6: - c->af = AF_INET6; + af = AF_INET6; break; #endif - case K_ATALK: - c->af = AF_APPLETALK; - break; case K_LINK: - c->af = AF_LINK; + af = AF_LINK; break; case K_FIB: if (!--argc) usage(*argv); - error = fiboptlist_csv(c, *++argv, &c->fibl_head); + error = fiboptlist_csv(*++argv, &fibl_head); if (error) errx(EX_USAGE, "invalid fib number: %s", *argv); break; @@ -533,26 +480,25 @@ flushroutes(struct rt_ctx *c, int argc, char *argv[]) usage(*argv); } } - if (TAILQ_EMPTY(&c->fibl_head)) { - error = fiboptlist_csv(c, "default", &c->fibl_head); + if (TAILQ_EMPTY(&fibl_head)) { + error = fiboptlist_csv("default", &fibl_head); if (error) errx(EX_OSERR, "fiboptlist_csv failed."); } - TAILQ_FOREACH(fl, &c->fibl_head, fl_next) - flushroutes_fib(c, fl->fl_num); + TAILQ_FOREACH(fl, &fibl_head, fl_next) + flushroutes_fib(fl->fl_num); } static int -flushroutes_fib(struct rt_ctx *c, int fib) +flushroutes_fib(int fib) { struct rt_msghdr *rtm; size_t needed; char *buf, *next, *lim; - int mib[6], rlen, seqno, count = 0; + int mib[7], rlen, seqno, count = 0; int error; - error = set_sofib(c, fib); - error += set_procfib(fib); + error = set_sofib(fib); if (error) { warn("fib number %d is ignored", fib); return (error); @@ -562,14 +508,15 @@ retry: mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ - mib[3] = 0; /* wildcard address family */ + mib[3] = AF_UNSPEC; mib[4] = NET_RT_DUMP; mib[5] = 0; /* no flags */ - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + mib[6] = fib; + if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) err(EX_OSERR, "route-sysctl-estimate"); - if ((buf = malloc(needed)) == NULL && needed != 0) + if ((buf = malloc(needed)) == NULL) errx(EX_OSERR, "malloc failed"); - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) { if (errno == ENOMEM && count++ < 10) { warnx("Routing table grew, retrying"); sleep(1); @@ -579,145 +526,158 @@ retry: err(EX_OSERR, "route-sysctl-get"); } lim = buf + needed; - if (c->verbose) - (void) printf("Examining routing table from sysctl\n"); + if (verbose) + (void)printf("Examining routing table from sysctl\n"); seqno = 0; /* ??? */ for (next = buf; next < lim; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)next; - if (c->verbose) - print_rtmsg(c, rtm, rtm->rtm_msglen); + rtm = (struct rt_msghdr *)(void *)next; + if (verbose) + print_rtmsg(rtm, rtm->rtm_msglen); if ((rtm->rtm_flags & RTF_GATEWAY) == 0) continue; - if (c->af != 0) { + if (af != 0) { struct sockaddr *sa = (struct sockaddr *)(rtm + 1); - if (sa->sa_family != c->af) + if (sa->sa_family != af) continue; } - if (c->debugonly) + if (debugonly) continue; rtm->rtm_type = RTM_DELETE; rtm->rtm_seq = seqno; - rlen = write(c->s, next, rtm->rtm_msglen); + rlen = write(s, next, rtm->rtm_msglen); if (rlen < 0 && errno == EPERM) err(1, "write to routing socket"); if (rlen < (int)rtm->rtm_msglen) { warn("write to routing socket"); - (void) printf("got only %d for rlen\n", rlen); + (void)printf("got only %d for rlen\n", rlen); free(buf); goto retry; break; } seqno++; - if (c->qflag) + if (qflag) continue; - if (c->verbose) - print_rtmsg(c, rtm, rlen); + if (verbose) + print_rtmsg(rtm, rlen); else { struct sockaddr *sa = (struct sockaddr *)(rtm + 1); printf("%-20.20s ", rtm->rtm_flags & RTF_HOST ? - routename(c, sa) : netname(c, sa)); + routename(sa) : netname(sa)); sa = (struct sockaddr *)(SA_SIZE(sa) + (char *)sa); - printf("%-20.20s ", routename(c, sa)); + printf("%-20.20s ", routename(sa)); if (fib >= 0) printf("-fib %-3d ", fib); printf("done\n"); } } - free(buf); return (error); } static const char * -routename(struct rt_ctx *c, struct sockaddr *sa) +routename(struct sockaddr *sa) { + struct sockaddr_dl *sdl; const char *cp; - struct hostent *hp; int n; - if (c->domain_initialized) { - c->domain_initialized = 1; - if (gethostname(c->domain, MAXHOSTNAMELEN) == 0 && - (cp = strchr(c->domain, '.'))) { - c->domain[MAXHOSTNAMELEN] = '\0'; - (void) strcpy(c->domain, cp + 1); + if (!domain_initialized) { + domain_initialized = true; + if (gethostname(domain, MAXHOSTNAMELEN) == 0 && + (cp = strchr(domain, '.'))) { + domain[MAXHOSTNAMELEN] = '\0'; + (void)strcpy(domain, cp + 1); } else - c->domain[0] = 0; + domain[0] = '\0'; } - if (sa->sa_len == 0) - strcpy(c->rt_line, "default"); - else switch (sa->sa_family) { - + /* If the address is zero-filled, use "default". */ + if (sa->sa_len == 0 && nflag == 0) + return ("default"); +#if defined(INET) || defined(INET6) + switch (sa->sa_family) { +#ifdef INET case AF_INET: - { struct in_addr in; - in = ((struct sockaddr_in *)sa)->sin_addr; - - cp = NULL; - if (in.s_addr == INADDR_ANY || sa->sa_len < 4) - cp = "default"; - if (cp == NULL && !c->nflag) { - hp = gethostbyaddr((char *)&in, sizeof (struct in_addr), - AF_INET); - if (hp != NULL) { - char *cptr; - cptr = strchr(hp->h_name, '.'); - if (cptr != NULL && - strcmp(cptr + 1, c->domain) == 0) - *cptr = '\0'; - cp = hp->h_name; - } - } - if (cp != NULL) { - strncpy(c->rt_line, cp, sizeof(c->rt_line) - 1); - c->rt_line[sizeof(c->rt_line) - 1] = '\0'; - } else - (void) sprintf(c->rt_line, "%s", inet_ntoa(in)); + /* If the address is zero-filled, use "default". */ + if (nflag == 0 && + ((struct sockaddr_in *)(void *)sa)->sin_addr.s_addr == + INADDR_ANY) + return("default"); break; - } +#endif +#ifdef INET6 + case AF_INET6: + /* If the address is zero-filled, use "default". */ + if (nflag == 0 && + IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)(void *)sa)->sin6_addr)) + return("default"); + break; +#endif + } +#endif + switch (sa->sa_family) { +#if defined(INET) || defined(INET6) +#ifdef INET + case AF_INET: +#endif #ifdef INET6 case AF_INET6: +#endif { - struct sockaddr_in6 sin6; /* use static var for safety */ - int niflags = 0; + struct sockaddr_storage ss; + int error; + char *p; - memset(&sin6, 0, sizeof(sin6)); - memcpy(&sin6, sa, sa->sa_len); - sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_family = AF_INET6; -#ifdef __KAME__ - if (sa->sa_len == sizeof(struct sockaddr_in6) && - (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || - IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr) || - IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr)) && - sin6.sin6_scope_id == 0) { - sin6.sin6_scope_id = - ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); - sin6.sin6_addr.s6_addr[2] = 0; - sin6.sin6_addr.s6_addr[3] = 0; + memset(&ss, 0, sizeof(ss)); + if (sa->sa_len == 0) + ss.ss_family = sa->sa_family; + else + memcpy(&ss, sa, sa->sa_len); + /* Expand sa->sa_len because it could be shortened. */ + if (sa->sa_family == AF_INET) + ss.ss_len = sizeof(struct sockaddr_in); + else if (sa->sa_family == AF_INET6) + ss.ss_len = sizeof(struct sockaddr_in6); + error = getnameinfo((struct sockaddr *)&ss, ss.ss_len, + rt_line, sizeof(rt_line), NULL, 0, + (nflag == 0) ? 0 : NI_NUMERICHOST); + if (error) { + warnx("getnameinfo(): %s", gai_strerror(error)); + strncpy(rt_line, "invalid", sizeof(rt_line)); } -#endif - if (c->nflag) - niflags |= NI_NUMERICHOST; - if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, - c->rt_line, sizeof(c->rt_line), NULL, 0, niflags) != 0) - strncpy(c->rt_line, "invalid", sizeof(c->rt_line)); - return(c->rt_line); + /* Remove the domain part if any. */ + p = strchr(rt_line, '.'); + if (p != NULL && strcmp(p + 1, domain) == 0) + *p = '\0'; + + return (rt_line); + break; } #endif - case AF_LINK: - return (link_ntoa((struct sockaddr_dl *)sa)); + sdl = (struct sockaddr_dl *)(void *)sa; + + if (sdl->sdl_nlen == 0 && + sdl->sdl_alen == 0 && + sdl->sdl_slen == 0) { + n = snprintf(rt_line, sizeof(rt_line), "link#%d", + sdl->sdl_index); + if (n > (int)sizeof(rt_line)) + rt_line[0] = '\0'; + return (rt_line); + } else + return (link_ntoa(sdl)); + break; default: { - u_short *sp = (u_short *)sa; + u_short *sp = (u_short *)(void *)sa; u_short *splim = sp + ((sa->sa_len + 1) >> 1); - char *cps = c->rt_line + sprintf(c->rt_line, "(%d)", sa->sa_family); - char *cpe = c->rt_line + sizeof(c->rt_line); + char *cps = rt_line + sprintf(rt_line, "(%d)", sa->sa_family); + char *cpe = rt_line + sizeof(rt_line); while (++sp < splim && cps < cpe) /* start with sa->sa_data */ if ((n = snprintf(cps, cpe - cps, " %x", *sp)) > 0) @@ -727,118 +687,98 @@ routename(struct rt_ctx *c, struct sockaddr *sa) break; } } - return (c->rt_line); + return (rt_line); } /* * Return the name of the network whose address is given. - * The address is assumed to be that of a net or subnet, not a host. + * The address is assumed to be that of a net, not a host. */ -const char * -netname(struct rt_ctx *c, struct sockaddr *sa) +static const char * +netname(struct sockaddr *sa) { - const char *cp = NULL; + struct sockaddr_dl *sdl; + int n; +#ifdef INET struct netent *np = NULL; - u_long net, mask; + const char *cp = NULL; u_long i; - int n, subnetshift; +#endif switch (sa->sa_family) { - +#ifdef INET case AF_INET: - { struct in_addr in; - in = ((struct sockaddr_in *)sa)->sin_addr; + { + struct in_addr in; + in = ((struct sockaddr_in *)(void *)sa)->sin_addr; i = in.s_addr = ntohl(in.s_addr); if (in.s_addr == 0) cp = "default"; - else if (!c->nflag) { - if (IN_CLASSA(i)) { - mask = IN_CLASSA_NET; - subnetshift = 8; - } else if (IN_CLASSB(i)) { - mask = IN_CLASSB_NET; - subnetshift = 8; - } else { - mask = IN_CLASSC_NET; - subnetshift = 4; - } - /* - * If there are more bits than the standard mask - * would suggest, subnets must be in use. - * Guess at the subnet mask, assuming reasonable - * width subnet fields. - */ - while (in.s_addr &~ mask) - mask = (long)mask >> subnetshift; - net = in.s_addr & mask; - while ((mask & 1) == 0) - mask >>= 1, net >>= 1; - np = getnetbyaddr(net, AF_INET); + else if (!nflag) { + np = getnetbyaddr(i, AF_INET); if (np != NULL) cp = np->n_name; } #define C(x) (unsigned)((x) & 0xff) if (cp != NULL) - strncpy(c->net_line, cp, sizeof(c->net_line)); + strncpy(net_line, cp, sizeof(net_line)); else if ((in.s_addr & 0xffffff) == 0) - (void) sprintf(c->net_line, "%u", C(in.s_addr >> 24)); + (void)sprintf(net_line, "%u", C(in.s_addr >> 24)); else if ((in.s_addr & 0xffff) == 0) - (void) sprintf(c->net_line, "%u.%u", C(in.s_addr >> 24), + (void)sprintf(net_line, "%u.%u", C(in.s_addr >> 24), C(in.s_addr >> 16)); else if ((in.s_addr & 0xff) == 0) - (void) sprintf(c->net_line, "%u.%u.%u", C(in.s_addr >> 24), + (void)sprintf(net_line, "%u.%u.%u", C(in.s_addr >> 24), C(in.s_addr >> 16), C(in.s_addr >> 8)); else - (void) sprintf(c->net_line, "%u.%u.%u.%u", C(in.s_addr >> 24), + (void)sprintf(net_line, "%u.%u.%u.%u", C(in.s_addr >> 24), C(in.s_addr >> 16), C(in.s_addr >> 8), C(in.s_addr)); #undef C break; - } - + } +#endif #ifdef INET6 case AF_INET6: { - struct sockaddr_in6 sin6; /* use static var for safety */ + struct sockaddr_in6 sin6; int niflags = 0; memset(&sin6, 0, sizeof(sin6)); memcpy(&sin6, sa, sa->sa_len); - sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_len = sizeof(sin6); sin6.sin6_family = AF_INET6; -#ifdef __KAME__ - if (sa->sa_len == sizeof(struct sockaddr_in6) && - (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) || - IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr) || - IN6_IS_ADDR_MC_NODELOCAL(&sin6.sin6_addr)) && - sin6.sin6_scope_id == 0) { - sin6.sin6_scope_id = - ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); - sin6.sin6_addr.s6_addr[2] = 0; - sin6.sin6_addr.s6_addr[3] = 0; - } -#endif - if (c->nflag) + if (nflag) niflags |= NI_NUMERICHOST; if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, - c->net_line, sizeof(c->net_line), NULL, 0, niflags) != 0) - strncpy(c->net_line, "invalid", sizeof(c->net_line)); + net_line, sizeof(net_line), NULL, 0, niflags) != 0) + strncpy(net_line, "invalid", sizeof(net_line)); - return(c->net_line); + return(net_line); } #endif - case AF_LINK: - return (link_ntoa((struct sockaddr_dl *)sa)); - + sdl = (struct sockaddr_dl *)(void *)sa; + + if (sdl->sdl_nlen == 0 && + sdl->sdl_alen == 0 && + sdl->sdl_slen == 0) { + n = snprintf(net_line, sizeof(net_line), "link#%d", + sdl->sdl_index); + if (n > (int)sizeof(net_line)) + net_line[0] = '\0'; + return (net_line); + } else + return (link_ntoa(sdl)); + break; default: { - u_short *sp = (u_short *)sa->sa_data; + u_short *sp = (u_short *)(void *)sa->sa_data; u_short *splim = sp + ((sa->sa_len + 1)>>1); - char *cps = c->net_line + sprintf(c->net_line, "af %d:", sa->sa_family); - char *cpe = c->net_line + sizeof(c->net_line); + char *cps = net_line + sprintf(net_line, "af %d:", sa->sa_family); + char *cpe = net_line + sizeof(net_line); while (sp < splim && cps < cpe) if ((n = snprintf(cps, cpe - cps, " %x", *sp++)) > 0) @@ -848,17 +788,18 @@ netname(struct rt_ctx *c, struct sockaddr *sa) break; } } - return (c->net_line); + return (net_line); } static void -set_metric(struct rt_ctx *c, char *value, int key) +set_metric(char *value, int key) { int flag = 0; + char *endptr; u_long noval, *valp = &noval; switch (key) { -#define caseof(x, y, z) case x: valp = &c->rt_metrics.z; flag = y; break +#define caseof(x, y, z) case x: valp = &rt_metrics.z; flag = y; break caseof(K_MTU, RTV_MTU, rmx_mtu); caseof(K_HOPCOUNT, RTV_HOPCOUNT, rmx_hopcount); caseof(K_EXPIRE, RTV_EXPIRE, rmx_expire); @@ -869,12 +810,23 @@ set_metric(struct rt_ctx *c, char *value, int key) caseof(K_RTTVAR, RTV_RTTVAR, rmx_rttvar); caseof(K_WEIGHT, RTV_WEIGHT, rmx_weight); } - c->rtm_inits |= flag; - if (c->lockrest || c->locking) - c->rt_metrics.rmx_locks |= flag; - if (c->locking) - c->locking = 0; - *valp = atoi(value); + rtm_inits |= flag; + if (lockrest || locking) + rt_metrics.rmx_locks |= flag; + if (locking) + locking = 0; + errno = 0; + *valp = strtol(value, &endptr, 0); + if (errno == 0 && *endptr != '\0') + errno = EINVAL; + if (errno) + err(EX_USAGE, "%s", value); + if (flag & RTV_EXPIRE && (value[0] == '+' || value[0] == '-')) { + struct timespec ts; + + clock_gettime(CLOCK_REALTIME_FAST, &ts); + *valp += ts.tv_sec; + } } #define F_ISHOST 0x01 @@ -884,51 +836,57 @@ set_metric(struct rt_ctx *c, char *value, int key) #define F_INTERFACE 0x10 static void -newroute(struct rt_ctx *c, int argc, char **argv) +newroute(int argc, char **argv) { + struct sigaction sa; struct hostent *hp; struct fibl *fl; char *cmd; const char *dest, *gateway, *errmsg; int key, error, flags, nrflags, fibnum; - if (c->uid != 0) { + if (uid != 0 && !debugonly && !tflag) errx(EX_NOPERM, "must be root to alter routing table"); - } - dest = NULL; gateway = NULL; flags = RTF_STATIC; nrflags = 0; hp = NULL; - TAILQ_INIT(&c->fibl_head); + TAILQ_INIT(&fibl_head); + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = stopit; + if (sigaction(SIGALRM, &sa, 0) == -1) + warn("sigaction SIGALRM"); cmd = argv[0]; if (*cmd != 'g' && *cmd != 's') - shutdown(c->s, SHUT_RD); /* Don't want to read back our messages */ - + shutdown(s, SHUT_RD); /* Don't want to read back our messages */ while (--argc > 0) { if (**(++argv)== '-') { switch (key = keyword(1 + *argv)) { case K_LINK: - c->af = AF_LINK; - c->aflen = sizeof(struct sockaddr_dl); + af = AF_LINK; + aflen = sizeof(struct sockaddr_dl); break; +#ifdef INET case K_4: case K_INET: - c->af = AF_INET; - c->aflen = sizeof(struct sockaddr_in); + af = AF_INET; + aflen = sizeof(struct sockaddr_in); break; +#endif #ifdef INET6 case K_6: case K_INET6: - c->af = AF_INET6; - c->aflen = sizeof(struct sockaddr_in6); + af = AF_INET6; + aflen = sizeof(struct sockaddr_in6); break; #endif case K_SA: - c->af = PF_ROUTE; - c->aflen = sizeof(union sockunion); + af = PF_ROUTE; + aflen = sizeof(struct sockaddr_storage); break; case K_IFACE: case K_INTERFACE: @@ -938,10 +896,10 @@ newroute(struct rt_ctx *c, int argc, char **argv) flags &= ~RTF_STATIC; break; case K_LOCK: - c->locking = 1; + locking = 1; break; case K_LOCKREST: - c->lockrest = 1; + lockrest = 1; break; case K_HOST: nrflags |= F_FORCEHOST; @@ -976,7 +934,7 @@ newroute(struct rt_ctx *c, int argc, char **argv) case K_FIB: if (!--argc) usage(NULL); - error = fiboptlist_csv(c, *++argv, &c->fibl_head); + error = fiboptlist_csv(*++argv, &fibl_head); if (error) errx(EX_USAGE, "invalid fib number: %s", *argv); @@ -984,35 +942,35 @@ newroute(struct rt_ctx *c, int argc, char **argv) case K_IFA: if (!--argc) usage(NULL); - getaddr(c, RTA_IFA, *++argv, 0, nrflags); + getaddr(RTAX_IFA, *++argv, 0, nrflags); break; case K_IFP: if (!--argc) usage(NULL); - getaddr(c, RTA_IFP, *++argv, 0, nrflags); + getaddr(RTAX_IFP, *++argv, 0, nrflags); break; case K_GENMASK: if (!--argc) usage(NULL); - getaddr(c, RTA_GENMASK, *++argv, 0, nrflags); + getaddr(RTAX_GENMASK, *++argv, 0, nrflags); break; case K_GATEWAY: if (!--argc) usage(NULL); - getaddr(c, RTA_GATEWAY, *++argv, 0, nrflags); + getaddr(RTAX_GATEWAY, *++argv, 0, nrflags); gateway = *argv; break; case K_DST: if (!--argc) usage(NULL); - if (getaddr(c, RTA_DST, *++argv, &hp, nrflags)) + if (getaddr(RTAX_DST, *++argv, &hp, nrflags)) nrflags |= F_ISHOST; dest = *argv; break; case K_NETMASK: if (!--argc) usage(NULL); - getaddr(c, RTA_NETMASK, *++argv, 0, nrflags); + getaddr(RTAX_NETMASK, *++argv, 0, nrflags); /* FALLTHROUGH */ case K_NET: nrflags |= F_FORCENET; @@ -1020,7 +978,7 @@ newroute(struct rt_ctx *c, int argc, char **argv) case K_PREFIXLEN: if (!--argc) usage(NULL); - if (prefixlen(c, *++argv) == -1) { + if (prefixlen(*++argv) == -1) { nrflags &= ~F_FORCENET; nrflags |= F_ISHOST; } else { @@ -1039,32 +997,44 @@ newroute(struct rt_ctx *c, int argc, char **argv) case K_WEIGHT: if (!--argc) usage(NULL); - set_metric(c, *++argv, key); + set_metric(*++argv, key); break; default: usage(1+*argv); } } else { - if ((c->rtm_addrs & RTA_DST) == 0) { + if ((rtm_addrs & RTA_DST) == 0) { dest = *argv; - if (getaddr(c, RTA_DST, *argv, &hp, nrflags)) + if (getaddr(RTAX_DST, *argv, &hp, nrflags)) nrflags |= F_ISHOST; - } else if ((c->rtm_addrs & RTA_GATEWAY) == 0) { + } else if ((rtm_addrs & RTA_GATEWAY) == 0) { gateway = *argv; - getaddr(c, RTA_GATEWAY, *argv, &hp, nrflags); + getaddr(RTAX_GATEWAY, *argv, &hp, nrflags); } else { - getaddr(c, RTA_NETMASK, *argv, 0, nrflags); + getaddr(RTAX_NETMASK, *argv, 0, nrflags); nrflags |= F_FORCENET; } } } + /* Do some sanity checks on resulting request */ + if (so[RTAX_DST].ss_len == 0) { + warnx("destination parameter required"); + usage(NULL); + } + + if (so[RTAX_NETMASK].ss_len != 0 && + so[RTAX_DST].ss_family != so[RTAX_NETMASK].ss_family) { + warnx("destination and netmask family need to be the same"); + usage(NULL); + } + if (nrflags & F_FORCEHOST) { nrflags |= F_ISHOST; #ifdef INET6 - if (c->af == AF_INET6) { - c->rtm_addrs &= ~RTA_NETMASK; - memset((void *)&c->so_mask, 0, sizeof(c->so_mask)); + if (af == AF_INET6) { + rtm_addrs &= ~RTA_NETMASK; + memset(&so[RTAX_NETMASK], 0, sizeof(so[RTAX_NETMASK])); } #endif } @@ -1075,23 +1045,21 @@ newroute(struct rt_ctx *c, int argc, char **argv) flags |= RTF_HOST; if ((nrflags & F_INTERFACE) == 0) flags |= RTF_GATEWAY; - if (nrflags & F_PROXY) { - c->so_dst.sinarp.sin_other = SIN_PROXY; + if (nrflags & F_PROXY) flags |= RTF_ANNOUNCE; - } if (dest == NULL) dest = ""; if (gateway == NULL) gateway = ""; - if (TAILQ_EMPTY(&c->fibl_head)) { - error = fiboptlist_csv(c, "default", &c->fibl_head); + if (TAILQ_EMPTY(&fibl_head)) { + error = fiboptlist_csv("default", &fibl_head); if (error) errx(EX_OSERR, "fiboptlist_csv failed."); } error = 0; - TAILQ_FOREACH(fl, &c->fibl_head, fl_next) { - fl->fl_error = newroute_fib(c, fl->fl_num, cmd, flags); + TAILQ_FOREACH(fl, &fibl_head, fl_next) { + fl->fl_error = newroute_fib(fl->fl_num, cmd, flags); if (fl->fl_error) fl->fl_errno = errno; error += fl->fl_error; @@ -1100,9 +1068,9 @@ newroute(struct rt_ctx *c, int argc, char **argv) exit(error); error = 0; - if (!c->qflag) { + if (!qflag) { fibnum = 0; - TAILQ_FOREACH(fl, &c->fibl_head, fl_next) { + TAILQ_FOREACH(fl, &fibl_head, fl_next) { if (fl->fl_error == 0) fibnum++; } @@ -1114,8 +1082,8 @@ newroute(struct rt_ctx *c, int argc, char **argv) if (*gateway) printf(": gateway %s", gateway); - if (c->numfibs > 1) { - TAILQ_FOREACH(fl, &c->fibl_head, fl_next) { + if (numfibs > 1) { + TAILQ_FOREACH(fl, &fibl_head, fl_next) { if (fl->fl_error == 0 && fl->fl_num >= 0) { if (firstfib) { @@ -1132,7 +1100,7 @@ newroute(struct rt_ctx *c, int argc, char **argv) } fibnum = 0; - TAILQ_FOREACH(fl, &c->fibl_head, fl_next) { + TAILQ_FOREACH(fl, &fibl_head, fl_next) { if (fl->fl_error != 0) { printf("%s %s %s", cmd, (nrflags & F_ISHOST) ? "host" : "net", dest); @@ -1175,47 +1143,45 @@ newroute(struct rt_ctx *c, int argc, char **argv) } static int -newroute_fib(struct rt_ctx *c, int fib, char *cmd, int flags) +newroute_fib(int fib, char *cmd, int flags) { int error; - error = set_sofib(c, fib); + error = set_sofib(fib); if (error) { warn("fib number %d is ignored", fib); return (error); } - error = rtmsg(c, *cmd, flags, fib); + error = rtmsg(*cmd, flags, fib); return (error); } +#ifdef INET static void -inet_makenetandmask(struct rt_ctx *c, u_long net, struct sockaddr_in *sin, u_long bits) +inet_makenetandmask(u_long net, struct sockaddr_in *sin, + struct sockaddr_in *sin_mask, u_long bits) { - u_long addr, mask = 0; - char *cp; + u_long mask = 0; + + rtm_addrs |= RTA_NETMASK; - c->rtm_addrs |= RTA_NETMASK; /* - * XXX: This approach unable to handle 0.0.0.1/32 correctly - * as inet_network() converts 0.0.0.1 and 1 equally. + * MSB of net should be meaningful. 0/0 is exception. */ - if (net <= 0xff) - addr = net << IN_CLASSA_NSHIFT; - else if (net <= 0xffff) - addr = net << IN_CLASSB_NSHIFT; - else if (net <= 0xffffff) - addr = net << IN_CLASSC_NSHIFT; - else - addr = net; + if (net > 0) + while ((net & 0xff000000) == 0) + net <<= 8; + /* * If no /xx was specified we must calculate the * CIDR address. */ - if ((bits == 0) && (addr != 0)) { + if ((bits == 0) && (net != 0)) { u_long i, j; - for(i=0,j=0xff; i<4; i++) { - if (addr & j) { + + for(i = 0, j = 0xff; i < 4; i++) { + if (net & j) { break; } j <<= 8; @@ -1226,43 +1192,31 @@ inet_makenetandmask(struct rt_ctx *c, u_long net, struct sockaddr_in *sin, u_lon if (bits != 0) mask = 0xffffffff << (32 - bits); - sin->sin_addr.s_addr = htonl(addr); - sin = &c->so_mask.sin; - sin->sin_addr.s_addr = htonl(mask); - sin->sin_len = 0; - sin->sin_family = 0; - cp = (char *)(&sin->sin_addr + 1); - while (*--cp == 0 && cp > (char *)sin) - ; - sin->sin_len = 1 + cp - (char *)sin; + sin->sin_addr.s_addr = htonl(net); + sin_mask->sin_addr.s_addr = htonl(mask); + sin_mask->sin_len = sizeof(struct sockaddr_in); + sin_mask->sin_family = AF_INET; } +#endif #ifdef INET6 /* * XXX the function may need more improvement... */ static int -inet6_makenetandmask(struct rt_ctx *c, struct sockaddr_in6 *sin6, const char *plen) +inet6_makenetandmask(struct sockaddr_in6 *sin6, const char *plen) { - struct in6_addr in6; if (plen == NULL) { if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && - sin6->sin6_scope_id == 0) { + sin6->sin6_scope_id == 0) plen = "0"; - } else if ((sin6->sin6_addr.s6_addr[0] & 0xe0) == 0x20) { - /* aggregatable global unicast - RFC2374 */ - memset(&in6, 0, sizeof(in6)); - if (!memcmp(&sin6->sin6_addr.s6_addr[8], - &in6.s6_addr[8], 8)) - plen = "64"; - } } if (plen == NULL || strcmp(plen, "128") == 0) return (1); - c->rtm_addrs |= RTA_NETMASK; - prefixlen(c, plen); + rtm_addrs |= RTA_NETMASK; + prefixlen(plen); return (0); } #endif @@ -1272,33 +1226,50 @@ inet6_makenetandmask(struct rt_ctx *c, struct sockaddr_in6 *sin6, const char *pl * returning 1 if a host address, 0 if a network address. */ static int -getaddr(struct rt_ctx *c, int which, char *str, struct hostent **hpp, int nrflags) +getaddr(int idx, char *str, struct hostent **hpp, int nrflags) { - sup su; + struct sockaddr *sa; +#if defined(INET) + struct sockaddr_in *sin; struct hostent *hp; struct netent *np; u_long val; char *q; - int afamily; /* local copy of af so we can change it */ +#elif defined(INET6) + char *q; +#endif - if (c->af == 0) { - c->af = AF_INET; - c->aflen = sizeof(struct sockaddr_in); + if (idx < 0 || idx >= RTAX_MAX) + usage("internal error"); + if (af == 0) { +#if defined(INET) + af = AF_INET; + aflen = sizeof(struct sockaddr_in); +#elif defined(INET6) + af = AF_INET6; + aflen = sizeof(struct sockaddr_in6); +#else + af = AF_LINK; + aflen = sizeof(struct sockaddr_dl); +#endif } - afamily = c->af; - c->rtm_addrs |= which; - switch (which) { - case RTA_DST: - su = &c->so_dst; - break; - case RTA_GATEWAY: - su = &c->so_gate; +#ifndef INET + hpp = NULL; +#endif + rtm_addrs |= (1 << idx); + sa = (struct sockaddr *)&so[idx]; + sa->sa_family = af; + sa->sa_len = aflen; + + switch (idx) { + case RTAX_GATEWAY: if (nrflags & F_INTERFACE) { struct ifaddrs *ifap, *ifa; + struct sockaddr_dl *sdl0 = (struct sockaddr_dl *)(void *)sa; struct sockaddr_dl *sdl = NULL; if (getifaddrs(&ifap)) - err(1, "getifaddrs"); + err(EX_OSERR, "getifaddrs"); for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr->sa_family != AF_LINK) @@ -1307,63 +1278,41 @@ getaddr(struct rt_ctx *c, int which, char *str, struct hostent **hpp, int nrflag if (strcmp(str, ifa->ifa_name) != 0) continue; - sdl = (struct sockaddr_dl *)ifa->ifa_addr; + sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; } /* If we found it, then use it */ if (sdl != NULL) { /* - * Copy is safe since we have a - * sockaddr_storage member in sockunion{}. * Note that we need to copy before calling * freeifaddrs(). */ - memcpy(&su->sdl, sdl, sdl->sdl_len); + memcpy(sdl0, sdl, sdl->sdl_len); } freeifaddrs(ifap); if (sdl != NULL) return(1); + else + errx(EX_DATAERR, + "interface '%s' does not exist", str); } break; - case RTA_NETMASK: - su = &c->so_mask; + case RTAX_IFP: + sa->sa_family = AF_LINK; break; - case RTA_GENMASK: - su = &c->so_genmask; - break; - case RTA_IFP: - su = &c->so_ifp; - afamily = AF_LINK; - break; - case RTA_IFA: - su = &c->so_ifa; - break; - default: - usage("internal error"); - /*NOTREACHED*/ } - su->sa.sa_len = c->aflen; - su->sa.sa_family = afamily; /* cases that don't want it have left already */ if (strcmp(str, "default") == 0) { /* * Default is net 0.0.0.0/0 */ - switch (which) { - case RTA_DST: - c->forcenet++; -#if 0 - bzero(su, sizeof(*su)); /* for readability */ -#endif - getaddr(c, RTA_NETMASK, str, 0, nrflags); + switch (idx) { + case RTAX_DST: + nrflags |= F_FORCENET; + getaddr(RTAX_NETMASK, str, 0, nrflags); break; -#if 0 - case RTA_NETMASK: - case RTA_GENMASK: - bzero(su, sizeof(*su)); /* for readability */ -#endif } return (0); } - switch (afamily) { + switch (sa->sa_family) { #ifdef INET6 case AF_INET6: { @@ -1371,129 +1320,130 @@ getaddr(struct rt_ctx *c, int which, char *str, struct hostent **hpp, int nrflag int ecode; q = NULL; - if (which == RTA_DST && (q = strchr(str, '/')) != NULL) + if (idx == RTAX_DST && (q = strchr(str, '/')) != NULL) *q = '\0'; memset(&hints, 0, sizeof(hints)); - hints.ai_family = afamily; /*AF_INET6*/ - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_family = sa->sa_family; + hints.ai_socktype = SOCK_DGRAM; ecode = getaddrinfo(str, NULL, &hints, &res); if (ecode != 0 || res->ai_family != AF_INET6 || - res->ai_addrlen != sizeof(su->sin6)) { - (void) fprintf(stderr, "%s: %s\n", str, - gai_strerror(ecode)); - exit(1); - } - memcpy(&su->sin6, res->ai_addr, sizeof(su->sin6)); -#ifdef __KAME__ - if ((IN6_IS_ADDR_LINKLOCAL(&su->sin6.sin6_addr) || - IN6_IS_ADDR_MC_LINKLOCAL(&su->sin6.sin6_addr) || - IN6_IS_ADDR_MC_NODELOCAL(&su->sin6.sin6_addr)) && - su->sin6.sin6_scope_id) { - *(u_int16_t *)&su->sin6.sin6_addr.s6_addr[2] = - htons(su->sin6.sin6_scope_id); - su->sin6.sin6_scope_id = 0; - } -#endif + res->ai_addrlen != sizeof(struct sockaddr_in6)) + errx(EX_OSERR, "%s: %s", str, gai_strerror(ecode)); + memcpy(sa, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); if (q != NULL) *q++ = '/'; - if (which == RTA_DST) - return (inet6_makenetandmask(c, &su->sin6, q)); + if (idx == RTAX_DST) + return (inet6_makenetandmask((struct sockaddr_in6 *)(void *)sa, q)); return (0); } #endif /* INET6 */ - case AF_LINK: - link_addr(str, &su->sdl); + link_addr(str, (struct sockaddr_dl *)(void *)sa); return (1); - case PF_ROUTE: - su->sa.sa_len = sizeof(*su); - sockaddr(str, &su->sa); + sockaddr(str, sa, sizeof(struct sockaddr_storage)); return (1); - +#ifdef INET case AF_INET: +#endif default: break; } +#ifdef INET + sin = (struct sockaddr_in *)(void *)sa; if (hpp == NULL) hpp = &hp; *hpp = NULL; q = strchr(str,'/'); - if (q != NULL && which == RTA_DST) { + if (q != NULL && idx == RTAX_DST) { *q = '\0'; if ((val = inet_network(str)) != INADDR_NONE) { - inet_makenetandmask( - c, val, &su->sin, strtoul(q+1, 0, 0)); + inet_makenetandmask(val, sin, + (struct sockaddr_in *)&so[RTAX_NETMASK], + strtoul(q+1, 0, 0)); return (0); } *q = '/'; } - if ((which != RTA_DST || c->forcenet == 0) && - inet_aton(str, &su->sin.sin_addr)) { - val = su->sin.sin_addr.s_addr; - if (which != RTA_DST || c->forcehost || - inet_lnaof(su->sin.sin_addr) != INADDR_ANY) + if ((idx != RTAX_DST || (nrflags & F_FORCENET) == 0) && + inet_aton(str, &sin->sin_addr)) { + val = sin->sin_addr.s_addr; + if (idx != RTAX_DST || nrflags & F_FORCEHOST || + inet_lnaof(sin->sin_addr) != INADDR_ANY) return (1); else { val = ntohl(val); goto netdone; } } - if (which == RTA_DST && c->forcehost == 0 && + if (idx == RTAX_DST && (nrflags & F_FORCEHOST) == 0 && ((val = inet_network(str)) != INADDR_NONE || ((np = getnetbyname(str)) != NULL && (val = np->n_net) != 0))) { netdone: - inet_makenetandmask(c, val, &su->sin, 0); + inet_makenetandmask(val, sin, + (struct sockaddr_in *)&so[RTAX_NETMASK], 0); return (0); } hp = gethostbyname(str); if (hp != NULL) { *hpp = hp; - su->sin.sin_family = hp->h_addrtype; - memmove((char *)&su->sin.sin_addr, hp->h_addr, - MIN((size_t)hp->h_length, sizeof(su->sin.sin_addr))); + sin->sin_family = hp->h_addrtype; + memmove((char *)&sin->sin_addr, hp->h_addr, + MIN((size_t)hp->h_length, sizeof(sin->sin_addr))); return (1); } +#endif errx(EX_NOHOST, "bad address: %s", str); } static int -prefixlen(struct rt_ctx *c, const char *str) +prefixlen(const char *str) { int len = atoi(str), q, r; int max; char *p; - c->rtm_addrs |= RTA_NETMASK; - switch (c->af) { + rtm_addrs |= RTA_NETMASK; + switch (af) { #ifdef INET6 case AF_INET6: + { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)&so[RTAX_NETMASK]; + max = 128; - p = (char *)&c->so_mask.sin6.sin6_addr; + p = (char *)&sin6->sin6_addr; + sin6->sin6_family = AF_INET6; + sin6->sin6_len = sizeof(*sin6); break; + } #endif +#ifdef INET case AF_INET: + { + struct sockaddr_in *sin = + (struct sockaddr_in *)&so[RTAX_NETMASK]; + max = 32; - p = (char *)&c->so_mask.sin.sin_addr; + p = (char *)&sin->sin_addr; + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); break; + } +#endif default: - fprintf(stderr, "prefixlen not supported in this af\n"); - exit(1); + errx(EX_OSERR, "prefixlen not supported in this af"); } - if (len < 0 || max < len) { - fprintf(stderr, "%s: bad value\n", str); - exit(1); - } + if (len < 0 || max < len) + errx(EX_USAGE, "%s: invalid prefixlen", str); q = len >> 3; r = len & 7; - c->so_mask.sa.sa_family = c->af; - c->so_mask.sa.sa_len = c->aflen; memset((void *)p, 0, max / 8); if (q > 0) memset((void *)p, 0xff, q); @@ -1506,7 +1456,7 @@ prefixlen(struct rt_ctx *c, const char *str) } static void -interfaces(struct rt_ctx *c) +interfaces(void) { size_t needed; int mib[6]; @@ -1517,14 +1467,14 @@ retry2: mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ - mib[3] = 0; /* wildcard address family */ + mib[3] = AF_UNSPEC; mib[4] = NET_RT_IFLIST; mib[5] = 0; /* no flags */ - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + if (sysctl(mib, nitems(mib), NULL, &needed, NULL, 0) < 0) err(EX_OSERR, "route-sysctl-estimate"); - if ((buf = malloc(needed)) == NULL && needed != 0) + if ((buf = malloc(needed)) == NULL) errx(EX_OSERR, "malloc failed"); - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + if (sysctl(mib, nitems(mib), buf, &needed, NULL, 0) < 0) { if (errno == ENOMEM && count++ < 10) { warnx("Routing table grew, retrying"); sleep(1); @@ -1535,19 +1485,18 @@ retry2: } lim = buf + needed; for (next = buf; next < lim; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)next; - print_rtmsg(c, rtm, rtm->rtm_msglen); + rtm = (struct rt_msghdr *)(void *)next; + print_rtmsg(rtm, rtm->rtm_msglen); } - free(buf); } static void -monitor(struct rt_ctx *c, int argc, char *argv[]) +monitor(int argc, char *argv[]) { int n, fib, error; char msg[2048], *endptr; - fib = c->defaultfib; + fib = defaultfib; while (argc > 1) { argc--; argv++; @@ -1562,7 +1511,7 @@ monitor(struct rt_ctx *c, int argc, char *argv[]) if (errno == 0) { if (*endptr != '\0' || fib < 0 || - (c->numfibs != -1 && fib > c->numfibs - 1)) + (numfibs != -1 && fib > numfibs - 1)) errno = EINVAL; } if (errno) @@ -1572,124 +1521,115 @@ monitor(struct rt_ctx *c, int argc, char *argv[]) usage(*argv); } } - error = set_sofib(c, fib); + error = set_sofib(fib); if (error) errx(EX_USAGE, "invalid fib number: %d", fib); - c->verbose = 1; - if (c->debugonly) { - interfaces(c); + verbose = 1; + if (debugonly) { + interfaces(); exit(0); } for (;;) { time_t now; - n = read(c->s, msg, 2048); + n = read(s, msg, 2048); now = time(NULL); - (void) printf("\ngot message of size %d on %s", n, ctime(&now)); - print_rtmsg(c, (struct rt_msghdr *)msg, n); + (void)printf("\ngot message of size %d on %s", n, ctime(&now)); + print_rtmsg((struct rt_msghdr *)(void *)msg, n); } } static int -rtmsg(struct rt_ctx *c, int cmd, int flags, int fib) +rtmsg(int cmd, int flags, int fib) { int rlen; - char *cp = c->m_rtmsg.m_space; + char *cp = m_rtmsg.m_space; int l; -#define NEXTADDR(w, u) \ - if (c->rtm_addrs & (w)) {\ - l = SA_SIZE(&(u.sa)); memmove(cp, &(u), l); cp += l;\ - if (c->verbose) sodump(&(u),#u);\ +#define NEXTADDR(w, u) \ + if (rtm_addrs & (w)) { \ + l = (((struct sockaddr *)&(u))->sa_len == 0) ? \ + sizeof(long) : \ + 1 + ((((struct sockaddr *)&(u))->sa_len - 1) \ + | (sizeof(long) - 1)); \ + memmove(cp, (char *)&(u), l); \ + cp += l; \ + if (verbose) \ + sodump((struct sockaddr *)&(u), #w); \ } errno = 0; - memset(&c->m_rtmsg, 0, sizeof(c->m_rtmsg)); + memset(&m_rtmsg, 0, sizeof(m_rtmsg)); if (cmd == 'a') cmd = RTM_ADD; else if (cmd == 'c') cmd = RTM_CHANGE; else if (cmd == 'g' || cmd == 's') { cmd = RTM_GET; - if (c->so_ifp.sa.sa_family == 0) { - c->so_ifp.sa.sa_family = AF_LINK; - c->so_ifp.sa.sa_len = sizeof(struct sockaddr_dl); - c->rtm_addrs |= RTA_IFP; + if (so[RTAX_IFP].ss_family == 0) { + so[RTAX_IFP].ss_family = AF_LINK; + so[RTAX_IFP].ss_len = sizeof(struct sockaddr_dl); + rtm_addrs |= RTA_IFP; } } else cmd = RTM_DELETE; -#define rtm c->m_rtmsg.m_rtm +#define rtm m_rtmsg.m_rtm rtm.rtm_type = cmd; rtm.rtm_flags = flags; rtm.rtm_version = RTM_VERSION; - rtm.rtm_seq = ++c->rtm_seq; - rtm.rtm_addrs = c->rtm_addrs; - rtm.rtm_rmx = c->rt_metrics; - rtm.rtm_inits = c->rtm_inits; - - if (c->rtm_addrs & RTA_NETMASK) - mask_addr(c); - NEXTADDR(RTA_DST, c->so_dst); - NEXTADDR(RTA_GATEWAY, c->so_gate); - NEXTADDR(RTA_NETMASK, c->so_mask); - NEXTADDR(RTA_GENMASK, c->so_genmask); - NEXTADDR(RTA_IFP, c->so_ifp); - NEXTADDR(RTA_IFA, c->so_ifa); - rtm.rtm_msglen = l = cp - (char *)&c->m_rtmsg; - if (c->verbose) - print_rtmsg(c, &rtm, l); - if (c->debugonly) + rtm.rtm_seq = ++rtm_seq; + rtm.rtm_addrs = rtm_addrs; + rtm.rtm_rmx = rt_metrics; + rtm.rtm_inits = rtm_inits; + + NEXTADDR(RTA_DST, so[RTAX_DST]); + NEXTADDR(RTA_GATEWAY, so[RTAX_GATEWAY]); + NEXTADDR(RTA_NETMASK, so[RTAX_NETMASK]); + NEXTADDR(RTA_GENMASK, so[RTAX_GENMASK]); + NEXTADDR(RTA_IFP, so[RTAX_IFP]); + NEXTADDR(RTA_IFA, so[RTAX_IFA]); + rtm.rtm_msglen = l = cp - (char *)&m_rtmsg; + if (verbose) + print_rtmsg(&rtm, l); + if (debugonly) return (0); - if ((rlen = write(c->s, (char *)&c->m_rtmsg, l)) < 0) { - if (errno == EPERM) + if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { + switch (errno) { + case EPERM: err(1, "writing to routing socket"); - warn("writing to routing socket"); + break; + case ESRCH: + warnx("route has not been found"); + break; + case EEXIST: + /* Handled by newroute() */ + break; + default: + warn("writing to routing socket"); + } return (-1); } if (cmd == RTM_GET) { + stop_read = 0; + alarm(READ_TIMEOUT); do { - l = read(c->s, (char *)&c->m_rtmsg, sizeof(c->m_rtmsg)); - } while (l > 0 && (rtm.rtm_seq != c->rtm_seq || rtm.rtm_pid != c->pid)); + l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); + } while (l > 0 && stop_read == 0 && + (rtm.rtm_seq != rtm_seq || rtm.rtm_pid != pid)); + if (stop_read != 0) { + warnx("read from routing socket timed out"); + return (-1); + } else + alarm(0); if (l < 0) warn("read from routing socket"); else - print_getmsg(c, &rtm, l, fib); + print_getmsg(&rtm, l, fib); } #undef rtm return (0); } -static void -mask_addr(struct rt_ctx *c) -{ - int olen = c->so_mask.sa.sa_len; - char *cp1 = olen + (char *)&c->so_mask, *cp2; - - for (c->so_mask.sa.sa_len = 0; cp1 > (char *)&c->so_mask; ) - if (*--cp1 != 0) { - c->so_mask.sa.sa_len = 1 + cp1 - (char *)&c->so_mask; - break; - } - if ((c->rtm_addrs & RTA_DST) == 0) - return; - switch (c->so_dst.sa.sa_family) { - case AF_INET: -#ifdef INET6 - case AF_INET6: -#endif - case AF_APPLETALK: - case 0: - return; - } - cp1 = c->so_mask.sa.sa_len + 1 + (char *)&c->so_dst; - cp2 = c->so_dst.sa.sa_len + 1 + (char *)&c->so_dst; - while (cp2 > cp1) - *--cp2 = 0; - cp2 = c->so_mask.sa.sa_len + 1 + (char *)&c->so_mask; - while (cp1 > c->so_dst.sa.sa_data) - *--cp1 &= *--cp2; -} - static const char *const msgtypes[] = { "", "RTM_ADD: Add Route", @@ -1713,25 +1653,25 @@ static const char *const msgtypes[] = { }; static const char metricnames[] = -"\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" -"\1mtu"; + "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" + "\1mtu"; static const char routeflags[] = -"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" -"\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" -"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" -"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY"; + "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" + "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" + "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" + "\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY"; static const char ifnetflags[] = -"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" -"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" -"\017LINK2\020MULTICAST"; + "\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP" + "\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1" + "\017LINK2\020MULTICAST"; static const char addrnames[] = -"\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; + "\1DST\2GATEWAY\3NETMASK\4GENMASK\5IFP\6IFA\7AUTHOR\010BRD"; static const char errfmt[] = -"\n%s: truncated route message, only %zu bytes left\n"; + "\n%s: truncated route message, only %zu bytes left\n"; static void -print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen) +print_rtmsg(struct rt_msghdr *rtm, size_t msglen) { struct if_msghdr *ifm; struct ifa_msghdr *ifam; @@ -1741,14 +1681,14 @@ print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen) struct if_announcemsghdr *ifan; const char *state; - if (c->verbose == 0) + if (verbose == 0) return; if (rtm->rtm_version != RTM_VERSION) { - (void) printf("routing message version %d not understood\n", + (void)printf("routing message version %d not understood\n", rtm->rtm_version); return; } - if (rtm->rtm_type < sizeof(msgtypes) / sizeof(msgtypes[0])) + if (rtm->rtm_type < nitems(msgtypes)) (void)printf("%s: ", msgtypes[rtm->rtm_type]); else (void)printf("unknown type %d: ", rtm->rtm_type); @@ -1765,7 +1705,7 @@ print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen) case RTM_IFINFO: REQUIRE(struct if_msghdr); ifm = (struct if_msghdr *)rtm; - (void) printf("if# %d, ", ifm->ifm_index); + (void)printf("if# %d, ", ifm->ifm_index); switch (ifm->ifm_data.ifi_link_state) { case LINK_STATE_DOWN: state = "down"; @@ -1777,33 +1717,33 @@ print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen) state = "unknown"; break; } - (void) printf("link: %s, flags:", state); - bprintf(stdout, ifm->ifm_flags, ifnetflags); - pmsg_addrs(c, (char *)(ifm + 1), ifm->ifm_addrs, msglen); + (void)printf("link: %s, flags:", state); + printb(ifm->ifm_flags, ifnetflags); + pmsg_addrs((char *)(ifm + 1), ifm->ifm_addrs, msglen); break; case RTM_NEWADDR: case RTM_DELADDR: REQUIRE(struct ifa_msghdr); ifam = (struct ifa_msghdr *)rtm; - (void) printf("metric %d, flags:", ifam->ifam_metric); - bprintf(stdout, ifam->ifam_flags, routeflags); - pmsg_addrs(c, (char *)(ifam + 1), ifam->ifam_addrs, msglen); + (void)printf("metric %d, flags:", ifam->ifam_metric); + printb(ifam->ifam_flags, routeflags); + pmsg_addrs((char *)(ifam + 1), ifam->ifam_addrs, msglen); break; #ifdef RTM_NEWMADDR case RTM_NEWMADDR: case RTM_DELMADDR: REQUIRE(struct ifma_msghdr); ifmam = (struct ifma_msghdr *)rtm; - pmsg_addrs(c, (char *)(ifmam + 1), ifmam->ifmam_addrs, msglen); + pmsg_addrs((char *)(ifmam + 1), ifmam->ifmam_addrs, msglen); break; #endif case RTM_IFANNOUNCE: REQUIRE(struct if_announcemsghdr); ifan = (struct if_announcemsghdr *)rtm; - (void) printf("if# %d, what: ", ifan->ifan_index); + (void)printf("if# %d, what: ", ifan->ifan_index); switch (ifan->ifan_what) { case IFAN_ARRIVAL: - printf("arrival"); + (void)printf("arrival"); break; case IFAN_DEPARTURE: printf("departure"); @@ -1817,10 +1757,10 @@ print_rtmsg(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen) break; default: - (void) printf("pid: %ld, seq %d, errno %d, flags:", + printf("pid: %ld, seq %d, errno %d, flags:", (long)rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno); - bprintf(stdout, rtm->rtm_flags, routeflags); - pmsg_common(c, rtm, msglen); + printb(rtm->rtm_flags, routeflags); + pmsg_common(rtm, msglen); } return; @@ -1831,16 +1771,16 @@ badlen: } static void -print_getmsg(struct rt_ctx *c, struct rt_msghdr *rtm, int msglen, int fib) +print_getmsg(struct rt_msghdr *rtm, int msglen, int fib) { - struct sockaddr *dst = NULL, *gate = NULL, *mask = NULL; - struct sockaddr_dl *ifp = NULL; - struct sockaddr *sa; + struct sockaddr *sp[RTAX_MAX]; + struct timespec ts; char *cp; int i; - (void) printf(" route to: %s\n", - routename(c, (struct sockaddr *)&c->so_dst)); + memset(sp, 0, sizeof(sp)); + (void)printf(" route to: %s\n", + routename((struct sockaddr *)&so[RTAX_DST])); if (rtm->rtm_version != RTM_VERSION) { warnx("routing message version %d not understood", rtm->rtm_version); @@ -1849,6 +1789,7 @@ print_getmsg(struct rt_ctx *c, struct rt_msghdr *rtm, int msglen, int fib) if (rtm->rtm_msglen > msglen) { warnx("message length mismatch, in packet %d, returned %d", rtm->rtm_msglen, msglen); + return; } if (rtm->rtm_errno) { errno = rtm->rtm_errno; @@ -1856,122 +1797,105 @@ print_getmsg(struct rt_ctx *c, struct rt_msghdr *rtm, int msglen, int fib) return; } cp = ((char *)(rtm + 1)); - if (rtm->rtm_addrs) - for (i = 1; i; i <<= 1) - if (i & rtm->rtm_addrs) { - sa = (struct sockaddr *)cp; - switch (i) { - case RTA_DST: - dst = sa; - break; - case RTA_GATEWAY: - gate = sa; - break; - case RTA_NETMASK: - mask = sa; - break; - case RTA_IFP: - if (sa->sa_family == AF_LINK && - ((struct sockaddr_dl *)sa)->sdl_nlen) - ifp = (struct sockaddr_dl *)sa; - break; - } - cp += SA_SIZE(sa); - } - if (dst && mask) - mask->sa_family = dst->sa_family; /* XXX */ - if (dst) - (void)printf("destination: %s\n", routename(c, dst)); - if (mask) { - int savenflag = c->nflag; - - c->nflag = 1; - (void)printf(" mask: %s\n", routename(c, mask)); - c->nflag = savenflag; - } - if (gate && rtm->rtm_flags & RTF_GATEWAY) - (void)printf(" gateway: %s\n", routename(c, gate)); + for (i = 0; i < RTAX_MAX; i++) + if (rtm->rtm_addrs & (1 << i)) { + sp[i] = (struct sockaddr *)cp; + cp += SA_SIZE((struct sockaddr *)cp); + } + if ((rtm->rtm_addrs & RTA_IFP) && + (sp[RTAX_IFP]->sa_family != AF_LINK || + ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen == 0)) + sp[RTAX_IFP] = NULL; + if (sp[RTAX_DST]) + (void)printf("destination: %s\n", routename(sp[RTAX_DST])); + if (sp[RTAX_NETMASK]) + (void)printf(" mask: %s\n", routename(sp[RTAX_NETMASK])); + if (sp[RTAX_GATEWAY] && (rtm->rtm_flags & RTF_GATEWAY)) + (void)printf(" gateway: %s\n", routename(sp[RTAX_GATEWAY])); if (fib >= 0) (void)printf(" fib: %u\n", (unsigned int)fib); - if (ifp) + if (sp[RTAX_IFP]) (void)printf(" interface: %.*s\n", - ifp->sdl_nlen, ifp->sdl_data); + ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_nlen, + ((struct sockaddr_dl *)(void *)sp[RTAX_IFP])->sdl_data); (void)printf(" flags: "); - bprintf(stdout, rtm->rtm_flags, routeflags); + printb(rtm->rtm_flags, routeflags); #define lock(f) ((rtm->rtm_rmx.rmx_locks & __CONCAT(RTV_,f)) ? 'L' : ' ') #define msec(u) (((u) + 500) / 1000) /* usec to msec */ - - (void) printf("\n%s\n", "\ - recvpipe sendpipe ssthresh rtt,msec mtu weight expire"); - printf("%8ld%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); - printf("%8ld%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); - printf("%8ld%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); - printf("%8ld%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); - printf("%8ld%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); - printf("%8ld%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT)); - if (rtm->rtm_rmx.rmx_expire) - rtm->rtm_rmx.rmx_expire -= time(0); - printf("%8ld%c\n", rtm->rtm_rmx.rmx_expire, lock(EXPIRE)); + printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe", + "sendpipe", "ssthresh", "rtt,msec", "mtu ", "weight", "expire"); + printf("%8lu%c ", rtm->rtm_rmx.rmx_recvpipe, lock(RPIPE)); + printf("%8lu%c ", rtm->rtm_rmx.rmx_sendpipe, lock(SPIPE)); + printf("%8lu%c ", rtm->rtm_rmx.rmx_ssthresh, lock(SSTHRESH)); + printf("%8lu%c ", msec(rtm->rtm_rmx.rmx_rtt), lock(RTT)); + printf("%8lu%c ", rtm->rtm_rmx.rmx_mtu, lock(MTU)); + printf("%8lu%c ", rtm->rtm_rmx.rmx_weight, lock(WEIGHT)); + if (rtm->rtm_rmx.rmx_expire > 0) + clock_gettime(CLOCK_REALTIME_FAST, &ts); + else + ts.tv_sec = 0; + printf("%8ld%c\n", (long)(rtm->rtm_rmx.rmx_expire - ts.tv_sec), + lock(EXPIRE)); #undef lock #undef msec #define RTA_IGN (RTA_DST|RTA_GATEWAY|RTA_NETMASK|RTA_IFP|RTA_IFA|RTA_BRD) - if (c->verbose) - pmsg_common(c, rtm, msglen); + if (verbose) + pmsg_common(rtm, msglen); else if (rtm->rtm_addrs &~ RTA_IGN) { - (void) printf("sockaddrs: "); - bprintf(stdout, rtm->rtm_addrs, addrnames); + (void)printf("sockaddrs: "); + printb(rtm->rtm_addrs, addrnames); putchar('\n'); } #undef RTA_IGN } static void -pmsg_common(struct rt_ctx *c, struct rt_msghdr *rtm, size_t msglen) +pmsg_common(struct rt_msghdr *rtm, size_t msglen) { - (void) printf("\nlocks: "); - bprintf(stdout, rtm->rtm_rmx.rmx_locks, metricnames); - (void) printf(" inits: "); - bprintf(stdout, rtm->rtm_inits, metricnames); + + (void)printf("\nlocks: "); + printb(rtm->rtm_rmx.rmx_locks, metricnames); + (void)printf(" inits: "); + printb(rtm->rtm_inits, metricnames); if (msglen > sizeof(struct rt_msghdr)) - pmsg_addrs(c, ((char *)(rtm + 1)), rtm->rtm_addrs, + pmsg_addrs(((char *)(rtm + 1)), rtm->rtm_addrs, msglen - sizeof(struct rt_msghdr)); else - (void) fflush(stdout); + (void)fflush(stdout); } static void -pmsg_addrs(struct rt_ctx *c, char *cp, int addrs, size_t len) +pmsg_addrs(char *cp, int addrs, size_t len) { struct sockaddr *sa; int i; if (addrs == 0) { - (void) putchar('\n'); + (void)putchar('\n'); return; } - (void) printf("\nsockaddrs: "); - bprintf(stdout, addrs, addrnames); - (void) putchar('\n'); - for (i = 1; i != 0; i <<= 1) - if (i & addrs) { + (void)printf("\nsockaddrs: "); + printb(addrs, addrnames); + putchar('\n'); + for (i = 0; i < RTAX_MAX; i++) + if (addrs & (1 << i)) { sa = (struct sockaddr *)cp; if (len == 0 || len < SA_SIZE(sa)) { - (void) printf(errfmt, __func__, len); + (void)printf(errfmt, __func__, len); break; } - (void) printf(" %s", routename(c, sa)); + (void)printf(" %s", routename(sa)); len -= SA_SIZE(sa); cp += SA_SIZE(sa); } - (void) putchar('\n'); - (void) fflush(stdout); + (void)putchar('\n'); + (void)fflush(stdout); } static void -bprintf(FILE *fp, int b, const char *sstr) +printb(int b, const char *str) { - const u_char *str = (const u_char *) sstr; int i; int gotsome = 0; @@ -1983,16 +1907,16 @@ bprintf(FILE *fp, int b, const char *sstr) i = '<'; else i = ','; - (void) putc(i, fp); + putchar(i); gotsome = 1; for (; (i = *str) > 32; str++) - (void) putc(i, fp); + putchar(i); } else while (*str > 32) str++; } if (gotsome) - (void) putc('>', fp); + putchar('>'); } int @@ -2006,19 +1930,32 @@ keyword(const char *cp) } static void -sodump(sup su, const char *which) +sodump(struct sockaddr *sa, const char *which) { - switch (su->sa.sa_family) { +#ifdef INET6 + char nbuf[INET6_ADDRSTRLEN]; +#endif + + switch (sa->sa_family) { case AF_LINK: - (void) printf("%s: link %s; ", - which, link_ntoa(&su->sdl)); + (void)printf("%s: link %s; ", which, + link_ntoa((struct sockaddr_dl *)(void *)sa)); break; +#ifdef INET case AF_INET: - (void) printf("%s: inet %s; ", - which, inet_ntoa(su->sin.sin_addr)); + (void)printf("%s: inet %s; ", which, + inet_ntoa(((struct sockaddr_in *)(void *)sa)->sin_addr)); break; +#endif +#ifdef INET6 + case AF_INET6: + (void)printf("%s: inet6 %s; ", which, inet_ntop(sa->sa_family, + &((struct sockaddr_in6 *)(void *)sa)->sin6_addr, nbuf, + sizeof(nbuf))); + break; +#endif } - (void) fflush(stdout); + (void)fflush(stdout); } /* States*/ @@ -2031,10 +1968,9 @@ sodump(sup su, const char *which) #define DELIM (4*2) static void -sockaddr(char *addr, struct sockaddr *sa) +sockaddr(char *addr, struct sockaddr *sa, size_t size) { char *cp = (char *)sa; - int size = sa->sa_len; char *cplim = cp + size; int byte = 0, state = VIRGIN, new = 0 /* foil gcc */; diff --git a/freebsd/sbin/route/rtems-bsd-route-data.h b/freebsd/sbin/route/rtems-bsd-route-data.h new file mode 100644 index 00000000..b3854595 --- /dev/null +++ b/freebsd/sbin/route/rtems-bsd-route-data.h @@ -0,0 +1,3 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +/* route.c */ diff --git a/freebsd/sbin/route/rtems-bsd-route-namespace.h b/freebsd/sbin/route/rtems-bsd-route-namespace.h new file mode 100644 index 00000000..4f49513e --- /dev/null +++ b/freebsd/sbin/route/rtems-bsd-route-namespace.h @@ -0,0 +1,2 @@ +/* generated by userspace-header-gen.py */ +/* route.c */ diff --git a/freebsd/sbin/route/rtems-bsd-route-route-data.h b/freebsd/sbin/route/rtems-bsd-route-route-data.h new file mode 100644 index 00000000..8b54078f --- /dev/null +++ b/freebsd/sbin/route/rtems-bsd-route-route-data.h @@ -0,0 +1,30 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-route-data.h" +/* route.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int pid); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int rtm_addrs); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int s); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int nflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int af); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int qflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int tflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int verbose); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int aflen); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int locking); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int lockrest); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int debugonly); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static struct rt_metrics rt_metrics); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static u_long rtm_inits); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static uid_t uid); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int defaultfib); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int numfibs); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static _Bool domain_initialized); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static int rtm_seq); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static struct m_rtmsg m_rtmsg); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static struct fibl_head_t fibl_head); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static sig_atomic_t volatile stop_read); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static struct sockaddr_storage so[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static char domain[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static char rt_line[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_route, static char net_line[]); diff --git a/freebsd/sbin/sysctl/rtems-bsd-sysctl-data.h b/freebsd/sbin/sysctl/rtems-bsd-sysctl-data.h new file mode 100644 index 00000000..8746008a --- /dev/null +++ b/freebsd/sbin/sysctl/rtems-bsd-sysctl-data.h @@ -0,0 +1,3 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +/* sysctl.c */ diff --git a/freebsd/sbin/sysctl/rtems-bsd-sysctl-namespace.h b/freebsd/sbin/sysctl/rtems-bsd-sysctl-namespace.h new file mode 100644 index 00000000..858b515f --- /dev/null +++ b/freebsd/sbin/sysctl/rtems-bsd-sysctl-namespace.h @@ -0,0 +1,2 @@ +/* generated by userspace-header-gen.py */ +/* sysctl.c */ diff --git a/freebsd/sbin/sysctl/rtems-bsd-sysctl-sysctl-data.h b/freebsd/sbin/sysctl/rtems-bsd-sysctl-sysctl-data.h new file mode 100644 index 00000000..6c6b3453 --- /dev/null +++ b/freebsd/sbin/sysctl/rtems-bsd-sysctl-sysctl-data.h @@ -0,0 +1,23 @@ +/* generated by userspace-header-gen.py */ +#include <rtems/linkersets.h> +#include "rtems-bsd-sysctl-data.h" +/* sysctl.c */ +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static char const *conffile); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int aflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int bflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int Bflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int dflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int eflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int hflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int iflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int Nflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int nflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int oflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int qflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int tflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int Tflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int Wflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int xflag); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int ctl_sign[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static int ctl_size[]); +RTEMS_LINKER_RWSET_CONTENT(bsd_prog_sysctl, static char const *ctl_typename[]); diff --git a/freebsd/sbin/sysctl/sysctl.c b/freebsd/sbin/sysctl/sysctl.c index 87d9da32..fdbecd5f 100644 --- a/freebsd/sbin/sysctl/sysctl.c +++ b/freebsd/sbin/sysctl/sysctl.c @@ -1,5 +1,9 @@ #include <machine/rtems-bsd-user-space.h> +#ifdef __rtems__ +#include "rtems-bsd-sysctl-namespace.h" +#endif /* __rtems__ */ + /* * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. @@ -42,22 +46,13 @@ static char sccsid[] = "@(#)from: sysctl.c 8.1 (Berkeley) 6/6/93"; static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ + #ifdef __rtems__ #define __need_getopt_newlib #include <getopt.h> -#define RTEMS_BSD_PROGRAM_NO_OPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_SOCKET_WRAP -#define RTEMS_BSD_PROGRAM_NO_CLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_FOPEN_WRAP -#define RTEMS_BSD_PROGRAM_NO_FCLOSE_WRAP -#define RTEMS_BSD_PROGRAM_NO_MALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_CALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_REALLOC_WRAP -#define RTEMS_BSD_PROGRAM_NO_FREE_WRAP #include <machine/rtems-bsd-program.h> #include <machine/rtems-bsd-commands.h> #endif /* __rtems__ */ - #include <rtems/bsd/sys/param.h> #include <sys/time.h> #include <rtems/bsd/sys/resource.h> @@ -65,6 +60,16 @@ static const char rcsid[] = #include <sys/sysctl.h> #include <sys/vmmeter.h> +#ifdef __amd64__ +#include <sys/efi.h> +#include <machine/metadata.h> +#endif + +#if defined(__amd64__) || defined(__i386__) +#include <machine/pc/bios.h> +#endif + +#include <assert.h> #include <ctype.h> #include <err.h> #include <errno.h> @@ -73,71 +78,112 @@ static const char rcsid[] = #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sysexits.h> #include <unistd.h> +#ifdef __rtems__ +#include "rtems-bsd-sysctl-sysctl-data.h" +#endif /* __rtems__ */ + +static const char *conffile; -static int aflag, bflag, dflag, eflag, hflag, iflag; -static int Nflag, nflag, oflag, qflag, xflag, warncount; +static int aflag, bflag, Bflag, dflag, eflag, hflag, iflag; +static int Nflag, nflag, oflag, qflag, tflag, Tflag, Wflag, xflag; static int oidfmt(int *, int, char *, u_int *); -static void parse(const char *); +static int parsefile(const char *); +static int parse(const char *, int); static int show_var(int *, int); static int sysctl_all(int *oid, int len); -static int name2oid(char *, int *); +static int name2oid(const char *, int *); -static int set_IK(const char *, int *); +static int strIKtoi(const char *, char **, const char *); + +static int ctl_sign[CTLTYPE+1] = { + [CTLTYPE_INT] = 1, + [CTLTYPE_LONG] = 1, + [CTLTYPE_S8] = 1, + [CTLTYPE_S16] = 1, + [CTLTYPE_S32] = 1, + [CTLTYPE_S64] = 1, +}; + +static int ctl_size[CTLTYPE+1] = { + [CTLTYPE_INT] = sizeof(int), + [CTLTYPE_UINT] = sizeof(u_int), + [CTLTYPE_LONG] = sizeof(long), + [CTLTYPE_ULONG] = sizeof(u_long), + [CTLTYPE_S8] = sizeof(int8_t), + [CTLTYPE_S16] = sizeof(int16_t), + [CTLTYPE_S32] = sizeof(int32_t), + [CTLTYPE_S64] = sizeof(int64_t), + [CTLTYPE_U8] = sizeof(uint8_t), + [CTLTYPE_U16] = sizeof(uint16_t), + [CTLTYPE_U32] = sizeof(uint32_t), + [CTLTYPE_U64] = sizeof(uint64_t), +}; + +static const char *ctl_typename[CTLTYPE+1] = { + [CTLTYPE_INT] = "integer", + [CTLTYPE_UINT] = "unsigned integer", + [CTLTYPE_LONG] = "long integer", + [CTLTYPE_ULONG] = "unsigned long", + [CTLTYPE_U8] = "uint8_t", + [CTLTYPE_U16] = "uint16_t", + [CTLTYPE_U32] = "uint16_t", + [CTLTYPE_U64] = "uint64_t", + [CTLTYPE_S8] = "int8_t", + [CTLTYPE_S16] = "int16_t", + [CTLTYPE_S32] = "int32_t", + [CTLTYPE_S64] = "int64_t", + [CTLTYPE_NODE] = "node", + [CTLTYPE_STRING] = "string", + [CTLTYPE_OPAQUE] = "opaque", +}; static void usage(void) { (void)fprintf(stderr, "%s\n%s\n", - "usage: sysctl [-bdehiNnoqx] name[=value] ...", - " sysctl [-bdehNnoqx] -a"); + "usage: sysctl [-bdehiNnoqTtWx] [ -B <bufsize> ] [-f filename] name[=value] ...", + " sysctl [-bdehNnoqTtWx] [ -B <bufsize> ] -a"); exit(1); } #ifdef __rtems__ -static int main(int argc, char **argv); +static int main(int argc, char *argv[]); + +RTEMS_LINKER_RWSET(bsd_prog_sysctl, char); -int rtems_bsd_command_sysctl(int argc, char *argv[]) +int +rtems_bsd_command_sysctl(int argc, char *argv[]) { int exit_code; + void *data_begin; + size_t data_size; - rtems_bsd_program_lock(); - - aflag = bflag = dflag = eflag = hflag = iflag = 0; - Nflag = nflag = oflag = qflag = xflag = warncount = 0; - - exit_code = rtems_bsd_program_call_main("sysctl", main, argc, argv); + data_begin = RTEMS_LINKER_SET_BEGIN(bsd_prog_sysctl); + data_size = RTEMS_LINKER_SET_SIZE(bsd_prog_sysctl); + rtems_bsd_program_lock(); + exit_code = rtems_bsd_program_call_main_with_data_restore("sysctl", + main, argc, argv, data_begin, data_size); rtems_bsd_program_unlock(); return exit_code; } #endif /* __rtems__ */ - int main(int argc, char **argv) { int ch; + int warncount = 0; -#ifdef __rtems__ - struct getopt_data getopt_data; - memset(&getopt_data, 0, sizeof(getopt_data)); -#define optind getopt_data.optind -#define optarg getopt_data.optarg -#define opterr getopt_data.opterr -#define optopt getopt_data.optopt -#define getopt(argc, argv, opt) getopt_r(argc, argv, "+" opt, &getopt_data) -#endif /* __rtems__ */ - -#ifndef __rtems__ setlocale(LC_NUMERIC, ""); setbuf(stdout,0); setbuf(stderr,0); -#endif /* __rtems__ */ - while ((ch = getopt(argc, argv, "AabdehiNnoqwxX")) != -1) { + while ((ch = getopt(argc, argv, "AabB:def:hiNnoqtTwWxX")) != -1) { switch (ch) { case 'A': /* compatibility */ @@ -149,12 +195,18 @@ main(int argc, char **argv) case 'b': bflag = 1; break; + case 'B': + Bflag = strtol(optarg, NULL, 0); + break; case 'd': dflag = 1; break; case 'e': eflag = 1; break; + case 'f': + conffile = optarg; + break; case 'h': hflag = 1; break; @@ -173,10 +225,19 @@ main(int argc, char **argv) case 'q': qflag = 1; break; + case 't': + tflag = 1; + break; + case 'T': + Tflag = 1; + break; case 'w': /* compatibility */ /* ignored */ break; + case 'W': + Wflag = 1; + break; case 'X': /* compatibility */ aflag = xflag = 1; @@ -195,13 +256,17 @@ main(int argc, char **argv) usage(); if (aflag && argc == 0) exit(sysctl_all(0, 0)); - if (argc == 0) + if (argc == 0 && conffile == NULL) usage(); warncount = 0; + if (conffile != NULL) + warncount += parsefile(conffile); + while (argc-- > 0) - parse(*argv++); - exit(warncount); + warncount += parse(*argv++, 0); + + return (warncount); } /* @@ -209,47 +274,91 @@ main(int argc, char **argv) * Lookup and print out the MIB entry if it exists. * Set a new value if requested. */ -static void -parse(const char *string) +static int +parse(const char *string, int lineno) { int len, i, j; - void *newval = 0; + const void *newval; + const char *newvalstr = NULL; + int8_t i8val; + uint8_t u8val; + int16_t i16val; + uint16_t u16val; + int32_t i32val; + uint32_t u32val; int intval; unsigned int uintval; long longval; unsigned long ulongval; - size_t newsize = 0; + size_t newsize = Bflag; int64_t i64val; uint64_t u64val; int mib[CTL_MAXNAME]; - char *cp, *bufp, buf[BUFSIZ], *endptr, fmt[BUFSIZ]; + char *cp, *bufp, buf[BUFSIZ], *endptr = NULL, fmt[BUFSIZ], line[BUFSIZ]; u_int kind; + if (lineno) + snprintf(line, sizeof(line), " at line %d", lineno); + else + line[0] = '\0'; + cp = buf; - if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) - errx(1, "oid too long: '%s'", string); - bufp = strsep(&cp, "="); + if (snprintf(buf, BUFSIZ, "%s", string) >= BUFSIZ) { + warnx("oid too long: '%s'%s", string, line); + return (1); + } + bufp = strsep(&cp, "=:"); if (cp != NULL) { + /* Tflag just lists tunables, do not allow assignment */ + if (Tflag || Wflag) { + warnx("Can't set variables when using -T or -W"); + usage(); + } while (isspace(*cp)) cp++; - newval = cp; + /* Strip a pair of " or ' if any. */ + switch (*cp) { + case '\"': + case '\'': + if (cp[strlen(cp) - 1] == *cp) + cp[strlen(cp) - 1] = '\0'; + cp++; + } + newvalstr = cp; newsize = strlen(cp); } + /* Trim spaces */ + cp = bufp + strlen(bufp) - 1; + while (cp >= bufp && isspace((int)*cp)) { + *cp = '\0'; + cp--; + } len = name2oid(bufp, mib); if (len < 0) { if (iflag) - return; + return (0); if (qflag) - exit(1); - else - errx(1, "unknown oid '%s'", bufp); + return (1); + else { + if (errno == ENOENT) { + warnx("unknown oid '%s'%s", bufp, line); + } else { + warn("unknown oid '%s'%s", bufp, line); + } + return (1); + } } - if (oidfmt(mib, len, fmt, &kind)) - err(1, "couldn't find format of oid '%s'", bufp); + if (oidfmt(mib, len, fmt, &kind)) { + warn("couldn't find format of oid '%s'%s", bufp, line); + if (iflag) + return (1); + else + exit(1); + } - if (newval == NULL || dflag) { + if (newvalstr == NULL || dflag) { if ((kind & CTLTYPE) == CTLTYPE_NODE) { if (dflag) { i = show_var(mib, len); @@ -263,92 +372,131 @@ parse(const char *string) putchar('\n'); } } else { - if ((kind & CTLTYPE) == CTLTYPE_NODE) - errx(1, "oid '%s' isn't a leaf node", bufp); + if ((kind & CTLTYPE) == CTLTYPE_NODE) { + warnx("oid '%s' isn't a leaf node%s", bufp, line); + return (1); + } if (!(kind & CTLFLAG_WR)) { if (kind & CTLFLAG_TUN) { - warnx("oid '%s' is a read only tunable", bufp); - errx(1, "Tunable values are set in /boot/loader.conf"); - } else { - errx(1, "oid '%s' is read only", bufp); - } + warnx("oid '%s' is a read only tunable%s", bufp, line); + warnx("Tunable values are set in /boot/loader.conf"); + } else + warnx("oid '%s' is read only%s", bufp, line); + return (1); } - if ((kind & CTLTYPE) == CTLTYPE_INT || - (kind & CTLTYPE) == CTLTYPE_UINT || - (kind & CTLTYPE) == CTLTYPE_LONG || - (kind & CTLTYPE) == CTLTYPE_ULONG || - (kind & CTLTYPE) == CTLTYPE_S64 || - (kind & CTLTYPE) == CTLTYPE_U64) { - if (strlen(newval) == 0) - errx(1, "empty numeric value"); + switch (kind & CTLTYPE) { + case CTLTYPE_INT: + case CTLTYPE_UINT: + case CTLTYPE_LONG: + case CTLTYPE_ULONG: + case CTLTYPE_S8: + case CTLTYPE_S16: + case CTLTYPE_S32: + case CTLTYPE_S64: + case CTLTYPE_U8: + case CTLTYPE_U16: + case CTLTYPE_U32: + case CTLTYPE_U64: + if (strlen(newvalstr) == 0) { + warnx("empty numeric value"); + return (1); + } + /* FALLTHROUGH */ + case CTLTYPE_STRING: + break; + default: + warnx("oid '%s' is type %d," + " cannot set that%s", bufp, + kind & CTLTYPE, line); + return (1); } + errno = 0; + switch (kind & CTLTYPE) { case CTLTYPE_INT: - if (strcmp(fmt, "IK") == 0) { - if (!set_IK(newval, &intval)) - errx(1, "invalid value '%s'", - (char *)newval); - } else { - intval = (int)strtol(newval, &endptr, + if (strncmp(fmt, "IK", 2) == 0) + intval = strIKtoi(newvalstr, &endptr, fmt); + else + intval = (int)strtol(newvalstr, &endptr, 0); - if (endptr == newval || *endptr != '\0') - errx(1, "invalid integer '%s'", - (char *)newval); - } newval = &intval; newsize = sizeof(intval); break; case CTLTYPE_UINT: - uintval = (int) strtoul(newval, &endptr, 0); - if (endptr == newval || *endptr != '\0') - errx(1, "invalid unsigned integer '%s'", - (char *)newval); + uintval = (int) strtoul(newvalstr, &endptr, 0); newval = &uintval; newsize = sizeof(uintval); break; case CTLTYPE_LONG: - longval = strtol(newval, &endptr, 0); - if (endptr == newval || *endptr != '\0') - errx(1, "invalid long integer '%s'", - (char *)newval); + longval = strtol(newvalstr, &endptr, 0); newval = &longval; newsize = sizeof(longval); break; case CTLTYPE_ULONG: - ulongval = strtoul(newval, &endptr, 0); - if (endptr == newval || *endptr != '\0') - errx(1, "invalid unsigned long integer" - " '%s'", (char *)newval); + ulongval = strtoul(newvalstr, &endptr, 0); newval = &ulongval; newsize = sizeof(ulongval); break; case CTLTYPE_STRING: + newval = newvalstr; + break; + case CTLTYPE_S8: + i8val = (int8_t)strtol(newvalstr, &endptr, 0); + newval = &i8val; + newsize = sizeof(i8val); + break; + case CTLTYPE_S16: + i16val = (int16_t)strtol(newvalstr, &endptr, + 0); + newval = &i16val; + newsize = sizeof(i16val); + break; + case CTLTYPE_S32: + i32val = (int32_t)strtol(newvalstr, &endptr, + 0); + newval = &i32val; + newsize = sizeof(i32val); break; case CTLTYPE_S64: - i64val = strtoimax(newval, &endptr, 0); - if (endptr == newval || *endptr != '\0') - errx(1, "invalid int64_t '%s'", - (char *)newval); + i64val = strtoimax(newvalstr, &endptr, 0); newval = &i64val; newsize = sizeof(i64val); break; + case CTLTYPE_U8: + u8val = (uint8_t)strtoul(newvalstr, &endptr, 0); + newval = &u8val; + newsize = sizeof(u8val); + break; + case CTLTYPE_U16: + u16val = (uint16_t)strtoul(newvalstr, &endptr, + 0); + newval = &u16val; + newsize = sizeof(u16val); + break; + case CTLTYPE_U32: + u32val = (uint32_t)strtoul(newvalstr, &endptr, + 0); + newval = &u32val; + newsize = sizeof(u32val); + break; case CTLTYPE_U64: - u64val = strtoumax(newval, &endptr, 0); - if (endptr == newval || *endptr != '\0') - errx(1, "invalid uint64_t '%s'", - (char *)newval); + u64val = strtoumax(newvalstr, &endptr, 0); newval = &u64val; newsize = sizeof(u64val); break; - case CTLTYPE_OPAQUE: - /* FALLTHROUGH */ default: - errx(1, "oid '%s' is type %d," - " cannot set that", bufp, - kind & CTLTYPE); + /* NOTREACHED */ + abort(); + } + + if (errno != 0 || endptr == newvalstr || + (endptr != NULL && *endptr != '\0')) { + warnx("invalid %s '%s'%s", ctl_typename[kind & CTLTYPE], + newvalstr, line); + return (1); } i = show_var(mib, len); @@ -357,18 +505,20 @@ parse(const char *string) putchar('\n'); switch (errno) { case EOPNOTSUPP: - errx(1, "%s: value is not available", - string); + warnx("%s: value is not available%s", + string, line); + return (1); case ENOTDIR: - errx(1, "%s: specification is incomplete", - string); + warnx("%s: specification is incomplete%s", + string, line); + return (1); case ENOMEM: - errx(1, "%s: type is unknown to this program", - string); + warnx("%s: type is unknown to this program%s", + string, line); + return (1); default: - warn("%s", string); - warncount++; - return; + warn("%s%s", string, line); + return (1); } } if (!bflag) @@ -380,34 +530,86 @@ parse(const char *string) putchar('\n'); nflag = i; } + + return (0); +} + +static int +parsefile(const char *filename) +{ + FILE *file; + char line[BUFSIZ], *p, *pq, *pdq; + int warncount = 0, lineno = 0; + + file = fopen(filename, "r"); + if (file == NULL) + err(EX_NOINPUT, "%s", filename); + while (fgets(line, sizeof(line), file) != NULL) { + lineno++; + p = line; + pq = strchr(line, '\''); + pdq = strchr(line, '\"'); + /* Replace the first # with \0. */ + while((p = strchr(p, '#')) != NULL) { + if (pq != NULL && p > pq) { + if ((p = strchr(pq+1, '\'')) != NULL) + *(++p) = '\0'; + break; + } else if (pdq != NULL && p > pdq) { + if ((p = strchr(pdq+1, '\"')) != NULL) + *(++p) = '\0'; + break; + } else if (p == line || *(p-1) != '\\') { + *p = '\0'; + break; + } + p++; + } + /* Trim spaces */ + p = line + strlen(line) - 1; + while (p >= line && isspace((int)*p)) { + *p = '\0'; + p--; + } + p = line; + while (isspace((int)*p)) + p++; + if (*p == '\0') + continue; + else + warncount += parse(p, lineno); + } + fclose(file); + + return (warncount); } /* These functions will dump out various interesting structures. */ +#ifndef __rtems__ static int -S_clockinfo(int l2, void *p) +S_clockinfo(size_t l2, void *p) { -#ifndef __rtems__ struct clockinfo *ci = (struct clockinfo*)p; if (l2 != sizeof(*ci)) { - warnx("S_clockinfo %d != %zu", l2, sizeof(*ci)); + warnx("S_clockinfo %zu != %zu", l2, sizeof(*ci)); return (1); } printf(hflag ? "{ hz = %'d, tick = %'d, profhz = %'d, stathz = %'d }" : "{ hz = %d, tick = %d, profhz = %d, stathz = %d }", ci->hz, ci->tick, ci->profhz, ci->stathz); -#endif /* __rtems__ */ return (0); } +#endif /* __rtems__ */ static int -S_loadavg(int l2, void *p) +S_loadavg(size_t l2, void *p) { struct loadavg *tv = (struct loadavg*)p; if (l2 != sizeof(*tv)) { - warnx("S_loadavg %d != %zu", l2, sizeof(*tv)); + warnx("S_loadavg %zu != %zu", l2, sizeof(*tv)); return (1); } printf(hflag ? "{ %'.2f %'.2f %'.2f }" : "{ %.2f %.2f %.2f }", @@ -418,14 +620,14 @@ S_loadavg(int l2, void *p) } static int -S_timeval(int l2, void *p) +S_timeval(size_t l2, void *p) { struct timeval *tv = (struct timeval*)p; time_t tv_sec; char *p1, *p2; if (l2 != sizeof(*tv)) { - warnx("S_timeval %d != %zu", l2, sizeof(*tv)); + warnx("S_timeval %zu != %zu", l2, sizeof(*tv)); return (1); } printf(hflag ? "{ sec = %'jd, usec = %'ld } " : @@ -442,13 +644,13 @@ S_timeval(int l2, void *p) } static int -S_vmtotal(int l2, void *p) +S_vmtotal(size_t l2, void *p) { struct vmtotal *v = (struct vmtotal *)p; int pageKilo = getpagesize() / 1024; if (l2 != sizeof(*v)) { - warnx("S_vmtotal %d != %zu", l2, sizeof(*v)); + warnx("S_vmtotal %zu != %zu", l2, sizeof(*v)); return (1); } @@ -461,44 +663,179 @@ S_vmtotal(int l2, void *p) "%hd Sleep: %hd)\n", v->t_rq, v->t_dw, v->t_pw, v->t_sl); printf( - "Virtual Memory:\t\t(Total: %dK Active: %dK)\n", - v->t_vm * pageKilo, v->t_avm * pageKilo); - printf("Real Memory:\t\t(Total: %dK Active: %dK)\n", - v->t_rm * pageKilo, v->t_arm * pageKilo); - printf("Shared Virtual Memory:\t(Total: %dK Active: %dK)\n", - v->t_vmshr * pageKilo, v->t_avmshr * pageKilo); - printf("Shared Real Memory:\t(Total: %dK Active: %dK)\n", - v->t_rmshr * pageKilo, v->t_armshr * pageKilo); - printf("Free Memory:\t%dK\n", v->t_free * pageKilo); + "Virtual Memory:\t\t(Total: %jdK Active: %jdK)\n", + (intmax_t)v->t_vm * pageKilo, (intmax_t)v->t_avm * pageKilo); + printf("Real Memory:\t\t(Total: %jdK Active: %jdK)\n", + (intmax_t)v->t_rm * pageKilo, (intmax_t)v->t_arm * pageKilo); + printf("Shared Virtual Memory:\t(Total: %jdK Active: %jdK)\n", + (intmax_t)v->t_vmshr * pageKilo, (intmax_t)v->t_avmshr * pageKilo); + printf("Shared Real Memory:\t(Total: %jdK Active: %jdK)\n", + (intmax_t)v->t_rmshr * pageKilo, (intmax_t)v->t_armshr * pageKilo); + printf("Free Memory:\t%jdK", (intmax_t)v->t_free * pageKilo); return (0); } +#ifdef __amd64__ +#define efi_next_descriptor(ptr, size) \ + ((struct efi_md *)(((uint8_t *) ptr) + size)) + static int -set_IK(const char *str, int *val) +S_efi_map(size_t l2, void *p) { - float temp; - int len, kelv; - const char *p; - char *endptr; + struct efi_map_header *efihdr; + struct efi_md *map; + const char *type; + size_t efisz; + int ndesc, i; + + static const char *types[] = { + "Reserved", + "LoaderCode", + "LoaderData", + "BootServicesCode", + "BootServicesData", + "RuntimeServicesCode", + "RuntimeServicesData", + "ConventionalMemory", + "UnusableMemory", + "ACPIReclaimMemory", + "ACPIMemoryNVS", + "MemoryMappedIO", + "MemoryMappedIOPortSpace", + "PalCode" + }; + + /* + * Memory map data provided by UEFI via the GetMemoryMap + * Boot Services API. + */ + if (l2 < sizeof(*efihdr)) { + warnx("S_efi_map length less than header"); + return (1); + } + efihdr = p; + efisz = (sizeof(struct efi_map_header) + 0xf) & ~0xf; + map = (struct efi_md *)((uint8_t *)efihdr + efisz); - if ((len = strlen(str)) == 0) + if (efihdr->descriptor_size == 0) return (0); + if (l2 != efisz + efihdr->memory_size) { + warnx("S_efi_map length mismatch %zu vs %zu", l2, efisz + + efihdr->memory_size); + return (1); + } + ndesc = efihdr->memory_size / efihdr->descriptor_size; + + printf("\n%23s %12s %12s %8s %4s", + "Type", "Physical", "Virtual", "#Pages", "Attr"); + + for (i = 0; i < ndesc; i++, + map = efi_next_descriptor(map, efihdr->descriptor_size)) { + if (map->md_type <= EFI_MD_TYPE_PALCODE) + type = types[map->md_type]; + else + type = "<INVALID>"; + printf("\n%23s %012lx %12p %08lx ", type, map->md_phys, + map->md_virt, map->md_pages); + if (map->md_attr & EFI_MD_ATTR_UC) + printf("UC "); + if (map->md_attr & EFI_MD_ATTR_WC) + printf("WC "); + if (map->md_attr & EFI_MD_ATTR_WT) + printf("WT "); + if (map->md_attr & EFI_MD_ATTR_WB) + printf("WB "); + if (map->md_attr & EFI_MD_ATTR_UCE) + printf("UCE "); + if (map->md_attr & EFI_MD_ATTR_WP) + printf("WP "); + if (map->md_attr & EFI_MD_ATTR_RP) + printf("RP "); + if (map->md_attr & EFI_MD_ATTR_XP) + printf("XP "); + if (map->md_attr & EFI_MD_ATTR_RT) + printf("RUNTIME"); + } + return (0); +} +#endif + +#if defined(__amd64__) || defined(__i386__) +static int +S_bios_smap_xattr(size_t l2, void *p) +{ + struct bios_smap_xattr *smap, *end; + + if (l2 % sizeof(*smap) != 0) { + warnx("S_bios_smap_xattr %zu is not a multiple of %zu", l2, + sizeof(*smap)); + return (1); + } + + end = (struct bios_smap_xattr *)((char *)p + l2); + for (smap = p; smap < end; smap++) + printf("\nSMAP type=%02x, xattr=%02x, base=%016jx, len=%016jx", + smap->type, smap->xattr, (uintmax_t)smap->base, + (uintmax_t)smap->length); + return (0); +} +#endif + +static int +strIKtoi(const char *str, char **endptrp, const char *fmt) +{ + int kelv; + float temp; + size_t len; + const char *p; + int prec, i; + + assert(errno == 0); + + len = strlen(str); + /* caller already checked this */ + assert(len > 0); + + /* + * A format of "IK" is in deciKelvin. A format of "IK3" is in + * milliKelvin. The single digit following IK is log10 of the + * multiplying factor to convert Kelvin into the untis of this sysctl, + * or the dividing factor to convert the sysctl value to Kelvin. Numbers + * larger than 6 will run into precision issues with 32-bit integers. + * Characters that aren't ASCII digits after the 'K' are ignored. No + * localization is present because this is an interface from the kernel + * to this program (eg not an end-user interface), so isdigit() isn't + * used here. + */ + if (fmt[2] != '\0' && fmt[2] >= '0' && fmt[2] <= '9') + prec = fmt[2] - '0'; + else + prec = 1; p = &str[len - 1]; - if (*p == 'C' || *p == 'F') { - temp = strtof(str, &endptr); - if (endptr == str || endptr != p) - return (0); - if (*p == 'F') - temp = (temp - 32) * 5 / 9; - kelv = temp * 10 + 2732; + if (*p == 'C' || *p == 'F' || *p == 'K') { + temp = strtof(str, endptrp); + if (*endptrp != str && *endptrp == p && errno == 0) { + if (*p == 'F') + temp = (temp - 32) * 5 / 9; + *endptrp = NULL; + if (*p != 'K') + temp += 273.15; + for (i = 0; i < prec; i++) + temp *= 10.0; + return ((int)(temp + 0.5)); + } } else { - kelv = (int)strtol(str, &endptr, 10); - if (endptr == str || *endptr != '\0') - return (0); + /* No unit specified -> treat it as a raw number */ + kelv = (int)strtol(str, endptrp, 10); + if (*endptrp != str && *endptrp == p && errno == 0) { + *endptrp = NULL; + return (kelv); + } } - *val = kelv; - return (1); + + errno = ERANGE; + return (0); } /* @@ -511,7 +848,7 @@ set_IK(const char *str, int *val) */ static int -name2oid(char *name, int *oidp) +name2oid(const char *name, int *oidp) { int oid[2]; int i; @@ -553,21 +890,6 @@ oidfmt(int *oid, int len, char *fmt, u_int *kind) return (0); } -static int ctl_sign[CTLTYPE+1] = { - [CTLTYPE_INT] = 1, - [CTLTYPE_LONG] = 1, - [CTLTYPE_S64] = 1, -}; - -static int ctl_size[CTLTYPE+1] = { - [CTLTYPE_INT] = sizeof(int), - [CTLTYPE_UINT] = sizeof(u_int), - [CTLTYPE_LONG] = sizeof(long), - [CTLTYPE_ULONG] = sizeof(u_long), - [CTLTYPE_S64] = sizeof(int64_t), - [CTLTYPE_U64] = sizeof(int64_t), -}; - /* * This formats and outputs the value of one variable * @@ -579,8 +901,8 @@ static int show_var(int *oid, int nlen) { u_char buf[BUFSIZ], *val, *oval, *p; - char name[BUFSIZ], *fmt; - const char *sep, *sep1; + char name[BUFSIZ], fmt[BUFSIZ]; + const char *sep, *sep1, *prntype; int qoid[CTL_MAXNAME+2]; uintmax_t umv; intmax_t mv; @@ -588,12 +910,15 @@ show_var(int *oid, int nlen) size_t intlen; size_t j, len; u_int kind; - int (*func)(int, void *); + float base; + int (*func)(size_t, void *); + int prec; /* Silence GCC. */ umv = mv = intlen = 0; bzero(buf, BUFSIZ); + bzero(fmt, BUFSIZ); bzero(name, BUFSIZ); qoid[0] = 0; memcpy(qoid + 2, oid, nlen * sizeof(int)); @@ -604,6 +929,15 @@ show_var(int *oid, int nlen) if (i || !j) err(1, "sysctl name %d %zu %d", i, j, errno); + oidfmt(oid, nlen, fmt, &kind); + /* if Wflag then only list sysctls that are writeable and not stats. */ + if (Wflag && ((kind & CTLFLAG_WR) == 0 || (kind & CTLFLAG_STATS) != 0)) + return 1; + + /* if Tflag then only list sysctls that are tuneables. */ + if (Tflag && (kind & CTLFLAG_TUN) == 0) + return 1; + if (Nflag) { printf("%s", name); return (0); @@ -614,19 +948,34 @@ show_var(int *oid, int nlen) else sep = ": "; - if (dflag) { /* just print description */ + ctltype = (kind & CTLTYPE); + if (tflag || dflag) { + if (!nflag) + printf("%s%s", name, sep); + if (ctl_typename[ctltype] != NULL) + prntype = ctl_typename[ctltype]; + else + prntype = "unknown"; + if (tflag && dflag) + printf("%s%s", prntype, sep); + else if (tflag) { + printf("%s", prntype); + return (0); + } qoid[1] = 5; j = sizeof(buf); i = sysctl(qoid, nlen + 2, buf, &j, 0, 0); - if (!nflag) - printf("%s%s", name, sep); printf("%s", buf); return (0); } /* find an estimate of how much we need for this var */ - j = 0; - i = sysctl(oid, nlen, 0, &j, 0, 0); - j += j; /* we want to be sure :-) */ + if (Bflag) + j = Bflag; + else { + j = 0; + i = sysctl(oid, nlen, 0, &j, 0, 0); + j += j; /* we want to be sure :-) */ + } val = oval = malloc(j + 1); if (val == NULL) { @@ -635,7 +984,7 @@ show_var(int *oid, int nlen) } len = j; i = sysctl(oid, nlen, val, &len, 0, 0); - if (i || !len) { + if (i != 0 || (len == 0 && ctltype != CTLTYPE_STRING)) { free(oval); return (1); } @@ -646,10 +995,7 @@ show_var(int *oid, int nlen) return (0); } val[len] = '\0'; - fmt = buf; - oidfmt(oid, nlen, fmt, &kind); p = val; - ctltype = (kind & CTLTYPE); sign = ctl_sign[ctltype]; intlen = ctl_size[ctltype]; @@ -665,7 +1011,13 @@ show_var(int *oid, int nlen) case CTLTYPE_UINT: case CTLTYPE_LONG: case CTLTYPE_ULONG: + case CTLTYPE_S8: + case CTLTYPE_S16: + case CTLTYPE_S32: case CTLTYPE_S64: + case CTLTYPE_U8: + case CTLTYPE_U16: + case CTLTYPE_U32: case CTLTYPE_U64: if (!nflag) printf("%s%s", name, sep); @@ -683,6 +1035,21 @@ show_var(int *oid, int nlen) umv = *(u_long *)p; mv = *(long *)p; break; + case CTLTYPE_S8: + case CTLTYPE_U8: + umv = *(uint8_t *)p; + mv = *(int8_t *)p; + break; + case CTLTYPE_S16: + case CTLTYPE_U16: + umv = *(uint16_t *)p; + mv = *(int16_t *)p; + break; + case CTLTYPE_S32: + case CTLTYPE_U32: + umv = *(uint32_t *)p; + mv = *(int32_t *)p; + break; case CTLTYPE_S64: case CTLTYPE_U64: umv = *(uint64_t *)p; @@ -697,8 +1064,19 @@ show_var(int *oid, int nlen) else if (fmt[1] == 'K') { if (mv < 0) printf("%jd", mv); - else - printf("%.1fC", (mv - 2732.0) / 10); + else { + /* + * See strIKtoi for details on fmt. + */ + prec = 1; + if (fmt[2] != '\0') + prec = fmt[2] - '0'; + base = 1.0; + for (int i = 0; i < prec; i++) + base *= 10.0; + printf("%.*fC", prec, + (float)mv / base - 273.15); + } } else printf(hflag ? "%'jd" : "%jd", mv); sep1 = " "; @@ -711,13 +1089,25 @@ show_var(int *oid, int nlen) case CTLTYPE_OPAQUE: i = 0; if (strcmp(fmt, "S,clockinfo") == 0) +#ifndef __rtems__ func = S_clockinfo; +#else /* __rtems__ */ + func = NULL; +#endif /* __rtems__ */ else if (strcmp(fmt, "S,timeval") == 0) func = S_timeval; else if (strcmp(fmt, "S,loadavg") == 0) func = S_loadavg; else if (strcmp(fmt, "S,vmtotal") == 0) func = S_vmtotal; +#ifdef __amd64__ + else if (strcmp(fmt, "S,efi_map_header") == 0) + func = S_efi_map; +#endif +#if defined(__amd64__) || defined(__i386__) + else if (strcmp(fmt, "S,bios_smap_xattr") == 0) + func = S_bios_smap_xattr; +#endif else func = NULL; if (func) { |