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 */ |