Deleted Added
full compact
ip_fw_dynamic.c (261915) ip_fw_dynamic.c (272840)
1/*-
2 * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.

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

19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.

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

19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26#include <sys/cdefs.h>
27__FBSDID("$FreeBSD: head/sys/netpfil/ipfw/ip_fw_dynamic.c 261915 2014-02-15 12:25:01Z dim $");
27__FBSDID("$FreeBSD: head/sys/netpfil/ipfw/ip_fw_dynamic.c 272840 2014-10-09 19:32:35Z melifaro $");
28
29#define DEB(x)
30#define DDB(x) x
31
32/*
33 * Dynamic rule support for ipfw
34 */
35

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

42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/malloc.h>
46#include <sys/mbuf.h>
47#include <sys/kernel.h>
48#include <sys/ktr.h>
49#include <sys/lock.h>
28
29#define DEB(x)
30#define DDB(x) x
31
32/*
33 * Dynamic rule support for ipfw
34 */
35

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

42
43#include <sys/param.h>
44#include <sys/systm.h>
45#include <sys/malloc.h>
46#include <sys/mbuf.h>
47#include <sys/kernel.h>
48#include <sys/ktr.h>
49#include <sys/lock.h>
50#include <sys/rmlock.h>
50#include <sys/socket.h>
51#include <sys/sysctl.h>
52#include <sys/syslog.h>
53#include <net/ethernet.h> /* for ETHERTYPE_IP */
54#include <net/if.h>
55#include <net/if_var.h>
56#include <net/vnet.h>
57

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

191
192#ifdef USERSPACE /* emulation of UMA object counters for userspace */
193#define uma_zone_get_cur(x) ipfw_dyn_count
194#endif /* USERSPACE */
195
196static int last_log; /* Log ratelimiting */
197
198static void ipfw_dyn_tick(void *vnetx);
51#include <sys/socket.h>
52#include <sys/sysctl.h>
53#include <sys/syslog.h>
54#include <net/ethernet.h> /* for ETHERTYPE_IP */
55#include <net/if.h>
56#include <net/if_var.h>
57#include <net/vnet.h>
58

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

192
193#ifdef USERSPACE /* emulation of UMA object counters for userspace */
194#define uma_zone_get_cur(x) ipfw_dyn_count
195#endif /* USERSPACE */
196
197static int last_log; /* Log ratelimiting */
198
199static void ipfw_dyn_tick(void *vnetx);
199static void check_dyn_rules(struct ip_fw_chain *, struct ip_fw *,
200 int, int, int);
200static void check_dyn_rules(struct ip_fw_chain *, ipfw_range_tlv *, int, int);
201#ifdef SYSCTL_NODE
202
203static int sysctl_ipfw_dyn_count(SYSCTL_HANDLER_ARGS);
204static int sysctl_ipfw_dyn_max(SYSCTL_HANDLER_ARGS);
205
206SYSBEGIN(f2)
207
208SYSCTL_DECL(_net_inet_ip_fw);

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

668
669/**
670 * Install dynamic state for rule type cmd->o.opcode
671 *
672 * Returns 1 (failure) if state is not installed because of errors or because
673 * session limitations are enforced.
674 */
675int
201#ifdef SYSCTL_NODE
202
203static int sysctl_ipfw_dyn_count(SYSCTL_HANDLER_ARGS);
204static int sysctl_ipfw_dyn_max(SYSCTL_HANDLER_ARGS);
205
206SYSBEGIN(f2)
207
208SYSCTL_DECL(_net_inet_ip_fw);

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

