Deleted Added
sdiff udiff text old ( 126259 ) new ( 126261 )
full compact
1/* $OpenBSD: pf_ioctl.c,v 1.81 2003/08/22 21:50:34 david Exp $ */
2
3/*
4 * Copyright (c) 2001 Daniel Hartmeier
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions

--- 20 unchanged lines hidden (view full) ---

29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Effort sponsored in part by the Defense Advanced Research Projects
32 * Agency (DARPA) and Air Force Research Laboratory, Air Force
33 * Materiel Command, USAF, under agreement number F30602-01-2-0537.
34 *
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/mbuf.h>
40#include <sys/filio.h>
41#include <sys/fcntl.h>
42#include <sys/socket.h>
43#include <sys/socketvar.h>
44#include <sys/kernel.h>
45#include <sys/time.h>
46#include <sys/timeout.h>
47#include <sys/pool.h>
48#include <sys/malloc.h>
49
50#include <net/if.h>
51#include <net/if_types.h>
52#include <net/route.h>
53
54#include <netinet/in.h>
55#include <netinet/in_var.h>
56#include <netinet/in_systm.h>
57#include <netinet/ip.h>
58#include <netinet/ip_var.h>
59#include <netinet/ip_icmp.h>
60
61#include <net/pfvar.h>
62
63#ifdef INET6
64#include <netinet/ip6.h>
65#include <netinet/in_pcb.h>
66#endif /* INET6 */
67
68#ifdef ALTQ
69#include <altq/altq.h>
70#endif
71
72void pfattach(int);
73int pfopen(dev_t, int, int, struct proc *);
74int pfclose(dev_t, int, int, struct proc *);
75struct pf_pool *pf_get_pool(char *, char *, u_int32_t,
76 u_int8_t, u_int8_t, u_int8_t, u_int8_t, u_int8_t);
77int pf_get_ruleset_number(u_int8_t);
78void pf_init_ruleset(struct pf_ruleset *);
79void pf_mv_pool(struct pf_palist *, struct pf_palist *);
80void pf_empty_pool(struct pf_palist *);
81int pfioctl(dev_t, u_long, caddr_t, int, struct proc *);
82
83extern struct timeout pf_expire_to;
84
85struct pf_rule pf_default_rule;
86
87#define TAGID_MAX 50000
88TAILQ_HEAD(pf_tags, pf_tagname) pf_tags = TAILQ_HEAD_INITIALIZER(pf_tags);
89
90#define DPFPRINTF(n, x) if (pf_status.debug >= (n)) printf x
91
92void
93pfattach(int num)
94{
95 u_int32_t *timeout = pf_default_rule.timeout;
96
97 pool_init(&pf_tree_pl, sizeof(struct pf_tree_node), 0, 0, 0, "pftrpl",
98 NULL);
99 pool_init(&pf_rule_pl, sizeof(struct pf_rule), 0, 0, 0, "pfrulepl",
100 &pool_allocator_nointr);

--- 23 unchanged lines hidden (view full) ---

124
125 /* default rule should never be garbage collected */
126 pf_default_rule.entries.tqe_prev = &pf_default_rule.entries.tqe_next;
127 pf_default_rule.action = PF_PASS;
128 pf_default_rule.nr = -1;
129
130 /* initialize default timeouts */
131 timeout[PFTM_TCP_FIRST_PACKET] = 120; /* First TCP packet */
132 timeout[PFTM_TCP_OPENING] = 30; /* No response yet */
133 timeout[PFTM_TCP_ESTABLISHED] = 24*60*60; /* Established */
134 timeout[PFTM_TCP_CLOSING] = 15 * 60; /* Half closed */
135 timeout[PFTM_TCP_FIN_WAIT] = 45; /* Got both FINs */
136 timeout[PFTM_TCP_CLOSED] = 90; /* Got a RST */
137 timeout[PFTM_UDP_FIRST_PACKET] = 60; /* First UDP packet */
138 timeout[PFTM_UDP_SINGLE] = 30; /* Unidirectional */
139 timeout[PFTM_UDP_MULTIPLE] = 60; /* Bidirectional */
140 timeout[PFTM_ICMP_FIRST_PACKET] = 20; /* First ICMP packet */

--- 5 unchanged lines hidden (view full) ---

146 timeout[PFTM_INTERVAL] = 10; /* Expire interval */
147
148 timeout_set(&pf_expire_to, pf_purge_timeout, &pf_expire_to);
149 timeout_add(&pf_expire_to, timeout[PFTM_INTERVAL] * hz);
150
151 pf_normalize_init();
152 pf_status.debug = PF_DEBUG_URGENT;
153}
154
155int
156pfopen(dev_t dev, int flags, int fmt, struct proc *p)
157{
158 if (minor(dev) >= 1)
159 return (ENXIO);
160 return (0);
161}
162
163int
164pfclose(dev_t dev, int flags, int fmt, struct proc *p)
165{
166 if (minor(dev) >= 1)
167 return (ENXIO);
168 return (0);
169}
170
171struct pf_pool *
172pf_get_pool(char *anchorname, char *rulesetname, u_int32_t ticket,
173 u_int8_t rule_action, u_int8_t rule_number, u_int8_t r_last,
174 u_int8_t active, u_int8_t check_ticket)
175{
176 struct pf_ruleset *ruleset;
177 struct pf_rule *rule;

--- 166 unchanged lines hidden (view full) ---

344}
345
346void
347pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
348{
349 struct pf_anchor *anchor;
350 int i;
351
352 if (ruleset == NULL || ruleset->anchor == NULL || ruleset->tables > 0 || ruleset->topen)
353 return;
354 for (i = 0; i < PF_RULESET_MAX; ++i)
355 if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
356 !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr))
357 return;
358
359 anchor = ruleset->anchor;
360 TAILQ_REMOVE(&anchor->rulesets, ruleset, entries);

