1333537SdesIndex: daemon/worker.c
2333537Sdes===================================================================
3333537Sdes--- daemon/worker.c	(revision 4191)
4333537Sdes+++ daemon/worker.c	(working copy)
5333537Sdes@@ -663,8 +663,21 @@
6333537Sdes 		if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
7333537Sdes 			LDNS_RCODE_SERVFAIL, edns, worker->scratchpad))
8333537Sdes 			goto bail_out;
9333537Sdes-		error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
10333537Sdes-			qinfo, id, flags, edns);
11333537Sdes+		if (qinfo->qtype == LDNS_RR_TYPE_A &&
12333537Sdes+			worker->env.cfg->redirect_bogus_ipv4) {
13333537Sdes+			/* BAD cached */
14333537Sdes+			fixed_address_encode(repinfo->c->buffer,
15333537Sdes+				LDNS_RCODE_NOERROR, qinfo, id, flags, edns,
16333537Sdes+				worker->env.cfg->redirect_bogus_ipv4);
17333537Sdes+		} else if (qinfo->qtype == LDNS_RR_TYPE_AAAA &&
18333537Sdes+			worker->env.cfg->redirect_bogus_ipv6) {
19333537Sdes+			fixed_address_encode(repinfo->c->buffer,
20333537Sdes+				LDNS_RCODE_NOERROR, qinfo, id, flags, edns,
21333537Sdes+				worker->env.cfg->redirect_bogus_ipv6);
22333537Sdes+		} else {
23333537Sdes+			error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL, 
24333537Sdes+ 			qinfo, id, flags, edns);
25333537Sdes+		}
26333537Sdes 		rrset_array_unlock_touch(worker->env.rrset_cache, 
27333537Sdes 			worker->scratchpad, rep->ref, rep->rrset_count);
28333537Sdes 		if(worker->stats.extended) {
29333537SdesIndex: doc/unbound.conf.5.in
30333537Sdes===================================================================
31333537Sdes--- doc/unbound.conf.5.in	(revision 4191)
32333537Sdes+++ doc/unbound.conf.5.in	(working copy)
33333537Sdes@@ -1244,6 +1244,18 @@
34333537Sdes This can make ordinary queries complete (if repeatedly queried for),
35333537Sdes and enter the cache, whilst also mitigating the traffic flow by the
36333537Sdes factor given.
37333537Sdes+.TP 5
38333537Sdes+.B redirect-bogus-ipv4: \fI<IPv4 address>
39333537Sdes+Set a fixed address for DNSSEC failures that are cached
40333537Sdes+Instead of responding to A queries with SERVFAIL, respond
41333537Sdes+with NOERROR and the address specified here
42333537Sdes+The TTL of the response will be 5 seconds
43333537Sdes+.TP 5
44333537Sdes+.B redirect-bogus-ipv6: \fI<IPv4 address>
45333537Sdes+Set a fixed address for DNSSEC failures that are cached
46333537Sdes+Instead of responding to AAAA queries with SERVFAIL, respond
47333537Sdes+with NOERROR and the address specified here
48333537Sdes+The TTL of the response will be 5 seconds
49333537Sdes .SS "Remote Control Options"
50333537Sdes In the
51333537Sdes .B remote\-control:
52333537SdesIndex: services/mesh.c
53333537Sdes===================================================================
54333537Sdes--- services/mesh.c	(revision 4191)
55333537Sdes+++ services/mesh.c	(working copy)
56333537Sdes@@ -1006,6 +1006,7 @@
57333537Sdes 	struct timeval end_time;
58333537Sdes 	struct timeval duration;
59333537Sdes 	int secure;
60333537Sdes+	int bogus_override = 0;
61333537Sdes 	/* Copy the client's EDNS for later restore, to make sure the edns
62333537Sdes 	 * compare is with the correct edns options. */
63333537Sdes 	struct edns_data edns_bak = r->edns;
64333537Sdes@@ -1016,6 +1017,7 @@
65333537Sdes 		rcode = LDNS_RCODE_SERVFAIL;
66333537Sdes 		if(m->s.env->cfg->stat_extended) 
67333537Sdes 			m->s.env->mesh->ans_bogus++;
68333537Sdes+		bogus_override = 1;
69333537Sdes 	}
70333537Sdes 	if(rep && rep->security == sec_status_secure)
71333537Sdes 		secure = 1;
72333537Sdes@@ -1047,17 +1049,34 @@
73333537Sdes 	} else if(rcode) {
74333537Sdes 		m->s.qinfo.qname = r->qname;
75333537Sdes 		m->s.qinfo.local_alias = r->local_alias;
76333537Sdes-		if(rcode == LDNS_RCODE_SERVFAIL) {
77333537Sdes-			if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
78333537Sdes-				rep, rcode, &r->edns, m->s.region))
79333537Sdes-					r->edns.opt_list = NULL;
80333537Sdes-		} else { 
81333537Sdes-			if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
82333537Sdes-				&r->edns, m->s.region))
83333537Sdes-					r->edns.opt_list = NULL;
84333537Sdes+		if(bogus_override && m->s.qinfo.qtype == LDNS_RR_TYPE_A &&
85333537Sdes+			m->s.env->cfg->redirect_bogus_ipv4) {
86333537Sdes+			fixed_address_encode(r->query_reply.c->buffer,
87333537Sdes+				LDNS_RCODE_NOERROR, &m->s.qinfo, r->qid,
88333537Sdes+				r->qflags, &r->edns,
89333537Sdes+				m->s.env->cfg->redirect_bogus_ipv4);
90333537Sdes+		} else if(bogus_override &&
91333537Sdes+			m->s.qinfo.qtype == LDNS_RR_TYPE_AAAA &&
92333537Sdes+			m->s.env->cfg->redirect_bogus_ipv6) {
93333537Sdes+			fixed_address_encode(r->query_reply.c->buffer,
94333537Sdes+				LDNS_RCODE_NOERROR, &m->s.qinfo, r->qid,
95333537Sdes+				r->qflags, &r->edns,
96333537Sdes+				m->s.env->cfg->redirect_bogus_ipv6);
97333537Sdes+		} else {
98333537Sdes+			if(rcode == LDNS_RCODE_SERVFAIL) {
99333537Sdes+				if(!inplace_cb_reply_servfail_call(m->s.env,
100333537Sdes+					&m->s.qinfo, &m->s,
101333537Sdes+					rep, rcode, &r->edns, m->s.region))
102333537Sdes+						r->edns.opt_list = NULL;
103333537Sdes+			} else { 
104333537Sdes+				if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo,
105333537Sdes+					&m->s, rep, rcode, &r->edns,
106333537Sdes+					m->s.region))
107333537Sdes+						r->edns.opt_list = NULL;
108333537Sdes+			}
109333537Sdes+			error_encode(r->query_reply.c->buffer, rcode,
110333537Sdes+				&m->s.qinfo, r->qid, r->qflags, &r->edns);
111333537Sdes 		}
112333537Sdes-		error_encode(r->query_reply.c->buffer, rcode, &m->s.qinfo,
113333537Sdes-			r->qid, r->qflags, &r->edns);
114333537Sdes 		comm_point_send_reply(&r->query_reply);
115333537Sdes 	} else {
116333537Sdes 		size_t udp_size = r->edns.udp_size;
117333537SdesIndex: util/config_file.c
118333537Sdes===================================================================
119333537Sdes--- util/config_file.c	(revision 4191)
120333537Sdes+++ util/config_file.c	(working copy)
121333537Sdes@@ -273,6 +273,8 @@
122333537Sdes 	cfg->ratelimit_factor = 10;
123333537Sdes 	cfg->qname_minimisation = 0;
124333537Sdes 	cfg->qname_minimisation_strict = 0;
125333537Sdes+	cfg->redirect_bogus_ipv4 = NULL;
126333537Sdes+	cfg->redirect_bogus_ipv6 = NULL;
127333537Sdes 	cfg->shm_enable = 0;
128333537Sdes 	cfg->shm_key = 11777;
129333537Sdes 	cfg->dnscrypt = 0;
130333537Sdes@@ -602,6 +604,10 @@
131333537Sdes 		}
132333537Sdes 		oi[cfg->num_out_ifs++] = d;
133333537Sdes 		cfg->out_ifs = oi;
134333537Sdes+	} else if (strcmp(opt, "redirect-bogus-ipv4:") == 0) {
135333537Sdes+		cfg->redirect_bogus_ipv4 = strdup(val);
136333537Sdes+	} else if (strcmp(opt, "redirect-bogus-ipv6:") == 0) {
137333537Sdes+		cfg->redirect_bogus_ipv6 = strdup(val);
138333537Sdes 	} else {
139333537Sdes 		/* unknown or unsupported (from the set_option interface):
140333537Sdes 		 * interface, outgoing-interface, access-control,
141333537Sdes@@ -1250,6 +1256,12 @@
142333537Sdes 	free(cfg->dnstap_version);
143333537Sdes 	config_deldblstrlist(cfg->ratelimit_for_domain);
144333537Sdes 	config_deldblstrlist(cfg->ratelimit_below_domain);
145333537Sdes+	if (cfg->redirect_bogus_ipv4) {
146333537Sdes+		free(cfg->redirect_bogus_ipv4);
147333537Sdes+	}
148333537Sdes+	if (cfg->redirect_bogus_ipv6) {
149333537Sdes+		free(cfg->redirect_bogus_ipv6);
150333537Sdes+	}
151333537Sdes #ifdef USE_IPSECMOD
152333537Sdes 	free(cfg->ipsecmod_hook);
153333537Sdes 	config_delstrlist(cfg->ipsecmod_whitelist);
154333537SdesIndex: util/config_file.h
155333537Sdes===================================================================
156333537Sdes--- util/config_file.h	(revision 4191)
157333537Sdes+++ util/config_file.h	(working copy)
158333537Sdes@@ -444,6 +444,9 @@
159333537Sdes 	/** minimise QNAME in strict mode, minimise according to RFC.
160333537Sdes 	 *  Do not apply fallback */
161333537Sdes 	int qname_minimisation_strict;
162333537Sdes+	/** construct fake responses for DNSSEC failures */
163333537Sdes+	char *redirect_bogus_ipv4;
164333537Sdes+	char *redirect_bogus_ipv6;
165333537Sdes 	/** SHM data - true if shm is enabled */
166333537Sdes 	int shm_enable;
167333537Sdes 	/** SHM data - key for the shm */
168333537SdesIndex: util/configlexer.lex
169333537Sdes===================================================================
170333537Sdes--- util/configlexer.lex	(revision 4191)
171333537Sdes+++ util/configlexer.lex	(working copy)
172333537Sdes@@ -410,6 +410,8 @@
173333537Sdes response-ip-tag{COLON}		{ YDVAR(2, VAR_RESPONSE_IP_TAG) }
174333537Sdes response-ip{COLON}		{ YDVAR(2, VAR_RESPONSE_IP) }
175333537Sdes response-ip-data{COLON}		{ YDVAR(2, VAR_RESPONSE_IP_DATA) }
176333537Sdes+redirect-bogus-ipv4{COLON}	{ YDVAR(1, VAR_REDIRECT_BOGUS_IPV4) }
177333537Sdes+redirect-bogus-ipv6{COLON}	{ YDVAR(1, VAR_REDIRECT_BOGUS_IPV6) }
178333537Sdes dnscrypt{COLON}			{ YDVAR(0, VAR_DNSCRYPT) }
179333537Sdes dnscrypt-enable{COLON}		{ YDVAR(1, VAR_DNSCRYPT_ENABLE) }
180333537Sdes dnscrypt-port{COLON}		{ YDVAR(1, VAR_DNSCRYPT_PORT) }
181333537SdesIndex: util/configparser.y
182333537Sdes===================================================================
183333537Sdes--- util/configparser.y	(revision 4191)
184333537Sdes+++ util/configparser.y	(working copy)
185333537Sdes@@ -44,6 +44,7 @@
186333537Sdes #include <stdlib.h>
187333537Sdes #include <assert.h>
188333537Sdes 
189333537Sdes+#include "sldns/str2wire.h"
190333537Sdes #include "util/configyyrename.h"
191333537Sdes #include "util/config_file.h"
192333537Sdes #include "util/net_help.h"
193333537Sdes@@ -141,6 +142,7 @@
194333537Sdes %token VAR_ACCESS_CONTROL_TAG_DATA VAR_VIEW VAR_ACCESS_CONTROL_VIEW
195333537Sdes %token VAR_VIEW_FIRST VAR_SERVE_EXPIRED VAR_FAKE_DSA VAR_FAKE_SHA1
196333537Sdes %token VAR_LOG_IDENTITY VAR_HIDE_TRUSTANCHOR VAR_TRUST_ANCHOR_SIGNALING
197333537Sdes+%token VAR_REDIRECT_BOGUS_IPV4 VAR_REDIRECT_BOGUS_IPV6
198333537Sdes %token VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY
199333537Sdes %token VAR_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER
200333537Sdes %token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT
201333537Sdes@@ -228,6 +230,7 @@
202333537Sdes 	server_access_control_tag_data | server_access_control_view |
203333537Sdes 	server_qname_minimisation_strict | server_serve_expired |
204333537Sdes 	server_fake_dsa | server_log_identity | server_use_systemd |
205333537Sdes+	server_redirect_bogus_ipv4 | server_redirect_bogus_ipv6 |
206333537Sdes 	server_response_ip_tag | server_response_ip | server_response_ip_data |
207333537Sdes 	server_shm_enable | server_shm_key | server_fake_sha1 |
208333537Sdes 	server_hide_trustanchor | server_trust_anchor_signaling |
209333537Sdes@@ -1873,6 +1876,34 @@
210333537Sdes 	#endif
211333537Sdes 	}
212333537Sdes 	;
213333537Sdes+server_redirect_bogus_ipv4: VAR_REDIRECT_BOGUS_IPV4 STRING_ARG
214333537Sdes+	{
215333537Sdes+		uint8_t data[4];
216333537Sdes+		size_t data_len = 4;
217333537Sdes+		OUTYY(("P(name:%s)\n", $2));
218333537Sdes+		if(cfg_parser->cfg->redirect_bogus_ipv4) {
219333537Sdes+			yyerror("redirect-bogus-ipv4, can only use one address");
220333537Sdes+		}
221333537Sdes+		if(sldns_str2wire_a_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) {
222333537Sdes+			yyerror("redirect-bogus-ipv4, not a valid IPv4 address");
223333537Sdes+		}
224333537Sdes+		free(cfg_parser->cfg->redirect_bogus_ipv4);
225333537Sdes+		cfg_parser->cfg->redirect_bogus_ipv4 = $2;
226333537Sdes+	}
227333537Sdes+server_redirect_bogus_ipv6: VAR_REDIRECT_BOGUS_IPV6 STRING_ARG
228333537Sdes+	{
229333537Sdes+		uint8_t data[16];
230333537Sdes+		size_t data_len = 16;
231333537Sdes+		OUTYY(("P(name:%s)\n", $2));
232333537Sdes+		if(cfg_parser->cfg->redirect_bogus_ipv6) {
233333537Sdes+			yyerror("redirect-bogus-ipv6, can only use one address");
234333537Sdes+		}
235333537Sdes+		if(sldns_str2wire_aaaa_buf($2, data, &data_len) != LDNS_WIREPARSE_ERR_OK) {
236333537Sdes+			yyerror("redirect-bogus-ipv6, not a valid IPv6 address");
237333537Sdes+		}
238333537Sdes+		free(cfg_parser->cfg->redirect_bogus_ipv6);
239333537Sdes+		cfg_parser->cfg->redirect_bogus_ipv6 = $2;
240333537Sdes+	}
241333537Sdes stub_name: VAR_NAME STRING_ARG
242333537Sdes 	{
243333537Sdes 		OUTYY(("P(name:%s)\n", $2));
244333537SdesIndex: util/data/msgencode.c
245333537Sdes===================================================================
246333537Sdes--- util/data/msgencode.c	(revision 4191)
247333537Sdes+++ util/data/msgencode.c	(working copy)
248333537Sdes@@ -48,6 +48,7 @@
249333537Sdes #include "util/regional.h"
250333537Sdes #include "util/net_help.h"
251333537Sdes #include "sldns/sbuffer.h"
252333537Sdes+#include "sldns/str2wire.h"
253333537Sdes #include "services/localzone.h"
254333537Sdes 
255333537Sdes /** return code that means the function ran out of memory. negative so it does
256333537Sdes@@ -914,3 +915,63 @@
257333537Sdes 		attach_edns_record(buf, &es);
258333537Sdes 	}
259333537Sdes }
260333537Sdes+
261333537Sdes+void 
262333537Sdes+fixed_address_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
263333537Sdes+	uint16_t qid, uint16_t qflags, struct edns_data* edns, char* data)
264333537Sdes+{
265333537Sdes+	uint16_t flags;
266333537Sdes+	uint8_t addr_data[16];
267333537Sdes+	size_t addr_len = 16;
268333537Sdes+	if (qinfo->qtype == LDNS_RR_TYPE_A) {
269333537Sdes+		sldns_str2wire_a_buf(data, addr_data, &addr_len);
270333537Sdes+	} else if (qinfo->qtype == LDNS_RR_TYPE_AAAA) {
271333537Sdes+		sldns_str2wire_aaaa_buf(data, addr_data, &addr_len);
272333537Sdes+	} else {
273333537Sdes+		return error_encode(buf, LDNS_RCODE_NOERROR, qinfo, qid, qflags, edns);
274333537Sdes+	}
275333537Sdes+	sldns_buffer_clear(buf);
276333537Sdes+	sldns_buffer_write(buf, &qid, sizeof(uint16_t));
277333537Sdes+	flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/
278333537Sdes+	flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
279333537Sdes+	sldns_buffer_write_u16(buf, flags);
280333537Sdes+	if(qinfo) flags = 1;
281333537Sdes+	else	flags = 0;
282333537Sdes+	sldns_buffer_write_u16(buf, flags);
283333537Sdes+	sldns_buffer_write_u16(buf, 1);
284333537Sdes+	flags = 0;
285333537Sdes+	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
286333537Sdes+	sldns_buffer_write(buf, &flags, sizeof(uint16_t));
287333537Sdes+	if(qinfo) {
288333537Sdes+		// query
289333537Sdes+		if(sldns_buffer_current(buf) == qinfo->qname)
290333537Sdes+			sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len);
291333537Sdes+		else	sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len);
292333537Sdes+		sldns_buffer_write_u16(buf, qinfo->qtype);
293333537Sdes+		sldns_buffer_write_u16(buf, qinfo->qclass);
294333537Sdes+		// faked answer
295333537Sdes+		if(sldns_buffer_current(buf) == qinfo->qname)
296333537Sdes+			sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len);
297333537Sdes+		else	sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len);
298333537Sdes+		sldns_buffer_write_u16(buf, qinfo->qtype);
299333537Sdes+		sldns_buffer_write_u16(buf, qinfo->qclass);
300333537Sdes+		sldns_buffer_write_u16(buf, 0);
301333537Sdes+		// TTL. Should we make this configurable too?
302333537Sdes+		sldns_buffer_write_u16(buf, 5);
303333537Sdes+		sldns_buffer_write_u16(buf, addr_len);
304333537Sdes+		sldns_buffer_write(buf, addr_data, addr_len);
305333537Sdes+		fflush(stderr);
306333537Sdes+	}
307333537Sdes+	sldns_buffer_flip(buf);
308333537Sdes+	if(edns) {
309333537Sdes+		struct edns_data es = *edns;
310333537Sdes+		es.edns_version = EDNS_ADVERTISED_VERSION;
311333537Sdes+		es.udp_size = EDNS_ADVERTISED_SIZE;
312333537Sdes+		es.ext_rcode = 0;
313333537Sdes+		es.bits &= EDNS_DO;
314333537Sdes+		if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
315333537Sdes+			edns->udp_size)
316333537Sdes+			return;
317333537Sdes+		attach_edns_record(buf, &es);
318333537Sdes+	}
319333537Sdes+}
320333537SdesIndex: util/data/msgencode.h
321333537Sdes===================================================================
322333537Sdes--- util/data/msgencode.h	(revision 4191)
323333537Sdes+++ util/data/msgencode.h	(working copy)
324333537Sdes@@ -128,4 +128,20 @@
325333537Sdes void error_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo,
326333537Sdes 	uint16_t qid, uint16_t qflags, struct edns_data* edns);
327333537Sdes 
328333537Sdes+/**
329333537Sdes+ * Encode a fixed address response.
330333537Sdes+ * This is a fake answer to either an A or AAA query
331333537Sdes+ *
332333537Sdes+ * It will answer with that address
333333537Sdes+ *
334333537Sdes+ * @param pkt: where to store the packet.
335333537Sdes+ * @param r: RCODE value to encode.
336333537Sdes+ * @param qinfo: if not NULL, the query is included.
337333537Sdes+ * @param qid: query ID to set in packet. network order.
338333537Sdes+ * @param qflags: original query flags (to copy RD and CD bits). host order.
339333537Sdes+ * @param edns: if not NULL, this is the query edns info,
340333537Sdes+ * 	and an edns reply is attached. Only attached if EDNS record fits reply.
341333537Sdes+ */
342333537Sdes+void fixed_address_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo,
343333537Sdes+	uint16_t qid, uint16_t qflags, struct edns_data* edns, char* address);
344333537Sdes #endif /* UTIL_DATA_MSGENCODE_H */
345