GNUnet  0.10.x
Functions
dnsparser.c File Reference

helper library to parse DNS packets. More...

#include "platform.h"
#include "gnunet_util_lib.h"
Include dependency graph for dnsparser.c:

Go to the source code of this file.

Functions

int GNUNET_DNSPARSER_check_label (const char *label)
 Check if a label in UTF-8 format can be coded into valid IDNA. More...
 
int GNUNET_DNSPARSER_check_name (const char *name)
 Check if a label in UTF-8 format can be coded into valid IDNA. More...
 
void GNUNET_DNSPARSER_free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa)
 Free SOA information record. More...
 
void GNUNET_DNSPARSER_free_cert (struct GNUNET_DNSPARSER_CertRecord *cert)
 Free CERT information record. More...
 
void GNUNET_DNSPARSER_free_srv (struct GNUNET_DNSPARSER_SrvRecord *srv)
 Free SRV information record. More...
 
void GNUNET_DNSPARSER_free_mx (struct GNUNET_DNSPARSER_MxRecord *mx)
 Free MX information record. More...
 
void GNUNET_DNSPARSER_free_record (struct GNUNET_DNSPARSER_Record *r)
 Free the given DNS record. More...
 
static char * parse_name (const char *udp_payload, size_t udp_payload_length, size_t *off, unsigned int depth)
 Parse name inside of a DNS query or record. More...
 
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. More...
 
int GNUNET_DNSPARSER_parse_query (const char *udp_payload, size_t udp_payload_length, size_t *off, struct GNUNET_DNSPARSER_Query *q)
 Parse a DNS query entry. More...
 
struct GNUNET_DNSPARSER_SoaRecordGNUNET_DNSPARSER_parse_soa (const char *udp_payload, size_t udp_payload_length, size_t *off)
 Parse a DNS SOA record. More...
 
struct GNUNET_DNSPARSER_MxRecordGNUNET_DNSPARSER_parse_mx (const char *udp_payload, size_t udp_payload_length, size_t *off)
 Parse a DNS MX record. More...
 
struct GNUNET_DNSPARSER_SrvRecordGNUNET_DNSPARSER_parse_srv (const char *udp_payload, size_t udp_payload_length, size_t *off)
 Parse a DNS SRV record. More...
 
struct GNUNET_DNSPARSER_CertRecordGNUNET_DNSPARSER_parse_cert (const char *udp_payload, size_t udp_payload_length, size_t *off)
 Parse a DNS CERT record. More...
 
int GNUNET_DNSPARSER_parse_record (const char *udp_payload, size_t udp_payload_length, size_t *off, struct GNUNET_DNSPARSER_Record *r)
 Parse a DNS record entry. More...
 
struct GNUNET_DNSPARSER_PacketGNUNET_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. More...
 
struct GNUNET_DNSPARSER_RecordGNUNET_DNSPARSER_duplicate_record (const struct GNUNET_DNSPARSER_Record *r)
 Duplicate (deep-copy) the given DNS record. More...
 
struct GNUNET_DNSPARSER_SoaRecordGNUNET_DNSPARSER_duplicate_soa_record (const struct GNUNET_DNSPARSER_SoaRecord *r)
 Duplicate (deep-copy) the given DNS record. More...
 
struct GNUNET_DNSPARSER_CertRecordGNUNET_DNSPARSER_duplicate_cert_record (const struct GNUNET_DNSPARSER_CertRecord *r)
 Duplicate (deep-copy) the given DNS record. More...
 
struct GNUNET_DNSPARSER_MxRecordGNUNET_DNSPARSER_duplicate_mx_record (const struct GNUNET_DNSPARSER_MxRecord *r)
 Duplicate (deep-copy) the given DNS record. More...
 
struct GNUNET_DNSPARSER_SrvRecordGNUNET_DNSPARSER_duplicate_srv_record (const struct GNUNET_DNSPARSER_SrvRecord *r)
 Duplicate (deep-copy) the given DNS record. More...
 
void GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p)
 Free memory taken by a packet. More...
 
int GNUNET_DNSPARSER_builder_add_name (char *dst, size_t dst_len, size_t *off, const char *name)
 Add a DNS name to the UDP packet at the given location, converting the name to IDNA notation as necessary. More...
 