--- 132 unchanged lines hidden (view full) ---

493 TAILQ_REMOVE(&pf_tags, p, entries);
494 free(p, M_TEMP);
495 }
496 break;
497 }
498 }
499}
500
501int
502pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
503{
504 struct pf_pooladdr *pa = NULL;
505 struct pf_pool *pool = NULL;
506 int s;
507 int error = 0;
508
509 /* XXX keep in sync with switch() below */
510 if (securelevel > 1)

--- 26 unchanged lines hidden (view full) ---

537 case DIOCRADDADDRS:
538 case DIOCRDELADDRS:
539 case DIOCRSETADDRS:
540 case DIOCRGETADDRS:
541 case DIOCRGETASTATS:
542 case DIOCRCLRASTATS:
543 case DIOCRTSTADDRS:
544 case DIOCOSFPGET:
545 break;
546 default:
547 return (EPERM);
548 }
549
550 if (!(flags & FWRITE))
551 switch (cmd) {
552 case DIOCGETRULES:

--- 13 unchanged lines hidden (view full) ---

566 case DIOCGETRULESETS:
567 case DIOCGETRULESET:
568 case DIOCRGETTABLES:
569 case DIOCRGETTSTATS:
570 case DIOCRGETADDRS:
571 case DIOCRGETASTATS:
572 case DIOCRTSTADDRS:
573 case DIOCOSFPGET:
574 break;
575 default:
576 return (EACCES);
577 }
578
579 switch (cmd) {
580
581 case DIOCSTART:
582 if (pf_status.running)
583 error = EEXIST;
584 else {
585 u_int32_t states = pf_status.states;
586 bzero(&pf_status, sizeof(struct pf_status));
587 pf_status.running = 1;
588 pf_status.states = states;
589 pf_status.since = time.tv_sec;
590 if (status_ifp != NULL)
591 strlcpy(pf_status.ifname,
592 status_ifp->if_xname, IFNAMSIZ);
593 DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
594 }
595 break;
596
597 case DIOCSTOP:
598 if (!pf_status.running)
599 error = ENOENT;
600 else {
601 pf_status.running = 0;
602 DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
603 }
604 break;
605
606 case DIOCBEGINRULES: {
607 struct pfioc_rule *pr = (struct pfioc_rule *)addr;
608 struct pf_ruleset *ruleset;
609 struct pf_rule *rule;

--- 493 unchanged lines hidden (view full) ---

1103 break;
1104 }
1105 s = splsoftnet();
1106 bcopy(&ps->state, state, sizeof(struct pf_state));
1107 state->rule.ptr = NULL;
1108 state->nat_rule.ptr = NULL;
1109 state->anchor.ptr = NULL;
1110 state->rt_ifp = NULL;
1111 state->creation = time.tv_sec;
1112 state->packets[0] = state->packets[1] = 0;
1113 state->bytes[0] = state->bytes[1] = 0;
1114 if (pf_insert_state(state)) {
1115 pool_put(&pf_state_pl, state);
1116 error = ENOMEM;
1117 }
1118 splx(s);
1119 break;

--- 19 unchanged lines hidden (view full) ---

1139 bcopy(n->state, &ps->state, sizeof(struct pf_state));
1140 ps->state.rule.nr = n->state->rule.ptr->nr;
1141 ps->state.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1142 -1 : n->state->nat_rule.ptr->nr;
1143 ps->state.anchor.nr = (n->state->anchor.ptr == NULL) ?
1144 -1 : n->state->anchor.ptr->nr;
1145 splx(s);
1146 ps->state.expire = pf_state_expires(n->state);
1147 if (ps->state.expire > time.tv_sec)
1148 ps->state.expire -= time.tv_sec;
1149 else
1150 ps->state.expire = 0;
1151 break;
1152 }
1153
1154 case DIOCGETSTATES: {
1155 struct pfioc_states *ps = (struct pfioc_states *)addr;
1156 struct pf_tree_node *n;
1157 struct pf_state *p, pstore;
1158 u_int32_t nr = 0;
1159 int space = ps->ps_len;
1160
1161 if (space == 0) {
1162 s = splsoftnet();
1163 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy)
1164 nr++;
1165 splx(s);
1166 ps->ps_len = sizeof(struct pf_state) * nr;
1167 return (0);
1168 }
1169
1170 s = splsoftnet();
1171 p = ps->ps_states;
1172 RB_FOREACH(n, pf_state_tree, &tree_ext_gwy) {
1173 int secs = time.tv_sec;
1174
1175 if ((nr + 1) * sizeof(*p) > (unsigned)ps->ps_len)
1176 break;
1177
1178 bcopy(n->state, &pstore, sizeof(pstore));
1179 pstore.rule.nr = n->state->rule.ptr->nr;
1180 pstore.nat_rule.nr = (n->state->nat_rule.ptr == NULL) ?
1181 -1 : n->state->nat_rule.ptr->nr;
1182 pstore.anchor.nr = (n->state->anchor.ptr == NULL) ?
1183 -1 : n->state->anchor.ptr->nr;
1184 pstore.creation = secs - pstore.creation;
1185 pstore.expire = pf_state_expires(n->state);
1186 if (pstore.expire > secs)
1187 pstore.expire -= secs;
1188 else
1189 pstore.expire = 0;
1190 error = copyout(&pstore, p, sizeof(*p));
1191 if (error) {
1192 splx(s);
1193 goto fail;
1194 }
1195 p++;
1196 nr++;
1197 }
1198 ps->ps_len = sizeof(struct pf_state) * nr;

