aboutsummaryrefslogtreecommitdiff
path: root/src/include/gnunet_dnsparser_lib.h
blob: b4f33dd5a28dae04a2d989633b6cf4e7bd371f3e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
/*
      This file is part of GNUnet
      (C) 2010-2013 Christian Grothoff (and other contributing authors)

      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
      by the Free Software Foundation; either version 2, or (at your
      option) any later version.

      GNUnet is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      General Public License for more details.

      You should have received a copy of the GNU General Public License
      along with GNUnet; see the file COPYING.  If not, write to the
      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      Boston, MA 02111-1307, USA.
 */

/**
 * @file include/gnunet_dnsparser_lib.h
 * @brief API for helper library to parse DNS packets. 
 * @author Philipp Toelke
 * @author Christian Grothoff
 */
#ifndef GNUNET_DNSPARSER_LIB_H
#define GNUNET_DNSPARSER_LIB_H

#include "gnunet_common.h"
#include "gnunet_tun_lib.h"

/**
 * Maximum length of a label in DNS.
 */
#define GNUNET_DNSPARSER_MAX_LABEL_LENGTH 63

/**
 * Maximum length of a name in DNS.
 */
#define GNUNET_DNSPARSER_MAX_NAME_LENGTH 253


/**
 * A few common DNS types.
 */
#define GNUNET_DNSPARSER_TYPE_A 1
#define GNUNET_DNSPARSER_TYPE_NS 2
#define GNUNET_DNSPARSER_TYPE_CNAME 5
#define GNUNET_DNSPARSER_TYPE_SOA 6
#define GNUNET_DNSPARSER_TYPE_PTR 12
#define GNUNET_DNSPARSER_TYPE_MX 15
#define GNUNET_DNSPARSER_TYPE_TXT 16
#define GNUNET_DNSPARSER_TYPE_AAAA 28
#define GNUNET_DNSPARSER_TYPE_SRV 33
#define GNUNET_DNSPARSER_TYPE_TLSA 52


/**
 * A DNS query.
 */
struct GNUNET_DNSPARSER_Query
{

  /**
   * Name of the record that the query is for (0-terminated).
   * In UTF-8 format.  The library will convert from and to DNS-IDNA 
   * as necessary.  Use 'GNUNET_DNSPARSER_check_label' to test if an
   * individual label is well-formed.  If a given name is not well-formed,
   * creating the DNS packet will fail.
   */
  char *name;

  /**
   * See GNUNET_DNSPARSER_TYPE_*.
   */
  uint16_t type;

  /**
   * See GNUNET_TUN_DNS_CLASS_*.
   */
  uint16_t class;

};


/**
 * Information from MX records (RFC 1035).
 */
struct GNUNET_DNSPARSER_MxRecord
{
  
  /**
   * Preference for this entry (lower value is higher preference).
   */
  uint16_t preference;

  /**
   * Name of the mail server.
   * In UTF-8 format.  The library will convert from and to DNS-IDNA 
   * as necessary.  Use 'GNUNET_DNSPARSER_check_label' to test if an
   * individual label is well-formed.  If a given name is not well-formed,
   * creating the DNS packet will fail.
   */
  char *mxhost;

};


/**
 * Information from SRV records (RFC 2782).  The 'service', 'proto'
 * and 'domain_name' fields together give the DNS-name which for SRV
 * records is of the form "_$SERVICE._$PROTO.$DOMAIN_NAME".  The DNS
 * parser provides the full name in 'struct DNSPARSER_Record' and the
 * individual components in the respective fields of this struct.
 * When serializing, you CAN set the 'name' field of 'struct
 * GNUNET_DNSPARSER_Record' to NULL, in which case the DNSPARSER code
 * will populate 'name' from the 'service', 'proto' and 'domain_name'
 * fields in this struct.
 */
struct GNUNET_DNSPARSER_SrvRecord
{
  
  /**
   * Service name without the underscore (!).  Note that RFC 6335 clarifies the
   * set of legal characters for service names.
   * In UTF-8 format.  The library will convert from and to DNS-IDNA 
   * as necessary.  Use 'GNUNET_DNSPARSER_check_label' to test if an
   * individual label is well-formed.  If a given name is not well-formed,
   * creating the DNS packet will fail.
   */
  char *service;

