diff --git a/modules/policy/README.rst b/modules/policy/README.rst
index 96a010dbbbe78159130b1c99f555f978be1d3496..ca2675a4836481d7d462627189a3ba8bd8536634 100644
--- a/modules/policy/README.rst
+++ b/modules/policy/README.rst
@@ -25,6 +25,7 @@ There are several defined actions:
 * ``DROP`` - terminate query resolution, returns SERVFAIL to requestor
 * ``TC`` - set TC=1 if the request came through UDP, forcing client to retry with TCP
 * ``FORWARD(ip)`` - forward query to given IP and proxy back response (stub mode)
+* ``REROUTE({{subnet,target}, ...})`` - reroute addresses in response matching given subnet to given target, e.g. ``{'192.0.2.0/24', '127.0.0.0'}`` will rewrite '192.0.2.55' to '127.0.0.55', see :ref:`renumber module <mod-renumber>` for more information.
 
 .. note:: The module (and ``kres``) expects domain names in wire format, not textual representation. So each label in name is prefixed with its length, e.g. "example.com" equals to ``"\7example\3com"``. You can use convenience function ``todname('example.com')`` for automatic conversion.
 
diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua
index dec443d4a073b04c69fbc8206fcd8d355fec64de..eb911fd7b5f736eb42d2bbce3d1feb845ff15e1f 100644
--- a/modules/policy/policy.lua
+++ b/modules/policy/policy.lua
@@ -13,9 +13,22 @@ local function forward(target)
 	end
 end
 
+-- Rewrite records in packet
+local function reroute(tbl, names)
+	-- Import renumbering rules
+	local ren = require('renumber')
+	local prefixes = {}
+	for from, to in pairs(tbl) do
+		table.insert(prefixes, names and ren.name(from, to) or ren.prefix(from, to))
+	end
+	-- Return rule closure
+	tbl = nil
+	return ren.rule(prefixes)
+end
+
 local policy = {
 	-- Policies
-	PASS = 1, DENY = 2, DROP = 3, TC = 4, FORWARD = forward,
+	PASS = 1, DENY = 2, DROP = 3, TC = 4, FORWARD = forward, REROUTE = reroute,
 	-- Special values
 	ANY = 0,
 }
@@ -120,9 +133,9 @@ function policy.rpz(action, path, format)
 end
 
 -- Evaluate packet in given rules to determine policy action
-function policy.evaluate(policy, req, query)
-	for i = 1, #policy.rules do
-		local action = policy.rules[i](req, query)
+function policy.evaluate(rules, req, query)
+	for i = 1, #rules do
+		local action = rules[i](req, query)
 		if action ~= nil then
 			return action
 		end
@@ -158,7 +171,12 @@ end
 policy.layer = {
 	begin = function(state, req)
 		req = kres.request_t(req)
-		local action = policy:evaluate(req, req:current())
+		local action = policy.evaluate(policy.rules, req, req:current())
+		return policy.enforce(state, req, action)
+	end,
+	finish = function(state, req)
+		req = kres.request_t(req)
+		local action = policy.evaluate(policy.postrules, req, req:current())
 		return policy.enforce(state, req, action)
 	end
 }
@@ -218,5 +236,6 @@ policy.todnames(private_zones)
 
 -- @var Default rules
 policy.rules = { policy.suffix_common(policy.DENY, private_zones, '\4arpa\0') }
+policy.postrules = {}
 
 return policy
diff --git a/modules/renumber/renumber.lua b/modules/renumber/renumber.lua
index 17fb302d472ea5fb8a27eab49c98d6ecc108404c..c4afb7366eb565f431cbaccd7fa86a88d91b65be 100644
--- a/modules/renumber/renumber.lua
+++ b/modules/renumber/renumber.lua
@@ -2,33 +2,59 @@
 local policy = require('policy')
 local ffi = require('ffi')
 local bit = require('bit')
-local mod = {}
 local prefixes = {}
--- Add subnet prefix rewrite rule
-local function add_prefix(subnet, addr)
+
+-- Create subnet prefix rule
+local function matchprefix(subnet, addr)
 	local target = kres.str2ip(addr)
 	if target == nil then error('[renumber] invalid address: '..addr) end
+	local addrtype = string.find(addr, ':', 1, true) and kres.type.AAAA or kres.type.A
 	local subnet_cd = ffi.new('char[16]')
-	local family = ffi.C.kr_straddr_family(subnet)
 	local bitlen = ffi.C.kr_straddr_subnet(subnet_cd, subnet)