668
669/**
670 * Install dynamic state for rule type cmd->o.opcode
671 *
672 * Returns 1 (failure) if state is not installed because of errors or because
673 * session limitations are enforced.
674 */
675int
676ipfw_install_state(struct ip_fw *rule, ipfw_insn_limit *cmd,
677 struct ip_fw_args *args, uint32_t tablearg)
676ipfw_install_state(struct ip_fw_chain *chain, struct ip_fw *rule,
677 ipfw_insn_limit *cmd, struct ip_fw_args *args, uint32_t tablearg)
678{
679 ipfw_dyn_rule *q;
680 int i;
681
682 DEB(print_dyn_rule(&args->f_id, cmd->o.opcode, "install_state", "");)
683
684 i = hash_packet(&args->f_id, V_curr_dyn_buckets);
685

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

712
713 case O_LIMIT: { /* limit number of sessions */
714 struct ipfw_flow_id id;
715 ipfw_dyn_rule *parent;
716 uint32_t conn_limit;
717 uint16_t limit_mask = cmd->limit_mask;
718 int pindex;
719
678{
679 ipfw_dyn_rule *q;
680 int i;
681
682 DEB(print_dyn_rule(&args->f_id, cmd->o.opcode, "install_state", "");)
683
684 i = hash_packet(&args->f_id, V_curr_dyn_buckets);
685

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

712
713 case O_LIMIT: { /* limit number of sessions */
714 struct ipfw_flow_id id;
715 ipfw_dyn_rule *parent;
716 uint32_t conn_limit;
717 uint16_t limit_mask = cmd->limit_mask;
718 int pindex;
719
720 conn_limit = IP_FW_ARG_TABLEARG(cmd->conn_limit);
720 conn_limit = IP_FW_ARG_TABLEARG(chain, cmd->conn_limit, limit);
721
722 DEB(
721
722 DEB(
723 if (cmd->conn_limit == IP_FW_TABLEARG)
723 if (cmd->conn_limit == IP_FW_TARG)
724 printf("ipfw: %s: O_LIMIT rule, conn_limit: %u "
725 "(tablearg)\n", __func__, conn_limit);
726 else
727 printf("ipfw: %s: O_LIMIT rule, conn_limit: %u\n",
728 __func__, conn_limit);
729 )
730
731 id.dst_ip = id.src_ip = id.dst_port = id.src_port = 0;

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

1003
1004 /* Run keepalive checks every keepalive_period iff ka is enabled */
1005 if ((V_dyn_keepalive_last + V_dyn_keepalive_period <= time_uptime) &&
1006 (V_dyn_keepalive != 0)) {
1007 V_dyn_keepalive_last = time_uptime;
1008 check_ka = 1;
1009 }
1010
724 printf("ipfw: %s: O_LIMIT rule, conn_limit: %u "
725 "(tablearg)\n", __func__, conn_limit);
726 else
727 printf("ipfw: %s: O_LIMIT rule, conn_limit: %u\n",
728 __func__, conn_limit);
729 )
730
731 id.dst_ip = id.src_ip = id.dst_port = id.src_port = 0;

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

1003
1004 /* Run keepalive checks every keepalive_period iff ka is enabled */
1005 if ((V_dyn_keepalive_last + V_dyn_keepalive_period <= time_uptime) &&
1006 (V_dyn_keepalive != 0)) {
1007 V_dyn_keepalive_last = time_uptime;
1008 check_ka = 1;
1009 }
1010
1011 check_dyn_rules(chain, NULL, RESVD_SET, check_ka, 1);
1011 check_dyn_rules(chain, NULL, check_ka, 1);
1012
1013 callout_reset_on(&V_ipfw_timeout, hz, ipfw_dyn_tick, vnetx, 0);
1014
1015 CURVNET_RESTORE();
1016}
1017
1018
1019/*

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

1035 * Additionally, function assume that dynamic rule/set is
1036 * ALREADY deleted so no new states can be generated by
1037 * 'deleted' rules.
1038 *
1039 * Write lock is needed to ensure that unused parent rules
1040 * are not freed by other instance (see stage 2, 3)
1041 */
1042static void
1012
1013 callout_reset_on(&V_ipfw_timeout, hz, ipfw_dyn_tick, vnetx, 0);
1014
1015 CURVNET_RESTORE();
1016}
1017
1018
1019/*

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

1035 * Additionally, function assume that dynamic rule/set is
1036 * ALREADY deleted so no new states can be generated by
1037 * 'deleted' rules.
1038 *
1039 * Write lock is needed to ensure that unused parent rules
1040 * are not freed by other instance (see stage 2, 3)
1041 */
1042static void
1043check_dyn_rules(struct ip_fw_chain *chain, struct ip_fw *rule,
1044 int set, int check_ka, int timer)
1043check_dyn_rules(struct ip_fw_chain *chain, ipfw_range_tlv *rt,
1044 int check_ka, int timer)
1045{
1046 struct mbuf *m0, *m, *mnext, **mtailp;
1047 struct ip *h;
1048 int i, dyn_count, new_buckets = 0, max_buckets;
1049 int expired = 0, expired_limits = 0, parents = 0, total = 0;
1050 ipfw_dyn_rule *q, *q_prev, *q_next;
1051 ipfw_dyn_rule *exp_head, **exptailp;
1052 ipfw_dyn_rule *exp_lhead, **expltailp;

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

1100 if (q->dyn_type == O_LIMIT_PARENT) {
1101 parents++;
1102 NEXT_RULE();
1103 }
1104
1105 /*
1106 * Remove rules which are:
1107 * 1) expired
1045{
1046 struct mbuf *m0, *m, *mnext, **mtailp;
1047 struct ip *h;
1048 int i, dyn_count, new_buckets = 0, max_buckets;
1049 int expired = 0, expired_limits = 0, parents = 0, total = 0;
1050 ipfw_dyn_rule *q, *q_prev, *q_next;
1051 ipfw_dyn_rule *exp_head, **exptailp;
1052 ipfw_dyn_rule *exp_lhead, **expltailp;

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

1100 if (q->dyn_type == O_LIMIT_PARENT) {
1101 parents++;
1102 NEXT_RULE();
1103 }
1104
1105 /*
1106 * Remove rules which are:
1107 * 1) expired
1108 * 2) created by given rule
1109 * 3) created by any rule in given set
1108 * 2) matches deletion range
1110 */
1111 if ((TIME_LEQ(q->expire, time_uptime)) ||
1109 */
1110 if ((TIME_LEQ(q->expire, time_uptime)) ||
1112 ((rule != NULL) && (q->rule == rule)) ||
1113 ((set != RESVD_SET) && (q->rule->set == set))) {
1111 (rt != NULL && ipfw_match_range(q->rule, rt))) {
1114 if (TIME_LE(time_uptime, q->expire) &&
1115 q->dyn_type == O_KEEP_STATE &&
1116 V_dyn_keep_states != 0) {
1117 /*
1118 * Do not delete state if
1119 * it is not expired and
1120 * dyn_keep_states is ON.
1121 * However we need to re-link it

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

1319 if (new_buckets != 0)
1320 resize_dynamic_table(chain, new_buckets);
1321}
1322
1323/*
1324 * Deletes all dynamic rules originated by given rule or all rules in
1325 * given set. Specify RESVD_SET to indicate set should not be used.
1326 * @chain - pointer to current ipfw rules chain
1112 if (TIME_LE(time_uptime, q->expire) &&
1113 q->dyn_type == O_KEEP_STATE &&
1114 V_dyn_keep_states != 0) {
1115 /*
1116 * Do not delete state if
1117 * it is not expired and
1118 * dyn_keep_states is ON.
1119 * However we need to re-link it

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

1317 if (new_buckets != 0)
1318 resize_dynamic_table(chain, new_buckets);
1319}
1320
1321/*
1322 * Deletes all dynamic rules originated by given rule or all rules in
1323 * given set. Specify RESVD_SET to indicate set should not be used.
1324 * @chain - pointer to current ipfw rules chain
1327 * @rule - delete all states originated by given rule if != NULL
1328 * @set - delete all states originated by any rule in set @set if != RESVD_SET
1325 * @rr - delete all states originated by rules in matched range.
1329 *
1330 * Function has to be called with IPFW_UH_WLOCK held.
1331 * Additionally, function assume that dynamic rule/set is
1332 * ALREADY deleted so no new states can be generated by
1333 * 'deleted' rules.
1334 */
1335void
1326 *
1327 * Function has to be called with IPFW_UH_WLOCK held.
1328 * Additionally, function assume that dynamic rule/set is
1329 * ALREADY deleted so no new states can be generated by
1330 * 'deleted' rules.
1331 */
1332void
1336ipfw_expire_dyn_rules(struct ip_fw_chain *chain, struct ip_fw *rule, int set)
1333ipfw_expire_dyn_rules(struct ip_fw_chain *chain, ipfw_range_tlv *rt)
1337{
1338
1334{
1335
1339 check_dyn_rules(chain, rule, set, 0, 0);
1336 check_dyn_rules(chain, rt, 0, 0);
1340}
1341
1337}
1338
1339/*
1340 * Check if rule contains at least one dynamic opcode.
1341 *
1342 * Returns 1 if such opcode is found, 0 otherwise.
1343 */
1344int
1345ipfw_is_dyn_rule(struct ip_fw *rule)
1346{
1347 int cmdlen, l;
1348 ipfw_insn *cmd;
1349
1350 l = rule->cmd_len;
1351 cmd = rule->cmd;
1352 cmdlen = 0;
1353 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) {
1354 cmdlen = F_LEN(cmd);
1355
1356 switch (cmd->opcode) {
1357 case O_LIMIT:
1358 case O_KEEP_STATE:
1359 case O_PROBE_STATE:
1360 case O_CHECK_STATE:
1361 return (1);
1362 }
1363 }
1364
1365 return (0);
1366}
1367
1342void
1343ipfw_dyn_init(struct ip_fw_chain *chain)
1344{
1345
1346 V_ipfw_dyn_v = NULL;
1347 V_dyn_buckets_max = 256; /* must be power of 2 */
1348 V_curr_dyn_buckets = 256; /* must be power of 2 */
1349

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

1439
1440 error = sysctl_handle_int(oidp, &nstates, 0, req);
1441
1442 return (error);
1443}
1444#endif
1445
1446/*
1368void
1369ipfw_dyn_init(struct ip_fw_chain *chain)
1370{
1371
1372 V_ipfw_dyn_v = NULL;
1373 V_dyn_buckets_max = 256; /* must be power of 2 */
1374 V_curr_dyn_buckets = 256; /* must be power of 2 */
1375

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

1465
1466 error = sysctl_handle_int(oidp, &nstates, 0, req);
1467
1468 return (error);
1469}
1470#endif
1471
1472/*
1447 * Returns number of dynamic rules.
1473 * Returns size of dynamic states in legacy format
1448 */
1449int
1450ipfw_dyn_len(void)
1451{
1452
1453 return (V_ipfw_dyn_v == NULL) ? 0 :
1454 (DYN_COUNT * sizeof(ipfw_dyn_rule));
1455}
1456
1457/*
1474 */
1475int
1476ipfw_dyn_len(void)
1477{
1478
1479 return (V_ipfw_dyn_v == NULL) ? 0 :
1480 (DYN_COUNT * sizeof(ipfw_dyn_rule));
1481}
1482
1483/*
1458 * Fill given buffer with dynamic states.
1484 * Returns number of dynamic states.
1485 * Used by dump format v1 (current).
1486 */
1487int
1488ipfw_dyn_get_count(void)
1489{
1490
1491 return (V_ipfw_dyn_v == NULL) ? 0 : DYN_COUNT;
1492}
1493
1494static void
1495export_dyn_rule(ipfw_dyn_rule *src, ipfw_dyn_rule *dst)
1496{
1497
1498 memcpy(dst, src, sizeof(*src));
1499 memcpy(&(dst->rule), &(src->rule->rulenum), sizeof(src->rule->rulenum));
1500 /*
1501 * store set number into high word of
1502 * dst->rule pointer.
1503 */
1504 memcpy((char *)&dst->rule + sizeof(src->rule->rulenum),
1505 &(src->rule->set), sizeof(src->rule->set));
1506 /*
1507 * store a non-null value in "next".
1508 * The userland code will interpret a
1509 * NULL here as a marker
1510 * for the last dynamic rule.
1511 */
1512 memcpy(&dst->next, &dst, sizeof(dst));
1513 dst->expire =
1514 TIME_LEQ(dst->expire, time_uptime) ? 0 : dst->expire - time_uptime;
1515}
1516
1517/*
1518 * Fills int buffer given by @sd with dynamic states.
1519 * Used by dump format v1 (current).
1520 *
1521 * Returns 0 on success.
1522 */
1523int
1524ipfw_dump_states(struct ip_fw_chain *chain, struct sockopt_data *sd)
1525{
1526 ipfw_dyn_rule *p;
1527 ipfw_obj_dyntlv *dst, *last;
1528 ipfw_obj_ctlv *ctlv;
1529 int i;
1530 size_t sz;
1531
1532 if (V_ipfw_dyn_v == NULL)
1533 return (0);
1534
1535 IPFW_UH_RLOCK_ASSERT(chain);
1536
1537 ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv));
1538 if (ctlv == NULL)
1539 return (ENOMEM);
1540 sz = sizeof(ipfw_obj_dyntlv);
1541 ctlv->head.type = IPFW_TLV_DYNSTATE_LIST;
1542 ctlv->objsize = sz;
1543 last = NULL;
1544
1545 for (i = 0 ; i < V_curr_dyn_buckets; i++) {
1546 IPFW_BUCK_LOCK(i);
1547 for (p = V_ipfw_dyn_v[i].head ; p != NULL; p = p->next) {
1548 dst = (ipfw_obj_dyntlv *)ipfw_get_sopt_space(sd, sz);
1549 if (dst == NULL) {
1550 IPFW_BUCK_UNLOCK(i);
1551 return (ENOMEM);
1552 }
1553
1554 export_dyn_rule(p, &dst->state);
1555 dst->head.length = sz;
1556 dst->head.type = IPFW_TLV_DYN_ENT;
1557 last = dst;
1558 }
1559 IPFW_BUCK_UNLOCK(i);
1560 }
1561
1562 if (last != NULL) /* mark last dynamic rule */
1563 last->head.flags = IPFW_DF_LAST;
1564
1565 return (0);
1566}
1567
1568/*
1569 * Fill given buffer with dynamic states (legacy format).
1459 * IPFW_UH_RLOCK has to be held while calling.
1460 */
1461void
1462ipfw_get_dynamic(struct ip_fw_chain *chain, char **pbp, const char *ep)
1463{
1464 ipfw_dyn_rule *p, *last = NULL;
1465 char *bp;
1466 int i;

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

1472 IPFW_UH_RLOCK_ASSERT(chain);
1473
1474 for (i = 0 ; i < V_curr_dyn_buckets; i++) {
1475 IPFW_BUCK_LOCK(i);
1476 for (p = V_ipfw_dyn_v[i].head ; p != NULL; p = p->next) {
1477 if (bp + sizeof *p <= ep) {
1478 ipfw_dyn_rule *dst =
1479 (ipfw_dyn_rule *)bp;
1570 * IPFW_UH_RLOCK has to be held while calling.
1571 */
1572void
1573ipfw_get_dynamic(struct ip_fw_chain *chain, char **pbp, const char *ep)
1574{
1575 ipfw_dyn_rule *p, *last = NULL;
1576 char *bp;
1577 int i;

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

1583 IPFW_UH_RLOCK_ASSERT(chain);
1584
1585 for (i = 0 ; i < V_curr_dyn_buckets; i++) {
1586 IPFW_BUCK_LOCK(i);
1587 for (p = V_ipfw_dyn_v[i].head ; p != NULL; p = p->next) {
1588 if (bp + sizeof *p <= ep) {
1589 ipfw_dyn_rule *dst =
1590 (ipfw_dyn_rule *)bp;
1480 bcopy(p, dst, sizeof *p);
1481 bcopy(&(p->rule->rulenum), &(dst->rule),
1482 sizeof(p->rule->rulenum));
1483 /*
1484 * store set number into high word of
1485 * dst->rule pointer.
1486 */
1487 bcopy(&(p->rule->set),
1488 (char *)&dst->rule +
1489 sizeof(p->rule->rulenum),
1490 sizeof(p->rule->set));
1491 /*
1492 * store a non-null value in "next".
1493 * The userland code will interpret a
1494 * NULL here as a marker
1495 * for the last dynamic rule.
1496 */
1497 bcopy(&dst, &dst->next, sizeof(dst));
1591
1592 export_dyn_rule(p, dst);
1498 last = dst;
1593 last = dst;
1499 dst->expire =
1500 TIME_LEQ(dst->expire, time_uptime) ?
1501 0 : dst->expire - time_uptime ;
1502 bp += sizeof(ipfw_dyn_rule);
1503 }
1504 }
1505 IPFW_BUCK_UNLOCK(i);
1506 }
1507
1508 if (last != NULL) /* mark last dynamic rule */
1509 bzero(&last->next, sizeof(last));
1510 *pbp = bp;
1511}
1512/* end of file */
1594 bp += sizeof(ipfw_dyn_rule);
1595 }
1596 }
1597 IPFW_BUCK_UNLOCK(i);
1598 }
1599
1600 if (last != NULL) /* mark last dynamic rule */
1601 bzero(&last->next, sizeof(last));
1602 *pbp = bp;
1603}
1604/* end of file */