From 6443a31ca8d6a85a0db3ce9f315338ec844a58b1 Mon Sep 17 00:00:00 2001 From: Tom Limoncelli Date: Thu, 3 Dec 2020 08:33:37 -0500 Subject: [PATCH] Fix REV and PTR (#979) * Fix REV and PTR --- docs/_includes/matrix.html | 4 +- pkg/js/helpers.js | 11 +- pkg/js/parse_tests/032-reverseip.js | 29 +++ pkg/js/parse_tests/032-reverseip.json | 79 ++++++++ pkg/js/parse_tests/033-revextend.js | 15 ++ pkg/js/parse_tests/033-revextend.json | 36 ++++ pkg/js/static.go | 253 +++++++++++++------------- pkg/normalize/validate.go | 13 +- pkg/transform/arpa.go | 11 ++ 9 files changed, 318 insertions(+), 133 deletions(-) create mode 100644 pkg/js/parse_tests/032-reverseip.js create mode 100644 pkg/js/parse_tests/032-reverseip.json create mode 100644 pkg/js/parse_tests/033-revextend.js create mode 100644 pkg/js/parse_tests/033-revextend.json diff --git a/docs/_includes/matrix.html b/docs/_includes/matrix.html index a9761533f..effcb44b1 100644 --- a/docs/_includes/matrix.html +++ b/docs/_includes/matrix.html @@ -884,7 +884,9 @@ - + + + diff --git a/pkg/js/helpers.js b/pkg/js/helpers.js index 942faf459..e532cc8fd 100644 --- a/pkg/js/helpers.js +++ b/pkg/js/helpers.js @@ -682,12 +682,17 @@ function recordBuilder(type, opts) { opts.transform(record, parsedArgs, modifiers); // Handle D_EXTEND() with subdomains. - if (d.subdomain && record.type != 'CF_REDIRECT' && - record.type != 'CF_TEMP_REDIRECT') { + if (d.subdomain && + record.type != 'CF_REDIRECT' && + record.type != 'CF_TEMP_REDIRECT') { + fqdn = [d.subdomain, d.name].join(".") + record.subdomain = d.subdomain; if (record.name == '@') { + record.subdomain = d.subdomain; record.name = d.subdomain; - } else { + } else if (fqdn != record.name && record.type != 'PTR') { + record.subdomain = d.subdomain; record.name += '.' + d.subdomain; } } diff --git a/pkg/js/parse_tests/032-reverseip.js b/pkg/js/parse_tests/032-reverseip.js new file mode 100644 index 000000000..a80b92409 --- /dev/null +++ b/pkg/js/parse_tests/032-reverseip.js @@ -0,0 +1,29 @@ +var REGISTRAR = NewRegistrar('none', 'NONE'); // No registrar. +var BIND = NewDnsProvider('bind', 'BIND'); + +D(REV('1.2.3.0/24'), REGISTRAR, DnsProvider(BIND), + PTR("1", 'foo.example.com.'), + PTR("1.2.3.2", 'bar.example.com.'), + PTR(REV("1.2.3.3"), 'baz.example.com.', {skip_fqdn_check:"true"}) +); +D_EXTEND(REV("1.2.3.4"), PTR("4", "silly.example.com.")) +D_EXTEND(REV("1.2.3.5"), PTR("1.2.3.5", "willy.example.com.")) +D_EXTEND(REV("1.2.3.6"), PTR(REV("1.2.3.6"), "billy.example.com.")) + +D_EXTEND(REV("1.2.3.0/24"), PTR("7", "my.example.com.")) +D_EXTEND(REV("1.2.3.0/24"), PTR("1.2.3.8", "fair.example.com.")) +D_EXTEND(REV("1.2.3.0/24"), PTR(REV("1.2.3.9/32"), "lady.example.com.", {skip_fqdn_check:"true"})) + +// Expected zone: 3.2.1.in-addr.arpa.zone +// $TTL 300 +//; generated with dnscontrol 2020-11-30T12:56:28-05:00 +//@ IN SOA DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2020113000 3600 600 604800 1440 +//1 IN PTR foo.example.com. +//2 IN PTR bar.example.com. +//3 IN PTR baz.example.com. +//4 IN PTR silly.example.com. +//5 IN PTR willy.example.com. +//6 IN PTR billy.example.com. +//7 IN PTR my.example.com. +//8 IN PTR fair.example.com. +//9 IN PTR lady.example.com. diff --git a/pkg/js/parse_tests/032-reverseip.json b/pkg/js/parse_tests/032-reverseip.json new file mode 100644 index 000000000..6c7c12c69 --- /dev/null +++ b/pkg/js/parse_tests/032-reverseip.json @@ -0,0 +1,79 @@ +{ + "dns_providers": [ + { + "name": "bind", + "type": "BIND" + } + ], + "domains": [ + { + "dnsProviders": { + "bind": -1 + }, + "name": "3.2.1.in-addr.arpa", + "records": [ + { + "name": "1", + "target": "foo.example.com.", + "type": "PTR" + }, + { + "name": "1.2.3.2", + "target": "bar.example.com.", + "type": "PTR" + }, + { + "meta": { + "skip_fqdn_check": "true" + }, + "name": "3.3.2.1.in-addr.arpa", + "target": "baz.example.com.", + "type": "PTR" + }, + { + "name": "4", + "subdomain": "4", + "target": "silly.example.com.", + "type": "PTR" + }, + { + "name": "1.2.3.5", + "subdomain": "5", + "target": "willy.example.com.", + "type": "PTR" + }, + { + "name": "6.3.2.1.in-addr.arpa", + "subdomain": "6", + "target": "billy.example.com.", + "type": "PTR" + }, + { + "name": "7", + "target": "my.example.com.", + "type": "PTR" + }, + { + "name": "1.2.3.8", + "target": "fair.example.com.", + "type": "PTR" + }, + { + "meta": { + "skip_fqdn_check": "true" + }, + "name": "9.3.2.1.in-addr.arpa", + "target": "lady.example.com.", + "type": "PTR" + } + ], + "registrar": "none" + } + ], + "registrars": [ + { + "name": "none", + "type": "NONE" + } + ] +} diff --git a/pkg/js/parse_tests/033-revextend.js b/pkg/js/parse_tests/033-revextend.js new file mode 100644 index 000000000..a1b85892d --- /dev/null +++ b/pkg/js/parse_tests/033-revextend.js @@ -0,0 +1,15 @@ +var REGISTRAR = NewRegistrar('none', 'NONE'); // No registrar. +var BIND = NewDnsProvider('bind', 'BIND'); + +// Delegating reverse zones +D(REV('1.3.0.0/16'), REGISTRAR, DnsProvider(BIND), + NS(REV('1.3.1.0/24'), "ns1.example.com.") +); +D_EXTEND(REV("1.3.2.0/24"), NS(REV("1.3.2.0/24"), "ns2.example.org.")) + +// Expeccted zone: 3.1.in-addr.arpa.zone +// $TTL 300 +// ; generated with dnscontrol 2020-11-30T12:58:47-05:00 +// @ IN SOA DEFAULT_NOT_SET. DEFAULT_NOT_SET. 2020113000 3600 600 604800 1440 +// 1 IN NS ns1.example.com. +// 2 IN NS ns2.example.org. diff --git a/pkg/js/parse_tests/033-revextend.json b/pkg/js/parse_tests/033-revextend.json new file mode 100644 index 000000000..80855c26a --- /dev/null +++ b/pkg/js/parse_tests/033-revextend.json @@ -0,0 +1,36 @@ +{ + "dns_providers": [ + { + "name": "bind", + "type": "BIND" + } + ], + "domains": [ + { + "dnsProviders": { + "bind": -1 + }, + "name": "3.1.in-addr.arpa", + "records": [ + { + "name": "1.3.1.in-addr.arpa", + "target": "ns1.example.com.", + "type": "NS" + }, + { + "name": "2.3.1.in-addr.arpa", + "subdomain": "2", + "target": "ns2.example.org.", + "type": "NS" + } + ], + "registrar": "none" + } + ], + "registrars": [ + { + "name": "none", + "type": "NONE" + } + ] +} diff --git a/pkg/js/static.go b/pkg/js/static.go index 97fa25f8c..787617c06 100644 --- a/pkg/js/static.go +++ b/pkg/js/static.go @@ -212,134 +212,135 @@ var _escData = map[string]*_escFile{ "/helpers.js": { name: "helpers.js", local: "pkg/js/helpers.js", - size: 28419, + size: 28640, modtime: 0, compressed: ` -H4sIAAAAAAAC/+x9aXcbN7Lod/2Kis67adJuU4ujzD3UcN4wWjI6o+2QdK7n6unxQmyQhN0EegC0aCZW -fvs7WBu9UbJPli/PHxI2UCgUCoVCVaEARbnAICQnMxkd7+zs7cHFHDYsB5wQCXJJBMxJimNdtsqFBJ5T -+J8FgwWmmCOJ/wckA7x6wIkGVyhUCyAU5BKDYDmfYZixBPdC/IhjWGL0SNINJPghXywIXZgOFWysG+++ -SfDjLsxTtIA1SVPVnmOUFIRBQjieyXQDhAqpqtgccmFwYWC5zHIJbK5alqjuwb9YHqUpCEnSFChW9LOG -0T3gOeNYtVdkz9hqpRmDYbZEdIFFb2fnEXGYMTqHAfyyAwDA8YIIyREXfbi7j3VZQsU04+yRJLhUzFaI -0FrBlKIVtqVPx6aLBM9RnsohXwgYwN398c7OPKczSRgFQokkKCU/407XElGiqI2qLZQ1Uvd0bIiskfKk -J3eEZc6pAEQBcY42ajYsDlgvyWwJa8yxpQRznIBgMFdjy7maM55TSVaa2zdrCn54c6Y4vMqQJA8kJXKj -xEAwKoBxIHMQbIUhQRsQGZ4RlELG2QwLLQdrlqcJPKhe/50TjpNewbYFlieMzski5zg5NYR6BnI9GM3H -XjgrerAexTVejxxjO6o+BrnJcAwrLJFDRebQUaXdYDrUNwwGEF0Nr98NLyPD2Sf9XzXdHC/U9IHC2YcC -cz/A39f/dbOiKS1muZflYtnheNE9DsejMNWGcErFrRWBZwfB5qbXgSKePXzAMxnBt99CRLLpjNFHzAVh -VERKBYTt1T/13SvDwUBN7wrJqZSdhvpulTGJyL6GMSUxN7xJRPYcbyheG7mwbPHsrUhJMcSALF8m8gcj -QX2Iori+IvvFz7jEqz788hTCzxhP6sv3tli9IbhdpZPJZR/24xKBAvPH2monC8o4TkLdU62SiC+wLCuE -kF123Z0ivhCdVWwXv+OV2hsYB4xmS1ixhMwJ5rGSKyKBCEC9Xs/DWYx9mKE0VQBrIpcWnwPSOqbvOlXs -ybkgjzjdOAgjnkoa+ALrbqhkmrMJksiL9bRHxLntsbPqliS2Y8dgxRBwKrBvNFQUVFqoIXaUoH7QKyCs -Uv/KLLr7cO+5dOzhnpr6utFjqXQ27eFPEtPEUtlTQ4thVaY2UDpLztYQ/ddwdH1x/WPf9uwnwyilnIo8 -yxiXOOlDBK9L5DsNUCmO4NQJeKXGEmaWlhmc2SxOzZIqVlQfTjhGEgOC0+uxRdiDdwLrDTdDHK2wxFwA -Em4tAKKJIl8EWv20ba1q7WFGPNiysg2ZfhoJDGD/GAj8Ndz3eimmC7k8BvL6dTghpekN4O9IdaKf6t0c -mm4QX+QrTGVrJwp+BYMC8I7cHzeTsGrsVclUbWPrEZrgTzdzzZAufDMYwJuDbk16VC28hkgt2QTPUqT2 -8RXjapYQBUZnuLSZBf04vRsSVCdDw2ganF1xOj17Pzm7NhPb7cO7LKnKCaBUmYYbQEmCE6MtTjvdWFkI -Xv0qOeKYzQNZKWFukpPpAkvThV2AljLHRgc4AJqn6RZ2rZEAymTBsw2WWnw1UcrKhBmiCuIBQ65HmBjp -P+10rR3aK3HWLi328KFXDHGge1QFQvLOfmw+jSC9CVoExfAGDn53qVedtkv+we8o+bWeQ4m8szAkuYdB -0OBYbR8plpEA9oj5mhNp1JDZUnpWMpulow8T5aGQVZZiTaVu6ZQtkrMloQvVHKULxolcriAXOIGHTSGQ -3R6cIJoQLem6DRbabUIU8Cc0k6ZQYWHzAH8krE1kTGMtfmpzVczJcLgYTDOFoNSyB5MlhpQp78Z2ohAY -Q6dkPjcPvlHZ5ml6XCm+xFTLWKvclRTHFnlQ3uC1GuagPLPk/m5XUbQbSIhxpITyA8b5fE4+wQB2e7vw -2mMpw85ZTgvIcGW9KaGx9AV7uPF1tadKRGXS1Nxo79ggtrPrzB+nWfTUKSvbD/Dz5zJBg0F5MFVbI6DB -zyMyU8ttidHZOYdZzjmmSvm4WQ/p8Q6AJcVpjr8Vk1ntvNBQZqYrTY9bgLVtT5I+kFittX51Tp1RX7aV -AqspNMtNM7+NnJ0P311OxmD9AMUMgaX2Uo3OKvQKSAYoy9KN/pGmMM9lzt0iEz2F70wZsto+laxAviZp -CrMUIw6IbiDj+JGwXMAjSnMsVIehrWJbea+z7lq3LY9ndWWot/WeGirNbtkYm0wuO4/dPoyxiW5MJpe6 -U7PFGmMrINuAB46hMlDHUjnxnceSgfoIAx1goosJO8050ib2Y0kd27lyyDs8bM97UqYwgMfjJn+jAXOg -fpzWHMBjT//u7P3fzv9JXnc7d2K1TNZ0c/+/u/9rL9jMfYu23fzRWT5qn0ZqTkkCie3dklPao3NKJAwg -ElGtl7vD+7ADC1lUlhxfGCgDWOALKn37AzeLarC5XjiiDwcxrPrw/X4Myz68/X5/362Y/C5KIrXL5b0l -vILD73zx2hYn8Ar+4ktpUPp23xdvwuLvjywF8GoA+Z0aw33JpX70i897oyVBcwvPCVyxkYWrJGz7O0ld -Ulo6vcJ5bhW+FfqIT4bD8xQtOnpxV2IChUDr5VOSarOgZgjp4ObngdEOYTd7e3AyHE5PRheTi5PhpXKO -iCQzlKpiHRPVUcEQRktPQdMB/PWv8JeuieuGEZ5dFwdR6ng3hv2ugqDihOVUa8N9WGFEBSSMRlKZJmrD -clE7rdWCIEIvbKyWhcNukajmKE3D6axFm2zzhlCTQ6yjTTlN8JxQnEQhMz0IvDn4khkOAid3igwl1hZX -ZSKGhkySxXbmrqzDrPbsrp6HIQxs3Q85SdXIomFkeT8cDl+CYThsQjIcFnguL4Zjg8gEYrYgU6AN2FSx -R/ff70Zn0wCpDaA9i7to19BDURnFlt/KHO/Dnef9XaS6i2Io1m8Qa7qLFBlRbJQrknj4c87xMCVITDYZ -LkNqUpsw2f9JjqiYM77qV5djrMmKfeyjYXkaA0zDBfGLAMB070DM13HJhgsCN7YNUqOZIjWcbtVkqoNY -Ztz7PjZZQEYtvtOMRO8MJkTqkYRmlDWc4p2nbnio0Mz/sqpTY/wmVMO6ssxLswpRKnDD6ryLhlEMRsxj -iE6uh1dn0b0PRdjOTCzCHzMcvS2LrRVYI75tYutb1YXWV/1WIjs6evu7C6z4oySWH73dLq8e4Oul1aP4 -Mlm1wvDfN9dnnZ8ZxVOSdAsBrlW17c/huKo82Db8cOS2Dz14+/u5oVdGbVv13Y+GYZcNkCZp+42XZ6eQ -3XK8dxicY5gCvYLLZWY1VwvrcFfvqyWT95Nq0e1kVC0a357XikY/VYuuh+WmLdpF13cD28vttItYw7Vr -lpOmjVsPszj4mNyc3nRkSlbdPlxIEEt3LIkoYM5NsEb347yLfWV0HRz+Z+/rFBJatFfqfv48JTRDSKJF -oYQWz6ip0DY2BLrur/PVA+YNVJZWQd3iFlWTu9AnWmZfZmRp0IaZ11Lv7G63SX3EGyVKRcgvhoQssDCb -lvlp0J7Wd6jd0/Hu125NpmNbbxhWqvcEtYMY6uwetxWmTMYfKFOJMON0QOarAawIuVpIX9AAXAzcQRcl -reBl0C/YggMpvJ2MXiaDt5NRXQKVvrOItPIzqBhPMI8zjueYYzrDsV4JsXLjyEwfxOFP2bMdaoT1Lq2S -/UoZ1aS1y1ZBczuMHkx7D3aU7QBm+NsU6p9ruVGUSa755MD0RzNcwTAHXJQ0tzBa0QLrj2Y4y0cHaT+b -YQ1LHaj5+rrlMB79ZGQ440Qt1k28xmSxlHHGuHxWZMejn+oCqw2FrxRXR0W7NBrytkg041tq/2xZE/zR -DbGQH/PdBGsG6yDNVyNOxj2U+v2VsjD+x/mtkYZiL9W76DNmmm7YIAiq+KtF4QW755zQBeYZJ3TLlP/J -JpkQy3n2BVujhg8G5jVHUfRFRp2bXGMr5QItcAwCp3gmGY/9makxlmaYSzInMySxntjJ5bjBAFelXz2t -moL22XKUtUOEFH/hQged5hqMRaenCkCwa+B3/dnPHxk5SAXSXHFQ+qMRzHGn2CTMdyNwyCjXICz7CiVR -pMVant5wk6j1qRIBCDzjT134/BmKnK5PxhPUcdJ3k5vx7eXFxByfFslSSyR13jHPZ/aI/0f2JsWPONVJ -zCCZai6y1OVST95P7CgiYaNWJiNttszpRwFsDodHRz0TZfW96ojIJzlWeIZuRfYhWuWpJPbICZ50woJN -oDo8OnrzsJHY4t3Z29PL5P3k6t3l5GJ8Ozw5a8UqMjTDDp+uBUZBl8Kd8kt9VgNO7s3Z4fvJy2xVNfz6 -MlWe/tdG3dzyqUz0H6M6FX+kyXvC9rRJgFyTGe6HMABOZIkRkjnhQtoGVcBP0iGywIQm5JEkOUpdF71y -m+ubyVnfHPNjjnWGSJGMdWAbxf5QRrjQA6PpBtBshoVoJSIGucwFEAkJw4JGOjFAYg5rJfprNWrVFaFu -iBXa/sHW+BHzGB42GtTl5YccMHTHOjlzpajEAh7Q7OMa8aRCWTkFfL3E5o5BimlHp4J2YTCAA51T1SFU -YqqmGqXppgsPHKOPFXQPnH3ENOAMRlzfJLCMl3hhz3UlFlL0aiFCqzoCPdQWId0edg0BCwEYwF0Aff+y -OGpTR3f798/31UhYLdh69b5ihj+35K/e11f81fvf0fD+s03n1acm36vFdn6RvXv9wiO/64aDjetxEQe4 -OhufjX46K8UVgmB5BSCMIFczTeCbATQkhkYFikK7ZFIAo9hbLPqQX+dRRV9wVhseN+tUljD9H566lfPa -gpBpW2JLQKtNJe418WL6e+Qc/AJUTKVM+/DYk8wi61aj+8WtCC+yU4keUhyk00/0EdpdytY672NJFss+ -HMZA8foHJHAf3t7HYKq/c9VHuvritg/f3987RNoK2T2AX+EQfoW38OsxfAe/whH8CvArfL/r00xSQvFz -mUkVerfl7pEMBlX4UkqnAtLkwgBI1tM/ywdWuqiqd8sJ+gakKUHNoZ72VigzcHEhhaSpSXhfJF8dJkx2 -SLeezfbU7X1ghHaiOKrUNurvkBiH1pC9Pd0t4JGacc8l9VHjkyp8llMaqIVXtgvPLfX9p/LLEhRwTJP/ -Mp4ppTWAO09V1kvZuhtDUKCWTNevJ7tyAvHUy8HetGJrOwL4FaJu08I30BboGCJ/2nTx4/XNyJw6BCo5 -LC3WfIIzjpXvm8Q6t8ZATZXOCvsKisvJ9LWKaodBVcuBaUU7ly4OldL3S1rZYp8MRz+eTTq1DaipOgY+ -Ce7NvZAOe0vJ7hSZNllpv5Qm0DeIyzuHJvLq9mY0mU5Gw+vx+c3oyijfVGtzo578hQq961bh63twFaJq -/NxFtS4ipbUjm5Wtf0uZlm2e39Kaif4ePWOauDzaqrGDJbLkF+pbn4AXm5cxbaoj7NY71GmeBlqm9QOR -d6MfzzqBuJgCLwFJ758YZ+/oR8rWVBFgDrStPXAzrbX3Za0oJM89BuWNn16Px2cnmhjMV0RKnLikXsRx -X1Xs7gKcMn18q/m+Mb4hllJ5Op0g4VGn3O0yugsAZ1SxJOjDZkIS4S68adj5XGEn4jlgP8QCZnpz7caZ -9FAu2TShQuAZDDQNapSNrc7P25vN523tXJsZo4Kp/Z8tTB7Brr94FpCvrxE5ldaDC2kOwNeAgLI3LOsB -3KZY6Xml7UpjAsYr5JrLCy6plOg07hX6iIEyuxJmWgpFz1zRWGGhY1o6aTshAmUZVmYJBeQyvjnWvfeU -DWSV6KtXO/AK/l6QvQOv9krXir153jGrUEjEZSk3mSWtZpQG9knerfnd+tqbS+wu5XQHulIBhUSP9Goz -F/0ejIrSY9G36+AXY8A+mfoAtgmGZVL0dNf3d/v3MHQWvtIqIbzjy6Dc5OAebjLjobtMFsa3tfN6Btxd -zSJJv5S379LV4ZVj1USJQGviHxJBMj0M6aZQmkYwHnCAS3VIcGJvZNm3CCxBvSC3Y5VLZO8MLcgjpiFZ -raxRg3Gy0zDMgi7JNGaDsyx+5f3HhMwVdic76rc24uwyEZ1fngxEHEiX350aPPLCz1b7UOEGft1mZO0a -A2kYvkSPOBisv9tnWF9tqXC7iQJE7RUtvaaCS6M2dbgpEtLu1YcWstl5t4Z7mjZQZ02G7V5o4L44ehRY -uMF8lKSpYU5aZ6PJqfPAbeqodEWPJTAommiPrgZYv3nNkm6bB7Fiicujb/Admm9Kb0G3twfmjQFZSK1e -VDYi1thI391gSaCIvv02ODIoVbX2bAcTICk9gFDCcdyI4amx1N8ED2wzPcXt/Gom0AZzzkajm1EfnDlU -uiIeNaBsl0fj3VkBqJrw1YCAvuSS2OtPvzyVAwGFRrAPoIQzU4tS/bXYbtz1vMqQFU7f7JLo1B3fpjZE -7fQWvq7Eq2fcXQVSC74abtSRW+cXqt6vmQ69H7+utYqc1rSPm4ja9Xun8EM2NCIqdtBOE44ymxoQdHtw -Q9MNbG28jQD9NIzIjYqPqhFrxdAwML1TWslpqhS+72ZnmyKrcqNRkVnJOFV7BtG7aiAZpQCVgza5m203 -kwMhLXAWlygPmiRJ7Yk5LWwj/dJN3rAF+kzfEva7g/uGfN8Xi1ZNxKItQOWO9++34vOhYDsyHexEJK3N -+ja9oq97e11xVyVA+aBBhkG7zHiV0iwzDcLykquXYY5q++XLClVboxvFs0B6MgYNUxo8glOrqz8m41vJ -tF+671YGeaps3HUztcGcOK438ZuaBy9mr9y0at39A9EkxcHFePO4g7/HLuq3lJPgPYRvv/VmlBL0bwYQ -nZxPR2enF6Ozk0kE337bosJrbSZnV7dFwy2mX/gYQ/B13LhoSyaojsW07yqhsboV8dYNPsTzegBRL4LX -z6CrLMLyAy89d4BiH5xqMNKsaJu6QPhLEcJnvGqUJMYh7STuqk/5+o9ydYM4KZlDce5Ote0eAxIiX2Eg -mULHsRA9bwcSe3pdMfcbLP2aaV+y6sMnvGalhdq0QJueizLofMBy5wVL1R0xll56Ki96y+zmR5gSPCMJ -hgckcALK41SkOvg33hN1zzEJswYLD1T50OqrlJikm940PsGkYEvPMGlYl85/cQ5X7wvMZsr0PLpx7gT2 -uGh8fansujy72a+Mv9K8a295H6p4J4rjWbNft/UBp692SPTgW12RFzgiqzYXZKsDUnc+Qsej8v7UF4K1 -aq1aILFmVPjA4lXrU1ZR3GwE2QetmmujzvgjyTJCF990oxpE9yVPUdT1Y/nROY5nLspMMihevvOGgIA5 -ZytYSpn19/aERLOP7BHzecrWvRlb7aG9/zzYP/rLd/t7B4cH33+/rzA9EuQafECPSMw4yWQPPbBc6jYp -eeCIb/YeUpJZuest5So4jbntJKwUsUz0+ziyp/PZOlHPOSp7e5BxLCXB/I05gSldINP/Xid3+/ddeAWH -R9934TWogoP7bqXksFby9r5beY/PHfTlq/BQnuYrfUPcXxBvuOIWRdUXsIKjfIWvoQ3NV7XnB43eh/9Q -dDYEb98qnfM3rXrevCldU1c0whWSy948ZYxrovf0aAsxUtg7Hr1ig92eG0K7ib+rlrI8maf6caCUIIFF -32TrYInc4YPQVAbZZD7rQd9kOp/ejm7e/2t6c36uMwNnHuU04+zTpg8Rm89dWuCtKtLh8ocUJ1UU160Y -aBkBpk3tz99dXrZhmOdpWsLxeoRIushpgcscz7xxjy2FLNBHNJZ2e0LA5nOzHVJJ/Osu5YOafpk8+2JL -K6emtl3BsYZeab3Ttm6un+2Fuk7eUaJ0B0rH48vmkflO3l1f/HQ2Gg8vx+PLpqHkDpUQaXkk5U7oi/u4 -fq4LMwwtz+/Gk5urGG5HNz9dnJ6NYHx7dnJxfnECo7OTm9EpTP51ezYOtMLU3YQtVsIIm6eBf+P7sLqB -vz8axVFX6x17N90O3PkIDVcDA8+jPQfOPJocxdvGVb57h4UkVHvSL2r1xx4e2zegX0MUK1VmDpQListH -vZaFJV+rkY9lb+z/M7ONme9Gl3X+vRtdqu3b1r/dP2gEebt/4KDOR41XXXWxSzEc355Pf3h3calWrEQf -sSjOYrTmzRCXoq8PaPVP927d+Pbc2fodyeABwwem9nDjY0QQdbVWT9EDTk3z0+ux+fRPBmWcrBDfBLh6 -0Cl05N8jfd7O0boP/6XzpDvmPWqNpWvsbGYe18spSs3j1M4QC+h0W4mmSPtjih5JVliTonwykzmMuX55 -UquZkBTzAqS2UWL7UnnxulHX3xewePEqS5E0uFGSEHtc6h4/Ndya6aT/JBzvVGTz/0jMoOcpkhLTPgwh -JUKGb3Kb9hbAbp7KtFxilBz0Ybhi+vV02H3I53PMgTO22jUnrDobU3uKPp+bSLzy775nc5gt9StOilGf -5BX6NCY/YzOuFfpEVvkKBPkZF97o5P3EM+wnk1ehiIHDoyNzusex0Kf6FPTVhywt0u6DsR8eHUXdYHMI -xLJhMzAK3cjj588QfBbHCIcNua6hsPvgO5KQYiQkHAK2Lz/WjE7boxW88PDDF4eKoNaQo7Xy9YqPbwYD -iKI6KlU3gGjK0Vpkc4/O7GbmAEWnkC6xl4tArsx+ZyIimTmKcdDKpgrOVdXawdKJgrafinsuBoEhwYVk -LXttGlzU9YiLlVdeajvFW4ZWVtWy0W9S/jvHQmfCuRf7AQW9B1EKtK4gdWw1JFm8BWdtQRGi3y+9d+ob -DCrwDTmMe3vmZAQliadFscPS6N6/ppHUj0GsMrmp3g4pCG2ecc3krHJiZgp7tUs+SirCu0PBTR9Fngua -zfW1M5zUw6uGEinTxhiocXMn7ycFxbGVgBh4FpvHAz2K7osPw59B3H3WGw/kyDnQSor0Hw2YEyVFxosw -KljJSVVMXLOyLJgbXk4SHExpwZVRaP1axuGLS3h0SQuiQqmWMRXlHlVRVML1W8iG4+mP29dfWWdU2VoR -pdpMa61YzHWrDNVk51lMRZpuKSQTvsC3zaTZapOcDIdbbBHCEjw3TWeMSvM2LEmLuHSH2eyoAnw6s28A -9uEHxlKMqD4TxDTRfz0D6wvWVi8SjpM9B99TMq9MDx8OK92iDZ6j4XieC5zUuhcix324tBvFydD9QQ8T -dEjZ2vwBFQ0XohaVVx2hY8wVcyvEiokzAYyhp3GsSZr0YWgxF/3N1Jh1JwpihnjS1JtPhuxt7y8wE4Kp -bjUTXr5pVwTcUOw3F/OptDhlFEfdcjHcRcfR/XETCjXmChpd1IzKVDl0Hp+n3g3LU/dNpXEXPn8uoMvA -lQi6r3I75mAA+1vA7Ei2VYeYTMJEgx0WrtC6HabmHFPJN6rIUM54IWBfaxRVp0atzeobYkGVX7b1B8S0 -ejoZDsvqKdLNohgCJHHpqc9ws2t5XOzlqLv1Pz3RKMDdllOWGNLAEgqlwJy/pJiac5cXUqgQFBSqrzty -3+0e77QtiS8gLBCsrydOy05cRRsSWd1IzBaK4PSfF1fu4qv/wyd/Ozz6Dh42Epf+isU/L646iPu36fRV -brurHx4dFQ//jlpvY7nhI84bhgyvBwXSYvQjl67AeyIlM9whsYINQMvHFyM3RJ+tuuYoyzDXxCxS9tDp -6p/Bn2eBlCG9Zc1Jio0vPRSF++B50CEUfmRdxSNiXylnVHKWAqKbNdrE+mVu1c7m4fsr0C5jVCBK5ObN -bIlnH62De80k7jvCiLBXFal227nyrnOasFlubrjDEqd6LD7Bd8x0Hrq5Fr9RNLE1BU7Ex16Ygqs10dT2 -4mNTNgPk8B4GsPtB7B7b49gZVupFU0LoLM0TDL0PwrHHP0avPmGgaTc5GB2ap2lcYA7/ikNwAGrwtJyA -Wlo7Gqgli1zXOVHG0geyLdtVfyeXF4pIogxoEWyrlxdT/8i5Szh23Xtx/Yj1vetqfeUtYLWv333Em3sd -c931hz27Vb0aAHqc+rum5p52/l8AAAD//0o7eJQDbwAA +H4sIAAAAAAAC/+x9WXfbONLou39Fxed+oZQw9JJ25jtya+6ovfT4jLcjyf1lxtdXA4uQhIQiOQBoRd1x +//Z7sBLgIjs+vbzcPHSLQKFQKBQKVYUCHBQMA+OUTHlwuLW1swNnM1hnBeCYcOALwmBGEhzKsmXBONAi +hX/PM5jjFFPE8b+BZ4CX9ziW4AKFaAEkBb7AwLKCTjFMsxhHLn5EMSwweiDJGmJ8X8znJJ2rDgVsKBtv +v4vxwzbMEjSHFUkS0Z5iFJeEQUwonvJkDSRlXFRlMyiYwoUhK3hecMhmoqVHdQT/zIogSYBxkiSQYkF/ +1jC6ezzLKBbtBdnTbLmUjMEwXaB0jlm0tfWAKEyzdAZ9+GULAIDiOWGcIsp6cHsXyrI4ZZOcZg8kxl5x +tkQkrRVMUrTEuvTxUHUR4xkqEj6gcwZ9uL073NqaFemUkywFkhJOUEJ+xp2uJsKjqI2qDZQ1Uvd4qIis +kfIoJ3eIeUFTBigFRClai9nQOGC1INMFrDDFmhJMcQwsg5kYW0HFnNEi5WQpuX21SsEOb5YJDi9zxMk9 +SQhfCzFgWcogo0BmwLIlhhitgeV4SlACOc2mmEk5WGVFEsO96PU/BaE4jkq2zTE/ytIZmRcUx8eKUMtA +Kgcj+Ri5syIHa1Fc4tXQMLYj6kPg6xyHsMQcGVRkBh1R2nWmQ3xDvw/BxeDyZnAeKM4+yv+K6aZ4LqYP +BM4elJh7Dv6e/K+ZFUlpOctRXrBFh+J599Adj8BUG8Jxyq61CDw5iGymeu0L4rP7T3jKA3j9GgKST6ZZ ++oApI1nKAqEC3Pbin/iOfDjoi+ldIj7hvNNQ360yJmb5SxjjibniTczyp3iT4pWSC80Wy96KlJRDdMiy +Zay4VxLUgyAI6yuyV/4MPV714JdHF36a0bi+fK/L1euC61U6Hp/3YDf0CGSYPtRWO5mnGcWxq3uqVRzR +Oea+QnDZpdfdMaJz1lmGevEbXom9IaOA0XQByywmM4JpKOSKcCAMUBRFFk5j7MEUJYkAWBG+0PgMkNQx +PdOpYE9BGXnAydpAKPEU0kDnWHaT8kxyNkYcWbGeRISd6h47y64nsR09Bi2GgBOGbaOBoKDSQgyxIwT1 +k1wBbpX457Po9tOd5dKhhXts6utKjqXS2STCXzhOY01lJIYWwtKn1lE6C5qtIPifwfDy7PLHnu7ZToZS +SkXKijzPKMdxDwJ465FvNEClOIBjI+CVGk2YWlpqcGqzOFZLqlxRPTiiGHEMCI4vRxphBDcMyw03RxQt +MceUAWJmLQBKY0E+c7T6cdtaldpDjbi/YWUrMu00EujD7iEQ+N7d96IEp3O+OATy9q07Id70OvC3pDrR +j/Vu9lU3iM6LJU55aycCfgn9EvCW3B02k7Bs7FXIVG1ji0ga4y9XM8mQLrzq9+HdXrcmPaIW3kIglmyM +pwkS+/gyo2KWUApZOsXeZub0Y/SuS1CdDAkjaTB2xfHk5OP45FJNbLcHN3lclRNAiTAN14DiGMdKWxx3 +uqGwEKz6FXJEcTZzZMXD3CQnkznmqgu9ADVlho0GsA9pkSQb2LVCDNKMlzxbYy7FVxIlrEyYolRA3GMo +5AhjJf3Hna62QyOPs3ppZfefonKIfdmjKGCcdnZD9akE6Z3TwimGd7D3u0u96LRd8vd+R8mv9exK5K2G +IfEd9J0Gh2L7SDAPGGQPmK4o4UoNqS0l0pLZLB09GAsPhSzzBEsqZUujbBGfLkg6F81RMs8o4YslFAzH +cL8uBbIbwRFKYyIlXbbBTLpNKAX8BU25KhRYspmDP2DaJlKmsRQ/sbkK5uTYXQyqmUDgtYxgvMCQZMK7 +0Z0IBMrQ8czn5sE3KtsiSQ4rxec4lTLWKnee4tggD8IbvBTD7PszS+5utwVF246EKEeKCT9gVMxm5Av0 +YTvahrcWiw87y4q0hHRX1jsPjabP2cOVrys9VcIqkybmRnrHCrGeXWP+GM0ip05Y2XaAX7/6BPX7/mCq +toZDg51HpKaW6hKlswsK04JSnArlY2bdpcc6AJoUozn+Wk5mtfNSQ6mZrjQ9bAGWtj2Je0BCsdZ61Tk1 +Rr1vKzlWk2uWq2Z2Gzk5Hdycj0eg/QDBDIa59FKVzir1CvAMUJ4na/kjSWBW8IKaRcYige9EGLLSPuVZ +iXxFkgSmCUYUULqGnOIHkhUMHlBSYCY6dG0V3cp6nXXXum15PKkrXb0t91RXaXZ9Y2w8Pu88dHswwiq6 +MR6fy07VFquMLYdsBe44hsJAHXHhxHcePAP1AfoywJTOx9lxQZE0sR88daznyiDvULc9jThPoA8Ph03+ +RgNmR/0YrdmHh0j+7uz8387/id92O7dsuYhX6fruf3f/146zmdsWbbv5g7F8xD6NxJySGGLduybH26OL +lHDoQ8CCWi+3+3duBxqyrPQcX+gLA5jhs5Tb9ntmFsVgC7lwWA/2Qlj24MNuCIsevP+wu2tWTHEbxIHY +5YpoAW9g/ztbvNLFMbyBv9jS1Cl9v2uL127xhwNNAbzpQ3ErxnDnudQPdvFZb9QTNLPwjMCVG5m7Sty2 +v5PUxd7SiUrnuVX4lugzPhoMThM078jFXYkJlAItl48n1WpBTRGSwc2vfaUd3G52duBoMJgcDc/GZ0eD +c+EcEU6mKBHFMiYqo4IujJSekqY9+P57+EtXxXXdCM+2iYMIdbwdwm5XQKTsKCtSqQ13YYlRyiDO0oAL +00RsWCZqJ7WaE0SI3MZiWRjsGolojpLEnc5atEk3bwg1GcQy2lSkMZ6RFMeBy0wLAu/2vmWGncDJrSBD +iLXGVZmIgSKT5KGeuQvtMIs9uyvnYQB9XfdDQRIxsmAQaN4PBoPnYBgMmpAMBiWe87PBSCFSgZgNyARo +AzZRbNH962Z4MnGQ6gDak7jLdg09lJVBqPktzPEe3Fre3waiuyCEcv06sabbQJARhEq5Io4HPxcUDxKC +2HidYx9SktqESf+PU5SyWUaXvepyDCVZoY19NCxPZYBJOCd+4QCo7g2I+jr0bDgncKPbIDGaCRLD6VZN +pjqIZsad7WOdO2TU4jvNSOTOoEKkFolrRmnDKdx67LqHCs3891WdGOMrVw3LSp+XahWihOGG1XkbDIIQ +lJiHEBxdDi5OgjsbitCdqViEPWY4eO+LrRZYJb5tYmtb1YXWVv1WIjs8eP+7Cyz7oySWHrzfLK8W4OXS +alF8m6xqYfjX1eVJ5+csxRMSd0sBrlW17c/uuKo82DR8d+S6Dzl4/fupoVdGrVv1zI+GYfsGSJO0/cbL +s1PKrh/vHTjnGKpArmC/TK3mamEd7uJjtWT8cVwtuh4Pq0Wj69Na0fCnatHlwG/aol1kfdexvcxOOw8l +XLtmOWrauOUwy4OP8dXxVYcnZNntwRkHtjDHkigFTKkK1sh+jHexK4yuvf3/jl6mkNC8vVL28+cpoSlC +HM1LJTR/Qk25trEi0HR/WSzvMW2g0lsFdYubVU3uUp9ImX2ekSVBG2ZeSr2xu80m9RmvhSiVIb8QYjLH +TG1a6qdCe1zfobaPR9sv3ZpUx7peMcyrtwS1gyjq9B63EcYn4w+UqZipcRog9dUAVoZcNaQtaAAuB26g +y5JWcB/0G7ZgRwqvx8PnyeD1eFiXQKHvNCKp/BSqjMaYhjnFM0xxOsWhXAmhcOPIVB7E4S/5kx1KhPUu +tZJ9oYxK0tplq6S5HUYOpr0HPcp2ADX8TQr1z7XcUpRzKvlkwORHM1zJMANcljS3UFpRA8uPZjjNRwOp +P5thFUsNqPp62XIYDX9SMpxTIhbrOlxhMl/wMM8of1JkR8Of6gIrDYUXiquhol0aFXkbJDqjG2r/bFlj +9MEMsZQf9d0EqwZrINVXI86MWijx+4WyMPr76bWShnIvlbvoE2aabNggCKL4xaLwjN1zRtI5pjkl6YYp +/5NNMsYWs/wbtkYJ7wzMao6y6JuMOjO5ylYqGJrjEBhO8JRnNLRnpspYmmLKyYxMEcdyYsfnowYDXJS+ +eFolBe2zZShrh3Ap/saFDjLN1RmLTE9lgGBbwW/bs58/MnKQMCS5YqDkRyOY4U65SajvRmCXUaaBW/YC +JVGmxWqeXlGVqPWlEgFwPOMvXfj6Fcqcri/KE5Rx0pvx1ej6/Gysjk/LZKkF4jLvmBZTfcT/Y/YuwQ84 +kUnMwDPRnOWJyaUefxzrUQRMR61URtp0UaSfGWQz2D84iFSU1fYqIyJf+EjgGZgV2YNgWSSc6CMneJQJ +CzqBav/g4N39mmONd2tnRy6Tj+OLm/Px2eh6cHTSipXlaIoNPlkLWQqyFG6FX2qzGnB8p84OP46fZ6uK +4deXqfD0Xxp1M8unMtF/jOoU/OEq7wnr0yYGfEWmuOfCABiRJUpIZoQyrhtUAb9wg0gDkzQmDyQuUGK6 +iPw2l1fjk5465scUywyRMhlrTzcK7aEMM6GHLE3WgKZTzFgrESHwRcGAcIgzzNJAJgZwTGElRH8lRi26 +IqkZYoW2v2cr/IBpCPdrCWry8l0OKLpDmZy5FFRiBvdo+nmFaFyhzE8BXy2wumOQ4LQjU0G70O/Dnsyp +6pCU41RMNUqSdRfuKUafK+juafYZpw5nMKLyJoFmPMdzfa7LMeMsqoUItepw9FBbhHRz2NUFLAWgD7cO +9N3z4qhNHd3u3j3dVyNhtWDrxceKGf7Ukr/4WF/xFx9/R8P7zzadl1+afK8W2/lZ9u7lM4/8LhsONi5H +ZRzg4mR0MvzpxIsrOMHyCoAbQa5mmsCrPjQkhgYlilK75JxBlmJrschDfplHFXzDWa173CxTWdz0f3js +Vs5rS0ImbYktDq06lThq4sXk98g5+AVSNuE86cFDxDONrFuN7pe3IqzITji6T7CTTj+WR2i3SbaSeR8L +Ml/0YD+EFK9+QAz34P1dCKr6O1N9IKvPrnvw4e7OIJJWyPYe/Ar78Cu8h18P4Tv4FQ7gV4Bf4cO2TTNJ +SIqfykyq0Lspd4/k0K/CeymdAkiSC30geSR/+gdWsqiqd/0EfQXSlKBmUE+iJcoVXFhKIWlq4t4XKZb7 +ccY7pFvPZnvsRp8yknaCMKjUNupvlxiDVpG9Od3N4ZGYccsl8VHjkyh8klMSqIVXugvLLfH9p/JLE+Rw +TJL/PJ4JpdWHW0tVHiXZqhuCUyCWTNeuJ71yHPGUy0HftMpWegTwKwTdpoWvoDXQIQT2tOnsx8uroTp1 +cFSyW1qu+RjnFAvfNw5lbo2Cmgid5fblFPvJ9LWKaodOVcuBaUU7exeHvPR9Tytr7OPB8MeTcae2ATVV +h0DHzr25Z9KhbynpnSKXJmva89IEegqxv3NIIi+ur4bjyXg4uBydXg0vlPJNpDZX6sleqJC7bhW+vgdX +IarGz21Q6yIQWjvQWdnyN+eJb/P8ltZM8LfgCdPE5NFWjR3MkSa/VN/yBLzcvJRpUx1ht96hTPNU0Dyp +H4jcDH886TjiogqsBMTRPzDOb9LPabZKBQHqQFvbA1eTWntb1oqC08JiEN748eVodHIkicF0STjHsUnq +RRT3RMX2NsBxJo9vJd/XyjfEnAtPp+MkPMqUu+0s3QaAk1SwxOlDZ0ISZi68SdjZTGAn7ClgO8QSZnJ1 +acYZR6jg2SROGcNT6EsaxCgbW52etjebzdramTbTLGWZ2P+zucoj2LYXzxzy5TUio9IiOOPqAHwFCNLs +XZZHANcJFnpeaDtvTJDRCrnq8oJJKiUyjXuJPmNIM70SplIKWaSuaCwxkzEtmbQdE4byHAuzJAVkMr4p +lr1HwgbSSvTNmy14A38ryd6CNzvetWJrnnfUKmQcUe7lJmdxqxklgW2Sd2t+t7z2ZhK7vZxuR1cKIJfo +oVxt6qLfvVJRcizydh38ogzYR1XvwDbBZDlnkez67nb3DgbGwhdaxYU3fOn7Tfbu4CpXHrrJZMnopnZW +z4C5q1km6Xt5+yZdHd4YVo2FCLQm/iHmJNPDIF2XSlMJxj12cIkOCY71jSz9FoEmKHJyO5YFR/rO0Jw8 +4NQlq5U1YjBGdhqGWdLFM4lZ4fTFz99/VMhcYDeyI35LI04vE9b55VFBhI502d2pwSMv/WyxD5Vu4Ms2 +I23XKEjF8AV6wM5g7d0+xfpqS4HbTBSgVF/RkmvKuTSqU4ebIiHtXr1rIaudd2O4p2kDNdak2+6ZBu6z +o0eOhevMhydNDXPSOhtNTp0FblNH3hW9LIZ+2UR6dDXA+s3rLO62eRDLLDZ59A2+Q/NN6Q3odnZAvTHA +S6mVi0pHxBobybsbWewootevnSMDr6q1Zz0YB4n3AIKH47ARw2Njqb0J7thmcorb+dVMoA7mnAyHV8Me +GHPIuyIeNKBsl0fl3WkBqJrw1YCAvOQS6+tPvzz6gYBSI+gHUNyZqUWpvi+3G3M9rzJkgdM2Oycydce2 +qQ1ROr2lr8vx8gl3V4DUgq+KG3Xk2vmFqverpkPux29rrQKjNfXjJqx2/d4ofJcNjYjKHbTThMNnUwOC +bgRXabKGjY03ESCfhmGFUvFBNWItGOoGpre8lZwkQuHbbrY2KbIqNxoVmZaMY7FnELmrOpLhBagMtMrd +bLuZ7AhpibO8RLnXJEliTyzS0jaSL90UDVugzfT1sN/u3TXk+z5btGoiFmwA8jvevduIz4aC9chksBOR +pDbrm/SKvO5tdcVtlQDhgzoZBu0yY1VKs8w0CMtzrl66Oartly8rVG2MbpTPAsnJ6DdMqfMITq2u/piM +bcWTnnffzQd5rGzcdTO1wZw4rDexm5oFL2fPb1q17v6O0jjBzsV49biDvcfO6reUY+c9hNevW80qIfiv ++hAcnU6GJ8dnw5OjcfBM+PHJxXXZqGmBzf4TC6Vx69AS6pOMO6Xst6Pt7lZbZ+6DDs7XYePC98xYGc9p +35m+DXvdSN4I7hhicvyv+l7r169rvJSpqr8TsW/7EEQBvH2C5oqG8V+viczpkH5Nq8EC1etW1Tkr2wt/ +PhEyQHGsvO1ObO4x+XebhB/vBIHJDMqkglQ6JiEgxoolBpILdBQzFlkjl+ij+Yov0+DG1PwWz2Vx3yeb +elqoSfs0vYWl0Nlo7NYz9JA5P/WesfI1mmZ28wtTMZ6SGMM9YjgG4U4LUg38O+tmm7emmFIwpXsNSOVi +eFlXsulV4/tSAtZ7Y0rCmrsKZ6dw8bHErKZMzqMZ55bjbLDGp6V8v+xJS2apnLFmk2TD41flI1gUT5ud +1o2vU73Y25KDb/WznuFlLdv8q43eVd2zcr2qyuNa3wjW6nPVoqQ1i8lGTS9a3+kKwmYLT7/W1VwbdEaf +SZ6TdP6qG9Qgus95Z6OuH/0X9SiemhA6yaF81s9aOQxmNFvCgvO8t7PDOJp+zh4wnSXZKppmyx208997 +uwd/+W53Z29/78OHXYHpgSDT4BN6QGxKSc4jdJ8VXLZJyD1FdL1zn5Bcy1204EvnqOm6E2deODaWj//w +SCbrdYLIeGE7O5BTzDnB9J06XvJux8l/b+Pb3bsuvIH9gw9deAuiYO+uWynZr5W8v+tWHhs0p5jF0s04 +SIulvP5ub7833N8LgurzXk6egsDX0CYtlrW3FZXeh/8SdDZEpt8LnfNXqXrevfPu4Asa4QLxRTRLsoxK +onfkaEsxEtg7Fr1gg96eG+LWsb2Il2RFPEvky0cJQQyznkpFwhyZkxUmqXRS5WxKh7ymdTq5Hl59/Ofk +6vRUpj1OLcpJTrMv6x4E2Wxmch6vRZE8C7hPcFxFcdmKIfUR4LSp/enN+XkbhlmRJB6Ot0NEknmRlrjU +2dM785KUywJ5/qRp18cf2WymtsOUE/t0jX8K1fPJ08/RtHJqotuVHGvoNa132tbN5ZO9pKaTm5QI3YGS +0ei8eWS2k5vLs59OhqPB+Wh03jSUwqBiLPFH4neSPruPy6e6UMOQ8nwzGl9dhHA9vPrp7PhkCKPrk6Oz +07MjGJ4cXQ2PYfzP65ORoxUm5ppvuRKGWL17/Btf9pUN7OXYIAy6Uu/oi/d64Mbpabj36LhR7Ql+6kXo +INw0Lv9iIWacpDJM8KxWf+zJuH7g+i0EoVBl6rS8pNg/x9Ys9JzHRj767uX/Z2YbM2+G53X+3QzPxfat +69/v7jWCvN/dM1Cnw8Z7vLLY5E+Ork8nP9ycnYsVy9FnzMqDJql5c0Q568nTZ/nTPMo3uj41tn6HZ3CP +Qfj+5oXKAIKu1OoJuseJan58OVKf9j2knJIlomsHVwSdUkf+LZDJBBStevA/Mgm8ox7blli6ys7O1MuB +RYoS9fK2McQcOs1WIimS/pigh5MllqQIn0ylRWMqn9WUasYlRT1vKW2UUD/DXj7d1LWXITRevMwTxBVu +FMdEnwWbl10Vt6byRkPsjnfC8tl/xWrQswRxjtMeDCAhjLsPjqv2GkBvnsK0XGAU7/VgsMzk0/CwfV/M +ZpgCzbLltjo+lqmm0lO0yeqE46V91D6fwXQhn6gSjPrCL9CXEfkZq3Et0ReyLJbAyM+49EbHH8eWYT+p +pBFBDOwfHKijS4qZTFlIQd7ryJPyToEz9v2Dg6DrbA6OWDZsBkqhK3n8+hWcz/KMZL8hkdcVdnuygDgk +GDEO+4D1s5Y1o1P3qAXPPdmxxa4iqDWkaCV8vfLjVb8PQVBHJer6EEwoWrF8ZtGp3UydDsn82AW2cuHI +ldrvVEQkV+dMBlrYVM6hsVg7mBtRkPZTeYlHIVAkmHizZq/O8Qu6FnG58vyltlU+1KhlVSwb+eDmfwrM +ZJqf+XMEgJzenSgFWlWQGrYqkjTekrO6oDx/2PUec7UN+hX4hgTNnR117IPi2NIi2KFpNI97pwGXL10s +c76uXn0pCW2eccnkvHIcqAqj2g0mIRXuxSjnGpMgzwTNZvJOHY7rsWNFCedJ49m+cnPHH8clxaGWgBBo +HqqXES2K7rNP+p9A3H3SG3fkyDjQQorkX0SYESFFyotQKljISVVMTDNfFtT1NSMJBsZbcD4KqV99HLbY +wyNLWhCVStXHVJZbVGWRh+u3kA3D0x83rz9fZ1TZWhGl2kxLrVjOdasM1WTnSUxlDrIXknGfF9xk0my0 +SY4Ggw22CMliPFNNp1nK1cO3JCnj0p1Mp36V4JOpfuCwBz9kWYJRKg88cRrLPw2C5e1xrRcJxfGOgY+E +zAvTw4bDvCvCzls7FM8KhuNa94wVuAfneqM4Gpi/VqKCDkm2Un8dRsK5qFnlyUroKHNFXXnRYmJMAGXo +SRwrksQ9GGjMZX9TMWbZiYCYIho39WYzPaPN/TlmgjPVrWbC8zftioAriu3moj6FFk+zFAddvxhug8Pg +7rAJhRhzBY0sakalqgw6i89Sb4ZlqXtVadyFr19LaB+4EkG3VWbH7PdhdwOYHsmmaheTygZpsMPcFVq3 +w8Sc45TTtShSlGe0FLCXGkXVqRFrs/pAmlNll239dTSpno4GA189BbJZEIKDJPTeMXU3u5aX056Pulv/ +uxqNAtxtOWUJIXEsIVcK1PlLglN17vJMCgWCkkLxdUvuut3DrbYl8Q2EOYL1cuKk7IRVtC6R1Y1EbaEI +jv9xdmFu9dq/6vLX/YPv4H7NsfcnOv5xdtFB1D68J++p6119/+CgfNV42HrVzAwfUdowZHjbL5GWox+a +XAwasYRMcYeEAtYB9Y8vhmaINhV3RVGeYyqJmSfZfacrfzp/ewaSDMkta0YSrHzpASvdB8uDDknhx6wr +eET0E+xZymmWAErXK7QO5bPjop2+ZGDvd5t0WIZSwtfvpgs8/awd3MuM454hjDB9DzOVbjsV3nWRxtm0 +UNf3YYETORabvTzKZJK9uvO/FjRlqxQoYZ8jN79YaqKJ7sXGpnR6y/4d9GH7E9s+1MexUyzUi6SEpNOk +iDFEn5hhj31pX3xCX9KuEkw6aZEkYYnZ/RMVzgGowtNyAqpp7UiglhR5WWdEGXMbyNZsF/0dnZ8JIokw +oJmzrZ6fTewL7iab2nRvxfUzlpfKq/WVh47Fvn77Ga/vZMx12x72bFf1qgNoccrvmpp73Pp/AQAA//93 +bW+i4G8AAA== `, }, } diff --git a/pkg/normalize/validate.go b/pkg/normalize/validate.go index 364a40105..468840bb5 100644 --- a/pkg/normalize/validate.go +++ b/pkg/normalize/validate.go @@ -98,9 +98,9 @@ func checkLabel(label string, rType string, target, domain string, meta map[stri if label[len(label)-1] == '.' { return fmt.Errorf("label %s.%s ends with a (.)", label, domain) } - if strings.HasSuffix(label, domain) { + if label == domain || strings.HasSuffix(label, "."+domain) { if m := meta["skip_fqdn_check"]; m != "true" { - return fmt.Errorf(`label %s ends with domain name %s. Record names should not be fully qualified. Add {skip_fqdn_check:"true"} to this record if you really want to make %s.%s`, label, domain, label, domain) + return fmt.Errorf(`label %q ends with domain name %q. Record names should not be fully qualified. Add {skip_fqdn_check:"true"} to this record if you really want to make %s.%s`, label, domain, label, domain) } } @@ -281,6 +281,13 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { if rec.TTL == 0 { rec.TTL = models.DefaultTTL } + // in-addr.arpa magic + if strings.HasSuffix(domain.Name, ".in-addr.arpa") || strings.HasSuffix(domain.Name, ".ip6.arpa") { + label := rec.GetLabel() + if label == domain.Name || strings.HasSuffix(label, "."+domain.Name) { + rec.SetLabel(label[0:(len(label)-len("."+domain.Name))], domain.Name) + } + } // Validate the unmodified inputs: if err := validateRecordTypes(rec, domain.Name, pTypes); err != nil { errs = append(errs, err) @@ -299,7 +306,7 @@ func ValidateAndNormalizeConfig(config *models.DNSConfig) (errs []error) { // We normalize them to a FQDN so there is less variation to handle. If a // provider API requires a shortname, the provider must do the shortening. origin := domain.Name + "." - if len(rec.SubDomain) > 0 { + if rec.SubDomain != "" { origin = rec.SubDomain + "." + origin } rec.SetTarget(dnsutil.AddOrigin(rec.GetTargetField(), origin)) diff --git a/pkg/transform/arpa.go b/pkg/transform/arpa.go index db700527a..12a8370d7 100644 --- a/pkg/transform/arpa.go +++ b/pkg/transform/arpa.go @@ -8,6 +8,17 @@ import ( // ReverseDomainName turns a CIDR block into a reversed (in-addr) name. func ReverseDomainName(cidr string) (string, error) { + + // If it is an IP address, add the /32 or /128 + ip := net.ParseIP(cidr) + if ip != nil { + if ip.To4() != nil { + cidr = cidr + "/32" + } else { + cidr = cidr + "/128" + } + } + a, c, err := net.ParseCIDR(cidr) if err != nil { return "", err