--- 32 unchanged lines hidden (view full) ---

1231 u_int32_t debug = pf_status.debug;
1232
1233 bzero(&pf_status, sizeof(struct pf_status));
1234 pf_status.running = running;
1235 pf_status.states = states;
1236 pf_status.since = since;
1237 pf_status.debug = debug;
1238 if (status_ifp != NULL)
1239 strlcpy(pf_status.ifname,
1240 status_ifp->if_xname, IFNAMSIZ);
1241 break;
1242 }
1243
1244 case DIOCNATLOOK: {
1245 struct pfioc_natlook *pnl = (struct pfioc_natlook *)addr;
1246 struct pf_state *st;
1247 struct pf_tree_node key;
1248 int direction = pnl->direction;

--- 85 unchanged lines hidden (view full) ---

1334 case DIOCSETLIMIT: {
1335 struct pfioc_limit *pl = (struct pfioc_limit *)addr;
1336 int old_limit;
1337
1338 if (pl->index < 0 || pl->index >= PF_LIMIT_MAX) {
1339 error = EINVAL;
1340 goto fail;
1341 }
1342 if (pool_sethardlimit(pf_pool_limits[pl->index].pp,
1343 pl->limit, NULL, 0) != 0) {
1344 error = EBUSY;
1345 goto fail;
1346 }
1347 old_limit = pf_pool_limits[pl->index].limit;
1348 pf_pool_limits[pl->index].limit = pl->limit;
1349 pl->limit = old_limit;
1350 break;
1351 }
1352
1353 case DIOCSETDEBUG: {
1354 u_int32_t *level = (u_int32_t *)addr;

--- 10 unchanged lines hidden (view full) ---

1365 TAILQ_FOREACH(rule,
1366 ruleset->rules[PF_RULESET_FILTER].active.ptr, entries)
1367 rule->evaluations = rule->packets =
1368 rule->bytes = 0;
1369 splx(s);
1370 break;
1371 }
1372
1373#ifdef ALTQ
1374 case DIOCSTARTALTQ: {
1375 struct pf_altq *altq;
1376 struct ifnet *ifp;
1377 struct tb_profile tb;
1378
1379 /* enable all altq interfaces on active list */
1380 s = splsoftnet();

--- 10 unchanged lines hidden (view full) ---

1391 /* set tokenbucket regulator */
1392 tb.rate = altq->ifbandwidth;
1393 tb.depth = altq->tbrsize;
1394 error = tbr_set(&ifp->if_snd, &tb);
1395 if (error != 0)
1396 break;
1397 }
1398 }
1399 if (error == 0)
1400 pfaltq_running = 1;
1401 splx(s);
1402 DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
1403 break;
1404 }
1405
1406 case DIOCSTOPALTQ: {
1407 struct pf_altq *altq;
1408 struct ifnet *ifp;

--- 15 unchanged lines hidden (view full) ---

1424 }
1425 /* clear tokenbucket regulator */
1426 tb.rate = 0;
1427 err = tbr_set(&ifp->if_snd, &tb);
1428 if (err != 0 && error == 0)
1429 error = err;
1430 }
1431 }
1432 if (error == 0)
1433 pfaltq_running = 0;
1434 splx(s);
1435 DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
1436 break;
1437 }
1438
1439 case DIOCBEGINALTQS: {
1440 u_int32_t *ticket = (u_int32_t *)addr;
1441 struct pf_altq *altq;
1442
1443 /* Purge the old altq list */
1444 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1445 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1446 if (altq->qname[0] == 0) {
1447 /* detach and destroy the discipline */
1448 error = altq_remove(altq);
1449 }
1450 pool_put(&pf_altq_pl, altq);
1451 }
1452 *ticket = ++ticket_altqs_inactive;
1453 break;
1454 }
1455
1456 case DIOCADDALTQ: {

--- 20 unchanged lines hidden (view full) ---

1477 if (strncmp(a->ifname, altq->ifname,
1478 IFNAMSIZ) == 0 && a->qname[0] == 0) {
1479 altq->altq_disc = a->altq_disc;
1480 break;
1481 }
1482 }
1483 }
1484
1485 error = altq_add(altq);
1486 if (error) {
1487 pool_put(&pf_altq_pl, altq);
1488 break;
1489 }
1490
1491 TAILQ_INSERT_TAIL(pf_altqs_inactive, altq, entries);
1492 bcopy(altq, &pa->altq, sizeof(struct pf_altq));
1493 break;

