4 new sysctls to avoid ipv6 DoS attacks from OpenBSD

This commit is contained in:
christos 2012-06-23 03:13:41 +00:00
parent 2c4ba053cf
commit 443eb0a284
10 changed files with 208 additions and 19 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: sysctl.7,v 1.72 2012/06/22 14:54:35 christos Exp $
.\" $NetBSD: sysctl.7,v 1.73 2012/06/23 03:13:41 christos Exp $
.\"
.\" Copyright (c) 1993
.\" The Regents of the University of California. All rights reserved.
@ -29,7 +29,7 @@
.\"
.\" @(#)sysctl.3 8.4 (Berkeley) 5/9/95
.\"
.Dd June 20, 2012
.Dd June 22, 2012
.Dt SYSCTL 7
.Os
.Sh NAME
@ -1614,9 +1614,13 @@ The currently defined protocols and names are:
.It ip6 log_interval integer yes
.It ip6 lowportmax integer yes
.It ip6 lowportmin integer yes
.It ip6 maxdynroutes integer yes
.It ip6 maxifprefixes integer yes
.It ip6 maxifdefrouters integer yes
.It ip6 maxflows integer yes
.It ip6 maxfragpackets integer yes
.It ip6 maxfrags integer yes
.It ip6 neighborgcthresh integer yes
.It ip6 redirect integer yes
.It ip6 rr_prune integer yes
.It ip6 use_deprecated integer yes
@ -1715,6 +1719,18 @@ The lowest port number to use for TCP and UDP reserved port allocation.
This cannot be set to less than 0 or greater than 1024, and must
be smaller than
.Li ip6.lowportmax .
.It Li ip6.maxdynroutes
Maximum number of routes created by redirect.
Set it to negative to disable.
The default value is 4096.
.It Li ip6.maxifprefixes
Maximum number of prefixes created by route advertisements per interface.
Set it to negative to disable.
The default value is 16.
.It Li ip6.maxifdefrouters 16
Maximum number of default routers created by route advertisements per interface.
Set it to negative to disable.
The default value is 16.
.It Li ip6.maxflows
IPv6 Fast Forwarding is enabled by default.
If set to 0, IPv6 Fast Forwarding is disabled.
@ -1731,6 +1747,10 @@ The maximum number of fragments the node will accept.
0 means that the node will not accept any fragments.
\-1 means that the node will accept as many fragments as it receives.
The flag is provided basically for avoiding possible DoS attacks.
.It Li ip6.neighborgcthresh
Maximum number of entries in neighbor cache.
Set to negative to disable.
The default value is 2048.
.It Li ip6.redirect
If set to 1, ICMPv6 redirects may be sent by the node.
This option is ignored unless the node is routing IP packets,

View File

