pf.c (285830) | pf.c (286014) |
---|---|
1/*- 2 * Copyright (c) 2001 Daniel Hartmeier 3 * Copyright (c) 2002 - 2008 Henning Brauer 4 * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org> 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 --- 22 unchanged lines hidden (view full) --- 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 * $OpenBSD: pf.c,v 1.634 2009/02/27 12:37:45 henning Exp $ 36 */ 37 38#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 2001 Daniel Hartmeier 3 * Copyright (c) 2002 - 2008 Henning Brauer 4 * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org> 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 --- 22 unchanged lines hidden (view full) --- 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 * $OpenBSD: pf.c,v 1.634 2009/02/27 12:37:45 henning Exp $ 36 */ 37 38#include <sys/cdefs.h> |
39__FBSDID("$FreeBSD: releng/10.2/sys/netpfil/pf/pf.c 284577 2015-06-18 20:59:48Z kp $"); | 39__FBSDID("$FreeBSD: releng/10.2/sys/netpfil/pf/pf.c 286014 2015-07-29 14:16:25Z glebius $"); |
40 41#include "opt_inet.h" 42#include "opt_inet6.h" 43#include "opt_bpf.h" 44#include "opt_pf.h" 45 46#include <sys/param.h> 47#include <sys/bus.h> --- 602 unchanged lines hidden (view full) --- 650 651 sh = &V_pf_srchash[pf_hashsrc(src, af)]; 652 PF_HASHROW_LOCK(sh); 653 LIST_FOREACH(n, &sh->nodes, entry) 654 if (n->rule.ptr == rule && n->af == af && 655 ((af == AF_INET && n->addr.v4.s_addr == src->v4.s_addr) || 656 (af == AF_INET6 && bcmp(&n->addr, src, sizeof(*src)) == 0))) 657 break; | 40 41#include "opt_inet.h" 42#include "opt_inet6.h" 43#include "opt_bpf.h" 44#include "opt_pf.h" 45 46#include <sys/param.h> 47#include <sys/bus.h> --- 602 unchanged lines hidden (view full) --- 650 651 sh = &V_pf_srchash[pf_hashsrc(src, af)]; 652 PF_HASHROW_LOCK(sh); 653 LIST_FOREACH(n, &sh->nodes, entry) 654 if (n->rule.ptr == rule && n->af == af && 655 ((af == AF_INET && n->addr.v4.s_addr == src->v4.s_addr) || 656 (af == AF_INET6 && bcmp(&n->addr, src, sizeof(*src)) == 0))) 657 break; |
658 if (n != NULL || returnlocked == 0) | 658 if (n != NULL) { 659 n->states++; |
659 PF_HASHROW_UNLOCK(sh); | 660 PF_HASHROW_UNLOCK(sh); |
661 } else if (returnlocked == 0) 662 PF_HASHROW_UNLOCK(sh); |
|
660 661 return (n); 662} 663 664static int 665pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, 666 struct pf_addr *src, sa_family_t af) 667{ --- 26 unchanged lines hidden (view full) --- 694 rule->max_src_conn_rate.seconds); 695 696 (*sn)->af = af; 697 (*sn)->rule.ptr = rule; 698 PF_ACPY(&(*sn)->addr, src, af); 699 LIST_INSERT_HEAD(&sh->nodes, *sn, entry); 700 (*sn)->creation = time_uptime; 701 (*sn)->ruletype = rule->action; | 663 664 return (n); 665} 666 667static int 668pf_insert_src_node(struct pf_src_node **sn, struct pf_rule *rule, 669 struct pf_addr *src, sa_family_t af) 670{ --- 26 unchanged lines hidden (view full) --- 697 rule->max_src_conn_rate.seconds); 698 699 (*sn)->af = af; 700 (*sn)->rule.ptr = rule; 701 PF_ACPY(&(*sn)->addr, src, af); 702 LIST_INSERT_HEAD(&sh->nodes, *sn, entry); 703 (*sn)->creation = time_uptime; 704 (*sn)->ruletype = rule->action; |
705 (*sn)->states = 1; |
|
702 if ((*sn)->rule.ptr != NULL) 703 counter_u64_add((*sn)->rule.ptr->src_nodes, 1); 704 PF_HASHROW_UNLOCK(sh); 705 counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_INSERT], 1); 706 } else { 707 if (rule->max_src_states && 708 (*sn)->states >= rule->max_src_states) { 709 counter_u64_add(V_pf_status.lcounters[LCNT_SRCSTATES], 710 1); 711 return (-1); 712 } 713 } 714 return (0); 715} 716 717void | 706 if ((*sn)->rule.ptr != NULL) 707 counter_u64_add((*sn)->rule.ptr->src_nodes, 1); 708 PF_HASHROW_UNLOCK(sh); 709 counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_INSERT], 1); 710 } else { 711 if (rule->max_src_states && 712 (*sn)->states >= rule->max_src_states) { 713 counter_u64_add(V_pf_status.lcounters[LCNT_SRCSTATES], 714 1); 715 return (-1); 716 } 717 } 718 return (0); 719} 720 721void |
718pf_unlink_src_node_locked(struct pf_src_node *src) | 722pf_unlink_src_node(struct pf_src_node *src) |
719{ | 723{ |
720#ifdef INVARIANTS 721 struct pf_srchash *sh; | |
722 | 724 |
723 sh = &V_pf_srchash[pf_hashsrc(&src->addr, src->af)]; 724 PF_HASHROW_ASSERT(sh); 725#endif | 725 PF_HASHROW_ASSERT(&V_pf_srchash[pf_hashsrc(&src->addr, src->af)]); |
726 LIST_REMOVE(src, entry); 727 if (src->rule.ptr) 728 counter_u64_add(src->rule.ptr->src_nodes, -1); | 726 LIST_REMOVE(src, entry); 727 if (src->rule.ptr) 728 counter_u64_add(src->rule.ptr->src_nodes, -1); |
729 counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], 1); | |
730} 731 | 729} 730 |
732void 733pf_unlink_src_node(struct pf_src_node *src) 734{ 735 struct pf_srchash *sh; 736 737 sh = &V_pf_srchash[pf_hashsrc(&src->addr, src->af)]; 738 PF_HASHROW_LOCK(sh); 739 pf_unlink_src_node_locked(src); 740 PF_HASHROW_UNLOCK(sh); 741} 742 743static void 744pf_free_src_node(struct pf_src_node *sn) 745{ 746 747 KASSERT(sn->states == 0, ("%s: %p has refs", __func__, sn)); 748 uma_zfree(V_pf_sources_z, sn); 749} 750 | |
751u_int 752pf_free_src_nodes(struct pf_src_node_list *head) 753{ 754 struct pf_src_node *sn, *tmp; 755 u_int count = 0; 756 757 LIST_FOREACH_SAFE(sn, head, entry, tmp) { | 731u_int 732pf_free_src_nodes(struct pf_src_node_list *head) 733{ 734 struct pf_src_node *sn, *tmp; 735 u_int count = 0; 736 737 LIST_FOREACH_SAFE(sn, head, entry, tmp) { |
758 pf_free_src_node(sn); | 738 uma_zfree(V_pf_sources_z, sn); |
759 count++; 760 } 761 | 739 count++; 740 } 741 |
742 counter_u64_add(V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], count); 743 |
|
762 return (count); 763} 764 765void 766pf_mtag_initialize() 767{ 768 769 pf_mtag_z = uma_zcreate("pf mtags", sizeof(struct m_tag) + --- 775 unchanged lines hidden (view full) --- 1545 struct pf_src_node *cur, *next; 1546 int i; 1547 1548 LIST_INIT(&freelist); 1549 for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask; i++, sh++) { 1550 PF_HASHROW_LOCK(sh); 1551 LIST_FOREACH_SAFE(cur, &sh->nodes, entry, next) 1552 if (cur->states == 0 && cur->expire <= time_uptime) { | 744 return (count); 745} 746 747void 748pf_mtag_initialize() 749{ 750 751 pf_mtag_z = uma_zcreate("pf mtags", sizeof(struct m_tag) + --- 775 unchanged lines hidden (view full) --- 1527 struct pf_src_node *cur, *next; 1528 int i; 1529 1530 LIST_INIT(&freelist); 1531 for (i = 0, sh = V_pf_srchash; i <= pf_srchashmask; i++, sh++) { 1532 PF_HASHROW_LOCK(sh); 1533 LIST_FOREACH_SAFE(cur, &sh->nodes, entry, next) 1534 if (cur->states == 0 && cur->expire <= time_uptime) { |
1553 pf_unlink_src_node_locked(cur); | 1535 pf_unlink_src_node(cur); |
1554 LIST_INSERT_HEAD(&freelist, cur, entry); 1555 } else if (cur->rule.ptr != NULL) 1556 cur->rule.ptr->rule_flag |= PFRULE_REFS; 1557 PF_HASHROW_UNLOCK(sh); 1558 } 1559 1560 pf_free_src_nodes(&freelist); 1561 1562 V_pf_status.src_nodes = uma_zone_get_cur(V_pf_sources_z); 1563} 1564 1565static void 1566pf_src_tree_remove_state(struct pf_state *s) 1567{ | 1536 LIST_INSERT_HEAD(&freelist, cur, entry); 1537 } else if (cur->rule.ptr != NULL) 1538 cur->rule.ptr->rule_flag |= PFRULE_REFS; 1539 PF_HASHROW_UNLOCK(sh); 1540 } 1541 1542 pf_free_src_nodes(&freelist); 1543 1544 V_pf_status.src_nodes = uma_zone_get_cur(V_pf_sources_z); 1545} 1546 1547static void 1548pf_src_tree_remove_state(struct pf_state *s) 1549{ |
1568 u_int32_t timeout; | 1550 struct pf_src_node *sn; 1551 struct pf_srchash *sh; 1552 uint32_t timeout; |
1569 | 1553 |
1554 timeout = s->rule.ptr->timeout[PFTM_SRC_NODE] ? 1555 s->rule.ptr->timeout[PFTM_SRC_NODE] : 1556 V_pf_default_rule.timeout[PFTM_SRC_NODE]; 1557 |
|
1570 if (s->src_node != NULL) { | 1558 if (s->src_node != NULL) { |
1559 sn = s->src_node; 1560 sh = &V_pf_srchash[pf_hashsrc(&sn->addr, sn->af)]; 1561 PF_HASHROW_LOCK(sh); |
|
1571 if (s->src.tcp_est) | 1562 if (s->src.tcp_est) |
1572 --s->src_node->conn; 1573 if (--s->src_node->states == 0) { 1574 timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; 1575 if (!timeout) 1576 timeout = 1577 V_pf_default_rule.timeout[PFTM_SRC_NODE]; 1578 s->src_node->expire = time_uptime + timeout; 1579 } | 1563 --sn->conn; 1564 if (--sn->states == 0) 1565 sn->expire = time_uptime + timeout; 1566 PF_HASHROW_UNLOCK(sh); |
1580 } 1581 if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) { | 1567 } 1568 if (s->nat_src_node != s->src_node && s->nat_src_node != NULL) { |
1582 if (--s->nat_src_node->states == 0) { 1583 timeout = s->rule.ptr->timeout[PFTM_SRC_NODE]; 1584 if (!timeout) 1585 timeout = 1586 V_pf_default_rule.timeout[PFTM_SRC_NODE]; 1587 s->nat_src_node->expire = time_uptime + timeout; 1588 } | 1569 sn = s->nat_src_node; 1570 sh = &V_pf_srchash[pf_hashsrc(&sn->addr, sn->af)]; 1571 PF_HASHROW_LOCK(sh); 1572 if (--sn->states == 0) 1573 sn->expire = time_uptime + timeout; 1574 PF_HASHROW_UNLOCK(sh); |
1589 } 1590 s->src_node = s->nat_src_node = NULL; 1591} 1592 1593/* 1594 * Unlink and potentilly free a state. Function may be 1595 * called with ID hash row locked, but always returns 1596 * unlocked, since it needs to go through key hash locking. --- 1969 unchanged lines hidden (view full) --- 3566 goto csfailed; 3567 } 3568 s->rt_kif = r->rpool.cur->kif; 3569 } 3570 3571 s->creation = time_uptime; 3572 s->expire = time_uptime; 3573 | 1575 } 1576 s->src_node = s->nat_src_node = NULL; 1577} 1578 1579/* 1580 * Unlink and potentilly free a state. Function may be 1581 * called with ID hash row locked, but always returns 1582 * unlocked, since it needs to go through key hash locking. --- 1969 unchanged lines hidden (view full) --- 3552 goto csfailed; 3553 } 3554 s->rt_kif = r->rpool.cur->kif; 3555 } 3556 3557 s->creation = time_uptime; 3558 s->expire = time_uptime; 3559 |
3574 if (sn != NULL) { | 3560 if (sn != NULL) |
3575 s->src_node = sn; | 3561 s->src_node = sn; |
3576 s->src_node->states++; 3577 } | |
3578 if (nsn != NULL) { 3579 /* XXX We only modify one side for now. */ 3580 PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); 3581 s->nat_src_node = nsn; | 3562 if (nsn != NULL) { 3563 /* XXX We only modify one side for now. */ 3564 PF_ACPY(&nsn->raddr, &nk->addr[1], pd->af); 3565 s->nat_src_node = nsn; |
3582 s->nat_src_node->states++; | |
3583 } 3584 if (pd->proto == IPPROTO_TCP) { 3585 if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m, 3586 off, pd, th, &s->src, &s->dst)) { 3587 REASON_SET(&reason, PFRES_MEMORY); 3588 pf_src_tree_remove_state(s); 3589 STATE_DEC_COUNTERS(s); 3590 uma_zfree(V_pf_state_z, s); --- 81 unchanged lines hidden (view full) --- 3672 return (PF_PASS); 3673 3674csfailed: 3675 if (sk != NULL) 3676 uma_zfree(V_pf_state_key_z, sk); 3677 if (nk != NULL) 3678 uma_zfree(V_pf_state_key_z, nk); 3679 | 3566 } 3567 if (pd->proto == IPPROTO_TCP) { 3568 if ((pd->flags & PFDESC_TCP_NORM) && pf_normalize_tcp_init(m, 3569 off, pd, th, &s->src, &s->dst)) { 3570 REASON_SET(&reason, PFRES_MEMORY); 3571 pf_src_tree_remove_state(s); 3572 STATE_DEC_COUNTERS(s); 3573 uma_zfree(V_pf_state_z, s); --- 81 unchanged lines hidden (view full) --- 3655 return (PF_PASS); 3656 3657csfailed: 3658 if (sk != NULL) 3659 uma_zfree(V_pf_state_key_z, sk); 3660 if (nk != NULL) 3661 uma_zfree(V_pf_state_key_z, nk); 3662 |
3680 if (sn != NULL && sn->states == 0 && sn->expire == 0) { 3681 pf_unlink_src_node(sn); 3682 pf_free_src_node(sn); | 3663 if (sn != NULL) { 3664 struct pf_srchash *sh; 3665 3666 sh = &V_pf_srchash[pf_hashsrc(&sn->addr, sn->af)]; 3667 PF_HASHROW_LOCK(sh); 3668 if (--sn->states == 0 && sn->expire == 0) { 3669 pf_unlink_src_node(sn); 3670 uma_zfree(V_pf_sources_z, sn); 3671 counter_u64_add( 3672 V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], 1); 3673 } 3674 PF_HASHROW_UNLOCK(sh); |
3683 } 3684 | 3675 } 3676 |
3685 if (nsn != sn && nsn != NULL && nsn->states == 0 && nsn->expire == 0) { 3686 pf_unlink_src_node(nsn); 3687 pf_free_src_node(nsn); | 3677 if (nsn != sn && nsn != NULL) { 3678 struct pf_srchash *sh; 3679 3680 sh = &V_pf_srchash[pf_hashsrc(&nsn->addr, nsn->af)]; 3681 PF_HASHROW_LOCK(sh); 3682 if (--nsn->states == 0 && nsn->expire == 0) { 3683 pf_unlink_src_node(nsn); 3684 uma_zfree(V_pf_sources_z, nsn); 3685 counter_u64_add( 3686 V_pf_status.scounters[SCNT_SRC_NODE_REMOVALS], 1); 3687 } 3688 PF_HASHROW_UNLOCK(sh); |
3688 } 3689 3690 return (PF_DROP); 3691} 3692 3693static int 3694pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, 3695 struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am, --- 2210 unchanged lines hidden (view full) --- 5906 M_SETFIB(m, r->rtableid); 5907 5908#ifdef ALTQ 5909 if (action == PF_PASS && r->qid) { 5910 if (pd.pf_mtag == NULL && 5911 ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { 5912 action = PF_DROP; 5913 REASON_SET(&reason, PFRES_MEMORY); | 3689 } 3690 3691 return (PF_DROP); 3692} 3693 3694static int 3695pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif, 3696 struct mbuf *m, void *h, struct pf_pdesc *pd, struct pf_rule **am, --- 2210 unchanged lines hidden (view full) --- 5907 M_SETFIB(m, r->rtableid); 5908 5909#ifdef ALTQ 5910 if (action == PF_PASS && r->qid) { 5911 if (pd.pf_mtag == NULL && 5912 ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { 5913 action = PF_DROP; 5914 REASON_SET(&reason, PFRES_MEMORY); |
5915 } else { 5916 if (pqid || (pd.tos & IPTOS_LOWDELAY)) 5917 pd.pf_mtag->qid = r->pqid; 5918 else 5919 pd.pf_mtag->qid = r->qid; 5920 /* Add hints for ecn. */ 5921 pd.pf_mtag->hdr = h; |
|
5914 } | 5922 } |
5915 if (pqid || (pd.tos & IPTOS_LOWDELAY)) 5916 pd.pf_mtag->qid = r->pqid; 5917 else 5918 pd.pf_mtag->qid = r->qid; 5919 /* add hints for ecn */ 5920 pd.pf_mtag->hdr = h; | |
5921 5922 } 5923#endif /* ALTQ */ 5924 5925 /* 5926 * connections redirected to loopback should not match sockets 5927 * bound specifically to loopback due to security implications, 5928 * see tcp_input() and in_pcblookup_listen(). --- 22 unchanged lines hidden (view full) --- 5951 if (m->m_flags & M_FASTFWD_OURS) { 5952 if (pd.pf_mtag == NULL && 5953 ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { 5954 action = PF_DROP; 5955 REASON_SET(&reason, PFRES_MEMORY); 5956 log = 1; 5957 DPFPRINTF(PF_DEBUG_MISC, 5958 ("pf: failed to allocate tag\n")); | 5923 5924 } 5925#endif /* ALTQ */ 5926 5927 /* 5928 * connections redirected to loopback should not match sockets 5929 * bound specifically to loopback due to security implications, 5930 * see tcp_input() and in_pcblookup_listen(). --- 22 unchanged lines hidden (view full) --- 5953 if (m->m_flags & M_FASTFWD_OURS) { 5954 if (pd.pf_mtag == NULL && 5955 ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { 5956 action = PF_DROP; 5957 REASON_SET(&reason, PFRES_MEMORY); 5958 log = 1; 5959 DPFPRINTF(PF_DEBUG_MISC, 5960 ("pf: failed to allocate tag\n")); |
5961 } else { 5962 pd.pf_mtag->flags |= 5963 PF_FASTFWD_OURS_PRESENT; 5964 m->m_flags &= ~M_FASTFWD_OURS; |
|
5959 } | 5965 } |
5960 pd.pf_mtag->flags |= PF_FASTFWD_OURS_PRESENT; 5961 m->m_flags &= ~M_FASTFWD_OURS; | |
5962 } 5963 ip_divert_ptr(*m0, dir == PF_IN ? DIR_IN : DIR_OUT); 5964 *m0 = NULL; 5965 5966 return (action); 5967 } else { 5968 /* XXX: ipfw has the same behaviour! */ 5969 action = PF_DROP; --- 365 unchanged lines hidden (view full) --- 6335 M_SETFIB(m, r->rtableid); 6336 6337#ifdef ALTQ 6338 if (action == PF_PASS && r->qid) { 6339 if (pd.pf_mtag == NULL && 6340 ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { 6341 action = PF_DROP; 6342 REASON_SET(&reason, PFRES_MEMORY); | 5966 } 5967 ip_divert_ptr(*m0, dir == PF_IN ? DIR_IN : DIR_OUT); 5968 *m0 = NULL; 5969 5970 return (action); 5971 } else { 5972 /* XXX: ipfw has the same behaviour! */ 5973 action = PF_DROP; --- 365 unchanged lines hidden (view full) --- 6339 M_SETFIB(m, r->rtableid); 6340 6341#ifdef ALTQ 6342 if (action == PF_PASS && r->qid) { 6343 if (pd.pf_mtag == NULL && 6344 ((pd.pf_mtag = pf_get_mtag(m)) == NULL)) { 6345 action = PF_DROP; 6346 REASON_SET(&reason, PFRES_MEMORY); |
6347 } else { 6348 if (pd.tos & IPTOS_LOWDELAY) 6349 pd.pf_mtag->qid = r->pqid; 6350 else 6351 pd.pf_mtag->qid = r->qid; 6352 /* Add hints for ecn. */ 6353 pd.pf_mtag->hdr = h; |
|
6343 } | 6354 } |
6344 if (pd.tos & IPTOS_LOWDELAY) 6345 pd.pf_mtag->qid = r->pqid; 6346 else 6347 pd.pf_mtag->qid = r->qid; 6348 /* add hints for ecn */ 6349 pd.pf_mtag->hdr = h; | |
6350 } 6351#endif /* ALTQ */ 6352 6353 if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP || 6354 pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && 6355 (s->nat_rule.ptr->action == PF_RDR || 6356 s->nat_rule.ptr->action == PF_BINAT) && 6357 IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) --- 95 unchanged lines hidden --- | 6355 } 6356#endif /* ALTQ */ 6357 6358 if (dir == PF_IN && action == PF_PASS && (pd.proto == IPPROTO_TCP || 6359 pd.proto == IPPROTO_UDP) && s != NULL && s->nat_rule.ptr != NULL && 6360 (s->nat_rule.ptr->action == PF_RDR || 6361 s->nat_rule.ptr->action == PF_BINAT) && 6362 IN6_IS_ADDR_LOOPBACK(&pd.dst->v6)) --- 95 unchanged lines hidden --- |