~~~~~~~~~~~~~~~~~~~~~
.. warning::
- The reverse DNS functions are under active development. **They may**
- **not be safe for production use.** The syntax of these functions may change at any
- time.
+ For :func:`createForward` and :func:`createForward6`, we recommend filtering with :func:`filterForward`, to prevent PowerDNS from generating A/AAAA responses to addresses outside of your network.
+ Not limiting responses like this may, in some situations, help attackers with impersonation and attacks like such as cookie stealing.
-.. function:: createReverse(format)
+.. function:: createReverse(format, [exceptions])
Used for generating default hostnames from IPv4 wildcard reverse DNS records, e.g. ``*.0.0.127.in-addr.arpa``
Returns a formatted hostname based on the format string passed.
:param format: A hostname string to format, for example ``%1%.%2%.%3%.%4%.static.example.com``.
-
+ :param exceptions: An optional table of overrides. For example ``{['10.10.10.10'] = 'quad10.example.com.'}`` would, when generating a name for IP ``10.10.10.10``, return ``quad10.example.com`` instead of something like ``10.10.10.10.example.com``.
+
**Formatting options:**
- ``%1%`` to ``%4%`` are individual octets
$ dig +short A 127.0.0.5.static.example.com @ns1.example.com
127.0.0.5
-.. function:: createReverse6(format)
+.. function:: createReverse6(format[, exceptions])
Used for generating default hostnames from IPv6 wildcard reverse DNS records, e.g. ``*.1.0.0.2.ip6.arpa``
Returns a formatted hostname based on the format string passed.
:param format: A hostname string to format, for example ``%33%.static6.example.com``.
-
+ :param exceptions: An optional table of overrides. For example ``{['2001:db8::1'] = 'example.example.com.'}`` would, when generating a name for IP ``2001:db8::1``, return ``example.example.com`` instead of something like ``2001--db8.example.com``.
+
Formatting options:
- ``%1%`` to ``%32%`` are individual characters (nibbles)
$ dig +short AAAA 2001-a-b--1.static6.example.com @ns1.example.com
2001:a:b::1
+.. function:: filterForward(address, masks[, fallback])
+
+ Used for limiting the output of :func:`createForward` and :func:`createForward6` to a set of netmasks.
+
+ :param address: A string containing an address, usually taken directly from :func:`createForward: or :func:`createForward6`.
+ :param masks: A NetmaskGroup; any address not matching the NMG will be replaced by the fallback address.
+ :param fallback: A string containing the fallback address. Defaults to ``0.0.0.0`` or ``::``.
+
+ Example::
+
+ *.static4.example.com IN LUA A "filterForward(createForward(), newNMG():addMasks{'192.0.2.0/24', '10.0.0.0/8'})"
+
Helper functions
~~~~~~~~~~~~~~~~
nmg = newNMG()
nmg:addMask("127.0.0.0/8")
nmg:addMasks({"213.244.168.0/24", "130.161.0.0/16"})
- nmg:addMasks(dofile("bad.ips")) -- contains return {"ip1","ip2"..}
+ nmg:addMasks(dofile("bad-ips.lua")) -- contains return {"ip1","ip2"..}
if nmg:match(dq.remoteaddr) then
print("Intercepting query from ", dq.remoteaddr)
Prefixing a mask with ``!`` excludes that mask from matching.
-.. function:: newNMG() -> NetMaskGroup
+.. function:: newNMG([masks]) -> NetMaskGroup
- Returns a new, empty :class:`NetMaskGroup`.
+ .. versionchanged:: 4.5.0
+ Added the optional ``masks`` parameter.
+
+ Returns a new :class:`NetMaskGroup`.
+ If no masks are passed, the object is empty.
+
+ :param {str} masks: The masks to add.
.. class:: NetMaskGroup
d_lw->registerToStringFunction(&Netmask::toString);
// NetmaskGroup
- d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); });
+ d_lw->writeFunction("newNMG", [](boost::optional<vector<pair<unsigned int, std::string>>> masks) {
+ auto nmg = NetmaskGroup();
+
+ if (masks) {
+ for(const auto& mask: *masks) {
+ nmg.addMask(mask.second);
+ }
+ }
+
+ return nmg;
+ });
+ // d_lw->writeFunction("newNMG", []() { return NetmaskGroup(); });
d_lw->registerFunction<void(NetmaskGroup::*)(const std::string&mask)>("addMask", [](NetmaskGroup&nmg, const std::string& mask) { nmg.addMask(mask); });
d_lw->registerFunction<void(NetmaskGroup::*)(const vector<pair<unsigned int, std::string>>&)>("addMasks", [](NetmaskGroup&nmg, const vector<pair<unsigned int, std::string>>& masks) { for(const auto& mask: masks) { nmg.addMask(mask.second); } });
d_lw->registerFunction("match", (bool (NetmaskGroup::*)(const ComboAddress&) const)&NetmaskGroup::match);
vector<ComboAddress> candidates;
- // exceptions are relative to zone
// so, query comes in for 4.3.2.1.in-addr.arpa, zone is called 2.1.in-addr.arpa
- // e["1.2.3.4"]="bert.powerdns.com" - should match, easy enough to do
- // the issue is with classless delegation..
+ // e["1.2.3.4"]="bert.powerdns.com" then provides an exception
if(e) {
ComboAddress req(labels[3]+"."+labels[2]+"."+labels[1]+"."+labels[0], 0);
const auto& uom = *e;
return std::string("unknown");
});
+ lua.writeFunction("filterForward", [](string address, NetmaskGroup& nmg, boost::optional<string> fallback) {
+ ComboAddress ca(address);
+
+ if (nmg.match(ComboAddress(address))) {
+ return address;
+ } else {
+ if (fallback) {
+ return *fallback;
+ }
+
+ if (ca.isIPv4()) {
+ return string("0.0.0.0");
+ } else {
+ return string("::");
+ }
+ }
+ });
+
/*
* Simplistic test to see if an IP address listens on a certain port
* Will return a single IP address from the set of available IP addresses. If
Prefixing a mask with ``!`` excludes that mask from matching.
-.. function:: newNMG() -> NetMaskGroup
+.. function:: newNMG([masks]) -> NetMaskGroup
+ .. versionchanged:: 4.6.0
+ Added the optional ``masks`` parameter.
- Returns a new, empty :class:`NetMaskGroup`.
+ Returns a new :class:`NetMaskGroup`.
+ If no masks are passed, the object is empty.
+
+ :param {str} masks: The masks to add.
.. class:: NetMaskGroup
resolve IN LUA A ";local r=resolve('localhost', 1) local t={{}} for _,v in ipairs(r) do table.insert(t, v:toString()) end return t"
-*.createforward IN LUA A "createForward()"
+*.createforward IN LUA A "filterForward(createForward(), newNMG{{'1.0.0.0/8', '64.0.0.0/8'}})"
*.createreverse IN LUA PTR "createReverse('%5%.example.com', {{['10.10.10.10'] = 'quad10.example.com.'}})"
*.createreverse6 IN LUA PTR "createReverse6('%33%.example.com', {{['2001:db8::1'] = 'example.example.com.'}})"
createforward6.example.org. 3600 IN SOA {soa}
createforward6.example.org. 3600 IN NS ns1.example.org.
createforward6.example.org. 3600 IN NS ns2.example.org.
-* IN LUA AAAA "createForward6()"
+* IN LUA AAAA "filterForward(createForward6(), newNMG{{'2000::/3'}}, 'fe80::1')"
"""
# the separate createforward6 zone is because some of the code in lua-record.cc insists on working relatively to the zone apex
}
"ip40414243": "64.65.66.67",
"ipp40414243": "0.0.0.0",
"ip4041424": "0.0.0.0",
+ "2.2.2.2": "0.0.0.0" # filtered
}),
".createreverse.example.org." : (dns.rdatatype.PTR, {
"4.3.2.1": "1-2-3-4.example.com.",
- "10.10.10.10": "quad10.example.com."
+ "10.10.10.10": "quad10.example.com." # exception
}),
".createforward6.example.org." : (dns.rdatatype.AAAA, {
- "2001--db8" : "2001::db8"
+ "2001--db8" : "2001::db8",
+ "4000-db8--1" : "fe80::1" # filtered, with fallback address override
}),
".createreverse6.example.org." : (dns.rdatatype.PTR, {
"8.b.d.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2" : "2001--db8.example.com.",
- "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2" : "example.example.com."
+ "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2" : "example.example.com." # exception
})
}