aboutsummaryrefslogtreecommitdiff
path: root/src/dns
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-01-05 12:17:50 +0000
committerChristian Grothoff <christian@grothoff.org>2012-01-05 12:17:50 +0000
commit2f26ab4c1a43a754fbb1d2cc3e27e82db272f81e (patch)
tree38d518fcdddb311e01207138bb1cae77237d5786 /src/dns
parent8b7ec32a2fd246b2356a056abd7d17ebac81edcf (diff)
downloadgnunet-2f26ab4c1a43a754fbb1d2cc3e27e82db272f81e.tar.gz
gnunet-2f26ab4c1a43a754fbb1d2cc3e27e82db272f81e.zip
-dns API improvements, towards serialization
Diffstat (limited to 'src/dns')
-rw-r--r--src/dns/dnsparser.c331
-rw-r--r--src/dns/gnunet-dns-monitor.c15
2 files changed, 322 insertions, 24 deletions
diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c
index 40870c597..10a9d6d9a 100644
--- a/src/dns/dnsparser.c
+++ b/src/dns/dnsparser.c
@@ -212,6 +212,7 @@ parse_record (const char *udp_payload,
212 size_t old_off; 212 size_t old_off;
213 struct soa_data soa; 213 struct soa_data soa;
214 uint16_t mxpref; 214 uint16_t mxpref;
215 uint16_t data_len;
215 216
216 name = parse_name (udp_payload, 217 name = parse_name (udp_payload,
217 udp_payload_length, 218 udp_payload_length,
@@ -227,11 +228,9 @@ parse_record (const char *udp_payload,
227 r->class = ntohs (rl.class); 228 r->class = ntohs (rl.class);
228 r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 229 r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
229 ntohl (rl.ttl))); 230 ntohl (rl.ttl)));
230 r->data_len = ntohs (rl.data_len); 231 data_len = ntohs (rl.data_len);
231 if (*off + r->data_len > udp_payload_length) 232 if (*off + data_len > udp_payload_length)
232 return GNUNET_SYSERR; 233 return GNUNET_SYSERR;
233 if (0 == r->data_len)
234 return GNUNET_OK;
235 switch (r->type) 234 switch (r->type)
236 { 235 {
237 case GNUNET_DNSPARSER_TYPE_NS: 236 case GNUNET_DNSPARSER_TYPE_NS:
@@ -242,7 +241,7 @@ parse_record (const char *udp_payload,
242 udp_payload_length, 241 udp_payload_length,
243 off, 0); 242 off, 0);
244 if ( (NULL == r->data.hostname) || 243 if ( (NULL == r->data.hostname) ||
245 (old_off + r->data_len != *off) ) 244 (old_off + data_len != *off) )
246 return GNUNET_SYSERR; 245 return GNUNET_SYSERR;
247 return GNUNET_OK; 246 return GNUNET_OK;
248 case GNUNET_DNSPARSER_TYPE_SOA: 247 case GNUNET_DNSPARSER_TYPE_SOA:
@@ -265,7 +264,7 @@ parse_record (const char *udp_payload,
265 r->data.soa->expire = ntohl (soa.expire); 264 r->data.soa->expire = ntohl (soa.expire);
266 r->data.soa->minimum_ttl = ntohl (soa.minimum); 265 r->data.soa->minimum_ttl = ntohl (soa.minimum);
267 (*off) += sizeof (soa); 266 (*off) += sizeof (soa);
268 if (old_off + r->data_len != *off) 267 if (old_off + data_len != *off)
269 return GNUNET_SYSERR; 268 return GNUNET_SYSERR;
270 return GNUNET_OK; 269 return GNUNET_OK;
271 case GNUNET_DNSPARSER_TYPE_MX: 270 case GNUNET_DNSPARSER_TYPE_MX:
@@ -279,15 +278,16 @@ parse_record (const char *udp_payload,
279 r->data.mx->mxhost = parse_name (udp_payload, 278 r->data.mx->mxhost = parse_name (udp_payload,
280 udp_payload_length, 279 udp_payload_length,
281 off, 0); 280 off, 0);
282 if (old_off + r->data_len != *off) 281 if (old_off + data_len != *off)
283 return GNUNET_SYSERR; 282 return GNUNET_SYSERR;
284 return GNUNET_OK; 283 return GNUNET_OK;
285 default: 284 default:
286 r->data.raw = GNUNET_malloc (r->data_len); 285 r->data.raw.data = GNUNET_malloc (data_len);
287 memcpy (r->data.raw, &udp_payload[*off], r->data_len); 286 r->data.raw.data_len = data_len;
287 memcpy (r->data.raw.data, &udp_payload[*off], data_len);
288 break; 288 break;
289 } 289 }
290 (*off) += r->data_len; 290 (*off) += data_len;
291 return GNUNET_OK; 291 return GNUNET_OK;
292} 292}
293 293
@@ -425,7 +425,7 @@ free_record (struct GNUNET_DNSPARSER_Record *r)
425 GNUNET_free_non_null (r->data.hostname); 425 GNUNET_free_non_null (r->data.hostname);
426 break; 426 break;
427 default: 427 default:
428 GNUNET_free_non_null (r->data.raw); 428 GNUNET_free_non_null (r->data.raw.data);
429 break; 429 break;
430 } 430 }
431} 431}
@@ -457,10 +457,208 @@ GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p)
457} 457}
458 458
459 459
460/* ********************** DNS packet assembly code **************** */
461
462
463/**
464 * Add a DNS name to the UDP packet at the given location.
465 *
466 * @param dst where to write the name
467 * @param dst_len number of bytes in dst
468 * @param off pointer to offset where to write the name (increment by bytes used)
469 * @param name name to write
470 * @return GNUNET_SYSERR if 'name' is invalid
471 * GNUNET_NO if 'name' did not fit
472 * GNUNET_OK if 'name' was added to 'dst'
473 */
474static int
475add_name (char *dst,
476 size_t dst_len,
477 size_t *off,
478 const char *name)
479{
480 const char *dot;
481 size_t start;
482 size_t pos;
483 size_t len;
484
485 if (NULL == name)
486 return GNUNET_SYSERR;
487 start = *off;
488 if (start + strlen (name) + 2 > dst_len)
489 return GNUNET_NO;
490 pos = start;
491 do
492 {
493 dot = strchr (name, '.');
494 if (NULL == dot)
495 len = strlen (name);
496 else
497 len = dot - name;
498 if ( (len >= 64) || (len == 0) )
499 return GNUNET_NO; /* segment too long or empty */
500 dst[pos++] = (char) (uint8_t) len;
501 memcpy (&dst[pos], name, len);
502 pos += len;
503 name += len + 1; /* also skip dot */
504 }
505 while (NULL != dot);
506 dst[pos++] = '\0'; /* terminator */
507 *off = pos;
508 return GNUNET_OK;
509}
510
511
512/**
513 * Add a DNS query to the UDP packet at the given location.
514 *
515 * @param dst where to write the query
516 * @param dst_len number of bytes in dst
517 * @param off pointer to offset where to write the query (increment by bytes used)
518 * @param query query to write
519 * @return GNUNET_SYSERR if 'query' is invalid
520 * GNUNET_NO if 'query' did not fit
521 * GNUNET_OK if 'query' was added to 'dst'
522 */
523static int
524add_query (char *dst,
525 size_t dst_len,
526 size_t *off,
527 const struct GNUNET_DNSPARSER_Query *query)
528{
529 int ret;
530 struct query_line ql;
531
532 ret = add_name (dst, dst_len - sizeof (struct query_line), off, query->name);
533 if (ret != GNUNET_OK)
534 return ret;
535 ql.type = htons (query->type);
536 ql.class = htons (query->class);
537 memcpy (&dst[*off], &ql, sizeof (ql));
538 (*off) += sizeof (ql);
539 return GNUNET_OK;
540}
541
542
543/**
544 * Add an MX record to the UDP packet at the given location.
545 *
546 * @param dst where to write the mx record
547 * @param dst_len number of bytes in dst
548 * @param off pointer to offset where to write the mx information (increment by bytes used)
549 * @param mx mx information to write
550 * @return GNUNET_SYSERR if 'mx' is invalid
551 * GNUNET_NO if 'mx' did not fit
552 * GNUNET_OK if 'mx' was added to 'dst'
553 */
554static int
555add_mx (char *dst,
556 size_t dst_len,
557 size_t *off,
558 const struct GNUNET_DNSPARSER_MxRecord *mx)
559{
560 return GNUNET_SYSERR; // not implemented
561}
562
563
564/**
565 * Add an SOA record to the UDP packet at the given location.
566 *
567 * @param dst where to write the SOA record
568 * @param dst_len number of bytes in dst
569 * @param off pointer to offset where to write the SOA information (increment by bytes used)
570 * @param soa SOA information to write
571 * @return GNUNET_SYSERR if 'soa' is invalid
572 * GNUNET_NO if 'soa' did not fit
573 * GNUNET_OK if 'soa' was added to 'dst'
574 */
575static int
576add_soa (char *dst,
577 size_t dst_len,
578 size_t *off,
579 const struct GNUNET_DNSPARSER_SoaRecord *soa)
580{
581 return GNUNET_SYSERR; // not implemented
582}
583
584
585/**
586 * Add a DNS record to the UDP packet at the given location.
587 *
588 * @param dst where to write the query
589 * @param dst_len number of bytes in dst
590 * @param off pointer to offset where to write the query (increment by bytes used)
591 * @param record record to write
592 * @return GNUNET_SYSERR if 'record' is invalid
593 * GNUNET_NO if 'record' did not fit
594 * GNUNET_OK if 'record' was added to 'dst'
595 */
596static int
597add_record (char *dst,
598 size_t dst_len,
599 size_t *off,
600 const struct GNUNET_DNSPARSER_Record *record)
601{
602 int ret;
603 size_t start;
604 size_t pos;
605 struct record_line rl;
606
607 start = *off;
608 ret = add_name (dst, dst_len - sizeof (struct record_line), off, record->name);
609 if (ret != GNUNET_OK)
610 return ret;
611 /* '*off' is now the position where we will need to write the record line */
612
613 pos = *off + sizeof (struct record_line);
614 switch (record->type)
615 {
616 case GNUNET_DNSPARSER_TYPE_MX:
617 ret = add_mx (dst, dst_len, &pos, record->data.mx);
618 break;
619 case GNUNET_DNSPARSER_TYPE_SOA:
620 ret = add_soa (dst, dst_len, &pos, record->data.soa);
621 break;
622 case GNUNET_DNSPARSER_TYPE_NS:
623 case GNUNET_DNSPARSER_TYPE_CNAME:
624 case GNUNET_DNSPARSER_TYPE_PTR:
625 ret = add_name (dst, dst_len, &pos, record->data.hostname);
626 break;
627 default:
628 if (pos + record->data.raw.data_len > dst_len)
629 {
630 ret = GNUNET_NO;
631 break;
632 }
633 memcpy (&dst[pos], record->data.raw.data, record->data.raw.data_len);
634 pos += record->data.raw.data_len;
635 break;
636 }
637 if (pos - (*off + sizeof (struct record_line)) > UINT16_MAX)
638 {
639 /* record data too long */
640 *off = start;
641 return GNUNET_NO;
642 }
643 rl.type = htons (record->type);
644 rl.class = htons (record->class);
645 rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000); /* in seconds */
646 rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct record_line))));
647 memcpy (&dst[*off], &rl, sizeof (struct record_line));
648 *off = pos;
649 return GNUNET_OK;
650}
651
652
653
460/** 654/**
461 * Given a DNS packet, generate the corresponding UDP payload. 655 * Given a DNS packet, generate the corresponding UDP payload.
656 * Note that we do not attempt to pack the strings with pointers
657 * as this would complicate the code and this is about being
658 * simple and secure, not fast, fancy and broken like bind.
462 * 659 *
463 * @param p packet to pack 660 * @param p packet to pack
661 * @param max maximum allowed size for the resulting UDP payload
464 * @param buf set to a buffer with the packed message 662 * @param buf set to a buffer with the packed message
465 * @param buf_length set to the length of buf 663 * @param buf_length set to the length of buf
466 * @return GNUNET_SYSERR if 'p' is invalid 664 * @return GNUNET_SYSERR if 'p' is invalid
@@ -468,18 +666,119 @@ GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p)
468 * GNUNET_OK if 'p' was packed completely into '*buf' 666 * GNUNET_OK if 'p' was packed completely into '*buf'
469 */ 667 */
470int 668int
471GNUNET_DNSPARSER_pack (struct GNUNET_DNSPARSER_Packet *p, 669GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p,
670 uint16_t max,
472 char **buf, 671 char **buf,
473 size_t *buf_length) 672 size_t *buf_length)
474{ 673{
475 // FIXME: not implemented 674 struct dns_header dns;
476 GNUNET_break (0); 675 size_t off;
477 return GNUNET_SYSERR; 676 char tmp[max];
677 unsigned int i;
678 int ret;
679 int trc;
680
681 if ( (p->num_queries > UINT16_MAX) ||
682 (p->num_answers > UINT16_MAX) ||
683 (p->num_authority_records > UINT16_MAX) ||
684 (p->num_additional_records > UINT16_MAX) )
685 return GNUNET_SYSERR;
686 dns.id = p->id;
687 dns.flags = p->flags;
688 dns.query_count = htons (p->num_queries);
689 dns.answer_rcount = htons (p->num_answers);
690 dns.authority_rcount = htons (p->num_authority_records);
691 dns.additional_rcount = htons (p->num_additional_records);
692 off = sizeof (struct dns_header);
693 trc = GNUNET_NO;
694 for (i=0;i<p->num_queries;i++)
695 {
696 ret = add_query (tmp, sizeof (tmp), &off, &p->queries[i]);
697 if (GNUNET_SYSERR == ret)
698 return GNUNET_SYSERR;
699 if (GNUNET_NO == ret)
700 {
701 dns.query_count = htons ((uint16_t) (i-1));
702 trc = GNUNET_YES;
703 break;
704 }
705 }
706 for (i=0;i<p->num_answers;i++)
707 {
708 ret = add_record (tmp, sizeof (tmp), &off, &p->answers[i]);
709 if (GNUNET_SYSERR == ret)
710 return GNUNET_SYSERR;
711 if (GNUNET_NO == ret)
712 {
713 dns.answer_rcount = htons ((uint16_t) (i-1));
714 trc = GNUNET_YES;
715 break;
716 }
717 }
718 for (i=0;i<p->num_authority_records;i++)
719 {
720 ret = add_record (tmp, sizeof (tmp), &off, &p->authority_records[i]);
721 if (GNUNET_SYSERR == ret)
722 return GNUNET_SYSERR;
723 if (GNUNET_NO == ret)
724 {
725 dns.authority_rcount = htons ((uint16_t) (i-1));
726 trc = GNUNET_YES;
727 break;
728 }
729 }
730 for (i=0;i<p->num_additional_records;i++)
731 {
732 ret = add_record (tmp, sizeof (tmp), &off, &p->additional_records[i]);
733 if (GNUNET_SYSERR == ret)
734 return GNUNET_SYSERR;
735 if (GNUNET_NO == ret)
736 {
737 dns.additional_rcount = htons (i-1);
738 trc = GNUNET_YES;
739 break;
740 }
741 }
742 if (GNUNET_YES == trc)
743 dns.flags.message_truncated = 1;
744
745
746 memcpy (tmp, &dns, sizeof (struct dns_header));
747 *buf = GNUNET_malloc (off);
748 *buf_length = off;
749 memcpy (*buf, tmp, off);
750 return trc;
478} 751}
479 752
480 753
481 754
482 755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
483/* legacy code follows */ 782/* legacy code follows */
484 783
485/** 784/**
diff --git a/src/dns/gnunet-dns-monitor.c b/src/dns/gnunet-dns-monitor.c
index 18d08d4fc..9e86f9c2d 100644
--- a/src/dns/gnunet-dns-monitor.c
+++ b/src/dns/gnunet-dns-monitor.c
@@ -134,16 +134,16 @@ display_record (const struct GNUNET_DNSPARSER_Record *record)
134 switch (record->type) 134 switch (record->type)
135 { 135 {
136 case GNUNET_DNSPARSER_TYPE_A: 136 case GNUNET_DNSPARSER_TYPE_A:
137 if (record->data_len != sizeof (struct in_addr)) 137 if (record->data.raw.data_len != sizeof (struct in_addr))
138 format = "<invalid>"; 138 format = "<invalid>";
139 else 139 else
140 format = inet_ntop (AF_INET, record->data.raw, buf, sizeof (buf)); 140 format = inet_ntop (AF_INET, record->data.raw.data, buf, sizeof (buf));
141 break; 141 break;
142 case GNUNET_DNSPARSER_TYPE_AAAA: 142 case GNUNET_DNSPARSER_TYPE_AAAA:
143 if (record->data_len != sizeof (struct in6_addr)) 143 if (record->data.raw.data_len != sizeof (struct in6_addr))
144 format = "<invalid>"; 144 format = "<invalid>";
145 else 145 else
146 format = inet_ntop (AF_INET6, record->data.raw, buf, sizeof (buf)); 146 format = inet_ntop (AF_INET6, record->data.raw.data, buf, sizeof (buf));
147 break; 147 break;
148 case GNUNET_DNSPARSER_TYPE_NS: 148 case GNUNET_DNSPARSER_TYPE_NS:
149 case GNUNET_DNSPARSER_TYPE_CNAME: 149 case GNUNET_DNSPARSER_TYPE_CNAME:
@@ -182,8 +182,8 @@ display_record (const struct GNUNET_DNSPARSER_Record *record)
182 case GNUNET_DNSPARSER_TYPE_TXT: 182 case GNUNET_DNSPARSER_TYPE_TXT:
183 GNUNET_asprintf (&tmp, 183 GNUNET_asprintf (&tmp,
184 "%.*s", 184 "%.*s",
185 (unsigned int) record->data_len, 185 (unsigned int) record->data.raw.data_len,
186 record->data.raw); 186 record->data.raw.data);
187 format = tmp; 187 format = tmp;
188 break; 188 break;
189 default: 189 default:
@@ -191,12 +191,11 @@ display_record (const struct GNUNET_DNSPARSER_Record *record)
191 break; 191 break;
192 } 192 }
193 fprintf (stdout, 193 fprintf (stdout,
194 "\t\t%s %s: %s = %s (%u bytes, %u s)\n", 194 "\t\t%s %s: %s = %s (%u s)\n",
195 get_class (record->class), 195 get_class (record->class),
196 get_type (record->type), 196 get_type (record->type),
197 record->name, 197 record->name,
198 format, 198 format,
199 (unsigned int) record->data_len,
200 (unsigned int) (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000)); 199 (unsigned int) (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value / 1000));
201 GNUNET_free_non_null (tmp); 200 GNUNET_free_non_null (tmp);
202} 201}