GNUnet  0.10.x
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_dnsparser_lib.h"
30 #include "gnunet-service-gns.h"
33 #include "gns.h"
34 
35 
41 {
42 
47 
52 
57 
62 
67 
68 };
69 
70 
75 
80 
85 
86 
94 static void
95 reply_to_dns (void *cls, uint32_t rd_count,
96  const struct GNUNET_GNSRECORD_Data *rd)
97 {
98  struct InterceptLookupHandle *ilh = cls;
99  struct GNUNET_DNSPARSER_Packet *packet = ilh->packet;
100  struct GNUNET_DNSPARSER_Query *query = &packet->queries[0];
101  uint32_t i;
102  size_t len;
103  int ret;
104  char *buf;
105  unsigned int num_answers;
106  unsigned int skip_answers;
107  unsigned int skip_additional;
108  size_t off = 0;
109 
110  /* Put records in the DNS packet */
111  num_answers = 0;
112  for (i=0; i < rd_count; i++)
113  if (rd[i].record_type == query->type)
114  num_answers++;
115  skip_answers = 0;
116  skip_additional = 0;
117 
118  {
119  struct GNUNET_DNSPARSER_Record answer_records[num_answers];
120  struct GNUNET_DNSPARSER_Record additional_records[rd_count - num_answers];
121 
122  packet->answers = answer_records;
123  packet->additional_records = additional_records;
124  /* FIXME: need to handle #GNUNET_GNSRECORD_RF_SHADOW_RECORD option
125  (by ignoring records where this flag is set if there is any
126  other record of that type in the result set) */
127  for (i=0; i < rd_count; i++)
128  {
129  if (rd[i].record_type == query->type)
130  {
131  answer_records[i - skip_answers].name = query->name;
132  answer_records[i - skip_answers].type = rd[i].record_type;
133  switch(rd[i].record_type)
134  {
138  answer_records[i - skip_answers].data.hostname
140  rd[i].data_size,
141  &off);
142  if ( (off != rd[i].data_size) ||
143  (NULL == answer_records[i].data.hostname) )
144  {
145  GNUNET_break_op (0);
146  skip_answers++;
147  }
148  break;
150  answer_records[i - skip_answers].data.soa
151  = GNUNET_DNSPARSER_parse_soa (rd[i].data,
152  rd[i].data_size,
153  &off);
154  if ( (off != rd[i].data_size) ||
155  (NULL == answer_records[i].data.soa) )
156  {
157  GNUNET_break_op (0);
158  skip_answers++;
159  }
160  break;
162  /* FIXME: SRV is not yet supported */
163  skip_answers++;
164  break;
166  answer_records[i - skip_answers].data.mx
167  = GNUNET_DNSPARSER_parse_mx (rd[i].data,
168  rd[i].data_size,
169  &off);
170  if ( (off != rd[i].data_size) ||
171  (NULL == answer_records[i].data.hostname) )
172  {
173  GNUNET_break_op (0);
174  skip_answers++;
175  }
176  break;
177  default:
178  answer_records[i - skip_answers].data.raw.data_len = rd[i].data_size;
179  answer_records[i - skip_answers].data.raw.data = (char*)rd[i].data;
180  break;
181  }
182  GNUNET_break (0 == (rd[i - skip_answers].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
183  answer_records[i - skip_answers].expiration_time.abs_value_us = rd[i].expiration_time;
184  answer_records[i - skip_answers].dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
185  }
186  else
187  {
188  additional_records[i - skip_additional].name = query->name;
189  additional_records[i - skip_additional].type = rd[i].record_type;
190  switch(rd[i].record_type)
191  {
195  additional_records[i - skip_additional].data.hostname
197  rd[i].data_size,
198  &off);
199  if ( (off != rd[i].data_size) ||
200  (NULL == additional_records[i].data.hostname) )
201  {
202  GNUNET_break_op (0);
203  skip_additional++;
204  }
205  break;
207  additional_records[i - skip_additional].data.soa
208  = GNUNET_DNSPARSER_parse_soa (rd[i].data,
209  rd[i].data_size,
210  &off);
211  if ( (off != rd[i].data_size) ||
212  (NULL == additional_records[i].data.hostname) )
213  {
214  GNUNET_break_op (0);
215  skip_additional++;
216  }
217  break;
219  additional_records[i - skip_additional].data.mx
220  = GNUNET_DNSPARSER_parse_mx (rd[i].data,
221  rd[i].data_size,
222  &off);
223  if ( (off != rd[i].data_size) ||
224  (NULL == additional_records[i].data.hostname) )
225  {
226  GNUNET_break_op (0);
227  skip_additional++;
228  }
229  break;
231  /* FIXME: SRV is not yet supported */
232  skip_answers++;
233  break;
234  default:
235  additional_records[i - skip_additional].data.raw.data_len = rd[i].data_size;
236  additional_records[i - skip_additional].data.raw.data = (char*)rd[i].data;
237  break;
238  }
239  GNUNET_break (0 == (rd[i - skip_additional].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION));
240  additional_records[i - skip_additional].expiration_time.abs_value_us = rd[i].expiration_time;
241  additional_records[i - skip_additional].dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
242  }
243  }
244  packet->num_answers = num_answers - skip_answers;
245  packet->num_additional_records = rd_count - num_answers - skip_additional;
246  packet->flags.authoritative_answer = 1;
247  if (NULL == rd)
249  else
251  packet->flags.query_or_response = 1;
252  ret = GNUNET_DNSPARSER_pack (packet,
253  1024, /* maximum allowed size for DNS reply */
254  &buf,
255  &len);
256  if (GNUNET_OK != ret)
257  {
259  _("Error converting GNS response to DNS response!\n"));
260  if (GNUNET_NO == ret)
261  GNUNET_free (buf);
262  }
263  else
264  {
266  len,
267  buf);
268  GNUNET_free (buf);
269  }
270  packet->num_answers = 0;
271  packet->answers = NULL;
272  packet->num_additional_records = 0;
273  packet->additional_records = NULL;
275  }
276  GNUNET_CONTAINER_DLL_remove (ilh_head, ilh_tail, ilh);
277  GNUNET_free (ilh);
278 }
279 
280 
289 static void
291  struct GNUNET_DNS_RequestHandle *rh,
292  size_t request_length,
293  const char *request)
294 {
295  struct GNUNET_DNSPARSER_Packet *p;
296  struct InterceptLookupHandle *ilh;
297  struct GNUNET_CRYPTO_EcdsaPublicKey zone;
298 
300  "Hijacked a DNS request. Processing.\n");
301  if (NULL == (p = GNUNET_DNSPARSER_parse (request, request_length)))
302  {
304  "Received malformed DNS packet, leaving it untouched.\n");
307  return;
308  }
309 
310  /* Check TLD and decide if we or legacy dns is responsible */
311  if (1 != p->num_queries)
312  {
314  "Not exactly one query in DNS packet. Forwarding untouched.\n");
317  return;
318  }
319 
320  /* Check for GNS TLDs. */
321  if (GNUNET_YES ==
323  &zone))
324  {
325  /* Start resolution in GNS */
326  ilh = GNUNET_new (struct InterceptLookupHandle);
327  GNUNET_CONTAINER_DLL_insert (ilh_head,
328  ilh_tail,
329  ilh);
330  ilh->packet = p;
331  ilh->request_handle = rh;
332  ilh->lookup = GNS_resolver_lookup (&zone,
333  p->queries[0].type,
334  p->queries[0].name,
335  GNUNET_NO,
336  &reply_to_dns, ilh);
337  return;
338  }
339  /* This request does not concern us. Forward to real DNS. */
341  "Request for `%s' is forwarded to DNS untouched.\n",
342  p->queries[0].name);
345 }
346 
347 
354 int
356 {
358  "DNS hijacking enabled. Connecting to DNS service.\n");
359  dns_handle = GNUNET_DNS_connect (c,
362  NULL);
363  if (NULL == dns_handle)
364  {
366  _("Failed to connect to the DNS service!\n"));
367  return GNUNET_SYSERR;
368  }
369  return GNUNET_YES;
370 }
371 
372 
376 void
378 {
379  struct InterceptLookupHandle *ilh;
380 
381  while (NULL != (ilh = ilh_head))
382  {
383  GNUNET_CONTAINER_DLL_remove (ilh_head,
384  ilh_tail,
385  ilh);
389  GNUNET_free (ilh);
390  }
391  if (NULL != dns_handle)
392  {
393  GNUNET_DNS_disconnect (dns_handle);
394  dns_handle = NULL;
395  }
396 }
397 
398 /* end of gnunet-service-gns_interceptor.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
struct GNUNET_DNSPARSER_Record * answers
Array of all answers in the packet, must contain "num_answers" entries.
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
void GNS_resolver_lookup_cancel(struct GNS_ResolverHandle *rh)
Cancel active resolution (i.e.
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
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:344
struct InterceptLookupHandle * prev
We keep these in a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct GNUNET_DNSPARSER_Packet * packet
the dns parser packet received
#define GNUNET_DNSPARSER_TYPE_CNAME
static struct InterceptLookupHandle * ilh_tail
Tail of the DLL.
const char * GNS_get_tld(const char *name)
Obtain the TLD of the given name.
unsigned int return_code
See GNUNET_TUN_DNS_RETURN_CODE_ defines.
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
Handle to a DNS intercepted reslution request.
void GNUNET_DNSPARSER_free_packet(struct GNUNET_DNSPARSER_Packet *p)
Free memory taken by a packet.
Definition: dnsparser.c:854
#define GNUNET_NO
Definition: gnunet_common.h:81
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:401
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
size_t data_size
Number of bytes in data.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
struct GNUNET_DNSPARSER_Record * additional_records
Array of all additional answers in the packet, must contain "num_additional_records" entries...
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_DNSPARSER_TYPE_MX
unsigned int num_answers
Number of answers in the packet, should be 0 for queries.
uint64_t abs_value_us
The actual value.
IPC messages between GNS API and GNS service.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
int GNS_interceptor_init(const struct GNUNET_CONFIGURATION_Handle *c)
Initialized the interceptor.
Handle to a currenty pending resolution.
unsigned int authoritative_answer
Set to 1 if this is an authoritative answer.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
#define GNUNET_DNSPARSER_TYPE_PTR
unsigned int query_or_response
query:0, response:1
void GNUNET_DNS_disconnect(struct GNUNET_DNS_Handle *dh)
Disconnect from the DNS service.
Definition: dns_api.c:373
#define GNUNET_DNSPARSER_TYPE_SOA
struct GNS_ResolverHandle * lookup
Handle for the lookup operation.
char * name
Name of the record that the query is for (0-terminated).
char * hostname
For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname.
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
struct GNUNET_DNSPARSER_SoaRecord * soa
SOA data for SOA records.
unsigned int num_additional_records
Number of additional records in the packet, should be 0 for queries.
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:662
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
uint64_t expiration_time
Expiration time for the DNS record.
static struct InterceptLookupHandle * ilh_head
Head of the DLL.
static void handle_dns_request(void *cls, struct GNUNET_DNS_RequestHandle *rh, size_t request_length, const char *request)
The DNS request handler.
#define GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR
RFC 1035 codes.
static char buf[2048]
void GNS_interceptor_done()
Disconnect from interceptor.
GNU Name System (main service)
static struct GNUNET_DNS_Handle * dns_handle
Our handle to the DNS handler library.
A DNS response record.
struct GNUNET_DNSPARSER_Query * queries
Array of all queries in the packet, must contain "num_queries" entries.
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:446
struct InterceptLookupHandle * next
We keep these in a DLL.
DNS handle.
Definition: dns_api.c:58
GNUnet GNS service.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
size_t data_len
Number of bytes in data.
void * data
Binary record data.
struct GNUNET_DNS_RequestHandle * request_handle
the request handle to reply to
struct GNS_ResolverHandle * GNS_resolver_lookup(const struct GNUNET_CRYPTO_EcdsaPublicKey *zone, uint32_t record_type, const char *name, enum GNUNET_GNS_LocalOptions options, GNS_ResultProcessor proc, void *proc_cls)
Lookup of a record in a specific zone calls lookup result processor on result.
#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&#39;r...
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:350
struct GNUNET_TIME_Absolute expiration_time
When does the record expire?
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:306
struct GNUNET_DNSPARSER_MxRecord * mx
MX data for MX records.
#define GNUNET_TUN_DNS_RETURN_CODE_NAME_ERROR
uint32_t record_type
Type of the GNS/DNS record.
Handle to identify an individual DNS request.
Definition: dns_api.c:34
configuration data
Definition: configuration.c:85
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:247
#define GNUNET_DNSPARSER_TYPE_NS
int GNS_find_tld(const char *tld_str, struct GNUNET_CRYPTO_EcdsaPublicKey *pkey)
Find GNS zone belonging to TLD tld.
Easy-to-process, parsed version of a DNS packet.
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
#define GNUNET_log(kind,...)
uint16_t dns_traffic_class
See GNUNET_TUN_DNS_CLASS_*.
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:275
char * name
Name of the record that the query is for (0-terminated).
This client should be called on requests that have not yet been resolved as this client provides a re...
unsigned int num_queries
Number of queries in the packet.
#define GNUNET_YES
Definition: gnunet_common.h:80
This flag is currently unused; former RF_PENDING flag.
union GNUNET_DNSPARSER_Record::@27 data
Payload of the record (which one of these is valid depends on the &#39;type&#39;).
struct GNUNET_TUN_DnsFlags flags
Bitfield of DNS flags.
#define GNUNET_DNSPARSER_TYPE_SRV
uint32_t data
The data value.
static size_t data_size
Number of bytes in data.
struct GNUNET_DNSPARSER_RawRecord raw
Raw data for all other types.
#define GNUNET_free(ptr)
Wrapper around free.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
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.