GNUnet  0.19.4
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 
46 {
51 
56 
61 
66 
71 };
72 
73 
78 
83 
88 
89 
97 static void
98 reply_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 skip_answers;
110  unsigned int skip_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  skip_answers = 0;
119  skip_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 - skip_answers].name = query->name;
135  answer_records[i - skip_answers].type = rd[i].record_type;
136  switch (rd[i].record_type)
137  {
141  answer_records[i - skip_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  skip_answers++;
150  }
151  break;
152 
154  answer_records[i - skip_answers].data.soa
156  rd[i].data_size,
157  &off);
158  if ((off != rd[i].data_size) ||
159  (NULL == answer_records[i].data.soa))
160  {
161  GNUNET_break_op (0);
162  skip_answers++;
163  }
164  break;
165 
167  /* FIXME: SRV is not yet supported */
168  skip_answers++;
169  break;
170 
172  answer_records[i - skip_answers].data.mx
174  rd[i].data_size,
175  &off);
176  if ((off != rd[i].data_size) ||
177  (NULL == answer_records[i].data.hostname))
178  {
179  GNUNET_break_op (0);
180  skip_answers++;
181  }
182  break;
183 
184  default:
185  answer_records[i - skip_answers].data.raw.data_len = rd[i].data_size;
186  answer_records[i - skip_answers].data.raw.data = (char *) rd[i].data;
187  break;
188  }
189  GNUNET_break (0 == (rd[i - skip_answers].flags
191  answer_records[i - skip_answers].expiration_time.abs_value_us =
192  rd[i].expiration_time;
193  answer_records[i - skip_answers].dns_traffic_class =
195  }
196  else
197  {
198  additional_records[i - skip_additional].name = query->name;
199  additional_records[i - skip_additional].type = rd[i].record_type;
200  switch (rd[i].record_type)
201  {
205  additional_records[i - skip_additional].data.hostname
207  rd[i].data_size,
208  &off);
209  if ((off != rd[i].data_size) ||
210  (NULL == additional_records[i].data.hostname))
211  {
212  GNUNET_break_op (0);
213  skip_additional++;
214  }
215  break;
216 
218  additional_records[i - skip_additional].data.soa
220  rd[i].data_size,
221  &off);
222  if ((off != rd[i].data_size) ||
223  (NULL == additional_records[i].data.hostname))
224  {
225  GNUNET_break_op (0);
226  skip_additional++;
227  }
228  break;
229 
231  additional_records[i - skip_additional].data.mx
233  rd[i].data_size,
234  &off);
235  if ((off != rd[i].data_size) ||
236  (NULL == additional_records[i].data.hostname))
237  {
238  GNUNET_break_op (0);
239  skip_additional++;
240  }
241  break;
242 
244  /* FIXME: SRV is not yet supported */
245  skip_answers++;
246  break;
247 
248  default:
249  additional_records[i - skip_additional].data.raw.data_len =
250  rd[i].data_size;
251  additional_records[i - skip_additional].data.raw.data =
252  (char *) rd[i].data;
253  break;
254  }
255  GNUNET_break (0 == (rd[i - skip_additional].flags
257  additional_records[i - skip_additional].expiration_time.abs_value_us =
258  rd[i].expiration_time;
259  additional_records[i - skip_additional].dns_traffic_class =
261  }
262  }
263  packet->num_answers = num_answers - skip_answers;
264  packet->num_additional_records = rd_count - num_answers - skip_additional;
265  packet->flags.authoritative_answer = 1;
266  if (NULL == rd)
268  else
270  packet->flags.query_or_response = 1;
271  ret = GNUNET_DNSPARSER_pack (packet,
272  1024, /* maximum allowed size for DNS reply */
273  &buf,
274  &len);
275  if (GNUNET_OK != ret)
276  {
278  _ ("Error converting GNS response to DNS response!\n"));
279  if (GNUNET_NO == ret)
280  GNUNET_free (buf);
281  }
282  else
283  {
285  len,
286  buf);
287  GNUNET_free (buf);
288  }
289  packet->num_answers = 0;
290  packet->answers = NULL;
291  packet->num_additional_records = 0;
292  packet->additional_records = NULL;
294  }
296  GNUNET_free (ilh);
297 }
298 
299 
308 static void
310  struct GNUNET_DNS_RequestHandle *rh,
311  size_t request_length,
312  const char *request)
313 {
314  struct GNUNET_DNSPARSER_Packet *p;
315  struct InterceptLookupHandle *ilh;
317 
319  "Hijacked a DNS request. Processing.\n");
320  if (NULL == (p = GNUNET_DNSPARSER_parse (request, request_length)))
321  {
323  "Received malformed DNS packet, leaving it untouched.\n");
325  return;
326  }
327 
328  /* Check TLD and decide if we or legacy dns is responsible */
329  if (1 != p->num_queries)
330  {
332  "Not exactly one query in DNS packet. Forwarding untouched.\n");
335  return;
336  }
337 
338  /* Check for GNS TLDs. */
339  if (GNUNET_YES ==
340  GNS_find_tld (GNS_get_tld (p->queries[0].name),
341  &zone))
342  {
343  /* Start resolution in GNS */
344  ilh = GNUNET_new (struct InterceptLookupHandle);
346  ilh_tail,
347  ilh);
348  ilh->packet = p;
349  ilh->request_handle = rh;
351  p->queries[0].type,
352  p->queries[0].name,
355  &reply_to_dns, ilh);
356  return;
357  }
358  /* This request does not concern us. Forward to real DNS. */
360  "Request for `%s' is forwarded to DNS untouched.\n",
361  p->queries[0].name);
364 }
365 
366 
367 int
369 {
371  "DNS hijacking enabled. Connecting to DNS service.\n");
375  NULL);
376  if (NULL == dns_handle)
377  {
379  _ ("Failed to connect to the DNS service!\n"));
380  return GNUNET_SYSERR;
381  }
382  return GNUNET_YES;
383 }
384 
385 
389 void
391 {
392  struct InterceptLookupHandle *ilh;
393 
394  while (NULL != (ilh = ilh_head))
395  {
397  ilh_tail,
398  ilh);
402  GNUNET_free (ilh);
403  }
404  if (NULL != dns_handle)
405  {
407  dns_handle = NULL;
408  }
409 }
410 
411 
412 /* end of gnunet-service-gns_interceptor.c */
IPC messages between GNS API and GNS service.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static size_t data_size
Number of bytes in data.
Definition: gnunet-abd.c:187
uint32_t data
The data value.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
static char * zone
Name of the zone being managed.
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.
const char * GNS_get_tld(const char *name)
Obtain the TLD of the given name.
int GNS_find_tld(const char *tld_str, struct GNUNET_IDENTITY_PublicKey *pkey)
Find GNS zone belonging to TLD tld.
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_IDENTITY_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 char buf[2048]
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.
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:391
void GNUNET_DNSPARSER_free_packet(struct GNUNET_DNSPARSER_Packet *p)
Free memory taken by a packet.
Definition: dnsparser.c:854
#define GNUNET_DNSPARSER_TYPE_SRV
#define GNUNET_DNSPARSER_TYPE_SOA
#define GNUNET_DNSPARSER_TYPE_PTR
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:656
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:436
#define GNUNET_DNSPARSER_TYPE_NS
#define GNUNET_DNSPARSER_TYPE_CNAME
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:1259
#define GNUNET_DNSPARSER_TYPE_MX
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:334
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_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 request is given to other clients or the glob...
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
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:177
Handle to a currently pending resolution.
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?
union GNUNET_DNSPARSER_Record::@24 data
Payload of the record (which one of these is valid depends on the 'type').
char * name
Name of the record that the query is for (0-terminated).
struct GNUNET_DNSPARSER_RawRecord raw
Raw data for all other types.
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.
An identity key as per LSD0001.
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 reslution 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