]> git.ipfire.org Git - thirdparty/pdns.git/blob - docs/lua-records/functions.rst
Merge pull request #13879 from Habbie/auth-lua-filterforward-empty
[thirdparty/pdns.git] / docs / lua-records / functions.rst
1 Preset variables
2 ----------------
3
4 LUA rules run within the same environment as described in
5 :doc:`../modes-of-operation`.
6
7 The Lua snippets can query the following variables:
8
9 Query variables
10 ~~~~~~~~~~~~~~~
11 ``dh``
12 The :class:`DNSHeader` of the received query.
13 ``dnssecOK``
14 A boolean describing if the DNSSEC OK (DO) bit was set in the query.
15 ``ednsPKTSize``
16 The advertised EDNS buffer size.
17 ``qname``
18 The name of the requested record. This is a :class:`DNSName`.
19 ``zone``
20 The zone this LUA record is in. This is a :class:`DNSName`.
21 ``zoneid``
22 The id of the zone. This is an integer.
23 ``tcp``
24 Whether or not the query was received over TCP.
25
26 Client variables
27 ~~~~~~~~~~~~~~~~
28 ``ecswho``
29 The EDNS Client Subnet, should one have been set on the query. Unset
30 otherwise. This is a :class:`Netmask`.
31 ``bestwho``
32 In absence of ECS, this is set to the IP address of requesting resolver.
33 Otherwise set to the network part of the EDNS Client Subnet supplied by the
34 resolver. This is a :class:`ComboAddress`.
35 ``who``
36 IP address of requesting resolver as a :class:`ComboAddress`.
37 ``localwho``
38 IP address (including port) of socket on which the question arrived.
39
40 Functions available
41 -------------------
42
43 Record creation functions
44 ~~~~~~~~~~~~~~~~~~~~~~~~~
45
46 .. function:: ifportup(portnum, addresses[, options])
47
48 Simplistic test to see if an IP address listens on a certain port. This will
49 attempt a TCP connection on port ``portnum`` and consider it available if the
50 connection establishes. No data will be sent or read on that connection. Note
51 that both IPv4 and IPv6 addresses can be tested, but that it is an error to
52 list IPv4 addresses on an AAAA record, or IPv6 addresses on an A record.
53
54 Will return a single address from the set of available addresses. If
55 no address is available, will return a random element of the set of
56 addresses supplied for testing.
57
58 :param int portnum: The port number to test connections to.
59 :param {str} addresses: The list of addresses to check connectivity for.
60 :param options: Table of options for this specific check, see below.
61
62 Various options can be set in the ``options`` parameter:
63
64 - ``selector``: used to pick the address(es) from the list of available addresses. Choices include 'pickclosest', 'random', 'hashed', 'all' (default 'random').
65 - ``backupSelector``: used to pick the address(es) from all addresses if all addresses are down. Choices include 'pickclosest', 'random', 'hashed', 'all' (default 'random').
66 - ``source``: Source address to check from
67 - ``timeout``: Maximum time in seconds that you allow the check to take (default 2)
68
69
70 .. function:: ifurlup(url, addresses[, options])
71
72 More sophisticated test that attempts an actual http(s) connection to
73 ``url``. In addition, a list of sets of IP addresses can be supplied. The
74 first set with at least one available address is selected. The ``selector`` then
75 selects from the subset of available addresses of the selected set.
76 An URL is considered available if the HTTP response code is 200 and optionally if
77 the content matches the ``stringmatch`` option.
78
79 :param string url: The url to retrieve.
80 :param addresses: List of sets of addresses to check the URL on.
81 :param options: Table of options for this specific check, see below.
82
83 Various options can be set in the ``options`` parameter:
84
85 - ``selector``: used to pick the address(es) from the subset of available addresses of the selected set. Choices include 'pickclosest', 'random', 'hashed', 'all' (default 'random').
86 - ``backupSelector``: used to pick the address from all addresses if all addresses are down. Choices include 'pickclosest', 'random', 'hashed', 'all' (default 'random').
87 - ``source``: Source address to check from
88 - ``timeout``: Maximum time in seconds that you allow the check to take (default 2)
89 - ``stringmatch``: check ``url`` for this string, only declare 'up' if found
90 - ``useragent``: Set the HTTP "User-Agent" header in the requests. By default it is set to "PowerDNS Authoritative Server"
91 - ``byteslimit``: Limit the maximum download size to ``byteslimit`` bytes (default 0 meaning no limit).
92
93 An example of a list of address sets:
94
95 .. code-block:: lua
96
97 ifurlup("https://example.com/", { {"192.0.2.20", "203.0.113.4"}, {"203.0.113.2"} })
98
99 .. function:: ifurlextup(groups-of-address-url-pairs[, options])
100
101 Very similar to ``ifurlup``, but the returned IPs are decoupled from their external health check URLs.
102 This is useful when health checking already happens elsewhere, and that state is exposed over HTTP(S).
103 Health checks are considered positive if the HTTP response code is 200 and optionally if the content matches the ``stringmatch`` option.
104
105 Options are identical to those for ``ifurlup``.
106
107 Example:
108
109 .. code-block:: lua
110
111 ifurlextup({{['192.168.0.1']='https://example.com/',['192.168.0.2']='https://example.com/404'}})
112
113 Example with two groups:
114
115 .. code-block:: lua
116
117 ifurlextup({{['192.168.0.1']='https://example.net/404',['192.168.0.2']='https://example.com/404'}, {['192.168.0.3']='https://example.net/'}})"
118
119 The health checker will look up the first two URLs (using normal DNS resolution to find them - whenever possible, use URLs with IPs in them).
120 The 404s will cause the first group of IPs to get marked as down, after which the URL in the second group is tested.
121 The third IP will get marked up assuming ``https://example.net/`` responds with HTTP response code 200.
122
123 .. function:: pickrandom(values)
124
125 Returns a random value from the list supplied.
126
127 :param values: A list of strings such as IPv4 or IPv6 address.
128
129 This function also works for CNAME or TXT records.
130
131 .. function:: pickrandomsample(number, values)
132
133 Returns N random values from the list supplied.
134
135 :param number: Number of values to return
136 :param values: A list of strings such as IPv4 or IPv6 address.
137
138 This function also works for CNAME or TXT records.
139
140 .. function:: pickhashed(values)
141
142 Based on the hash of ``bestwho``, returns a random value from the list supplied.
143
144 :param values: A list of strings such as IPv4 or IPv6 address.
145
146 This function also works for CNAME or TXT records.
147
148 .. function:: pickclosest(addresses)
149
150 Returns IP address deemed closest to the ``bestwho`` IP address.
151
152 :param addresses: A list of strings with the possible IP addresses.
153
154 .. function:: latlon()
155
156 Returns text listing fractional latitude/longitude associated with the ``bestwho`` IP address.
157
158 .. function:: latlonloc()
159
160 Returns text in LOC record format listing latitude/longitude associated with the ``bestwho`` IP address.
161
162 .. function:: closestMagic()
163
164 Suitable for use as a wildcard LUA A record. Will parse the query name which should be in format::
165
166 192-0-2-1.192-0-2-2.198-51-100-1.magic.v4.powerdns.org
167
168 It will then resolve to an A record with the IP address closest to ``bestwho`` from the list
169 of supplied addresses.
170
171 In the ``magic.v4.powerdns.org`` this looks like::
172
173 *.magic.v4.powerdns.org IN LUA A "closestMagic()"
174
175
176 In another zone, a record is then present like this::
177
178 www-balanced.powerdns.org IN CNAME 192-0-2-1.192-0-2-2.198-51-100-1.magic.v4.powerdns.org
179
180 This effectively opens up your server to being a 'geographical load balancer as a service'.
181
182 Performs no uptime checking.
183
184 .. function:: all(values)
185
186 Returns all values.
187
188 :param values: A list of strings such as IPv4 or IPv6 address.
189
190 This function also works for CNAME or TXT records.
191
192 .. function:: view(pairs)
193
194 Shorthand function to implement 'views' for all record types.
195
196 :param pairs: A list of netmask/result pairs.
197
198 An example::
199
200 view.v4.powerdns.org IN LUA A ("view({ "
201 "{ {'192.168.0.0/16'}, {'192.168.1.54'}},"
202 "{ {'0.0.0.0/0'}, {'192.0.2.1'}} "
203 " }) " )
204
205 This will return IP address 192.168.1.54 for queries coming from
206 192.168.0.0/16, and 192.0.2.1 for all other queries.
207
208 This function also works for CNAME or TXT records.
209
210 .. function:: pickchashed(values)
211
212 Based on the hash of ``bestwho``, returns a string from the list
213 supplied, as weighted by the various ``weight`` parameters and distributed consistently.
214 Performs no uptime checking.
215
216 :param values: table of weight, string (such as IPv4 or IPv6 address).
217
218 This function works almost like :func:`pickwhashed` while bringing the following properties:
219 - reordering the list of entries won't affect the distribution
220 - updating the weight of an entry will only affect a part of the distribution
221 - because of the previous properties, the CPU and memory cost is a bit higher than :func:`pickwhashed`
222
223 Hashes will be pre computed the first time such a record is hit and refreshed if needed. If updating the list is done often,
224 the cash may grow. A cleanup routine is performed every :ref:`setting-lua-consistent-hashes-cleanup-interval` seconds (default 1h)
225 and cleans cached entries for records that haven't been used for :ref:`setting-lua-consistent-hashes-expire-delay` seconds (default 24h)
226
227 An example::
228
229 mydomain.example.com IN LUA A ("pickchashed({ "
230 " {15, "192.0.2.1"}, "
231 " {100, "198.51.100.5"} "
232 "}) ")
233
234
235 .. function:: pickwhashed(values)
236
237 Based on the hash of ``bestwho``, returns a string from the list
238 supplied, as weighted by the various ``weight`` parameters.
239 Performs no uptime checking.
240
241 :param values: table of weight, string (such as IPv4 or IPv6 address).
242
243 Because of the hash, the same client keeps getting the same answer, but
244 given sufficient clients, the load is still spread according to the weight
245 factors.
246
247 This function also works for CNAME or TXT records.
248
249 An example::
250
251 mydomain.example.com IN LUA A ("pickwhashed({ "
252 " {15, "192.0.2.1"}, "
253 " {100, "198.51.100.5"} "
254 "}) ")
255
256 .. function:: picknamehashed(values)
257
258 Based on the hash of the DNS record name, returns a string from the list supplied, as weighted by the various ``weight`` parameters.
259 Performs no uptime checking.
260
261 :param values: table of weight, string (such as IPv4 or IPv6 address).
262
263 This allows basic persistent load balancing across a number of backends.
264 It means that ``test.mydomain.example.com`` will always resolve to the same IP, but ``test2.mydomain.example.com`` may go elsewhere.
265 This function is only useful for wildcard records.
266
267 This works similar to round-robin load balancing, but has the advantage of making traffic for the same domain always end up on the same server which can help cache hit rates.
268
269 This function also works for CNAME or TXT records.
270
271 An example::
272
273 *.mydomain.example.com IN LUA A ("picknamehashed({ "
274 " {15, "192.0.2.1"}, "
275 " {100, "198.51.100.5"} "
276 "}) ")
277
278
279 .. function:: pickwrandom(values)
280
281 Returns a random string from the list supplied, as weighted by the
282 various ``weight`` parameters. Performs no uptime checking.
283
284 :param values: table of weight, string (such as IPv4 or IPv6 address).
285
286 See :func:`pickwhashed` for an example.
287
288 This function also works for CNAME or TXT records.
289
290 Reverse DNS functions
291 ~~~~~~~~~~~~~~~~~~~~~
292
293 .. warning::
294 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.
295 Not limiting responses like this may, in some situations, help attackers with impersonation and attacks like such as cookie stealing.
296
297 .. function:: createReverse(format, [exceptions])
298
299 Used for generating default hostnames from IPv4 wildcard reverse DNS records, e.g. ``*.0.0.127.in-addr.arpa``
300
301 See :func:`createReverse6` for IPv6 records (ip6.arpa)
302
303 See :func:`createForward` for creating the A records on a wildcard record such as ``*.static.example.com``
304
305 Returns a formatted hostname based on the format string passed.
306
307 :param format: A hostname string to format, for example ``%1%.%2%.%3%.%4%.static.example.com``.
308 :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``.
309
310 **Formatting options:**
311
312 - ``%1%`` to ``%4%`` are individual octets
313 - Example record query: ``1.0.0.127.in-addr.arpa``
314 - ``%1%`` = 127
315 - ``%2%`` = 0
316 - ``%3%`` = 0
317 - ``%4%`` = 1
318 - ``%5%`` joins the four decimal octets together with dashes
319 - Example: ``%5%.static.example.com`` is equivalent to ``%1%-%2%-%3%-%4%.static.example.com``
320 - ``%6%`` converts each octet from decimal to hexadecimal and joins them together
321 - Example: A query for ``15.0.0.127.in-addr.arpa``
322 - ``%6`` would be ``7f00000f`` (127 is 7f, and 15 is 0f in hexadecimal)
323
324 Example records::
325
326 *.0.0.127.in-addr.arpa IN LUA PTR "createReverse('%1%.%2%.%3%.%4%.static.example.com')"
327 *.1.0.127.in-addr.arpa IN LUA PTR "createReverse('%5%.static.example.com')"
328 *.2.0.127.in-addr.arpa IN LUA PTR "createReverse('%6%.static.example.com')"
329
330 When queried::
331
332 # -x is syntactic sugar to request the PTR record for an IPv4/v6 address such as 127.0.0.5
333 # Equivalent to dig PTR 5.0.0.127.in-addr.arpa
334 $ dig +short -x 127.0.0.5 @ns1.example.com
335 127.0.0.5.static.example.com.
336 $ dig +short -x 127.0.1.5 @ns1.example.com
337 127-0-0-5.static.example.com.
338 $ dig +short -x 127.0.2.5 @ns1.example.com
339 7f000205.static.example.com.
340
341 .. function:: createForward()
342
343 Used to generate the reverse DNS domains made from :func:`createReverse`
344
345 Generates an A record for a dotted or hexadecimal IPv4 domain (e.g. 127.0.0.1.static.example.com)
346
347 It does not take any parameters, it simply interprets the zone record to find the IP address.
348
349 An example record for zone ``static.example.com``::
350
351 *.static.example.com IN LUA A "createForward()"
352
353 This function supports the forward dotted format (``127.0.0.1.static.example.com``), and the hex format, when prefixed by two ignored characters (``ip40414243.static.example.com``)
354
355 When queried::
356
357 $ dig +short A 127.0.0.5.static.example.com @ns1.example.com
358 127.0.0.5
359
360 Since 4.8.0: the hex format can be prefixed by any number of characters (within DNS label length limits), including zero characters (so no prefix).
361
362 .. function:: createReverse6(format[, exceptions])
363
364 Used for generating default hostnames from IPv6 wildcard reverse DNS records, e.g. ``*.1.0.0.2.ip6.arpa``
365
366 **For simplicity purposes, only small sections of IPv6 rDNS domains are used in most parts of this guide,**
367 **as a full ip6.arpa record is around 80 characters long**
368
369 See :func:`createReverse` for IPv4 records (in-addr.arpa)
370
371 See :func:`createForward6` for creating the AAAA records on a wildcard record such as ``*.static.example.com``
372
373 Returns a formatted hostname based on the format string passed.
374
375 :param format: A hostname string to format, for example ``%33%.static6.example.com``.
376 :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``.
377
378 Formatting options:
379
380 - ``%1%`` to ``%32%`` are individual characters (nibbles)
381 - **Example PTR record query:** ``a.0.0.0.1.0.0.2.ip6.arpa``
382 - ``%1%`` = 2
383 - ``%2%`` = 0
384 - ``%3%`` = 0
385 - ``%4%`` = 1
386 - ``%33%`` converts the compressed address format into a dashed format, e.g. ``2001:a::1`` to ``2001-a--1``
387 - ``%34%`` to ``%41%`` represent the 8 uncompressed 2-byte chunks
388 - **Example:** PTR query for ``2001:a:b::123``
389 - ``%34%`` - returns ``2001`` (chunk 1)
390 - ``%35%`` - returns ``000a`` (chunk 2)
391 - ``%41%`` - returns ``0123`` (chunk 8)
392
393 Example records::
394
395 *.1.0.0.2.ip6.arpa IN LUA PTR "createReverse6('%33%.static6.example.com')"
396 *.2.0.0.2.ip6.arpa IN LUA PTR "createReverse6('%34%.%35%.static6.example.com')"
397
398 When queried::
399
400 # -x is syntactic sugar to request the PTR record for an IPv4/v6 address such as 2001::1
401 # Equivalent to dig PTR 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.b.0.0.0.a.0.0.0.1.0.0.2.ip6.arpa
402 # readable version: 1.0.0.0 .0.0.0.0 .0.0.0.0 .0.0.0.0 .0.0.0.0 .b.0.0.0 .a.0.0.0 .1.0.0.2 .ip6.arpa
403
404 $ dig +short -x 2001:a:b::1 @ns1.example.com
405 2001-a-b--1.static6.example.com.
406
407 $ dig +short -x 2002:a:b::1 @ns1.example.com
408 2002.000a.static6.example.com
409
410 .. function:: createForward6()
411
412 Used to generate the reverse DNS domains made from :func:`createReverse6`
413
414 Generates an AAAA record for a dashed compressed IPv6 domain (e.g. ``2001-a-b--1.static6.example.com``)
415
416 It does not take any parameters, it simply interprets the zone record to find the IP address.
417
418 An example record for zone ``static.example.com``::
419
420 *.static6.example.com IN LUA AAAA "createForward6()"
421
422 This function supports the dashed compressed format (i.e. ``2001-a-b--1.static6.example.com``), and the dot-split uncompressed format (``2001.db8.6.5.4.3.2.1.static6.example.com``)
423
424 When queried::
425
426 $ dig +short AAAA 2001-a-b--1.static6.example.com @ns1.example.com
427 2001:a:b::1
428
429 Since 4.8.0: a non-split full length format (``20010002000300040005000600070db8.example.com``) is also supported, optionally prefixed, in which case the last 32 characters will be considered.
430
431 .. function:: filterForward(address, masks[, fallback])
432
433 .. versionadded:: 4.5.0
434
435 Used for limiting the output of :func:`createForward` and :func:`createForward6` to a set of netmasks.
436
437 :param address: A string containing an address, usually taken directly from :func:`createForward: or :func:`createForward6`.
438 :param masks: A NetmaskGroup; any address not matching the NMG will be replaced by the fallback address.
439 :param fallback: A string containing the fallback address. Defaults to ``0.0.0.0`` or ``::``.
440
441 Example::
442
443 *.static4.example.com IN LUA A "filterForward(createForward(), newNMG({'192.0.2.0/24', '10.0.0.0/8'}))"
444
445 Since 4.9.0: if the fallback parameter is an empty string, ``filterForward`` returns an empty set, yielding a NODATA answer.
446 You cannot combine this feature with DNSSEC.
447
448 Helper functions
449 ~~~~~~~~~~~~~~~~
450
451 .. function:: asnum(number)
452 asnum(numbers)
453
454 Returns true if the ``bestwho`` IP address is determined to be from
455 any of the listed AS numbers.
456
457 :param int number: An AS number
458 :param [int] numbers: A list of AS numbers
459
460 .. function:: country(country)
461 country(countries)
462
463 Returns true if the ``bestwho`` IP address of the client is within the
464 two letter ISO country code passed, as described in :doc:`../backends/geoip`.
465
466 :param string country: A country code like "NL"
467 :param [string] countries: A list of country codes
468
469 .. function:: countryCode()
470
471 Returns two letter ISO country code based ``bestwho`` IP address, as described in :doc:`../backends/geoip`.
472 If the two letter ISO country code is unknown "--" will be returned.
473
474 .. function:: region(region)
475 region(regions)
476
477 Returns true if the ``bestwho`` IP address of the client is within the
478 two letter ISO region code passed, as described in :doc:`../backends/geoip`.
479
480 :param string region: A region code like "CA"
481 :param [string] regions: A list of regions codes
482
483 .. function:: regionCode()
484
485 Returns two letter ISO region code based ``bestwho`` IP address, as described in :doc:`../backends/geoip`.
486 If the two letter ISO region code is unknown "--" will be returned.
487
488 .. function:: continent(continent)
489 continent(continents)
490
491 Returns true if the ``bestwho`` IP address of the client is within the
492 continent passed, as described in :doc:`../backends/geoip`.
493
494 :param string continent: A continent code like "EU"
495 :param [string] continents: A list of continent codes
496
497 .. function:: continentCode()
498
499 Returns two letter ISO continent code based ``bestwho`` IP address, as described in :doc:`../backends/geoip`.
500 If the two letter ISO continent code is unknown "--" will be returned.
501
502 .. function:: netmask(netmasks)
503
504 Returns true if ``bestwho`` is within any of the listed subnets.
505
506 :param [string] netmasks: The list of IP addresses to check against
507
508 .. function:: dblookup(name, type)
509
510 .. versionadded:: 4.9.0
511
512 Does a database lookup for name and type, and returns a (possibly empty) array of string results.
513
514 Please keep the following in mind:
515
516 * it does not evaluate any LUA code found
517 * if you needed just one string, perhaps you want ``dblookup('www.example.org', pdns.A)[1]`` to take the first item from the array
518 * some things, like ifurlup, don't like empty tables, so be careful not to accidentally look up a name that does not have any records of that type, if you are going to use the result in ``ifurlup``
519
520 Example usage: ::
521
522 www IN LUA A "ifurlup('https://www.example.com/', {dblookup('www1.example.com', pdns.A), dblookup('www2.example.com', pdns.A), dblookup('www3.example.com', pdns.A)})"
523
524 :param string name: Name to look up in the database
525 :param int type: DNS type to look for