summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/pfctl/pfctl.c603
-rw-r--r--sys/net/pf.c478
-rw-r--r--sys/net/pfvar.h62
3 files changed, 721 insertions, 422 deletions
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 9586094faf0..7908642a536 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfctl.c,v 1.8 2001/06/25 10:14:07 deraadt Exp $ */
+/* $OpenBSD: pfctl.c,v 1.9 2001/06/25 17:17:06 dhartmei Exp $ */
/*
* Copyright (c) 2001, Daniel Hartmeier
@@ -46,42 +46,37 @@
#include "pfctl_parser.h"
-void printerror(char *);
-void usage(char *);
+void print_error(char *);
+void usage();
char *load_file(char *, size_t *);
+int pfctl_enable(int);
+int pfctl_disable(int);
+int pfctl_clear_rules(int);
+int pfctl_clear_nat(int);
+int pfctl_clear_states(int);
+int pfctl_show_rules(int);
+int pfctl_show_nat(int);
+int pfctl_show_states(int, u_int8_t);
+int pfctl_show_status(int);
+int pfctl_rules(int, char *);
+int pfctl_nat(int, char *);
+int pfctl_log(int, char *);
int main(int, char *[]);
void
-printerror(char *s)
+print_error(char *s)
{
fprintf(stderr, "ERROR: %s: %s\n", s, strerror(errno));
return;
}
void
-usage(char *argv0)
+usage()
{
- char *n = rindex(argv0, '/');
-
- if (n != NULL)
- n++;
- else
- n = argv0;
- fprintf(stderr, "Usage: %s command argument\n", n);
- fprintf(stderr, "\tstart\t\t\tStart packet filter\n");
- fprintf(stderr, "\tstop\t\t\tStop packet filter\n");
- fprintf(stderr, "\tshow\trules\t\tShow filter rules\n");
- fprintf(stderr, "\t\tnat\t\t NAT/RDR rules\n");
- fprintf(stderr, "\t\tstates [proto]\t list of active states\n");
- fprintf(stderr, "\t\tstatus\t\t status\n");
- fprintf(stderr, "\tclear\trules\t\tClear filter rules\n");
- fprintf(stderr, "\t\tnat\t\t NAT/RDR rules\n");
- fprintf(stderr, "\t\tstates\t\t states\n");
- fprintf(stderr, "\tparse\trules\t<file>\tCheck syntax of filter rules\n");
- fprintf(stderr, "\t\tnat\t<file>\t NAT/RDR rules\n");
- fprintf(stderr, "\tload\trules\t<file>\tLoad filter rules\n");
- fprintf(stderr, "\t\tnat\t<file>\t NAT/RDR rules\n");
- fprintf(stderr, "\tlog\t\t<if>\tSet interface to log\n");
+ extern char *__progname;
+
+ fprintf(stderr, "usage: %s [-d] [-c set] [-r file]", __progname);
+ fprintf(stderr, " [-n file] [-s set] [-l if] [-e]\n");
}
char *
@@ -116,257 +111,363 @@ load_file(char *name, size_t *len)
}
int
-main(int argc, char *argv[])
+pfctl_enable(int dev)
{
- int dev;
- struct pfioc *ub;
- u_int16_t n = 0;
+ if (ioctl(dev, DIOCSTART)) {
+ print_error("DIOCSTART");
+ return 1;
+ }
+ printf("pf enabled\n");
+ return 0;
+}
- ub = malloc(sizeof(struct pfioc));
- if (ub == NULL) {
- printf("ERROR: malloc() failed\n");
- return (1);
+int
+pfctl_disable(int dev)
+{
+ if (ioctl(dev, DIOCSTOP)) {
+ print_error("DIOCSTOP");
+ return 1;
}
- ub->size = 131072;
- ub->buffer = malloc(ub->size);
- if (ub->buffer == NULL) {
- printf("ERROR: malloc() failed\n");
+ printf("pf disabled\n");
+ return 0;
+}
+
+int
+pfctl_clear_rules(int dev)
+{
+ struct pfioc_rule pr;
+
+ if (ioctl(dev, DIOCBEGINRULES, &pr.ticket)) {
+ print_error("DIOCBEGINRULES");
return (1);
- }
- memset(ub->buffer, 0, ub->size);
- ub->entries = 0;
- if (argc < 2) {
- usage(argv[0]);
+ } else if (ioctl(dev, DIOCCOMMITRULES, &pr.ticket)) {
+ print_error("DIOCCOMMITRULES");
return (1);
}
- dev = open("/dev/pf", O_RDWR);
- if (dev < 0) {
- printerror("open(/dev/pf)");
+ printf("rules cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_nat(int dev)
+{
+ struct pfioc_nat pn;
+ struct pfioc_rdr pr;
+
+ if (ioctl(dev, DIOCBEGINNATS, &pn.ticket)) {
+ print_error("DIOCBEGINNATS");
+ return (1);
+ } else if (ioctl(dev, DIOCCOMMITNATS, &pn.ticket)) {
+ print_error("DIOCCOMMITNATS");
+ return (1);
+ } else if (ioctl(dev, DIOCBEGINRDRS, &pr.ticket)) {
+ print_error("DIOCBEGINRDRS");
+ return (1);
+ } else if (ioctl(dev, DIOCCOMMITRDRS, &pr.ticket)) {
+ print_error("DIOCCOMMITRDRS");
return (1);
}
- if (!strcmp(argv[1], "start")) {
- if (ioctl(dev, DIOCSTART))
- printerror("DIOCSTART");
- else
- printf("packetfilter started\n");
+ printf("nat cleared\n");
+ return (0);
+}
+
+int
+pfctl_clear_states(int dev)
+{
+ if (ioctl(dev, DIOCCLRSTATES)) {
+ print_error("DIOCCLRSTATES");
+ return (1);
}
- else if (!strcmp(argv[1], "stop")) {
- if (ioctl(dev, DIOCSTOP))
- printerror("DIOCSTOP");
- else
- printf("packetfilter stopped\n");
+ printf("states cleared\n");
+ return (0);
+}
+
+int
+pfctl_show_rules(int dev)
+{
+ struct pfioc_rule pr;
+ u_int32_t nr, mnr;
+
+ if (ioctl(dev, DIOCGETRULES, &pr)) {
+ print_error("DIOCGETRULES");
+ return (1);
}
- else if (!strcmp(argv[1], "show")) {
- if (argc < 3) {
- close(dev);
- usage(argv[0]);
+ mnr = pr.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRULE, &pr)) {
+ print_error("DIOCGETRULE");
return (1);
}
- if (!strcmp(argv[2], "rules")) {
- struct pf_rule *rule = ub->buffer;
-
- ub->entries = ub->size / sizeof(struct pf_rule);
- if (ioctl(dev, DIOCGETRULES, ub))
- printerror("DIOCGETRULES");
- for (n = 0; n < ub->entries; ++n) {
- printf("@%u ", n + 1);
- print_rule(rule + n);
- }
- }
- else if (!strcmp(argv[2], "nat")) {
- struct pf_nat *nat = ub->buffer;
- struct pf_rdr *rdr = ub->buffer;
-
- ub->entries = ub->size / sizeof(struct pf_nat);
- if (ioctl(dev, DIOCGETNAT, ub))
- printerror("DIOCGETNAT");
- for (n = 0; n < ub->entries; ++n)
- print_nat(nat + n);
- ub->entries = ub->size / sizeof(struct pf_rdr);
- if (ioctl(dev, DIOCGETRDR, ub))
- printerror("DIOCGETRDR");
- for (n = 0; n < ub->entries; ++n)
- print_rdr(rdr + n);
- }
- else if (!strcmp(argv[2], "states")) {
- u_int8_t proto = 0;
- struct pf_state *state = ub->buffer;
-
- if (argc >= 4) {
- if (!strcmp(argv[3], "tcp"))
- proto = IPPROTO_TCP;
- else if (!strcmp(argv[3], "udp"))
- proto = IPPROTO_UDP;
- else if (!strcmp(argv[3], "icmp"))
- proto = IPPROTO_ICMP;
- else {
- close(dev);
- usage(argv[0]);
- return (1);
- }
- }
- ub->entries = ub->size / sizeof(struct pf_state);
- if (ioctl(dev, DIOCGETSTATES, ub))
- printerror("DIOCGETSTATES");
- for (n = ub->entries; n > 0; --n)
- if (!proto || (state[n - 1].proto == proto))
- print_state(state + n - 1);
- }
- else if (!strcmp(argv[2], "status")) {
- struct pf_status *status = ub->buffer;
+ printf("@%u ", nr + 1);
+ print_rule(&pr.rule);
+ }
+ return (0);
+}
- ub->entries = 1;
- if (ioctl(dev, DIOCGETSTATUS, ub))
- printerror("DIOCGETSTATUS");
- print_status(status);
- }
- else {
- close(dev);
- usage(argv[0]);
- return (1);
- }
+int
+pfctl_show_nat(int dev)
+{
+ struct pfioc_nat pn;
+ struct pfioc_rdr pr;
+ u_int32_t mnr, nr;
+
+ if (ioctl(dev, DIOCGETNATS, &pn)) {
+ print_error("DIOCGETNATS");
+ return (1);
}
- else if (!strcmp(argv[1], "clear")) {
- if (argc < 3) {
- close(dev);
- usage(argv[0]);
- return (1);
- }
- ub->entries = 0;
- if (!strcmp(argv[2], "rules")) {
- if (ioctl(dev, DIOCSETRULES, ub))
- printerror("DIOCSETRULES");
- else printf("rules cleared\n");
- }
- else if (!strcmp(argv[2], "nat")) {
- if (ioctl(dev, DIOCSETNAT, ub))
- printerror("DIOCSETNAT");
- else if (ioctl(dev, DIOCSETRDR, ub))
- printerror("DIOCSETRDR");
- else printf("nat cleared\n");
- }
- else if (!strcmp(argv[2], "states")) {
- if (ioctl(dev, DIOCCLRSTATES))
- printerror("DIOCCLRSTATES");
- else
- printf("states cleared\n");
- }
- else {
- close(dev);
- usage(argv[0]);
+ mnr = pn.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pn.nr = nr;
+ if (ioctl(dev, DIOCGETNAT, &pn)) {
+ print_error("DIOCGETNAT");
return (1);
}
+ print_nat(&pn.nat);
}
- else if (!strcmp(argv[1], "log")) {
- if (argc < 3) {
- close(dev);
- usage(argv[0]);
- return (1);
- }
- strncpy(ub->buffer, argv[2], 16);
- if (ioctl(dev, DIOCSETSTATUSIF, ub))
- printerror("DIOCSETSTATUSIF");
- else
- printf("now logging %s\n", argv[2]);
+ if (ioctl(dev, DIOCGETRDRS, &pr)) {
+ print_error("DIOCGETRDRS");
+ return (1);
}
- else if (!strcmp(argv[1], "parse") || !strcmp(argv[1], "load")) {
- int load = !strcmp(argv[1], "load");
- char *buf, *s;
- size_t len;
- unsigned nr = 0;
- if ((argc < 4) || (strcmp(argv[2], "nat") &&
- strcmp(argv[2], "rules"))) {
- close(dev);
- usage(argv[0]);
+ mnr = pr.nr;
+ for (nr = 0; nr < mnr; ++nr) {
+ pr.nr = nr;
+ if (ioctl(dev, DIOCGETRDR, &pr)) {
+ print_error("DIOCGETRDR");
return (1);
}
- buf = load_file(argv[3], &len);
- if (buf == NULL)
- return (1);
+ print_rdr(&pr.rdr);
+ }
+ return (0);
+}
- if (!strcmp(argv[2], "rules")) {
- struct pf_rule *rule = ub->buffer;
-
- n = 0;
- nr = 0;
- s = buf;
- do {
- char *line = next_line(&s);
- nr++;
- if (*line && (*line != '#'))
- if (parse_rule(nr, line, rule + n))
- n++;
- } while (s < (buf + len));
- ub->entries = n;
- if (load) {
- if (ioctl(dev, DIOCSETRULES, ub))
- printerror("DIOCSETRULES");
- else
- printf("%u rules loaded\n",
- ub->entries);
- } else
- for (n = 0; n < ub->entries; ++n)
- print_rule(rule + n);
- } else {
- struct pf_nat *nat = ub->buffer;
- struct pf_rdr *rdr = ub->buffer;
-
- n = 0;
- nr = 0;
- s = buf;
- do {
- char *line = next_line(&s);
- nr++;
- if (*line && (*line == 'n'))
- if (parse_nat(nr, line, nat + n))
- n++;
- } while (s < (buf + len));
- ub->entries = n;
- if (load) {
- if (ioctl(dev, DIOCSETNAT, ub))
- printerror("DIOCSETNAT");
- else
- printf("%u nat entries loaded\n",
- ub->entries);
- } else
- for (n = 0; n < ub->entries; ++n)
- print_nat(nat + n);
- free(buf);
- buf = load_file(argv[3], &len);
- if (buf == NULL)
- return (1);
- n = 0;
- nr = 0;
- s = buf;
- do {
- char *line = next_line(&s);
- nr++;
- if (*line && (*line == 'r'))
- if (parse_rdr(nr, line, rdr + n))
- n++;
- } while (s < (buf + len));
- ub->entries = n;
- if (load) {
- if (ioctl(dev, DIOCSETRDR, ub))
- printerror("DIOCSETRDR");
- else
- printf("%u rdr entries loaded\n",
- ub->entries);
- } else
- for (n = 0; n < ub->entries; ++n)
- print_rdr(rdr + n);
- }
+int
+pfctl_show_states(int dev, u_int8_t proto)
+{
+ struct pfioc_state ps;
+
+ ps.nr = 0;
+ while (!ioctl(dev, DIOCGETSTATE, &ps)) {
+ if (!proto || (ps.state.proto == proto))
+ print_state(&ps.state);
+ ps.nr++;
+ }
+ return (0);
+}
+
+int
+pfctl_show_status(int dev)
+{
+ struct pf_status status;
+ if (ioctl(dev, DIOCGETSTATUS, &status)) {
+ print_error("DIOCGETSTATUS");
+ return (1);
+ }
+ print_status(&status);
+ return (0);
+}
+
+int
+pfctl_rules(int dev, char *filename)
+{
+ struct pfioc_rule pr;
+ char *buf, *s;
+ size_t len;
+ unsigned n, nr;
+
+ buf = load_file(filename, &len);
+ if (buf == NULL)
+ return (1);
+ if (ioctl(dev, DIOCBEGINRULES, &pr.ticket)) {
+ print_error("DIOCBEGINRULES");
free(buf);
+ return (1);
}
- else {
- close(dev);
- usage(argv[0]);
+ n = 0;
+ nr = 0;
+ s = buf;
+ do {
+ char *line = next_line(&s);
+ nr++;
+ if (*line && (*line != '#'))
+ if (parse_rule(nr, line, &pr.rule)) {
+ if (ioctl(dev, DIOCADDRULE, &pr)) {
+ print_error("DIOCADDRULE");
+ free(buf);
+ return (1);
+ }
+ n++;
+ }
+ } while (s < (buf + len));
+ free(buf);
+ if (ioctl(dev, DIOCCOMMITRULES, &pr.ticket)) {
+ print_error("DIOCCOMMITRULES");
return (1);
}
- close(dev);
- free(ub->buffer);
- free(ub);
+ printf("%u rules loaded\n", n);
+ return (0);
+}
+
+int
+pfctl_nat(int dev, char *filename)
+{
+ struct pfioc_nat pn;
+ struct pfioc_rdr pr;
+ char *buf, *s;
+ size_t len;
+ unsigned n, nr;
+
+ if (ioctl(dev, DIOCBEGINNATS, &pn.ticket)) {
+ print_error("DIOCBEGINNATS");
+ return (1);
+ }
+ buf = load_file(filename, &len);
+ if (buf == NULL)
+ return (1);
+ n = 0;
+ nr = 0;
+ s = buf;
+ do {
+ char *line = next_line(&s);
+ nr++;
+ if (*line && (*line == 'n'))
+ if (parse_nat(nr, line, &pn.nat)) {
+ if (ioctl(dev, DIOCADDNAT, &pn)) {
+ print_error("DIOCADDNAT");
+ free(buf);
+ return (1);
+ }
+ n++;
+ }
+ } while (s < (buf + len));
+ free(buf);
+ if (ioctl(dev, DIOCCOMMITNATS, &pn.ticket)) {
+ print_error("DIOCCOMMITNATS");
+ return (1);
+ }
+ printf("%u nat entries loaded\n", n);
+
+ if (ioctl(dev, DIOCBEGINRDRS, &pr.ticket)) {
+ print_error("DIOCBEGINRDRS");
+ return 1;
+ }
+ buf = load_file(filename, &len);
+ if (buf == NULL)
+ return (1);
+ n = 0;
+ nr = 0;
+ s = buf;
+ do {
+ char *line = next_line(&s);
+ nr++;
+ if (*line && (*line == 'r'))
+ if (parse_rdr(nr, line, &pr.rdr)) {
+ if (ioctl(dev, DIOCADDRDR, &pr)) {
+ print_error("DIOCADDRDR");
+ free(buf);
+ return (1);
+ }
+ n++;
+ }
+ } while (s < (buf + len));
+ free(buf);
+ if (ioctl(dev, DIOCCOMMITRDRS, &pr.ticket)) {
+ print_error("DIOCCOMMITRDRS");
+ return (1);
+ }
+ printf("%u rdr entries loaded\n", n);
+ return (0);
+}
+
+int
+pfctl_log(int dev, char *ifname)
+{
+ struct pfioc_if pi;
+
+ strncpy(pi.ifname, ifname, 16);
+ if (ioctl(dev, DIOCSETSTATUSIF, &pi)) {
+ print_error("DIOCSETSTATUSIF");
+ return (1);
+ }
+ printf("now logging %s\n", pi.ifname);
return (0);
}
+int
+main(int argc, char *argv[])
+{
+ extern char *optarg;
+ extern int optind;
+ int error = 0;
+ int dev;
+ int ch;
+
+ if (argc <= 1) {
+ usage();
+ return (0);
+ }
+ dev = open("/dev/pf", O_RDWR);
+ if (dev < 0) {
+ print_error("open(/dev/pf)");
+ return (1);
+ }
+ while (!error && (ch = getopt(argc, argv, "dc:r:n:s:l:e")) != -1) {
+ switch (ch) {
+ case 'd':
+ if (pfctl_disable(dev))
+ error = 1;
+ break;
+ case 'c':
+ if (!strcmp(optarg, "rules")) {
+ if (pfctl_clear_rules(dev))
+ error = 1;
+ } else if (!strcmp(optarg, "nat")) {
+ if (pfctl_clear_nat(dev))
+ error = 1;
+ } else if (!strcmp(optarg, "states")) {
+ if (pfctl_clear_states(dev))
+ error = 1;
+ } else
+ error = 1;
+ break;
+ case 'r':
+ if (pfctl_rules(dev, optarg))
+ error = 1;
+ break;
+ case 'n':
+ if (pfctl_nat(dev, optarg))
+ error = 1;
+ break;
+ case 's':
+ if (!strcmp(optarg, "rules")) {
+ if (pfctl_show_rules(dev))
+ error = 1;
+ } else if (!strcmp(optarg, "nat")) {
+ if (pfctl_show_nat(dev))
+ error = 1;
+ } else if (!strcmp(optarg, "states")) {
+ if (pfctl_show_states(dev, 0))
+ error = 1;
+ } else if (!strcmp(optarg, "status")) {
+ if (pfctl_show_status(dev))
+ error = 1;
+ } else
+ error = 1;
+ break;
+ case 'l':
+ if (pfctl_log(dev, optarg))
+ error = 1;
+ break;
+ case 'e':
+ if (pfctl_enable(dev))
+ error = 1;
+ break;
+ default:
+ usage();
+ error = 1;
+ }
+ }
+ close(dev);
+ return (error);
+}
diff --git a/sys/net/pf.c b/sys/net/pf.c
index b5d5c38ab69..9050c8977ab 100644
--- a/sys/net/pf.c
+++ b/sys/net/pf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pf.c,v 1.32 2001/06/25 16:53:20 jasoni Exp $ */
+/* $OpenBSD: pf.c,v 1.33 2001/06/25 17:17:04 dhartmei Exp $ */
/*
* Copyright (c) 2001, Daniel Hartmeier
@@ -74,16 +74,27 @@ struct pf_tree_node {
* Global variables
*/
-struct pf_rule *pf_rulehead;
-struct pf_nat *pf_nathead;
-struct pf_rdr *pf_rdrhead;
-struct pf_state *pfstatehead;
+struct pf_rule *pf_rulehead_active;
+struct pf_rule *pf_rulehead_inactive;
+struct pf_rule *pf_ruletail_active;
+struct pf_rule *pf_ruletail_inactive;
+struct pf_nat *pf_nathead_active;
+struct pf_nat *pf_nathead_inactive;
+struct pf_rdr *pf_rdrhead_active;
+struct pf_rdr *pf_rdrhead_inactive;
+struct pf_state *pf_statehead;
struct pf_tree_node *tree_lan_ext, *tree_ext_gwy;
struct timeval pftv;
struct pf_status pf_status;
struct ifnet *status_ifp;
u_int32_t pf_last_purge = 0;
+u_int32_t ticket_rules_active = 0;
+u_int32_t ticket_rules_inactive = 0;
+u_int32_t ticket_nats_active = 0;
+u_int32_t ticket_nats_inactive = 0;
+u_int32_t ticket_rdrs_active = 0;
+u_int32_t ticket_rdrs_inactive = 0;
u_int16_t pf_next_port_tcp = 50001;
u_int16_t pf_next_port_udp = 50001;
@@ -365,8 +376,8 @@ insert_state(struct pf_state *state)
printf("pf: ERROR! insert failed\n");
}
- state->next = pfstatehead;
- pfstatehead = state;
+ state->next = pf_statehead;
+ pf_statehead = state;
pf_status.state_inserts++;
pf_status.states++;
@@ -376,7 +387,7 @@ void
purge_expired_states(void)
{
struct pf_tree_key key;
- struct pf_state *cur = pfstatehead, *prev = NULL;
+ struct pf_state *cur = pf_statehead, *prev = NULL;
while (cur != NULL) {
if (cur->expire <= pftv.tv_sec) {
@@ -401,9 +412,9 @@ purge_expired_states(void)
tree_remove(&tree_ext_gwy, &key);
if (find_state(tree_ext_gwy, &key) != NULL)
printf("pf: ERROR! remove failed\n");
- (prev ? prev->next : pfstatehead) = cur->next;
+ (prev ? prev->next : pf_statehead) = cur->next;
pool_put(&pf_state_pl, cur);
- cur = (prev ? prev->next : pfstatehead);
+ cur = (prev ? prev->next : pf_statehead);
pf_status.state_removals++;
pf_status.states--;
} else {
@@ -509,34 +520,17 @@ int
pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
{
int error = 0;
- struct pfioc *ub;
- void *kb = NULL;
int s;
if (!(flags & FWRITE))
return (EACCES);
if ((cmd != DIOCSTART) && (cmd != DIOCSTOP) && (cmd != DIOCCLRSTATES)) {
- ub = (struct pfioc *)addr;
- if (ub == NULL)
+ if (addr == NULL) {
return (EINVAL);
- kb = malloc(ub->size, M_DEVBUF, M_NOWAIT);
- if (kb == NULL)
- return (ENOMEM);
- if (copyin(ub->buffer, kb, ub->size)) {
- free(kb, M_DEVBUF);
- return (EIO);
}
}
- s = splsoftnet();
-
- microtime(&pftv);
- if (pftv.tv_sec - pf_last_purge >= 10) {
- purge_expired_states();
- pf_last_purge = pftv.tv_sec;
- }
-
switch (cmd) {
case DIOCSTART:
@@ -561,143 +555,314 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
break;
- case DIOCSETRULES: {
- struct pf_rule *rules = (struct pf_rule *)kb, *ruletail = NULL;
- u_int16_t n;
- while (pf_rulehead != NULL) {
- struct pf_rule *next = pf_rulehead->next;
- pool_put(&pf_rule_pl, pf_rulehead);
- pf_rulehead = next;
+ case DIOCBEGINRULES: {
+ u_int32_t *ticket = (u_int32_t *)addr;
+
+ while (pf_rulehead_inactive != NULL) {
+ struct pf_rule *next = pf_rulehead_inactive->next;
+ pool_put(&pf_rule_pl, pf_rulehead_inactive);
+ pf_rulehead_inactive = next;
}
- for (n = 0; n < ub->entries; ++n) {
- struct pf_rule *rule;
+ *ticket = ++ticket_rules_inactive;
+ break;
+ }
+
+ case DIOCADDRULE: {
+ struct pfioc_rule *pr = (struct pfioc_rule *)addr;
+ struct pf_rule *rule;
- rule = pool_get(&pf_rule_pl, PR_NOWAIT);
- if (rule == NULL) {
- error = ENOMEM;
+ if (pr->ticket != ticket_rules_inactive) {
+ error = EBUSY;
+ goto done;
+ }
+ rule = pool_get(&pf_rule_pl, PR_NOWAIT);
+ if (rule == NULL) {
+ error = ENOMEM;
+ goto done;
+ }
+ bcopy(&pr->rule, rule, sizeof(struct pf_rule));
+ rule->ifp = NULL;
+ if (rule->ifname[0]) {
+ rule->ifp = ifunit(rule->ifname);
+ if (rule->ifp == NULL) {
+ pool_put(&pf_rule_pl, rule);
+ error = EINVAL;
goto done;
}
- bcopy(rules + n, rule, sizeof(struct pf_rule));
- rule->ifp = NULL;
- if (rule->ifname[0]) {
- rule->ifp = ifunit(rule->ifname);
- if (rule->ifp == NULL) {
- pool_put(&pf_rule_pl, rule);
- error = EINVAL;
- goto done;
- }
- }
- rule->next = NULL;
- if (ruletail != NULL) {
- ruletail->next = rule;
- ruletail = rule;
- } else
- pf_rulehead = ruletail = rule;
}
+ rule->next = NULL;
+ if (pf_ruletail_inactive != NULL) {
+ pf_ruletail_inactive->next = rule;
+ pf_ruletail_inactive = rule;
+ } else
+ pf_rulehead_inactive = pf_ruletail_inactive = rule;
+ break;
+ }
+
+ case DIOCCOMMITRULES: {
+ u_int32_t *ticket = (u_int32_t *)addr;
+
+ if (*ticket != ticket_rules_inactive) {
+ error = EBUSY;
+ goto done;
+ }
+ s = splsoftnet();
+ while (pf_rulehead_active != NULL) {
+ struct pf_rule *next = pf_rulehead_active->next;
+ pool_put(&pf_rule_pl, pf_rulehead_active);
+ pf_rulehead_active = next;
+ }
+ pf_rulehead_active = pf_rulehead_inactive;
+ pf_ruletail_active = pf_ruletail_inactive;
+ pf_rulehead_inactive = NULL;
+ pf_ruletail_inactive = NULL;
+ ticket_rules_active = ticket_rules_inactive;
+ splx(s);
break;
}
case DIOCGETRULES: {
- struct pf_rule *rules = (struct pf_rule *)kb;
- struct pf_rule *rule = pf_rulehead;
- u_int16_t n = 0;
- while ((rule != NULL) && (n < ub->entries)) {
- bcopy(rule, rules + n, sizeof(struct pf_rule));
- n++;
+ struct pfioc_rule *pr = (struct pfioc_rule *)addr;
+ struct pf_rule *rule;
+
+ s = splsoftnet();
+ rule = pf_rulehead_active;
+ pr->nr = 0;
+ while (rule != NULL) {
+ pr->nr++;
+ rule = rule->next;
+ }
+ pr->ticket = ticket_rules_active;
+ splx(s);
+ break;
+ }
+
+ case DIOCGETRULE: {
+ struct pfioc_rule *pr = (struct pfioc_rule *)addr;
+ struct pf_rule *rule;
+ u_int32_t nr;
+
+ if (pr->ticket != ticket_rules_active) {
+ error = EBUSY;
+ goto done;
+ }
+ s = splsoftnet();
+ rule = pf_rulehead_active;
+ nr = 0;
+ while ((rule != NULL) && (nr < pr->nr)) {
rule = rule->next;
+ nr++;
+ }
+ if (rule == NULL) {
+ error = EBUSY;
+ splx(s);
+ goto done;
}
- ub->entries = n;
+ bcopy(rule, &pr->rule, sizeof(struct pf_rule));
+ splx(s);
break;
}
- case DIOCSETNAT: {
- struct pf_nat *nats = (struct pf_nat *)kb;
- u_int16_t n;
- while (pf_nathead != NULL) {
- struct pf_nat *next = pf_nathead->next;
+ case DIOCBEGINNATS: {
+ u_int32_t *ticket = (u_int32_t *)addr;
- pool_put(&pf_nat_pl, pf_nathead);
- pf_nathead = next;
+ while (pf_nathead_inactive != NULL) {
+ struct pf_nat *next = pf_nathead_inactive->next;
+ pool_put(&pf_nat_pl, pf_nathead_inactive);
+ pf_nathead_inactive = next;
}
- for (n = 0; n < ub->entries; ++n) {
- struct pf_nat *nat;
+ *ticket = ++ticket_nats_inactive;
+ break;
+ }
- nat = pool_get(&pf_nat_pl, PR_NOWAIT);
- if (nat == NULL) {
- error = ENOMEM;
- goto done;
- }
- bcopy(nats + n, nat, sizeof(struct pf_nat));
- nat->ifp = ifunit(nat->ifname);
- if (nat->ifp == NULL) {
- pool_put(&pf_nat_pl, nat);
- error = EINVAL;
- goto done;
- }
- nat->next = pf_nathead;
- pf_nathead = nat;
+ case DIOCADDNAT: {
+ struct pfioc_nat *pn = (struct pfioc_nat *)addr;
+ struct pf_nat *nat;
+
+ if (pn->ticket != ticket_nats_inactive) {
+ error = EBUSY;
+ goto done;
+ }
+ nat = pool_get(&pf_nat_pl, PR_NOWAIT);
+ if (nat == NULL) {
+ error = ENOMEM;
+ goto done;
+ }
+ bcopy(&pn->nat, nat, sizeof(struct pf_nat));
+ nat->ifp = ifunit(nat->ifname);
+ if (nat->ifp == NULL) {
+ pool_put(&pf_nat_pl, nat);
+ error = EINVAL;
+ goto done;
+ }
+ nat->next = pf_nathead_inactive;
+ pf_nathead_inactive = nat;
+ break;
+ }
+
+ case DIOCCOMMITNATS: {
+ u_int32_t *ticket = (u_int32_t *)addr;
+
+ if (*ticket != ticket_nats_inactive) {
+ error = EBUSY;
+ goto done;
+ }
+ s = splsoftnet();
+ while (pf_nathead_active != NULL) {
+ struct pf_nat *next = pf_nathead_active->next;
+ pool_put(&pf_nat_pl, pf_nathead_active);
+ pf_nathead_active = next;
+ }
+ pf_nathead_active = pf_nathead_inactive;
+ pf_nathead_inactive = NULL;
+ ticket_nats_active = ticket_nats_inactive;
+ splx(s);
+ break;
+ }
+
+ case DIOCGETNATS: {
+ struct pfioc_nat *pn = (struct pfioc_nat *)addr;
+ struct pf_nat *nat;
+
+ s = splsoftnet();
+ nat = pf_nathead_active;
+ pn->nr = 0;
+ while (nat != NULL) {
+ pn->nr++;
+ nat = nat->next;
}
+ pn->ticket = ticket_nats_active;
+ splx(s);
break;
}
case DIOCGETNAT: {
- struct pf_nat *nats = (struct pf_nat *)kb;
- struct pf_nat *nat = pf_nathead;
- u_int16_t n = 0;
- while ((nat != NULL) && (n < ub->entries)) {
- bcopy(nat, nats + n, sizeof(struct pf_nat));
- n++;
+ struct pfioc_nat *pn = (struct pfioc_nat *)addr;
+ struct pf_nat *nat;
+ u_int32_t nr;
+
+ if (pn->ticket != ticket_nats_active) {
+ error = EBUSY;
+ goto done;
+ }
+ s = splsoftnet();
+ nat = pf_nathead_active;
+ nr = 0;
+ while ((nat != NULL) && (nr < pn->nr)) {
nat = nat->next;
+ nr++;
}
- ub->entries = n;
+ if (nat == NULL) {
+ error = EBUSY;
+ splx(s);
+ goto done;
+ }
+ bcopy(nat, &pn->nat, sizeof(struct pf_nat));
+ splx(s);
break;
}
- case DIOCSETRDR: {
- struct pf_rdr *rdrs = (struct pf_rdr *)kb;
- u_int16_t n;
- while (pf_rdrhead != NULL) {
- struct pf_rdr *next = pf_rdrhead->next;
+ case DIOCBEGINRDRS: {
+ u_int32_t *ticket = (u_int32_t *)addr;
- pool_put(&pf_rdr_pl, pf_rdrhead);
- pf_rdrhead = next;
+ while (pf_rdrhead_inactive != NULL) {
+ struct pf_rdr *next = pf_rdrhead_inactive->next;
+ pool_put(&pf_rdr_pl, pf_rdrhead_inactive);
+ pf_rdrhead_inactive = next;
}
- for (n = 0; n < ub->entries; ++n) {
- struct pf_rdr *rdr;
+ *ticket = ++ticket_rdrs_inactive;
+ break;
+ }
- rdr = pool_get(&pf_rdr_pl, PR_NOWAIT);
- if (rdr == NULL) {
- error = ENOMEM;
- goto done;
- }
- bcopy(rdrs + n, rdr, sizeof(struct pf_rdr));
- rdr->ifp = ifunit(rdr->ifname);
- if (rdr->ifp == NULL) {
- pool_put(&pf_rdr_pl, rdr);
- error = EINVAL;
- goto done;
- }
- rdr->next = pf_rdrhead;
- pf_rdrhead = rdr;
+ case DIOCADDRDR: {
+ struct pfioc_rdr *pr = (struct pfioc_rdr *)addr;
+ struct pf_rdr *rdr;
+
+ if (pr->ticket != ticket_rdrs_inactive) {
+ error = EBUSY;
+ goto done;
+ }
+ rdr = pool_get(&pf_rdr_pl, PR_NOWAIT);
+ if (rdr == NULL) {
+ error = ENOMEM;
+ goto done;
+ }
+ bcopy(&pr->rdr, rdr, sizeof(struct pf_rdr));
+ rdr->ifp = ifunit(rdr->ifname);
+ if (rdr->ifp == NULL) {
+ pool_put(&pf_rdr_pl, rdr);
+ error = EINVAL;
+ goto done;
}
+ rdr->next = pf_rdrhead_inactive;
+ pf_rdrhead_inactive = rdr;
+ break;
+ }
+
+ case DIOCCOMMITRDRS: {
+ u_int32_t *ticket = (u_int32_t *)addr;
+
+ if (*ticket != ticket_rdrs_inactive) {
+ error = EBUSY;
+ goto done;
+ }
+ s = splsoftnet();
+ while (pf_rdrhead_active != NULL) {
+ struct pf_rdr *next = pf_rdrhead_active->next;
+ pool_put(&pf_rdr_pl, pf_rdrhead_active);
+ pf_rdrhead_active = next;
+ }
+ pf_rdrhead_active = pf_rdrhead_inactive;
+ pf_rdrhead_inactive = NULL;
+ ticket_rdrs_active = ticket_rdrs_inactive;
+ splx(s);
+ break;
+ }
+
+ case DIOCGETRDRS: {
+ struct pfioc_rdr *pr = (struct pfioc_rdr *)addr;
+ struct pf_rdr *rdr;
+
+ s = splsoftnet();
+ rdr = pf_rdrhead_active;
+ pr->nr = 0;
+ while (rdr != NULL) {
+ pr->nr++;
+ rdr = rdr->next;
+ }
+ pr->ticket = ticket_rdrs_active;
+ splx(s);
break;
}
case DIOCGETRDR: {
- struct pf_rdr *rdrs = (struct pf_rdr *)kb;
- struct pf_rdr *rdr = pf_rdrhead;
- u_int16_t n = 0;
- while ((rdr != NULL) && (n < ub->entries)) {
- bcopy(rdr, rdrs + n, sizeof(struct pf_rdr));
- n++;
+ struct pfioc_rdr *pr = (struct pfioc_rdr *)addr;
+ struct pf_rdr *rdr;
+ u_int32_t nr;
+
+ if (pr->ticket != ticket_rdrs_active) {
+ error = EBUSY;
+ goto done;
+ }
+ s = splsoftnet();
+ rdr = pf_rdrhead_active;
+ nr = 0;
+ while ((rdr != NULL) && (nr < pr->nr)) {
rdr = rdr->next;
+ nr++;
+ }
+ if (rdr == NULL) {
+ error = EBUSY;
+ splx(s);
+ goto done;
}
- ub->entries = n;
+ bcopy(rdr, &pr->rdr, sizeof(struct pf_rdr));
+ splx(s);
break;
}
case DIOCCLRSTATES: {
- struct pf_state *state = pfstatehead;
+ struct pf_state *state = pf_statehead;
while (state != NULL) {
state->expire = 0;
state = state->next;
@@ -706,29 +871,35 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
break;
}
- case DIOCGETSTATES: {
- struct pf_state *states = (struct pf_state *)kb;
+ case DIOCGETSTATE: {
+ struct pfioc_state *ps = (struct pfioc_state *)addr;
struct pf_state *state;
- u_int16_t n = 0;
- state = pfstatehead;
- while ((state != NULL) && (n < ub->entries)) {
- bcopy(state, states + n, sizeof(struct pf_state));
- states[n].creation = pftv.tv_sec - states[n].creation;
- if (states[n].expire <= pftv.tv_sec)
- states[n].expire = 0;
- else
- states[n].expire -= pftv.tv_sec;
- n++;
+ u_int32_t nr;
+
+ state = pf_statehead;
+ nr = 0;
+ while ((state != NULL) && (nr < ps->nr)) {
state = state->next;
+ nr++;
}
- ub->entries = n;
+ if (state == NULL) {
+ error = EBUSY;
+ goto done;
+ }
+ bcopy(state, &ps->state, sizeof(struct pf_state));
+ ps->state.creation = pftv.tv_sec - ps->state.creation;
+ if (ps->state.expire <= pftv.tv_sec)
+ ps->state.expire = 0;
+ else
+ ps->state.expire -= pftv.tv_sec;
break;
}
case DIOCSETSTATUSIF: {
- char *ifname = (char *)kb;
- struct ifnet *ifp = ifunit(ifname);
- if (ifp == NULL)
+ struct pfioc_if *pi = (struct pfioc_if *)addr;
+ struct ifnet *ifp;
+
+ if ((ifp = ifunit(pi->ifname)) == NULL)
error = EINVAL;
else
status_ifp = ifp;
@@ -736,12 +907,15 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
case DIOCGETSTATUS: {
- struct pf_status *st = (struct pf_status *)kb;
+ struct pf_status *s = (struct pf_status *)addr;
u_int8_t running = pf_status.running;
u_int32_t states = pf_status.states;
- bcopy(&pf_status, st, sizeof(struct pf_status));
- st->since = st->since ? pftv.tv_sec - st->since : 0;
- ub->entries = 1;
+
+ bcopy(&pf_status, s, sizeof(struct pf_status));
+ if (s->since)
+ s->since = pftv.tv_sec - s->since;
+ else
+ s->since = 0;
bzero(&pf_status, sizeof(struct pf_status));
pf_status.running = running;
pf_status.states = states;
@@ -755,12 +929,6 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
done:
- splx(s);
- if (kb != NULL) {
- if (copyout(kb, ub->buffer, ub->size))
- error = EIO;
- free(kb, M_DEVBUF);
- }
return (error);
}
@@ -932,7 +1100,7 @@ match_port(u_int8_t op, u_int16_t a1, u_int16_t a2, u_int16_t p)
struct pf_nat *
get_nat(struct ifnet *ifp, u_int8_t proto, u_int32_t addr)
{
- struct pf_nat *n = pf_nathead, *nm = NULL;
+ struct pf_nat *n = pf_nathead_active, *nm = NULL;
while (n && nm == NULL) {
if (n->ifp == ifp &&
@@ -948,7 +1116,7 @@ get_nat(struct ifnet *ifp, u_int8_t proto, u_int32_t addr)
struct pf_rdr *
get_rdr(struct ifnet *ifp, u_int8_t proto, u_int32_t addr, u_int16_t port)
{
- struct pf_rdr *r = pf_rdrhead, *rm = NULL;
+ struct pf_rdr *r = pf_rdrhead_active, *rm = NULL;
while (r && rm == NULL) {
if (r->ifp == ifp &&
(!r->proto || r->proto == proto) &&
@@ -969,7 +1137,7 @@ pf_test_tcp(int direction, struct ifnet *ifp, int off, struct ip *h,
struct pf_rdr *rdr = NULL;
u_int32_t baddr;
u_int16_t bport;
- struct pf_rule *r = pf_rulehead, *rm = NULL;
+ struct pf_rule *r = pf_rulehead_active, *rm = NULL;
u_int16_t nr = 1, mnr = 0;
if (direction == PF_OUT) {
@@ -1113,7 +1281,7 @@ pf_test_udp(int direction, struct ifnet *ifp, int off, struct ip *h,
struct pf_rdr *rdr = NULL;
u_int32_t baddr;
u_int16_t bport;
- struct pf_rule *r = pf_rulehead, *rm = NULL;
+ struct pf_rule *r = pf_rulehead_active, *rm = NULL;
u_int16_t nr = 1, mnr = 0;
if (direction == PF_OUT) {
@@ -1233,7 +1401,7 @@ pf_test_icmp(int direction, struct ifnet *ifp, int off, struct ip *h,
{
struct pf_nat *nat = NULL;
u_int32_t baddr;
- struct pf_rule *r = pf_rulehead, *rm = NULL;
+ struct pf_rule *r = pf_rulehead_active, *rm = NULL;
u_int16_t nr = 1, mnr = 0;
if (direction == PF_OUT) {
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index e3ff3152f0c..af8a7f277cf 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pfvar.h,v 1.9 2001/06/25 10:07:15 art Exp $ */
+/* $OpenBSD: pfvar.h,v 1.10 2001/06/25 17:17:03 dhartmei Exp $ */
/*
* Copyright (c) 2001, Daniel Hartmeier
@@ -129,13 +129,34 @@ struct pf_status {
};
/*
- * ioctl parameter structure
+ * ioctl parameter structures
*/
-struct pfioc {
- u_int32_t size;
- u_int16_t entries;
- void *buffer;
+struct pfioc_rule {
+ u_int32_t ticket;
+ u_int32_t nr;
+ struct pf_rule rule;
+};
+
+struct pfioc_nat {
+ u_int32_t ticket;
+ u_int32_t nr;
+ struct pf_nat nat;
+};
+
+struct pfioc_rdr {
+ u_int32_t ticket;
+ u_int32_t nr;
+ struct pf_rdr rdr;
+};
+
+struct pfioc_state {
+ u_int32_t nr;
+ struct pf_state state;
+};
+
+struct pfioc_if {
+ char ifname[IFNAMSIZ];
};
/*
@@ -144,16 +165,25 @@ struct pfioc {
#define DIOCSTART _IO ('D', 1)
#define DIOCSTOP _IO ('D', 2)
-#define DIOCSETRULES _IOWR('D', 3, struct pfioc)
-#define DIOCGETRULES _IOWR('D', 4, struct pfioc)
-#define DIOCSETNAT _IOWR('D', 5, struct pfioc)
-#define DIOCGETNAT _IOWR('D', 6, struct pfioc)
-#define DIOCSETRDR _IOWR('D', 7, struct pfioc)
-#define DIOCGETRDR _IOWR('D', 8, struct pfioc)
-#define DIOCCLRSTATES _IO ('D', 9)
-#define DIOCGETSTATES _IOWR('D', 10, struct pfioc)
-#define DIOCSETSTATUSIF _IOWR('D', 11, struct pfioc)
-#define DIOCGETSTATUS _IOWR('D', 12, struct pfioc)
+#define DIOCBEGINRULES _IOWR('D', 3, u_int32_t)
+#define DIOCADDRULE _IOWR('D', 4, struct pfioc_rule)
+#define DIOCCOMMITRULES _IOWR('D', 5, u_int32_t)
+#define DIOCGETRULES _IOWR('D', 6, struct pfioc_rule)
+#define DIOCGETRULE _IOWR('D', 7, struct pfioc_rule)
+#define DIOCBEGINNATS _IOWR('D', 8, u_int32_t)
+#define DIOCADDNAT _IOWR('D', 9, struct pfioc_nat)
+#define DIOCCOMMITNATS _IOWR('D', 10, u_int32_t)
+#define DIOCGETNATS _IOWR('D', 11, struct pfioc_nat)
+#define DIOCGETNAT _IOWR('D', 12, struct pfioc_nat)
+#define DIOCBEGINRDRS _IOWR('D', 13, u_int32_t)
+#define DIOCADDRDR _IOWR('D', 14, struct pfioc_rdr)
+#define DIOCCOMMITRDRS _IOWR('D', 15, u_int32_t)
+#define DIOCGETRDRS _IOWR('D', 16, struct pfioc_rdr)
+#define DIOCGETRDR _IOWR('D', 17, struct pfioc_rdr)
+#define DIOCCLRSTATES _IO ('D', 18)
+#define DIOCGETSTATE _IOWR('D', 19, struct pfioc_state)
+#define DIOCSETSTATUSIF _IOWR('D', 20, struct pfioc_if)
+#define DIOCGETSTATUS _IOWR('D', 21, struct pf_status)
#ifdef _KERNEL