Last active
February 20, 2020 01:40
-
-
Save nfnty/1dec1910a5ce4ad01fee29595e9e5ba8 to your computer and use it in GitHub Desktop.
powerdns-recursor lua-dns-script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"BlacklistSuffixes": [ | |
], | |
"WhitelistSuffixes": [ | |
"bitcointalk.org." | |
], | |
"WhitelistFullmatches": [ | |
"s3.amazonaws.com.", | |
"yui.yahooapis.com." | |
], | |
"LocalSuffixes": [ | |
"test." | |
], | |
"Addresses": [ | |
{ | |
"Subnet4": "10.1.0.1/24", | |
"Gateway4": "10.1.0.1", | |
"Subnet6": "fd00:0:0:1::/64", | |
"Gateway6": "fd00:0:0:1::1", | |
"Zone": "client" | |
}, | |
{ | |
"Subnet4": "10.2.0.1/24", | |
"Gateway4": "10.2.0.1", | |
"Subnet6": "fd00:0:0:2::/64", | |
"Gateway6": "fd00:0:0:2::1", | |
"Zone": "admin" | |
} | |
], | |
"Zones": { | |
"gateway": { | |
"printer.test.": {"28": "fd00:0:0:3::2", "1": "10.3.0.2"} | |
}, | |
"client": { | |
"gateway.test.": {"28": "gateway", "1": "gateway"}, | |
"printer.test.": {"28": "fd00:0:0:3::2", "1": "10.3.0.2"} | |
}, | |
"admin": { | |
"gateway.test.": {"28": "gateway", "1": "gateway"}, | |
"printer.test.": {"28": "fd00:0:0:3::2", "1": "10.3.0.2"} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- luacheck: globals addNTA | |
-- Local | |
addNTA('test.') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- luacheck: globals preresolve pdns newNMG newCA newDS newDN pdnslog | |
local json = require('json') | |
local PATH_BLACKLISTS = '/mnt/blacklists' | |
local PATH_ETC = '/etc/powerdns' | |
local function json_decode(path) | |
local fileobject = io.open(path, 'r') | |
local decoded = json.decode(fileobject:read('*all')) | |
fileobject:close() | |
return decoded | |
end | |
local CONFIG = json_decode(PATH_ETC .. '/config.json') | |
local DS_LOCAL = newDS() | |
DS_LOCAL:add(CONFIG['LocalSuffixes']) | |
local function scandir_files(path_dir) | |
local paths_file = {} | |
for path_file in io.popen('find "' .. path_dir .. '" -type f'):lines() do | |
paths_file[#paths_file+1] = path_file | |
end | |
return paths_file | |
end | |
local function array_contains(array, value) | |
for _, value_a in ipairs(array) do | |
if value_a == value then | |
return true | |
end | |
end | |
return false | |
end | |
local function blacklists_parse(path) | |
local ds_blacklist = newDS() | |
local ds_whitelist = newDS() | |
ds_whitelist:add(CONFIG['WhitelistSuffixes']) | |
local dn_line | |
for _, path_file in ipairs(scandir_files(path)) do | |
for line in io.lines(path_file) do | |
if line ~= nil and line ~= '' then | |
dn_line = newDN(line) | |
if ds_whitelist:check(dn_line) then | |
pdnslog(json.encode({ | |
message='whitelist suffix', | |
path=path_file, | |
domain=dn_line:toString(), | |
})) | |
elseif array_contains(CONFIG['WhitelistFullmatches'], dn_line:toString()) then | |
pdnslog(json.encode({ | |
message='whitelist fullmatch', | |
path=path_file, | |
domain=dn_line:toString(), | |
})) | |
else | |
ds_blacklist:add(dn_line) | |
end | |
end | |
end | |
end | |
for _, suffix in ipairs(CONFIG['BlacklistSuffixes']) do | |
ds_blacklist:add(suffix) | |
end | |
return ds_blacklist | |
end | |
local DS_BLACKLIST = blacklists_parse(PATH_BLACKLISTS) | |
local function log_dq(dq, message) | |
pdnslog(json.encode({ | |
message=message, | |
qname=dq.qname:toString(), | |
qtype=dq.qtype, | |
rcode=dq.rcode, | |
isTcp=dq.isTcp, | |
remoteaddr=dq.remoteaddr:toString(), | |
localaddr=dq.localaddr:toString(), | |
variable=dq.variable, | |
followupFunction=dq.followupFunction, | |
followCNAMERecords=dq.followCNAMERecords, | |
getFakeAAAARecords=dq.getFakeAAAARecords, | |
getFakePTRRecords=dq.getFakePTRRecords, | |
udpQueryResponse=dq.udpQueryResponse, | |
})) | |
end | |
function preresolve(dq) | |
-- Zone | |
local zone, ca_gateway4, ca_gateway6, nmg_cidr | |
for _, dict in ipairs(CONFIG['Addresses']) do | |
ca_gateway4, ca_gateway6 = newCA(dict['Gateway4']), newCA(dict['Gateway6']) | |
nmg_cidr = newNMG() | |
nmg_cidr:addMasks({dict['Subnet4'], dict['Subnet6']}) | |
if dq.remoteaddr:equal(ca_gateway4) or dq.remoteaddr:equal(ca_gateway6) then | |
zone = CONFIG['Zones']['gateway'] | |
break | |
elseif nmg_cidr:match(dq.remoteaddr) then | |
zone = CONFIG['Zones'][dict['Zone']] | |
break | |
end | |
end | |
if not zone then | |
dq.variable = true | |
dq.rcode = pdns.NXDOMAIN | |
log_dq(dq, 'no zone') | |
return true | |
end | |
-- Blacklist | |
if DS_BLACKLIST:check(dq.qname) then | |
dq.rcode = pdns.NXDOMAIN | |
log_dq(dq, 'blacklisted') | |
return true | |
end | |
-- Local | |
if DS_LOCAL:check(dq.qname) then | |
-- No cache | |
dq.variable = true | |
-- Retrieve records | |
local records = zone[dq.qname:toString()] | |
if records == nil then | |
dq.rcode = pdns.NXDOMAIN | |
log_dq(dq, 'local unknown') | |
return true | |
end | |
-- Normal answer | |
dq.rcode = 0 | |
-- Retrieve record | |
local record = records[tostring(dq.qtype)] | |
if record == nil then | |
log_dq(dq, 'local unknown record') | |
return true | |
end | |
-- Special answer for gateway record | |
if record == 'gateway' then | |
if dq.qtype == pdns.A then | |
dq:addAnswer(dq.qtype, ca_gateway4:toString(), 3600) | |
return true | |
elseif dq.qtype == pdns.AAAA then | |
dq:addAnswer(dq.qtype, ca_gateway6:toString(), 3600) | |
return true | |
end | |
end | |
-- Answer | |
dq:addAnswer(dq.qtype, record, 3600) | |
return true | |
end | |
-- No answer | |
return false | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment