diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-05 12:17:50 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-05 12:17:50 +0000 |
commit | 2f26ab4c1a43a754fbb1d2cc3e27e82db272f81e (patch) | |
tree | 38d518fcdddb311e01207138bb1cae77237d5786 /src/dns | |
parent | 8b7ec32a2fd246b2356a056abd7d17ebac81edcf (diff) | |
download | gnunet-2f26ab4c1a43a754fbb1d2cc3e27e82db272f81e.tar.gz gnunet-2f26ab4c1a43a754fbb1d2cc3e27e82db272f81e.zip |
-dns API improvements, towards serialization
Diffstat (limited to 'src/dns')
-rw-r--r-- | src/dns/dnsparser.c | 331 | ||||
-rw-r--r-- | src/dns/gnunet-dns-monitor.c | 15 |
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 | */ | ||
474 | static int | ||
475 | add_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 | */ | ||
523 | static int | ||
524 | add_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 | */ | ||
554 | static int | ||
555 | add_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 | */ | ||
575 | static int | ||
576 | add_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 | */ | ||
596 | static int | ||
597 | add_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 | */ |
470 | int | 668 | int |
471 | GNUNET_DNSPARSER_pack (struct GNUNET_DNSPARSER_Packet *p, | 669 | GNUNET_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 | } |