--- 18 unchanged lines hidden (view full) ---

1512 pf_altqs_active = pf_altqs_inactive;
1513 pf_altqs_inactive = old_altqs;
1514 ticket_altqs_active = ticket_altqs_inactive;
1515
1516 /* Attach new disciplines */
1517 TAILQ_FOREACH(altq, pf_altqs_active, entries) {
1518 if (altq->qname[0] == 0) {
1519 /* attach the discipline */
1520 error = altq_pfattach(altq);
1521 if (error) {
1522 splx(s);
1523 goto fail;
1524 }
1525 }
1526 }
1527
1528 /* Purge the old altq list */
1529 while ((altq = TAILQ_FIRST(pf_altqs_inactive)) != NULL) {
1530 TAILQ_REMOVE(pf_altqs_inactive, altq, entries);
1531 if (altq->qname[0] == 0) {
1532 /* detach and destroy the discipline */
1533 err = altq_pfdetach(altq);
1534 if (err != 0 && error == 0)
1535 error = err;
1536 err = altq_remove(altq);
1537 if (err != 0 && error == 0)
1538 error = err;
1539 }
1540 pool_put(&pf_altq_pl, altq);
1541 }
1542 splx(s);
1543
1544 /* update queue IDs */
1545 pf_rule_set_qid(
1546 pf_main_ruleset.rules[PF_RULESET_FILTER].active.ptr);

--- 69 unchanged lines hidden (view full) ---

1616 altq = TAILQ_NEXT(altq, entries);
1617 nr++;
1618 }
1619 if (altq == NULL) {
1620 error = EBUSY;
1621 splx(s);
1622 break;
1623 }
1624 error = altq_getqstats(altq, pq->buf, &nbytes);
1625 splx(s);
1626 if (error == 0) {
1627 pq->scheduler = altq->scheduler;
1628 pq->nbytes = nbytes;
1629 }
1630 break;
1631 }
1632#endif /* ALTQ */

--- 515 unchanged lines hidden (view full) ---

2148 break;
2149 }
2150
2151 default:
2152 error = ENODEV;
2153 break;
2154 }
2155fail:
2156
2157 return (error);
2158}