int GNUNET_DNSPARSER_builder_add_query (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_Query *query)
 Add a DNS query to the UDP packet at the given location. More...
 
int GNUNET_DNSPARSER_builder_add_mx (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_MxRecord *mx)
 Add an MX record to the UDP packet at the given location. More...
 
int GNUNET_DNSPARSER_builder_add_cert (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_CertRecord *cert)
 Add a CERT record to the UDP packet at the given location. More...
 
int GNUNET_DNSPARSER_builder_add_soa (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_SoaRecord *soa)
 Add an SOA record to the UDP packet at the given location. More...
 
int GNUNET_DNSPARSER_builder_add_srv (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_SrvRecord *srv)
 Add an SRV record to the UDP packet at the given location. More...
 
static int add_record (char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_Record *record)
 Add a DNS record to the UDP packet at the given location. More...
 
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. More...
 
char * GNUNET_DNSPARSER_bin_to_hex (const void *data, size_t data_size)
 Convert a block of binary data to HEX. More...
 
size_t GNUNET_DNSPARSER_hex_to_bin (const char *hex, void *data)
 Convert a HEX string to block of binary data. More...
 

Detailed Description

helper library to parse DNS packets.

Author
Philipp Toelke
Christian Grothoff

Definition in file dnsparser.c.

Function Documentation

◆ parse_name()

static char* parse_name ( const char *  udp_payload,
size_t  udp_payload_length,
size_t *  off,
unsigned int  depth 
)
static

Parse name inside of a DNS query or record.

Parameters
udp_payloadentire UDP payload
udp_payload_lengthlength of udp_payload
offpointer to the offset of the name to parse in the udp_payload (to be incremented by the size of the name)
depthcurrent depth of our recursion (to prevent stack overflow)
Returns
name as 0-terminated C string on success, NULL if the payload is malformed

Definition at line 220 of file dnsparser.c.

References _, GNUNET_asprintf(), GNUNET_break_op, GNUNET_ERROR_TYPE_INFO, GNUNET_free, GNUNET_log, GNUNET_strdup, len, and ret.

Referenced by GNUNET_DNSPARSER_parse_name().