  /**
   * Transport protocol (typcially "tcp" or "udp", but others might be allowed).
   * Without the underscore (!).
   */
  char *proto;

  /**
   * Domain name for which the record is valid
   * In UTF-8 format.  The library will convert from and to DNS-IDNA 
   * as necessary.  Use 'GNUNET_DNSPARSER_check_label' to test if an
   * individual label is well-formed.  If a given name is not well-formed,
   * creating the DNS packet will fail.
   */
  char *domain_name;

  /**
   * Hostname offering the service.
   * In UTF-8 format.  The library will convert from and to DNS-IDNA 
   * as necessary.  Use 'GNUNET_DNSPARSER_check_label' to test if an
   * individual label is well-formed.  If a given name is not well-formed,
   * creating the DNS packet will fail.
   */
  char *target;

  /**
   * Preference for this entry (lower value is higher preference).  Clients
   * will contact hosts from the lowest-priority group first and fall back
   * to higher priorities if the low-priority entries are unavailable.
   */
  uint16_t priority;

  /**
   * Relative weight for records with the same priority.  Clients will use
   * the hosts of the same (lowest) priority with a probability proportional
   * to the weight given.
   */
  uint16_t weight;

  /**
   * TCP or UDP port of the service.
   */
  uint16_t port;

};

  
/**
 * Information from SOA records (RFC 1035).
 */
struct GNUNET_DNSPARSER_SoaRecord
{
  
  /**
   *The domainname of the name server that was the
   * original or primary source of data for this zone.
   * In UTF-8 format.  The library will convert from and to DNS-IDNA 
   * as necessary.  Use 'GNUNET_DNSPARSER_check_label' to test if an
   * individual label is well-formed.  If a given name is not well-formed,
   * creating the DNS packet will fail.
   */
  char *mname;

  /**
   * A domainname which specifies the mailbox of the
   * person responsible for this zone.
   * In UTF-8 format.  The library will convert from and to DNS-IDNA 
   * as necessary.  Use 'GNUNET_DNSPARSER_check_label' to test if an
   * individual label is well-formed.  If a given name is not well-formed,
   * creating the DNS packet will fail.
   */
  char *rname;

  /**
   * The version number of the original copy of the zone.  
   */
  uint32_t serial;

  /**
   * Time interval before the zone should be refreshed.
   */
  uint32_t refresh;

  /**
   * Time interval that should elapse before a failed refresh should
   * be retried.
   */
  uint32_t retry;

  /**
   * Time value that specifies the upper limit on the time interval
   * that can elapse before the zone is no longer authoritative.
   */
  uint32_t expire;

  /**
   * The bit minimum TTL field that should be exported with any RR
   * from this zone.
   */
  uint32_t minimum_ttl;
  
};


/**
 * Binary record information (unparsed).
 */
struct GNUNET_DNSPARSER_RawRecord
{

  /**
   * Binary record data.
   */
  void *data;

  /**
   * Number of bytes in data.
   */
  size_t data_len;
};


/**
 * A DNS response record.
 */
struct GNUNET_DNSPARSER_Record
{

  /**
   * Name of the record that the query is for (0-terminated).
   * In UTF-8 format.  The library will convert from and to DNS-IDNA 
   * as necessary.  Use #GNUNET_DNSPARSER_check_label to test if an
   * individual label is well-formed.  If a given name is not well-formed,
   * creating the DNS packet will fail.
   */
  char *name;

  /**
   * Payload of the record (which one of these is valid depends on the 'type').
   */
  union 
  {

    /**
     * For NS, CNAME and PTR records, this is the uncompressed 0-terminated hostname.
   * In UTF-8 format.  The library will convert from and to DNS-IDNA 
   * as necessary.  Use #GNUNET_DNSPARSER_check_label to test if an
   * individual label is well-formed.  If a given name is not well-formed,
   * creating the DNS packet will fail.
     */
    char *hostname;
    
