- Fix double-free case on ICMP return case.
- npf_pfil_register: handle kernels without INET6 option correctly. - Reduce some #ifdefs.
This commit is contained in:
parent
ba12b0dcec
commit
3e491282a2
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_handler.c,v 1.15 2012/03/11 18:27:59 rmind Exp $ */
|
||||
/* $NetBSD: npf_handler.c,v 1.16 2012/05/06 02:45:25 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
|
||||
@ -34,7 +34,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.15 2012/03/11 18:27:59 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_handler.c,v 1.16 2012/05/06 02:45:25 rmind Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
@ -236,17 +236,20 @@ out:
|
||||
* Depending on the flags and protocol, return TCP reset (RST) or
|
||||
* ICMP destination unreachable.
|
||||
*/
|
||||
if (retfl) {
|
||||
npf_return_block(&npc, nbuf, retfl);
|
||||
if (retfl && npf_return_block(&npc, nbuf, retfl)) {
|
||||
*mp = NULL;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
npf_stats_inc(NPF_STAT_ERROR);
|
||||
} else {
|
||||
error = ENETUNREACH;
|
||||
}
|
||||
m_freem(*mp);
|
||||
*mp = NULL;
|
||||
|
||||
if (*mp) {
|
||||
m_freem(*mp);
|
||||
*mp = NULL;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -271,7 +274,7 @@ npf_pfil_register(void)
|
||||
npf_ph_if = pfil_head_get(PFIL_TYPE_IFNET, 0);
|
||||
npf_ph_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
|
||||
npf_ph_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
|
||||
if (npf_ph_if == NULL || npf_ph_inet == NULL || npf_ph_inet6 == NULL) {
|
||||
if (!npf_ph_if || (!npf_ph_inet && !npf_ph_inet6)) {
|
||||
npf_ph_if = NULL;
|
||||
error = ENOENT;
|
||||
goto fail;
|
||||
@ -283,13 +286,16 @@ npf_pfil_register(void)
|
||||
KASSERT(error == 0);
|
||||
|
||||
/* Packet IN/OUT handler on all interfaces and IP layer. */
|
||||
error = pfil_add_hook(npf_packet_handler, NULL,
|
||||
PFIL_WAITOK | PFIL_ALL, npf_ph_inet);
|
||||
KASSERT(error == 0);
|
||||
|
||||
error = pfil_add_hook(npf_packet_handler, NULL,
|
||||
PFIL_WAITOK | PFIL_ALL, npf_ph_inet6);
|
||||
KASSERT(error == 0);
|
||||
if (npf_ph_inet) {
|
||||
error = pfil_add_hook(npf_packet_handler, NULL,
|
||||
PFIL_WAITOK | PFIL_ALL, npf_ph_inet);
|
||||
KASSERT(error == 0);
|
||||
}
|
||||
if (npf_ph_inet6) {
|
||||
error = pfil_add_hook(npf_packet_handler, NULL,
|
||||
PFIL_WAITOK | PFIL_ALL, npf_ph_inet6);
|
||||
KASSERT(error == 0);
|
||||
}
|
||||
fail:
|
||||
KERNEL_UNLOCK_ONE(NULL);
|
||||
mutex_exit(softnet_lock);
|
||||
@ -308,15 +314,19 @@ npf_pfil_unregister(void)
|
||||
KERNEL_LOCK(1, NULL);
|
||||
|
||||
if (npf_ph_if) {
|
||||
(void)pfil_remove_hook(npf_packet_handler, NULL,
|
||||
PFIL_ALL, npf_ph_inet6);
|
||||
(void)pfil_remove_hook(npf_packet_handler, NULL,
|
||||
PFIL_ALL, npf_ph_inet);
|
||||
(void)pfil_remove_hook(npf_ifhook, NULL,
|
||||
PFIL_IFADDR | PFIL_IFNET, npf_ph_if);
|
||||
|
||||
npf_ph_if = NULL;
|
||||
}
|
||||
if (npf_ph_inet) {
|
||||
(void)pfil_remove_hook(npf_packet_handler, NULL,
|
||||
PFIL_ALL, npf_ph_inet);
|
||||
}
|
||||
if (npf_ph_inet6) {
|
||||
(void)pfil_remove_hook(npf_packet_handler, NULL,
|
||||
PFIL_ALL, npf_ph_inet6);
|
||||
}
|
||||
|
||||
npf_ph_if = NULL;
|
||||
|
||||
KERNEL_UNLOCK_ONE(NULL);
|
||||
mutex_exit(softnet_lock);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_impl.h,v 1.13 2012/04/14 19:01:21 rmind Exp $ */
|
||||
/* $NetBSD: npf_impl.h,v 1.14 2012/05/06 02:45:25 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2009-2012 The NetBSD Foundation, Inc.
|
||||
@ -173,7 +173,7 @@ int npf_tcpsaw(npf_cache_t *, tcp_seq *, tcp_seq *, uint32_t *);
|
||||
bool npf_fetch_tcpopts(const npf_cache_t *, nbuf_t *,
|
||||
uint16_t *, int *);
|
||||
bool npf_normalize(npf_cache_t *, nbuf_t *, bool, bool, u_int, u_int);
|
||||
void npf_return_block(npf_cache_t *, nbuf_t *, const int);
|
||||
bool npf_return_block(npf_cache_t *, nbuf_t *, const int);
|
||||
|
||||
/* Complex instructions. */
|
||||
int npf_match_ether(nbuf_t *, int, int, uint16_t, uint32_t *);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: npf_sendpkt.c,v 1.9 2012/02/20 00:18:20 rmind Exp $ */
|
||||
/* $NetBSD: npf_sendpkt.c,v 1.10 2012/05/06 02:45:25 rmind Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2010-2011 The NetBSD Foundation, Inc.
|
||||
@ -34,7 +34,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.9 2012/02/20 00:18:20 rmind Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.10 2012/05/06 02:45:25 rmind Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@ -54,6 +54,12 @@ __KERNEL_RCSID(0, "$NetBSD: npf_sendpkt.c,v 1.9 2012/02/20 00:18:20 rmind Exp $"
|
||||
|
||||
#define DEFAULT_IP_TTL (ip_defttl)
|
||||
|
||||
#ifndef INET6
|
||||
#define in6_cksum(...) 0
|
||||
#define ip6_output(...) 0
|
||||
#define icmp6_error(m, ...) m_freem(m)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* npf_return_tcp: return a TCP reset (RST) packet.
|
||||
*/
|
||||
@ -81,9 +87,10 @@ npf_return_tcp(npf_cache_t *npc)
|
||||
/* Create and setup a network buffer. */
|
||||
if (npf_iscached(npc, NPC_IP4)) {
|
||||
len = sizeof(struct ip) + sizeof(struct tcphdr);
|
||||
} else {
|
||||
KASSERT(npf_iscached(npc, NPC_IP6));
|
||||
} else if (npf_iscached(npc, NPC_IP6)) {
|
||||
len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr);
|
||||
} else {
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
m = m_gethdr(M_DONTWAIT, MT_HEADER);
|
||||
@ -149,24 +156,15 @@ npf_return_tcp(npf_cache_t *npc)
|
||||
ip->ip_ttl = DEFAULT_IP_TTL;
|
||||
} else {
|
||||
KASSERT(npf_iscached(npc, NPC_IP6));
|
||||
#ifdef INET6
|
||||
th->th_sum = in6_cksum(m, IPPROTO_TCP, sizeof(struct ip6_hdr),
|
||||
sizeof(struct tcphdr));
|
||||
#else
|
||||
KASSERT(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Pass to IP layer. */
|
||||
if (npf_iscached(npc, NPC_IP4)) {
|
||||
return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL);
|
||||
} else {
|
||||
#ifdef INET6
|
||||
return ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
return ip6_output(m, NULL, NULL, IPV6_FORWARDING, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -179,40 +177,41 @@ npf_return_icmp(npf_cache_t *npc, nbuf_t *nbuf)
|
||||
|
||||
if (npf_iscached(npc, NPC_IP4)) {
|
||||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_ADMIN_PROHIBIT, 0, 0);
|
||||
} else {
|
||||
KASSERT(npf_iscached(npc, NPC_IP6));
|
||||
#ifdef INET6
|
||||
return 0;
|
||||
} else if (npf_iscached(npc, NPC_IP6)) {
|
||||
icmp6_error(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* npf_return_block: return TCP reset or ICMP host unreachable packet.
|
||||
* TODO: user should be able to specify exact ICMP error codes in config
|
||||
*
|
||||
* => Returns true if the buffer was consumed (freed) and false otherwise.
|
||||
*/
|
||||
void
|
||||
bool
|
||||
npf_return_block(npf_cache_t *npc, nbuf_t *nbuf, const int retfl)
|
||||
{
|
||||
void *n_ptr = nbuf_dataptr(nbuf);
|
||||
|
||||
if (!npf_iscached(npc, NPC_IP46) && !npf_fetch_ip(npc, nbuf, n_ptr)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
switch (npf_cache_ipproto(npc)) {
|
||||
case IPPROTO_TCP:
|
||||
if (retfl & NPF_RULE_RETRST) {
|
||||
if (!npf_fetch_tcp(npc, nbuf, n_ptr)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
(void)npf_return_tcp(npc);
|
||||
}
|
||||
break;
|
||||
case IPPROTO_UDP:
|
||||
if (retfl & NPF_RULE_RETICMP) {
|
||||
(void)npf_return_icmp(npc, nbuf);
|
||||
}
|
||||
if (retfl & NPF_RULE_RETICMP)
|
||||
if (npf_return_icmp(npc, nbuf) == 0)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user