Stephane Lapie
2015-01-05 08:03:40 UTC
Hello,
I am currently in the process of dealing with water torture attacks on
our cache DNS servers (<randomstring>.domain.com queries that never
resolve and end up causing enormous upstream traffic, ultimately
crushing the authoritative server for domain.com).
To this end, I toyed around with unbound, and noticed that
unbound-control's lookup function has a very interesting feature :
$ sudo unbound-control lookup randomtest.google.com
The following name servers are used for lookup of randomtest.google.com.
;rrset 14224 4 0 8 0
google.com. 273424 IN NS ns2.google.com.
google.com. 273424 IN NS ns3.google.com.
google.com. 273424 IN NS ns4.google.com.
google.com. 273424 IN NS ns1.google.com.
;rrset 7350 1 0 8 0
ns1.google.com. 266550 IN A 216.239.32.10
;rrset 57726 1 0 8 0
ns4.google.com. 316926 IN A 216.239.38.10
;rrset 56988 1 0 8 0
ns3.google.com. 316188 IN A 216.239.36.10
;rrset 28120 1 0 8 0
ns2.google.com. 287320 IN A 216.239.34.10
Delegation with 4 names, of which 4 can be examined to query further
addresses.
It provides 4 IP addresses.
216.239.34.10 rto 87 msec, ttl 628, ping 71 var 4 rtt 87, tA 0, tAAAA
0, tother 0, EDNS 0 probed.
216.239.36.10 rto 645 msec, ttl 19, ping 101 var 136 rtt 645, tA 0,
tAAAA 0, tother 0, EDNS 0 probed.
216.239.38.10 rto 113 msec, ttl 31, ping 97 var 4 rtt 113, tA 0,
tAAAA 0, tother 0, EDNS 0 probed.
216.239.32.10 rto 99 msec, ttl 328, ping 47 var 13 rtt 99, tA 0,
tAAAA 0, tother 0, EDNS 0 probed.
Namely, for any given hostname, it can find the closest delegation point
(in this case, remove unambiguously and with no danger the random part
of the attack query, since it goes to the deepest component that retains
any meaning DNS-wise).
I thought that since the information was available within the Unbound
process, coding a Python module that would keep track of the count of
queries to a DDoSed delegation point would be a good start to an
algorithm for effectively blocking water torture attacks, but the
required function, dns_cache_find_delegation() was not available readily
from the Python API.
Therefore, I extended the Python API as per the attached file (also
available at
http://www.yomi.darkbsd.org/~darksoul/lookup-api-extension.patch), to
export struct delegpt and a find_delegation() function that would allow
to acquire the delegation point name, records and servers, from the
Python module environment.
Example of use case (extremely simplified, implementation of
allow_query() not disclosed) :
def operate(id, event, qstate, qdata):
delegation = find_delegation(qstate, qstate.qinfo.qname,
len(qstate.qinfo.qname))
if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
policy_result = allow_query(qstate.qinfo, delegation,
delegation_name)
if (policy_result): # Pass query to next module
qstate.ext_state[id] = MODULE_WAIT_MODULE
else:
qstate.ext_state[id] = MODULE_ERROR
return True
This patch, along with an actual module that will SERVFAIL (as above)
cache-missing queries going over threshold (therefore reducing upstream
traffic to a tenth of what it would be if honoring DDoS-related queries,
AND keeping it within our AS), has been running in our production
environment at ASAHI Net for several months now, and has been approved
for upstream contribution on our side.
I thought this feature would be very useful to have in the Python module
environment, so would it be possible for you to consider integrating
this patch as a standard feature in Unbound?
Thanks for your time,
I am currently in the process of dealing with water torture attacks on
our cache DNS servers (<randomstring>.domain.com queries that never
resolve and end up causing enormous upstream traffic, ultimately
crushing the authoritative server for domain.com).
To this end, I toyed around with unbound, and noticed that
unbound-control's lookup function has a very interesting feature :
$ sudo unbound-control lookup randomtest.google.com
The following name servers are used for lookup of randomtest.google.com.
;rrset 14224 4 0 8 0
google.com. 273424 IN NS ns2.google.com.
google.com. 273424 IN NS ns3.google.com.
google.com. 273424 IN NS ns4.google.com.
google.com. 273424 IN NS ns1.google.com.
;rrset 7350 1 0 8 0
ns1.google.com. 266550 IN A 216.239.32.10
;rrset 57726 1 0 8 0
ns4.google.com. 316926 IN A 216.239.38.10
;rrset 56988 1 0 8 0
ns3.google.com. 316188 IN A 216.239.36.10
;rrset 28120 1 0 8 0
ns2.google.com. 287320 IN A 216.239.34.10
Delegation with 4 names, of which 4 can be examined to query further
addresses.
It provides 4 IP addresses.
216.239.34.10 rto 87 msec, ttl 628, ping 71 var 4 rtt 87, tA 0, tAAAA
0, tother 0, EDNS 0 probed.
216.239.36.10 rto 645 msec, ttl 19, ping 101 var 136 rtt 645, tA 0,
tAAAA 0, tother 0, EDNS 0 probed.
216.239.38.10 rto 113 msec, ttl 31, ping 97 var 4 rtt 113, tA 0,
tAAAA 0, tother 0, EDNS 0 probed.
216.239.32.10 rto 99 msec, ttl 328, ping 47 var 13 rtt 99, tA 0,
tAAAA 0, tother 0, EDNS 0 probed.
Namely, for any given hostname, it can find the closest delegation point
(in this case, remove unambiguously and with no danger the random part
of the attack query, since it goes to the deepest component that retains
any meaning DNS-wise).
I thought that since the information was available within the Unbound
process, coding a Python module that would keep track of the count of
queries to a DDoSed delegation point would be a good start to an
algorithm for effectively blocking water torture attacks, but the
required function, dns_cache_find_delegation() was not available readily
from the Python API.
Therefore, I extended the Python API as per the attached file (also
available at
http://www.yomi.darkbsd.org/~darksoul/lookup-api-extension.patch), to
export struct delegpt and a find_delegation() function that would allow
to acquire the delegation point name, records and servers, from the
Python module environment.
Example of use case (extremely simplified, implementation of
allow_query() not disclosed) :
def operate(id, event, qstate, qdata):
delegation = find_delegation(qstate, qstate.qinfo.qname,
len(qstate.qinfo.qname))
if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
policy_result = allow_query(qstate.qinfo, delegation,
delegation_name)
if (policy_result): # Pass query to next module
qstate.ext_state[id] = MODULE_WAIT_MODULE
else:
qstate.ext_state[id] = MODULE_ERROR
return True
This patch, along with an actual module that will SERVFAIL (as above)
cache-missing queries going over threshold (therefore reducing upstream
traffic to a tenth of what it would be if honoring DDoS-related queries,
AND keeping it within our AS), has been running in our production
environment at ASAHI Net for several months now, and has been approved
for upstream contribution on our side.
I thought this feature would be very useful to have in the Python module
environment, so would it be possible for you to consider integrating
this patch as a standard feature in Unbound?
Thanks for your time,
--
Stephane LAPIE, EPITA SRS, Promo 2005
"Even when they have digital readouts, I can't understand them."
--MegaTokyo
Stephane LAPIE, EPITA SRS, Promo 2005
"Even when they have digital readouts, I can't understand them."
--MegaTokyo