diff --git a/modules/policy/README.rst b/modules/policy/README.rst
index 40edc49c1ab5f686c2b65490933d21466d6e0590..a0af187ba667f18b17e5686598bf5c7fec4fac80 100644
--- a/modules/policy/README.rst
+++ b/modules/policy/README.rst
@@ -24,6 +24,7 @@ There are several defined actions:
 * ``DENY`` - return NXDOMAIN answer
 * ``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)
 
 .. note:: The module (and ``kres``) treats domain names as wire, not textual representation. So each label in name is prefixed with its length, e.g. "example.com" equals to ``"\7example\3com"``.
 
@@ -52,14 +53,21 @@ Example configuration
 	end)
 	-- Enforce local RPZ
 	policy:add(policy.rpz(policy.DENY, 'blacklist.rpz'))
+  -- Forward all queries below 'company.se' to given resolver
+  policy:add(policy.suffix(policy.FORWARD('192.168.1.1'), {'\7company\2se'}))
+  -- Forward all queries matching pattern
+  policy:add(policy.pattern(policy.FORWARD('2001:DB8::1'), '\4bad[0-9]\2cz'))
+  -- Forward all queries (complete stub mode)
+  policy:add(policy.all(policy.FORWARD('2001:DB8::1')))
 
 Properties
 ^^^^^^^^^^
 
-.. envvar:: policy.PASS (number)
-.. envvar:: policy.DENY (number)
-.. envvar:: policy.DROP (number)
-.. envvar:: policy.TC   (number)
+.. envvar:: policy.PASS    (number)
+.. envvar:: policy.DENY    (number)
+.. envvar:: policy.DROP    (number)
+.. envvar:: policy.TC      (number)
+.. envvar:: policy.FORWARD (function)
 
 .. function:: policy:add(rule)
 
@@ -68,6 +76,12 @@ Properties
   
   Policy to block queries based on the QNAME regex matching.
 
+.. function:: policy.all(action)
+
+  :param action: executed action for all queries
+  
+  Perform action for all queries (no filtering).
+
 .. function:: policy.pattern(action, pattern)
 
   :param action: action if the pattern matches QNAME
diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua
index eeed4c5f83bfa05239e724857e84044f4584d06b..f67f5526cc6b5dd2f40e4c7f02c3e343f73fac72 100644
--- a/modules/policy/policy.lua
+++ b/modules/policy/policy.lua
@@ -1,11 +1,30 @@
 local kres = require('kres')
+
+-- Forward request, and solve as stub query
+local function forward(target)
+	local dst_ip = kres.str2ip(target)
+	if dst_ip == nil then error("FORWARD target '"..target..'" is not a valid IP address') end
+	return function(state, req)
+		req = kres.request_t(req)
+		local qry = req:current()
+		qry.flags = qry.flags + kres.query.STUB
+		qry:nslist(dst_ip)
+		return state
+	end
+end
+
 local policy = {
 	-- Policies
-	PASS = 1, DENY = 2, DROP = 3, TC = 4,
+	PASS = 1, DENY = 2, DROP = 3, TC = 4, FORWARD = forward,
 	-- Special values
 	ANY = 0,
 }
 
+-- All requests
+function policy.all(action)
+	return function(req, query) return action end
+end
+
 -- Requests which QNAME matches given zone list (i.e. suffix match)
 function policy.suffix(action, zone_list)
 	local AC = require('aho-corasick')
@@ -127,6 +146,8 @@ function policy.enforce(state, req, action)
 			answer:tc(1) -- ^ Only UDP queries
 			return kres.DONE
 		end
+	elseif type(action) == 'function' then
+		return action(state, req)
 	end
 	return state
 end
diff --git a/modules/view/README.rst b/modules/view/README.rst
index 0aebb6825b9df09e46910d4c2d826914d49affd0..ffa264ebf23fcde6b7da36ff7719f933bc9a12f2 100644
--- a/modules/view/README.rst
+++ b/modules/view/README.rst
@@ -38,6 +38,8 @@ Example configuration
 	view:addr('10.0.0.0/8', policy.suffix(policy.DROP, {'\3xxx'}))
 	-- RPZ for subset of clients
 	view:addr('192.168.1.0/24', policy.rpz(policy.PASS, 'whitelist.rpz'))
+	-- Forward all queries from given subnet to proxy
+	view:addr('10.0.0.0/8', policy.all(policy.FORWARD('2001:DB8::1')))
 
 Properties
 ^^^^^^^^^^