<ExcludeExitNodes {RU}
).REDIRECT
to the transparent proxy port in the PREROUTING
the nat
netfilter table.mangle
table, the label is then used to select the routing table that redirects traffic to the appropriate interface.ipset
used with hosts that are (once) blocked.ipset
with (times) blocked hostshttp://block.mts.ru/?host=/host/&url=/url/¶ms=/params/
. By address=/block.mts.ru/192.168.1.1
the same dnsmasq ( address=/block.mts.ru/192.168.1.1
) with the A-record block.mts.ru to the address of the web server of the router (and placing a simple script on it), you can locally generate a list of the requested network users resources, add them to the dnsmasq config, re-do nslookup (so that the ip address is added to ipset) and redirect the user to the original URL again. But the need to restart dnsmasq every time is somewhat dampening. Yes, and will work only for http.server=8.8.8.8, server=8.8.4.4
. I haven’t yet seen modifications by providers of third-party DNS servers. If they start, you can send domain requests from the forbidden list to another upstream (via VPN / Tor), but without need I wouldn’t have inflated the config. local config = { blSource = "antizapret", -- antizapret rublacklist groupBySld = 32, -- neverGroupMasks = { "^%a%a%a?.%a%a$" }, -- org.ru, net.ua neverGroupDomains = { ["livejournal.com"] = true, ["facebook.com"] = true , ["vk.com"] = true }, stripWww = true, convertIdn = true, torifyNsLookups = false, -- DNS TOR blMinimumEntries = 1000, -- , - dnsmasqConfigPath = "/etc/runblock/runblock.dnsmasq", ipsetConfigPath = "/etc/runblock/runblock.ipset", ipsetDns = "rublack-dns", ipsetIp = "rublack-ip", torDnsAddr = "127.0.0.1#9053" } local function prequire(package) local result, err = pcall(function() require(package) end) if not result then return nil, err end return require(package) -- return the package value end local idn = prequire("idn") if (not idn) and (config.convertIdn) then error("you need either put idn.lua (github.com/haste/lua-idn) in script dir or set 'convertIdn' to false") end local http = prequire("socket.http") if not http then local ltn12 = require("ltn12") end if not ltn12 then error("you need either install luasocket package (prefered) or put ltn12.lua in script dir") end local function hex2unicode(code) local n = tonumber(code, 16) if (n < 128) then return string.char(n) elseif (n < 2048) then return string.char(192 + ((n - (n % 64)) / 64), 128 + (n % 64)) else return string.char(224 + ((n - (n % 4096)) / 4096), 128 + (((n % 4096) - (n % 64)) / 64), 128 + (n % 64)) end end local function rublacklistExtractDomains() local currentRecord = "" local buffer = "" local bufferPos = 1 local streamEnded = false return function(chunk) local retVal = "" if chunk == nil then streamEnded = true else buffer = buffer .. chunk end while true do local escapeStart, escapeEnd, escapedChar = buffer:find("\\(.)", bufferPos) if escapedChar then currentRecord = currentRecord .. buffer:sub(bufferPos, escapeStart - 1) bufferPos = escapeEnd + 1 if escapedChar == "n" then retVal = currentRecord break elseif escapedChar == "u" then currentRecord = currentRecord .. "\\u" else currentRecord = currentRecord .. escapedChar end else currentRecord = currentRecord .. buffer:sub(bufferPos, #buffer) buffer = "" bufferPos = 1 if streamEnded then if currentRecord == "" then retVal = nil else retVal = currentRecord end end break end end if retVal and (retVal ~= "") then currentRecord = "" retVal = retVal:match("^[^;]*;([^;]+);[^;]*;[^;]*;[^;]*;[^;]*.*$") if retVal then retVal = retVal:gsub("\\u(%x%x%x%x)", hex2unicode) else retVal = "" end end return (retVal) end end local function antizapretExtractDomains() local currentRecord = "" local buffer = "" local bufferPos = 1 local streamEnded = false return function(chunk) local haveOutput = 0 local retVal = "" if chunk == nil then streamEnded = true else buffer = buffer .. chunk end local newlinePosition = buffer:find("\n", bufferPos) if newlinePosition then currentRecord = currentRecord .. buffer:sub(bufferPos, newlinePosition - 1) bufferPos = newlinePosition + 1 retVal = currentRecord else currentRecord = currentRecord .. buffer:sub(bufferPos, #buffer) buffer = "" bufferPos = 1 if streamEnded then if currentRecord == "" then retVal = nil else retVal = currentRecord end end end if retVal and (retVal ~= "") then currentRecord = "" end return (retVal) end end local function normalizeFqdn() return function(chunk) if chunk and (chunk ~= "") then if config["stripWww"] then chunk = chunk:gsub("^www%.", "") end if idn and config["convertIdn"] then chunk = idn.encode(chunk) end if #chunk > 255 then chunk = "" end chunk = chunk:lower() end return (chunk) end end local function cunstructTables(bltables) bltables = bltables or { fqdn = {}, sdcount = {}, ips = {} } local f = function(blEntry, err) if blEntry and (blEntry ~= "") then if blEntry:match("^%d+%.%d+%.%d+%.%d+$") then -- ip - iptables if not bltables.ips[blEntry] then bltables.ips[blEntry] = true end else -- , FQDN . 2 ( bl TLD - :)) local subDomain, secondLevelDomain = blEntry:match("^([a-z0-9%-%.]-)([a-z0-9%-]+%.[a-z0-9%-]+)$") if secondLevelDomain then bltables.fqdn[blEntry] = secondLevelDomain if 1 > 0 then bltables.sdcount[secondLevelDomain] = (bltables.sdcount[secondLevelDomain] or 0) + 1 end end end end return 1 end return f, bltables end local function compactDomainList(fqdnList, subdomainsCount) local domainTable = {} local numEntries = 0 if config.groupBySld and (config.groupBySld > 0) then for sld in pairs(subdomainsCount) do if config.neverGroupDomains[sld] then subdomainsCount[sld] = 0 break end for _, pattern in ipairs(config.neverGroupMasks) do if sld:find(pattern) then subdomainsCount[sld] = 0 break end end end end for fqdn, sld in pairs(fqdnList) do if (not fqdnList[sld]) or (fqdn == sld) then local keyValue; if config.groupBySld and (config.groupBySld > 0) and (subdomainsCount[sld] > config.groupBySld) then keyValue = sld else keyValue = fqdn end if not domainTable[keyValue] then domainTable[keyValue] = true numEntries = numEntries + 1 end end end return domainTable, numEntries end local function generateDnsmasqConfig(configPath, domainList) local configFile = assert(io.open(configPath, "w"), "could not open dnsmasq config") for fqdn in pairs(domainList) do if config.torifyNsLookups then configFile:write(string.format("server=/%s/%s\n", fqdn, config.torDnsAddr)) end configFile:write(string.format("ipset=/%s/%s\n", fqdn, config.ipsetDns)) end configFile:close() end local function generateIpsetConfig(configPath, ipList) local configFile = assert(io.open(configPath, "w"), "could not open ipset config") configFile:write(string.format("flush %s-tmp\n", config.ipsetIp)) for ipaddr in pairs(ipList) do configFile:write(string.format("add %s %s\n", config.ipsetIp, ipaddr)) end configFile:write(string.format("swap %s %s-tmp\n", config.ipsetIp, config.ipsetIp)) configFile:close() end local retVal, retCode, url local output, bltables = cunstructTables() if config.blSource == "rublacklist" then output = ltn12.sink.chain(ltn12.filter.chain(rublacklistExtractDomains(), normalizeFqdn()), output) url = "http://reestr.rublacklist.net/api/current" elseif config.blSource == "antizapret" then output = ltn12.sink.chain(ltn12.filter.chain(antizapretExtractDomains(), normalizeFqdn()), output) url = "http://api.antizapret.info/group.php?data=domain" else error("blacklist source should be either 'rublacklist' or 'antizapret'") end if http then retVal, retCode = http.request { url = url, sink = output } else retVal, retCode = ltn12.pump.all(ltn12.source.file(io.popen("wget -qO- " .. url)), output) end if (retVal == 1) and ((retCode == 200) or (http == nil)) then local domainTable, recordsNum = compactDomainList(bltables.fqdn, bltables.sdcount) if recordsNum > config.blMinimumEntries then generateDnsmasqConfig(config.dnsmasqConfigPath, domainTable) generateIpsetConfig(config.ipsetConfigPath, bltables.ips) print(string.format("blacklists updated. %d entries.", recordsNum)) os.exit(0) end end os.exit(1)
server=/onion/127.0.0.1#9053 ipset=/onion/onion conf-file=/etc/runblock/runblock.dnsmasq
list server '8.8.8.8' list server '8.8.4.4' list rebind_domain 'onion'
config ipset option name 'rublack-dns' option storage 'hash' option match 'dest_ip' option timeout '86400' config ipset option name 'rublack-ip' option storage 'hash' option match 'dest_ip' config ipset option name 'rublack-ip-tmp' option storage 'hash' option match 'dest_ip' config ipset option name 'onion' option storage 'hash' option match 'dest_ip' option timeout '86400' config redirect option name 'torify-blocked-dns' option src 'lan' option proto 'tcp' option ipset 'rublack-dns' option dest_port '9040' option dest 'lan' config redirect option name 'torify-blocked-ip' option src 'lan' option proto 'tcp' option ipset 'rublack-ip' option dest_port '9040' option dest 'lan' config redirect option name 'torify-onion' option src 'lan' option proto 'tcp' option ipset 'onion' option dest_port '9040' option dest 'lan'
cat /etc/runblock/runblock.ipset | ipset restore
User tor PidFile /var/run/tor.pid DataDirectory /var/lib/tor ExcludeExitNodes {RU} VirtualAddrNetwork 10.254.0.0/16 # .onion AutomapHostsOnResolve 1 TransPort 9040 TransListenAddress 127.0.0.1 TransListenAddress 192.168.1.1 # LAN DNSPort 9053 DNSListenAddress 127.0.0.1 #AvoidDiskWrites 1 # OpenWrt /var RAM (tmpfs) ,
/etc/runblock
, manually launch the lua /usr/bin/rublupdate.lua
script one-time, make sure that it worked without errors, add it to cron (a couple of times a day is enough) and forget about the Roskomnadzor. Well, until they start to block the torus, or sites that publish the registry).Source: https://habr.com/ru/post/270657/
All Articles