    /**
     * SOA data for SOA records.
     */
    struct GNUNET_DNSPARSER_SoaRecord *soa;
    
    /**
     * MX data for MX records.
     */
    struct GNUNET_DNSPARSER_MxRecord *mx;

    /**
     * SRV data for SRV records.
     */
    struct GNUNET_DNSPARSER_SrvRecord *srv;

    /**
     * Raw data for all other types.
     */
    struct GNUNET_DNSPARSER_RawRecord raw;

  } data;


  /**
   * When does the record expire?
   */
  struct GNUNET_TIME_Absolute expiration_time;

  /**
   * See GNUNET_DNSPARSER_TYPE_*.
   */
  uint16_t type;

  /**
   * See GNUNET_TUN_DNS_CLASS_*.
   */
  uint16_t class;

};


/**
 * Easy-to-process, parsed version of a DNS packet.
 */
struct GNUNET_DNSPARSER_Packet
{
  /**
   * Array of all queries in the packet, must contain "num_queries" entries.
   */
  struct GNUNET_DNSPARSER_Query *queries;

  /**
   * Array of all answers in the packet, must contain "num_answers" entries.
   */
  struct GNUNET_DNSPARSER_Record *answers;

  /**
   * Array of all authority records in the packet, must contain "num_authority_records" entries.
   */
  struct GNUNET_DNSPARSER_Record *authority_records;

  /**
   * Array of all additional answers in the packet, must contain "num_additional_records" entries.
   */
  struct GNUNET_DNSPARSER_Record *additional_records;

  /**
   * Number of queries in the packet.
   */
  unsigned int num_queries;

  /**
   * Number of answers in the packet, should be 0 for queries.
   */
  unsigned int num_answers;

  /**
   * Number of authoritative answers in the packet, should be 0 for queries.
   */
  unsigned int num_authority_records;

  /**
   * Number of additional records in the packet, should be 0 for queries.
   */
  unsigned int num_additional_records;

  /**
   * Bitfield of DNS flags.
   */ 
  struct GNUNET_TUN_DnsFlags flags;

  /**
   * DNS ID (to match replies to requests).
   */
  uint16_t id;

};


/**
 * Check if a label in UTF-8 format can be coded into valid IDNA.
 * This can fail if the ASCII-conversion becomes longer than 63 characters.
 *
 * @param label label to check (UTF-8 string)
 * @return GNUNET_OK if the label can be converted to IDNA,
 *         GNUNET_SYSERR if the label is not valid for DNS names
 */
int
GNUNET_DNSPARSER_check_label (const char *label);


/**
 * Check if a hostname in UTF-8 format can be coded into valid IDNA.
 * This can fail if a label becomes longer than 63 characters or if
 * the entire name exceeds 253 characters.
 *
 * @param name name to check (UTF-8 string)
 * @return GNUNET_OK if the label can be converted to IDNA,
 *         GNUNET_SYSERR if the label is not valid for DNS names
 */
int
GNUNET_DNSPARSER_check_name (const char *name);


/**
 * Parse a UDP payload of a DNS packet in to a nice struct for further
 * processing and manipulation.
 *
 * @param udp_payload wire-format of the DNS packet
 * @param udp_payload_length number of bytes in udp_payload 
 * @return NULL on error, otherwise the parsed packet
 */
struct GNUNET_DNSPARSER_Packet *
GNUNET_DNSPARSER_parse (const char *udp_payload,
			size_t udp_payload_length);


/**
 * Free memory taken by a packet.
 *
 * @param p packet to free
 */
void
GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p);


/**
 * Given a DNS packet, generate the corresponding UDP payload.
 *
 * @param p packet to pack
 * @param max maximum allowed size for the resulting UDP payload
 * @param buf set to a buffer with the packed message
 * @param buf_length set to the length of buf
 * @return GNUNET_SYSERR if 'p' is invalid
 *         GNUNET_NO if 'p' was truncated (but there is still a result in 'buf')
 *         GNUNET_OK if 'p' was packed completely into '*buf'
 */
int
GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p,
		       uint16_t max,
		       char **buf,
		       size_t *buf_length);


#endif