224 {
225  const uint8_t *input = (const uint8_t *) udp_payload;
226  char *ret;
227  char *tmp;
228  char *xstr;
229  uint8_t len;
230  size_t xoff;
231  char *utf8;
232  Idna_rc rc;
233 
234  ret = GNUNET_strdup ("");
235  while (1)
236  {
237  if (*off >= udp_payload_length)
238  {
239  GNUNET_break_op (0);
240  goto error;
241  }
242  len = input[*off];
243  if (0 == len)
244  {
245  (*off)++;
246  break;
247  }
248  if (len < 64)
249  {
250  if (*off + 1 + len > udp_payload_length)
251  {
252  GNUNET_break_op (0);
253  goto error;
254  }
255  GNUNET_asprintf (&tmp, "%.*s", (int) len, &udp_payload[*off + 1]);
256  if (IDNA_SUCCESS !=
257  (rc = idna_to_unicode_8z8z (tmp, &utf8, IDNA_ALLOW_UNASSIGNED)))
258  {
260  _ ("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"),
261  tmp,
262  idna_strerror (rc));
263  GNUNET_free (tmp);
264  GNUNET_asprintf (&tmp,
265  "%s%.*s.",
266  ret,
267  (int) len,
268  &udp_payload[*off + 1]);
269  }
270  else
271  {
272  GNUNET_free (tmp);
273  GNUNET_asprintf (&tmp, "%s%s.", ret, utf8);
274 #if WINDOWS
275  idn_free (utf8);
276 #else
277  free (utf8);
278 #endif
279  }
280  GNUNET_free (ret);
281  ret = tmp;
282  *off += 1 + len;
283  }
284  else if ((64 | 128) == (len & (64 | 128)))
285  {
286  if (depth > 32)
287  {
288  GNUNET_break_op (0);
289  goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */
290  }
291  /* pointer to string */
292  if (*off + 1 > udp_payload_length)
293  {
294  GNUNET_break_op (0);
295  goto error;
296  }
297  xoff = ((len - (64 | 128)) << 8) + input[*off + 1];
298  xstr = parse_name (udp_payload, udp_payload_length, &xoff, depth + 1);
299  if (NULL == xstr)
300  {
301  GNUNET_break_op (0);
302  goto error;
303  }
304  GNUNET_asprintf (&tmp, "%s%s.", ret, xstr);
305  GNUNET_free (ret);
306  GNUNET_free (xstr);
307  ret = tmp;
308  if (strlen (ret) > udp_payload_length)
309  {
310  GNUNET_break_op (0);
311  goto error; /* we are looping (building an infinite string) */
312  }
313  *off += 2;
314  /* pointers always terminate names */
315  break;
316  }
317  else
318  {
319  /* neither pointer nor inline string, not supported... */
320  GNUNET_break_op (0);
321  goto error;
322  }
323  }
324  if (0 < strlen (ret))
325  ret[strlen (ret) - 1] = '\0'; /* eat tailing '.' */
326  return ret;
327 error:
328  GNUNET_break_op (0);
329  GNUNET_free (ret);
330  return NULL;
331 }
static char * parse_name(const char *udp_payload, size_t udp_payload_length, size_t *off, unsigned int depth)
Parse name inside of a DNS query or record.
Definition: dnsparser.c:220
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
#define GNUNET_break_op(cond)
Use this for assertion violations caused by other peers (i.e.
#define GNUNET_log(kind,...)
#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...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_record()

static int add_record ( char *  dst,
size_t  dst_len,
size_t *  off,
const struct GNUNET_DNSPARSER_Record record 
)
static

Add a DNS record to the UDP packet at the given location.

Parameters
dstwhere to write the query
dst_lennumber of bytes in dst
offpointer to offset where to write the query (increment by bytes used) must not be changed if there is an error
recordrecord to write
Returns
GNUNET_SYSERR if record is invalid GNUNET_NO if record did not fit GNUNET_OK if record was added to dst

Definition at line 1161 of file dnsparser.c.

References GNUNET_DNSPARSER_Record::cert, GNUNET_DNSPARSER_RawRecord::data, GNUNET_DNSPARSER_Record::data, GNUNET_DNSPARSER_RawRecord::data_len, GNUNET_TUN_DnsRecordLine::data_len, GNUNET_DNSPARSER_Record::dns_traffic_class, GNUNET_TUN_DnsRecordLine::dns_traffic_class, GNUNET_DNSPARSER_Record::expiration_time, GNUNET_DNSPARSER_builder_add_cert(), GNUNET_DNSPARSER_builder_add_mx(), GNUNET_DNSPARSER_builder_add_name(), GNUNET_DNSPARSER_builder_add_soa(), GNUNET_DNSPARSER_builder_add_srv(), GNUNET_DNSPARSER_TYPE_CERT, GNUNET_DNSPARSER_TYPE_CNAME, GNUNET_DNSPARSER_TYPE_MX, GNUNET_DNSPARSER_TYPE_NS, GNUNET_DNSPARSER_TYPE_PTR, GNUNET_DNSPARSER_TYPE_SOA, GNUNET_DNSPARSER_TYPE_SRV, GNUNET_memcpy, GNUNET_NO, GNUNET_OK, GNUNET_TIME_absolute_get_remaining(), GNUNET_DNSPARSER_Record::hostname, GNUNET_DNSPARSER_Record::mx, GNUNET_DNSPARSER_Record::name, GNUNET_DNSPARSER_Record::raw, GNUNET_TIME_Relative::rel_value_us, ret, GNUNET_DNSPARSER_Record::soa, GNUNET_DNSPARSER_Record::srv, start, GNUNET_TUN_DnsRecordLine::ttl, GNUNET_DNSPARSER_Record::type, and GNUNET_TUN_DnsRecordLine::type.

Referenced by GNUNET_DNSPARSER_pack().

1165 {
1166  int ret;
1167  size_t start;
1168  size_t pos;
1169  struct GNUNET_TUN_DnsRecordLine rl;
1170 
1171  start = *off;
1173  dst_len -
1174  sizeof (
1175  struct GNUNET_TUN_DnsRecordLine),
1176  off,
1177  record->name);
1178  if (GNUNET_OK != ret)
1179  return ret;
1180  /* '*off' is now the position where we will need to write the record line */
1181 
1182  pos = *off + sizeof (struct GNUNET_TUN_DnsRecordLine);
1183  switch (record->type)
1184  {
1186  ret = GNUNET_DNSPARSER_builder_add_mx (dst, dst_len, &pos, record->data.mx);
1187  break;
1189  ret =
1190  GNUNET_DNSPARSER_builder_add_cert (dst, dst_len, &pos, record->data.cert);
1191  break;
1193  ret =
1194  GNUNET_DNSPARSER_builder_add_soa (dst, dst_len, &pos, record->data.soa);
1195  break;
1200  dst_len,
1201  &pos,
1202  record->data.hostname);
1203  break;
1205  ret =
1206  GNUNET_DNSPARSER_builder_add_srv (dst, dst_len, &pos, record->data.srv);
1207  break;
1208  default:
1209  if (pos + record->data.raw.data_len > dst_len)
1210  {
1211  ret = GNUNET_NO;
1212  break;
1213  }
1214  GNUNET_memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len);
1215  pos += record->data.raw.data_len;
1216  ret = GNUNET_OK;
1217  break;
1218  }
1219  if (GNUNET_OK != ret)
1220  {
1221  *off = start;
1222  return GNUNET_NO;
1223  }
1224 
1225  if (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine)) > UINT16_MAX)
1226  {
1227  /* record data too long */
1228  *off = start;
1229  return GNUNET_NO;
1230  }
1231  rl.type = htons (record->type);
1232  rl.dns_traffic_class = htons (record->dns_traffic_class);
1233  rl.ttl = htonl (
1235  1000LL / 1000LL); /* in seconds */
1236  rl.data_len = htons (
1237  (uint16_t) (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine))));
1238  GNUNET_memcpy (&dst[*off], &rl, sizeof (struct GNUNET_TUN_DnsRecordLine));
1239  *off = pos;
1240  return GNUNET_OK;
1241 }
uint16_t type
See GNUNET_DNSPARSER_TYPE_*.
uint64_t rel_value_us
The actual value.
#define GNUNET_DNSPARSER_TYPE_CNAME
struct GNUNET_DNSPARSER_SrvRecord * srv
SRV data for SRV records.
static int start
Set if we are to start default services (including ARM).
Definition: gnunet-arm.c:39
int GNUNET_DNSPARSER_builder_add_srv(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_SrvRecord *srv)
Add an SRV record to the UDP packet at the given location.
Definition: dnsparser.c:1125
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_DNSPARSER_TYPE_MX
General DNS record prefix.
#define GNUNET_DNSPARSER_TYPE_PTR
#define GNUNET_DNSPARSER_TYPE_SOA
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.
#define GNUNET_memcpy(dst, src, n)
struct GNUNET_DNSPARSER_SoaRecord * soa
SOA data for SOA records.
int GNUNET_DNSPARSER_builder_add_soa(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_SoaRecord *soa)
Add an SOA record to the UDP packet at the given location.
Definition: dnsparser.c:1084
int GNUNET_DNSPARSER_builder_add_cert(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_CertRecord *cert)
Add a CERT record to the UDP packet at the given location.
Definition: dnsparser.c:1037
size_t data_len
Number of bytes in data.
void * data
Binary record data.
int GNUNET_DNSPARSER_builder_add_mx(char *dst, size_t dst_len, size_t *off, const struct GNUNET_DNSPARSER_MxRecord *mx)
Add an MX record to the UDP packet at the given location.
Definition: dnsparser.c:1008
struct GNUNET_TIME_Absolute expiration_time
When does the record expire?
struct GNUNET_DNSPARSER_MxRecord * mx
MX data for MX records.
#define GNUNET_DNSPARSER_TYPE_NS
uint16_t dns_traffic_class
See GNUNET_TUN_DNS_CLASS_*.
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition: time.c:331
union GNUNET_DNSPARSER_Record::@27 data
Payload of the record (which one of these is valid depends on the &#39;type&#39;).
int GNUNET_DNSPARSER_builder_add_name(char *dst, size_t dst_len, size_t *off, const char *name)
Add a DNS name to the UDP packet at the given location, converting the name to IDNA notation as neces...
Definition: dnsparser.c:889
#define GNUNET_DNSPARSER_TYPE_SRV
struct GNUNET_DNSPARSER_RawRecord raw
Raw data for all other types.
#define GNUNET_DNSPARSER_TYPE_CERT
struct GNUNET_DNSPARSER_CertRecord * cert
CERT data for CERT records.
Here is the call graph for this function:
Here is the caller graph for this function: