GNUnet 0.25.0
 
Loading...
Searching...
No Matches
gnunet-service-gns_interceptor.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_dns_service.h"
29#include "gnunet-service-gns.h"
32#include "gns.h"
33
34
38#define MAX_RECURSION 256
39
40
72
73
78
83
88
89
97static void
98reply_to_dns (void *cls, uint32_t rd_count,
99 const struct GNUNET_GNSRECORD_Data *rd)
100{
101 struct InterceptLookupHandle *ilh = cls;
102 struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
103 struct GNUNET_DNSPARSER_Query *query = &packet->queries[0];
104 uint32_t i;
105 size_t len;
106 int ret;
107 char *buf;
108 unsigned int num_answers;
109 unsigned int skipped_answers;
110 unsigned int skipped_additional;
111 size_t off = 0;
112
113 /* Put records in the DNS packet */
114 num_answers = 0;
115 for (i = 0; i < rd_count; i++)
116 if (rd[i].record_type == query->type)
117 num_answers++;
118 skipped_answers = 0;
119 skipped_additional = 0;
120
121 {
122 struct GNUNET_DNSPARSER_Record answer_records[num_answers];
123 struct GNUNET_DNSPARSER_Record additional_records[rd_count - num_answers];
124
125 packet->answers = answer_records;
126 packet->additional_records = additional_records;
127 /* FIXME: need to handle #GNUNET_GNSRECORD_RF_SHADOW_RECORD option
128 (by ignoring records where this flag is set if there is any
129 other record of that type in the result set) */
130 for (i = 0; i < rd_count; i++)
131 {
132 if (rd[i].record_type == query->type)
133 {
134 answer_records[i - skipped_answers].name = query->name;
135 answer_records[i - skipped_answers].type = rd[i].record_type;
136 switch (rd[i].record_type)
137 {
141 answer_records[i - skipped_answers].data.hostname
143 rd[i].data_size,
144 &off);
145 if ((off != rd[i].data_size) ||
146 (NULL == answer_records[i].data.hostname))
147 {
148 GNUNET_break_op (0);
149 skipped_answers++;
150 continue;
151 }
152 break;
153
155 answer_records[i - skipped_answers].data.soa
157 rd[i].data_size,
158 &off);
159 if ((off != rd[i].data_size) ||
160 (NULL == answer_records[i].data.soa))
161 {
162 GNUNET_break_op (0);
163 skipped_answers++;
164 continue;
165 }
166 break;
167
169 /* FIXME: SRV is not yet supported */
170 skipped_answers++;
171 continue;
172
174 /* FIXME: URI is not yet supported */
175 skipped_answers++;
176 continue;
177
179 answer_records[i - skipped_answers].data.mx
181 rd[i].data_size,
182 &off);
183 if ((off != rd[i].data_size) ||
184 (NULL == answer_records[i].data.hostname))
185 {
186 GNUNET_break_op (0);
187 skipped_answers++;
188 continue;
189 }
190 break;
191
192 default:
193 answer_records[i - skipped_answers].data.raw.data_len = rd[i].
194 data_size;
195 answer_records[i - skipped_answers].data.raw.data = (char *) rd[i].
196 data;
197 break;
198 }
199 GNUNET_break (0 == (rd[i - skipped_answers].flags
201 answer_records[i - skipped_answers].expiration_time.abs_value_us =
203 answer_records[i - skipped_answers].dns_traffic_class =
205 }
206 else
207 {
208 additional_records[i - skipped_additional].name = query->name;
209 additional_records[i - skipped_additional].type = rd[i].record_type;
210 switch (rd[i].record_type)
211 {
215 additional_records[i - skipped_additional].data.hostname
217 rd[i].data_size,
218 &off);
219 if ((off != rd[i].data_size) ||
220 (NULL == additional_records[i].data.hostname))
221 {
222 GNUNET_break_op (0);
223 skipped_additional++;
224 continue;
225 }
226 break;
227
229 additional_records[i - skipped_additional].data.soa
231 rd[i].data_size,
232 &off);
233 if ((off != rd[i].data_size) ||
234 (NULL == additional_records[i].data.hostname))
235 {
236 GNUNET_break_op (0);
237 skipped_additional++;
238 continue;
239 }
240 break;
241
243 additional_records[i - skipped_additional].data.mx
245 rd[i].data_size,
246 &off);
247 if ((off != rd[i].data_size) ||
248 (NULL == additional_records[i].data.hostname))
249 {
250 GNUNET_break_op (0);
251 skipped_additional++;
252 continue;
253 }
254 break;
255
257 /* FIXME: SRV is not yet supported */
258 skipped_additional++;
259 continue;
260
262 additional_records[i - skipped_additional].data.uri
264 rd[i].data_size,
265 &off);
266 if ((off != rd[i].data_size) ||
267 (NULL == additional_records[i].data.uri))
268 {
269 GNUNET_break_op (0);
270 skipped_additional++;
271 continue;
272 }
273 break;
274
275 default:
276 additional_records[i - skipped_additional].data.raw.data_len =
277 rd[i].data_size;
278 additional_records[i - skipped_additional].data.raw.data =
279 (char *) rd[i].data;
280 break;
281 }
282 GNUNET_break (0 == (rd[i - skipped_additional].flags
284 additional_records[i - skipped_additional].expiration_time.abs_value_us
285 =
287 additional_records[i - skipped_additional].dns_traffic_class =
289 }
290 }
291 packet->num_answers = num_answers - skipped_answers;
292 packet->num_additional_records = rd_count - num_answers - skipped_additional
293 ;
294 packet->flags.authoritative_answer = 1;
295 if (NULL == rd)
297 else
299 packet->flags.query_or_response = 1;
300 ret = GNUNET_DNSPARSER_pack (packet,
301 1024, /* maximum allowed size for DNS reply */
302 &buf,
303 &len);
304 if (GNUNET_OK != ret)
305 {
307 _ ("Error converting GNS response to DNS response!\n"));
308 if (GNUNET_NO == ret)
309 GNUNET_free (buf);
310 }
311 else
312 {
314 len,
315 buf);
316 GNUNET_free (buf);
317 }
318 packet->num_answers = 0;
319 packet->answers = NULL;
320 packet->num_additional_records = 0;
321 packet->additional_records = NULL;
323 }
325 GNUNET_free (ilh);
326}
327
328
337static void
339 struct GNUNET_DNS_RequestHandle *rh,
340 size_t request_length,
341 const char *request)
342{
344 struct InterceptLookupHandle *ilh;
345 struct GNUNET_CRYPTO_PublicKey zone;
346
348 "Hijacked a DNS request. Processing.\n");
349 if (NULL == (p = GNUNET_DNSPARSER_parse (request, request_length)))
350 {
352 "Received malformed DNS packet, leaving it untouched.\n");
354 return;
355 }
356
357 /* Check TLD and decide if we or legacy dns is responsible */
358 if (1 != p->num_queries)
359 {
361 "Not exactly one query in DNS packet. Forwarding untouched.\n");
364 return;
365 }
366
367 /* Check for GNS TLDs. */
368 if (GNUNET_YES ==
369 GNS_find_tld (GNS_get_tld (p->queries[0].name),
370 &zone))
371 {
372 /* Start resolution in GNS */
373 ilh = GNUNET_new (struct InterceptLookupHandle);
375 ilh_tail,
376 ilh);
377 ilh->packet = p;
378 ilh->request_handle = rh;
379 ilh->lookup = GNS_resolver_lookup (&zone,
380 p->queries[0].type,
381 p->queries[0].name,
384 &reply_to_dns, ilh);
385 return;
386 }
387 /* This request does not concern us. Forward to real DNS. */
389 "Request for `%s' is forwarded to DNS untouched.\n",
390 p->queries[0].name);
393}
394
395
396int
398{
400 "DNS hijacking enabled. Connecting to DNS service.\n");
404 NULL);
405 if (NULL == dns_handle)
406 {
408 _ ("Failed to connect to the DNS service!\n"));
409 return GNUNET_SYSERR;
410 }
411 return GNUNET_YES;
412}
413
414
418void
420{
421 struct InterceptLookupHandle *ilh;
422
423 while (NULL != (ilh = ilh_head))
424 {
426 ilh_tail,
427 ilh);
431 GNUNET_free (ilh);
432 }
433 if (NULL != dns_handle)
434 {
436 dns_handle = NULL;
437 }
438}
439
440
441/* end of gnunet-service-gns_interceptor.c */
IPC messages between GNS API and GNS service.
static int ret
Final status code.
Definition gnunet-arm.c:93
static char * data
The data to insert into the dht.
static unsigned int rd_count
Number of records for currently parsed set.
static struct GNUNET_GNSRECORD_Data rd[50]
The record data under a single label.
static size_t data_size
Number of bytes in data.
enum GNUNET_GenericReturnValue GNS_find_tld(const char *tld_str, struct GNUNET_CRYPTO_PublicKey *pkey)
Find GNS zone belonging to TLD tld.
const char * GNS_get_tld(const char *name)
Obtain the TLD of the given name.
GNU Name System (main service)
static void handle_dns_request(void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request)
The DNS request handler.
int GNS_interceptor_init(const struct GNUNET_CONFIGURATION_Handle *c)
Initialize DNS interceptor.
static void reply_to_dns(void *cls, uint32_t rd_count, const struct GNUNET_GNSRECORD_Data *rd)
Reply to dns request with the result from our lookup.
static struct InterceptLookupHandle * ilh_head
Head of the DLL.
#define MAX_RECURSION
How deep do we allow recursions to go before we abort?
static struct InterceptLookupHandle * ilh_tail
Tail of the DLL.
void GNS_interceptor_done()
Disconnect from interceptor.
static struct GNUNET_DNS_Handle * dns_handle
Our handle to the DNS handler library.
void GNS_resolver_lookup_cancel(struct GNS_ResolverHandle *rh)
Cancel active resolution (i.e.
struct GNS_ResolverHandle * GNS_resolver_lookup(const struct GNUNET_CRYPTO_PublicKey *zone, uint32_t record_type, const char *name, enum GNUNET_GNS_LocalOptions options, uint16_t recursion_depth_limit, GNS_ResultProcessor proc, void *proc_cls)
Lookup of a record in a specific zone calls lookup result processor on result.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition gnunet-uri.c:38
static struct GNUNET_VPN_RedirectionRequest * request
Opaque redirection request handle.
Definition gnunet-vpn.c:40
API to access the DNS service.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_DNSPARSER_TYPE_URI
struct GNUNET_DNSPARSER_MxRecord * GNUNET_DNSPARSER_parse_mx(const char *udp_payload, size_t udp_payload_length, size_t *off)
Parse a DNS MX record.
Definition dnsparser.c:455
void GNUNET_DNSPARSER_free_packet(struct GNUNET_DNSPARSER_Packet *p)
Free memory taken by a packet.
Definition dnsparser.c:950
#define GNUNET_DNSPARSER_TYPE_SRV
#define GNUNET_DNSPARSER_TYPE_SOA
#define GNUNET_DNSPARSER_TYPE_PTR
struct GNUNET_DNSPARSER_SoaRecord * GNUNET_DNSPARSER_parse_soa(const char *udp_payload, size_t udp_payload_length, size_t *off)
Parse a DNS SOA record.
Definition dnsparser.c:410
#define GNUNET_DNSPARSER_TYPE_NS
#define GNUNET_DNSPARSER_TYPE_CNAME
struct GNUNET_DNSPARSER_UriRecord * GNUNET_DNSPARSER_parse_uri(const char *udp_payload, size_t udp_payload_length, size_t *off)
Parse a DNS URI record.
Definition dnsparser.c:537
char * GNUNET_DNSPARSER_parse_name(const char *udp_payload, size_t udp_payload_length, size_t *off)
Parse name inside of a DNS query or record.
Definition dnsparser.c:353
int GNUNET_DNSPARSER_pack(const struct GNUNET_DNSPARSER_Packet *p, uint16_t max, char **buf, size_t *buf_length)
Given a DNS packet p, generate the corresponding UDP payload.
Definition dnsparser.c:1400
#define GNUNET_DNSPARSER_TYPE_MX
struct GNUNET_DNSPARSER_Packet * GNUNET_DNSPARSER_parse(const char *udp_payload, size_t udp_payload_length)
Parse a UDP payload of a DNS packet in to a nice struct for further processing and manipulation.
Definition dnsparser.c:729
void GNUNET_DNS_disconnect(struct GNUNET_DNS_Handle *dh)
Disconnect from the DNS service.
Definition dns_api.c:363
void GNUNET_DNS_request_forward(struct GNUNET_DNS_RequestHandle *rh)
If a GNUNET_DNS_RequestHandler calls this function, the client has no desire to interfere with the re...
Definition dns_api.c:237
void GNUNET_DNS_request_answer(struct GNUNET_DNS_RequestHandle *rh, uint16_t reply_length, const char *reply)
If a GNUNET_DNS_RequestHandler calls this function, the request is supposed to be answered with the d...
Definition dns_api.c:296
struct GNUNET_DNS_Handle * GNUNET_DNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg, enum GNUNET_DNS_Flags flags, GNUNET_DNS_RequestHandler rh, void *rh_cls)
Connect to the service-dns.
Definition dns_api.c:340
void GNUNET_DNS_request_drop(struct GNUNET_DNS_RequestHandle *rh)
If a GNUNET_DNS_RequestHandler calls this function, the request is to be dropped and no response shou...
Definition dns_api.c:265
@ GNUNET_DNS_FLAG_PRE_RESOLUTION
This client should be called on requests that have not yet been resolved as this client provides a re...
@ GNUNET_GNS_LO_DEFAULT
Defaults, look in cache, then in DHT.
@ GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION
This expiration time of the record is a relative time (not an absolute time).
#define GNUNET_log(kind,...)
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
#define GNUNET_TUN_DNS_RETURN_CODE_NAME_ERROR
#define GNUNET_TUN_DNS_CLASS_INTERNET
A few common DNS classes (ok, only one is common, but I list a couple more to make it clear what we'r...
#define GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR
RFC 1035 codes.
#define _(String)
GNU gettext support macro.
Definition platform.h:179
Handle to a currently pending resolution.
An identity key as per LSD0001.
Easy-to-process, parsed version of a DNS packet.
struct GNUNET_DNSPARSER_Query * queries
Array of all queries in the packet, must contain "num_queries" entries.
unsigned int num_answers
Number of answers in the packet, should be 0 for queries.
struct GNUNET_TUN_DnsFlags flags
Bitfield of DNS flags.
struct GNUNET_DNSPARSER_Record * answers
Array of all answers in the packet, must contain "num_answers" entries.
unsigned int num_additional_records
Number of additional records in the packet, should be 0 for queries.
struct GNUNET_DNSPARSER_Record * additional_records
Array of all additional answers in the packet, must contain "num_additional_records" entries.
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
char * name
Name of the record that the query is for (0-terminated).
void * data
Binary record data.
size_t data_len
Number of bytes in data.
A DNS response record.
uint16_t dns_traffic_class
See GNUNET_TUN_DNS_CLASS_*.
struct GNUNET_DNSPARSER_SoaRecord * soa
SOA data for SOA records.
struct GNUNET_DNSPARSER_MxRecord * mx
MX data for MX records.
char * hostname
For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname.
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
struct GNUNET_TIME_Absolute expiration_time
When does the record expire?
char * name
Name of the record that the query is for (0-terminated).
struct GNUNET_DNSPARSER_RawRecord raw
Raw data for all other types.
union GNUNET_DNSPARSER_Record::@20 data
Payload of the record (which one of these is valid depends on the 'type').
struct GNUNET_DNSPARSER_UriRecord * uri
URI data for URI records.
DNS handle.
Definition dns_api.c:57
Handle to identify an individual DNS request.
Definition dns_api.c:35
uint32_t record_type
Type of the GNS/DNS record.
size_t data_size
Number of bytes in data.
uint64_t expiration_time
Expiration time for the DNS record.
uint64_t abs_value_us
The actual value.
unsigned int query_or_response
query:0, response:1
unsigned int return_code
See GNUNET_TUN_DNS_RETURN_CODE_ defines.
unsigned int authoritative_answer
Set to 1 if this is an authoritative answer.
Handle to a DNS intercepted resolution request.
struct InterceptLookupHandle * prev
We keep these in a DLL.
struct GNUNET_DNSPARSER_Packet * packet
the dns parser packet received
struct GNS_ResolverHandle * lookup
Handle for the lookup operation.
struct InterceptLookupHandle * next
We keep these in a DLL.
struct GNUNET_DNS_RequestHandle * request_handle
the request handle to reply to