@ -1,4 +1,4 @@
/* $NetBSD: icmp6.c,v 1.160 2012/03/22 20:34:40 drochner Exp $ */
/* $NetBSD: icmp6.c,v 1.161 2012/06/23 03:14:03 christos Exp $ */
/* $KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.160 2012/03/22 20:34:40 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.161 2012/06/23 03:14:03 christos Exp $");
#include "opt_inet.h"
#include "opt_ipsec.h"
@ -2279,6 +2279,8 @@ icmp6_redirect_input(struct mbuf *m, int off)
* (there will be additional hops, though).
*/
rtcount = rt_timer_count(icmp6_redirect_timeout_q);
if (0 <= ip6_maxdynroutes && rtcount >= ip6_maxdynroutes)
goto freeit;
if (0 <= icmp6_redirect_hiwat && rtcount > icmp6_redirect_hiwat)
return;
else if (0 <= icmp6_redirect_lowat &&

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6.c,v 1.160 2012/03/13 18:40:59 elad Exp $ */
/* $NetBSD: in6.c,v 1.161 2012/06/23 03:14:03 christos Exp $ */
/* $KAME: in6.c,v 1.198 2001/07/18 09:12:38 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.160 2012/03/13 18:40:59 elad Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6.c,v 1.161 2012/06/23 03:14:03 christos Exp $");
#include "opt_inet.h"
#include "opt_pfil_hooks.h"
@ -2283,6 +2283,8 @@ in6_domifattach(struct ifnet *ifp)
ext->nd_ifinfo = nd6_ifattach(ifp);
ext->scope6_id = scope6_ifattach(ifp);
ext->nprefixes = 0;
ext->ndefrouters = 0;
return ext;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_proto.c,v 1.96 2012/03/22 20:34:40 drochner Exp $ */
/* $NetBSD: in6_proto.c,v 1.97 2012/06/23 03:14:03 christos Exp $ */
/* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.96 2012/03/22 20:34:40 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: in6_proto.c,v 1.97 2012/06/23 03:14:03 christos Exp $");
#include "opt_gateway.h"
#include "opt_inet.h"
@ -439,6 +439,10 @@ int ip6_rr_prune = 5; /* router renumbering prefix
* walk list every 5 sec. */
int ip6_mcast_pmtu = 0; /* enable pMTU discovery for multicast? */
int ip6_v6only = 1;
int ip6_neighborgcthresh = 2048; /* Threshold # of NDP entries for GC */
int ip6_maxifprefixes = 16; /* Max acceptable prefixes via RA per IF */
int ip6_maxifdefrouters = 16; /* Max acceptable def routers via RA */
int ip6_maxdynroutes = 4096; /* Max # of routes created via redirect */
int ip6_keepfaith = 0;
time_t ip6_log_time = 0;

View File

@ -1,4 +1,4 @@
/* $NetBSD: in6_var.h,v 1.64 2009/01/15 23:22:15 christos Exp $ */
/* $NetBSD: in6_var.h,v 1.65 2012/06/23 03:14:03 christos Exp $ */
/* $KAME: in6_var.h,v 1.81 2002/06/08 11:16:51 itojun Exp $ */
/*
@ -94,6 +94,8 @@ struct in6_ifextra {
struct icmp6_ifstat *icmp6_ifstat;
struct nd_ifinfo *nd_ifinfo;
struct scope6_id *scope6_id;
int nprefixes;
int ndefrouters;
};
struct in6_ifaddr {

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_input.c,v 1.138 2012/06/22 14:54:35 christos Exp $ */
/* $NetBSD: ip6_input.c,v 1.139 2012/06/23 03:14:04 christos Exp $ */
/* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */
/*
@ -62,7 +62,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.138 2012/06/22 14:54:35 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.139 2012/06/23 03:14:04 christos Exp $");
#include "opt_gateway.h"
#include "opt_inet.h"
@ -1977,6 +1977,38 @@ sysctl_net_inet6_ip6_setup(struct sysctllog **clog)
SYSCTL_DESCR("selected algorithm"),
sysctl_rfc6056_selected6, 0, NULL, RFC6056_MAXLEN,
CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "neighborgcthresh",
SYSCTL_DESCR("Maximum number of entries in neighbor"
" cache"),
NULL, 1, &ip6_neighborgcthresh, 0,
CTL_NET, PF_INET6, IPPROTO_IPV6,
CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "maxifprefixes",
SYSCTL_DESCR("Maximum number of prefixes created by"
" route advertisement per interface"),
NULL, 1, &ip6_maxifprefixes, 0,
CTL_NET, PF_INET6, IPPROTO_IPV6,
CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "maxifdefrouters",
SYSCTL_DESCR("Maximum number of default routers created"
" by route advertisement per interface"),
NULL, 1, &ip6_maxifdefrouters, 0,
CTL_NET, PF_INET6, IPPROTO_IPV6,
CTL_CREATE, CTL_EOL);
sysctl_createv(clog, 0, NULL, NULL,
CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
CTLTYPE_INT, "maxdynroutes",
SYSCTL_DESCR("Maximum number of routes created via"
" redirect"),
NULL, 1, &ip6_maxdynroutes, 0,
CTL_NET, PF_INET6, IPPROTO_IPV6,
CTL_CREATE, CTL_EOL);
}
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_var.h,v 1.58 2012/01/19 13:19:34 liamjfoy Exp $ */
/* $NetBSD: ip6_var.h,v 1.59 2012/06/23 03:14:04 christos Exp $ */
/* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */
/*
@ -272,6 +272,11 @@ extern int ip6_rr_prune; /* router renumbering prefix
* walk list every 5 sec. */
extern int ip6_mcast_pmtu; /* enable pMTU discovery for multicast? */
extern int ip6_v6only;
extern int ip6_neighborgcthresh; /* Threshold # of NDP entries for GC */
extern int ip6_maxifprefixes; /* Max acceptable prefixes via RA per IF */
extern int ip6_maxifdefrouters; /* Max acceptable def routers via RA */
extern int ip6_maxdynroutes; /* Max # of routes created via redirect */
extern struct socket *ip6_mrouter; /* multicast routing daemon */
extern int ip6_sendredirects; /* send IP redirects when forwarding? */

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6.c,v 1.142 2012/03/22 20:34:41 drochner Exp $ */
/* $NetBSD: nd6.c,v 1.143 2012/06/23 03:14:04 christos Exp $ */
/* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.142 2012/03/22 20:34:41 drochner Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.143 2012/06/23 03:14:04 christos Exp $");
#include "opt_ipsec.h"
@ -131,6 +131,16 @@ static int fill_prlist(void *, size_t *, size_t);
MALLOC_DEFINE(M_IP6NDP, "NDP", "IPv6 Neighbour Discovery");
#define LN_DEQUEUE(ln) do { \
(ln)->ln_next->ln_prev = (ln)->ln_prev; \
(ln)->ln_prev->ln_next = (ln)->ln_next; \
} while (/*CONSTCOND*/0)
#define LN_INSERTHEAD(ln) do { \
(ln)->ln_next = llinfo_nd6.ln_next; \
llinfo_nd6.ln_next = (ln); \
(ln)->ln_prev = &llinfo_nd6; \
(ln)->ln_next->ln_prev = (ln); \
} while (/*CONSTCOND*/0)
void
nd6_init(void)
{
@ -473,6 +483,7 @@ nd6_llinfo_timer(void *arg)
}
break;
case ND6_LLINFO_PURGE:
case ND6_LLINFO_STALE:
/* Garbage Collection(RFC 2461 5.3) */
if (!ND6_LLINFO_PERMANENT(ln)) {
@ -1332,6 +1343,35 @@ nd6_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info)
ln->ln_prev = &llinfo_nd6;
ln->ln_next->ln_prev = ln;
/*
* If we have too many cache entries, initiate immediate
* purging for some "less recently used" entries. Note that
* we cannot directly call nd6_free() here because it would
* cause re-entering rtable related routines triggering an LOR
* problem for FreeBSD.
*/
if (ip6_neighborgcthresh >= 0 &&
nd6_inuse >= ip6_neighborgcthresh) {
int i;
for (i = 0; i < 10 && llinfo_nd6.ln_prev != ln; i++) {
struct llinfo_nd6 *ln_end = llinfo_nd6.ln_prev;
/* Move this entry to the head */
LN_DEQUEUE(ln_end);
LN_INSERTHEAD(ln_end);
if (ND6_LLINFO_PERMANENT(ln_end))
continue;
if (ln_end->ln_state > ND6_LLINFO_INCOMPLETE)
ln_end->ln_state = ND6_LLINFO_STALE;
else
ln_end->ln_state = ND6_LLINFO_PURGE;
nd6_llinfo_settimer(ln_end, 0);
}
}
RT_DPRINTF("rt->_rt_key = %p\n", (void *)rt->_rt_key);
/*
* check if rt_getkey(rt) is an address assigned
@ -2043,6 +2083,14 @@ nd6_output(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m0,
goto sendpkt; /* send anyway */
}
/*
* Move this entry to the head of the queue so that it is less likely
* for this entry to be a target of forced garbage collection (see
* nd6_rtrequest()).
*/
LN_DEQUEUE(ln);
LN_INSERTHEAD(ln);
/* We don't have to do link-layer address resolution on a p2p link. */
if ((ifp->if_flags & IFF_POINTOPOINT) != 0 &&
ln->ln_state < ND6_LLINFO_REACHABLE) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6.h,v 1.56 2011/11/19 22:51:29 tls Exp $ */
/* $NetBSD: nd6.h,v 1.57 2012/06/23 03:14:04 christos Exp $ */
/* $KAME: nd6.h,v 1.95 2002/06/08 11:31:06 itojun Exp $ */
/*
@ -51,6 +51,7 @@ struct llinfo_nd6 {
struct callout ln_timer_ch;
};
#define ND6_LLINFO_PURGE -3
#define ND6_LLINFO_NOSTATE -2
/*
* We don't need the WAITDELETE state any more, but we keep the definition
@ -303,6 +304,8 @@ struct nd_prefix {
int ndpr_refcnt; /* reference couter from addresses */
};
#define ndpr_next ndpr_entry.le_next
#define ndpr_raf ndpr_flags
#define ndpr_raf_onlink ndpr_flags.onlink
#define ndpr_raf_auto ndpr_flags.autonomous