-	table.insert(prefixes, {family, subnet_cd, bitlen, target})
+	-- Mask unspecified, renumber whole IP
+	if bitlen == 0 then
+		bitlen = #target * 8
+	end
+	return {subnet_cd, bitlen, target, addrtype}
+end
+
+-- Create name match rule
+local function matchname(name, addr)
+	local target = kres.str2ip(addr)
+	if target == nil then error('[renumber] invalid address: '..addr) end
+	local owner = todname(name)
+	if not name then error('[renumber] invalid name: '..name) end
+	local addrtype = string.find(addr, ':', 1, true) and kres.type.AAAA or kres.type.A
+	return {owner, nil, target, addrtype}
+end
+
+-- Add subnet prefix rewrite rule
+local function add_prefix(subnet, addr)
+	table.insert(prefixes, matchprefix(subnet, addr))
 end
--- Match IP against given subnet
-local function match_subnet(family, subnet, bitlen, addr)
-	return (#addr >= bitlen / 8) and (ffi.C.kr_bitcmp(subnet, addr, bitlen) == 0)
+
+-- Match IP against given subnet or record owner
+local function match_subnet(subnet, bitlen, addrtype, rr)
+	local addr = rr.rdata
+	return addrtype == rr.type and
+	       ((bitlen and (#addr >= bitlen / 8) and (ffi.C.kr_bitcmp(subnet, addr, bitlen) == 0)) or subnet == rr.owner)
 end
+
 -- Renumber address record
 local addr_buf = ffi.new('char[16]')
-local function renumber(tbl, rr)
+local function renumber_record(tbl, rr)
 	for i = 1, #tbl do
 		local prefix = tbl[i]
-		if match_subnet(prefix[1], prefix[2], prefix[3], rr.rdata) then
-			local to_copy = prefix[3]
+		-- Match record type to address family and record address to given subnet
+		-- If provided, compare record owner to prefix name
+		if match_subnet(prefix[1], prefix[2], prefix[4], rr) then
+			-- Replace part or whole address
+			local to_copy = prefix[2] or (#prefix[3] * 8)
 			local chunks = to_copy / 8
 			local rdlen = #rr.rdata
 			if rdlen < chunks then return rr end -- Address length mismatch
 			ffi.copy(addr_buf, rr.rdata, rdlen)
-			ffi.copy(addr_buf, prefix[4], chunks)
+			ffi.copy(addr_buf, prefix[3], chunks)
 			-- @todo: CIDR not supported
 			to_copy = to_copy - chunks * 8
 			rr.rdata = ffi.string(addr_buf, rdlen)
@@ -37,17 +63,10 @@ local function renumber(tbl, rr)
 	end	
 	return nil
 end
--- Config
-function mod.config (conf)
-	if conf == nil then return end
-	if type(conf) ~= 'table' or type(conf[1]) ~= 'table' then
-		error('[renumber] expected { {prefix, target}, ... }')
-	end
-	for i = 1, #conf do add_prefix(conf[i][1], conf[1][2]) end
-end
--- Layers
-mod.layer = {
-	finish = function (state, req)
+
+-- Renumber addresses based on config
+local function rule(prefixes)
+	return function (state, req)
 		if state == kres.FAIL then return state end
 		req = kres.request_t(req)
 		pkt = kres.pkt_t(req.answer)
@@ -59,8 +78,8 @@ mod.layer = {
 		local changed = false
 		for i = 1, ancount do
 			local rr = records[i]
-			if rr.type == kres.type.A then
-				local new_rr = renumber(prefixes, rr)
+			if rr.type == kres.type.A or rr.type == kres.type.AAAA then
+				local new_rr = renumber_record(prefixes, rr)
 				if new_rr ~= nil then
 					records[i] = new_rr
 					changed = true
@@ -83,5 +102,27 @@ mod.layer = {
 		end
 		return state
 	end
+end
+
+-- Export module interface
+local M = {
+	prefix = matchprefix,
+	name = matchname,
+	rule = rule,
+}
+
+-- Config
+function M.config (conf)
+	if conf == nil then return end
+	if type(conf) ~= 'table' or type(conf[1]) ~= 'table' then
+		error('[renumber] expected { {prefix, target}, ... }')
+	end
+	for i = 1, #conf do add_prefix(conf[i][1], conf[1][2]) end
+end
+
+-- Layers
+M.layer = {
+	finish = rule(prefixes),
 }
-return mod
+
+return M