View File

@ -1,4 +1,4 @@
/* $NetBSD: nd6_rtr.c,v 1.82 2011/11/19 22:51:29 tls Exp $ */
/* $NetBSD: nd6_rtr.c,v 1.83 2012/06/23 03:14:04 christos Exp $ */
/* $KAME: nd6_rtr.c,v 1.95 2001/02/07 08:09:47 itojun Exp $ */
/*
@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.82 2011/11/19 22:51:29 tls Exp $");
__KERNEL_RCSID(0, "$NetBSD: nd6_rtr.c,v 1.83 2012/06/23 03:14:04 christos Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -79,8 +79,9 @@ static void defrouter_delreq(struct nd_defrouter *);
static void nd6_rtmsg(int, struct rtentry *);
static int in6_init_prefix_ltimes(struct nd_prefix *);
static void in6_init_address_ltimes(struct nd_prefix *ndpr,
struct in6_addrlifetime *lt6);
static void in6_init_address_ltimes(struct nd_prefix *,
struct in6_addrlifetime *);
static void purge_detached(struct ifnet *);
static int rt6_deleteroute(struct rtentry *, void *);
@ -488,6 +489,7 @@ defrtrlist_del(struct nd_defrouter *dr)
struct nd_ifinfo *ndi = ND_IFINFO(dr->ifp);
struct nd_defrouter *deldr = NULL;
struct nd_prefix *pr;
struct in6_ifextra *ext = dr->ifp->if_afdata[AF_INET6];
/*
* Flush all the routing table entries that use the router
@ -521,6 +523,12 @@ defrtrlist_del(struct nd_defrouter *dr)
if (deldr)
defrouter_select();
ext->ndefrouters--;
if (ext->ndefrouters < 0) {
log(LOG_WARNING, "defrtrlist_del: negative count on %s\n",
dr->ifp->if_xname);
}
free(dr, M_IP6NDP);
}
@ -777,6 +785,13 @@ defrtrlist_update(struct nd_defrouter *new)
return (dr);
}
struct in6_ifextra *ext = new->ifp->if_afdata[AF_INET6];
if (ip6_maxifdefrouters >= 0 &&
ext->ndefrouters >= ip6_maxifdefrouters) {
splx(s);
return (NULL);
}
/* entry does not exist */
if (new->rtlifetime == 0) {
splx(s);
@ -818,6 +833,8 @@ insert:
defrouter_select();
ext->ndefrouters++;
splx(s);
return (n);
@ -875,6 +892,43 @@ nd6_prefix_lookup(struct nd_prefixctl *key)
return (search);
}
static void
purge_detached(struct ifnet *ifp)
{
struct nd_prefix *pr, *pr_next;
struct in6_ifaddr *ia;
struct ifaddr *ifa, *ifa_next;
for (pr = nd_prefix.lh_first; pr; pr = pr_next) {
pr_next = pr->ndpr_next;
/*
* This function is called when we need to make more room for
* new prefixes rather than keeping old, possibly stale ones.
* Detached prefixes would be a good candidate; if all routers
* that advertised the prefix expired, the prefix is also
* probably stale.
*/
if (pr->ndpr_ifp != ifp ||
IN6_IS_ADDR_LINKLOCAL(&pr->ndpr_prefix.sin6_addr) ||
((pr->ndpr_stateflags & NDPRF_DETACHED) == 0 &&
!LIST_EMPTY(&pr->ndpr_advrtrs)))
continue;
for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa_next) {
ifa_next = ifa->ifa_list.tqe_next;
if (ifa->ifa_addr->sa_family != AF_INET6)
continue;
ia = (struct in6_ifaddr *)ifa;
if ((ia->ia6_flags & IN6_IFF_AUTOCONF) ==
IN6_IFF_AUTOCONF && ia->ia6_ndpr == pr) {
in6_purgeaddr(ifa);
}
}
if (pr->ndpr_refcnt == 0)
prelist_remove(pr);
}
}
int
nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
struct nd_prefix **newp)
@ -882,6 +936,14 @@ nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
struct nd_prefix *new = NULL;
int i, s;
int error;
struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6];
if (ip6_maxifprefixes >= 0) {
if (ext->nprefixes >= ip6_maxifprefixes / 2)
purge_detached(pr->ndpr_ifp);
if (ext->nprefixes >= ip6_maxifprefixes)
return ENOMEM;
}
error = 0;
new = malloc(sizeof(*new), M_IP6NDP, M_NOWAIT|M_ZERO);
@ -930,6 +992,8 @@ nd6_prelist_add(struct nd_prefixctl *pr, struct nd_defrouter *dr,
if (dr)
pfxrtr_add(new, dr);
ext->nprefixes++;
return 0;
}
@ -938,6 +1002,7 @@ prelist_remove(struct nd_prefix *pr)
{
struct nd_pfxrouter *pfr, *next;
int e, s;
struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6];
/* make sure to invalidate the prefix until it is really freed. */
pr->ndpr_vltime = 0;
@ -972,6 +1037,12 @@ prelist_remove(struct nd_prefix *pr)
free(pfr, M_IP6NDP);
}
ext->nprefixes--;
if (ext->nprefixes < 0) {
log(LOG_WARNING, "prelist_remove: negative count on %s\n",
pr->ndpr_ifp->if_xname);
}
splx(s);
free(pr, M_IP6NDP);