diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-06-21 10:24:08 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-06-21 10:24:08 +0000 |
commit | 4720597f680ae81b1a7c5e43f6d05bc1fdbe183f (patch) | |
tree | ad9b8bbcd716bd404ba733ccb941a34f96298829 /src/dns | |
parent | ab8a8a6b9177b4af9aa923315a5dbf540091d3fa (diff) | |
download | gnunet-4720597f680ae81b1a7c5e43f6d05bc1fdbe183f.tar.gz gnunet-4720597f680ae81b1a7c5e43f6d05bc1fdbe183f.zip |
-towards fixing #2268: srv parsing/serialization
Diffstat (limited to 'src/dns')
-rw-r--r-- | src/dns/dnsparser.c | 128 |
1 files changed, 124 insertions, 4 deletions
diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c index c11ec25d6..c6a60cd44 100644 --- a/src/dns/dnsparser.c +++ b/src/dns/dnsparser.c | |||
@@ -325,6 +325,9 @@ parse_record (const char *udp_payload, | |||
325 | struct soa_data soa; | 325 | struct soa_data soa; |
326 | uint16_t mxpref; | 326 | uint16_t mxpref; |
327 | uint16_t data_len; | 327 | uint16_t data_len; |
328 | struct srv_data srv; | ||
329 | char *ndup; | ||
330 | char *tok; | ||
328 | 331 | ||
329 | name = parse_name (udp_payload, | 332 | name = parse_name (udp_payload, |
330 | udp_payload_length, | 333 | udp_payload_length, |
@@ -393,6 +396,49 @@ parse_record (const char *udp_payload, | |||
393 | if (old_off + data_len != *off) | 396 | if (old_off + data_len != *off) |
394 | return GNUNET_SYSERR; | 397 | return GNUNET_SYSERR; |
395 | return GNUNET_OK; | 398 | return GNUNET_OK; |
399 | case GNUNET_DNSPARSER_TYPE_SRV: | ||
400 | if ('_' != *r->data.hostname) | ||
401 | return GNUNET_SYSERR; /* all valid srv names must start with "_" */ | ||
402 | if (NULL == strstr (r->data.hostname, "._")) | ||
403 | return GNUNET_SYSERR; /* necessary string from "._$PROTO" not present */ | ||
404 | old_off = *off; | ||
405 | if (*off + sizeof (struct srv_data) > udp_payload_length) | ||
406 | return GNUNET_SYSERR; | ||
407 | memcpy (&srv, &udp_payload[*off], sizeof (struct srv_data)); | ||
408 | (*off) += sizeof (struct srv_data); | ||
409 | r->data.srv = GNUNET_malloc (sizeof (struct GNUNET_DNSPARSER_SrvRecord)); | ||
410 | r->data.srv->priority = ntohs (srv.prio); | ||
411 | r->data.srv->weight = ntohs (srv.weight); | ||
412 | r->data.srv->port = ntohs (srv.port); | ||
413 | /* parse 'data.hostname' into components, which are | ||
414 | "_$SERVICE._$PROTO.$DOMAIN_NAME" */ | ||
415 | ndup = GNUNET_strdup (r->data.hostname); | ||
416 | tok = strtok (ndup, "."); | ||
417 | GNUNET_assert ('_' == *tok); | ||
418 | r->data.srv->service = GNUNET_strdup (&tok[1]); | ||
419 | tok = strtok (NULL, "."); | ||
420 | if ('_' != *tok) | ||
421 | { | ||
422 | GNUNET_free (r->data.srv); | ||
423 | GNUNET_free (ndup); | ||
424 | return GNUNET_SYSERR; | ||
425 | } | ||
426 | r->data.srv->proto = GNUNET_strdup (&tok[1]); | ||
427 | tok = strtok (NULL, "."); | ||
428 | if (NULL == tok) | ||
429 | { | ||
430 | GNUNET_free (r->data.srv); | ||
431 | GNUNET_free (ndup); | ||
432 | return GNUNET_SYSERR; | ||
433 | } | ||
434 | r->data.srv->domain_name = GNUNET_strdup (tok); | ||
435 | GNUNET_free (ndup); | ||
436 | r->data.srv->target = parse_name (udp_payload, | ||
437 | udp_payload_length, | ||
438 | off, 0); | ||
439 | if (old_off + data_len != *off) | ||
440 | return GNUNET_SYSERR; | ||
441 | return GNUNET_OK; | ||
396 | default: | 442 | default: |
397 | r->data.raw.data = GNUNET_malloc (data_len); | 443 | r->data.raw.data = GNUNET_malloc (data_len); |
398 | r->data.raw.data_len = data_len; | 444 | r->data.raw.data_len = data_len; |
@@ -505,6 +551,24 @@ free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa) | |||
505 | 551 | ||
506 | 552 | ||
507 | /** | 553 | /** |
554 | * Free SRV information record. | ||
555 | * | ||
556 | * @param srv record to free | ||
557 | */ | ||
558 | static void | ||
559 | free_srv (struct GNUNET_DNSPARSER_SrvRecord *srv) | ||
560 | { | ||
561 | if (NULL == srv) | ||
562 | return; | ||
563 | GNUNET_free_non_null (srv->target); | ||
564 | GNUNET_free_non_null (srv->domain_name); | ||
565 | GNUNET_free_non_null (srv->proto); | ||
566 | GNUNET_free_non_null (srv->service); | ||
567 | GNUNET_free (srv); | ||
568 | } | ||
569 | |||
570 | |||
571 | /** | ||
508 | * Free MX information record. | 572 | * Free MX information record. |
509 | * | 573 | * |
510 | * @param mx record to free | 574 | * @param mx record to free |
@@ -531,6 +595,9 @@ free_record (struct GNUNET_DNSPARSER_Record *r) | |||
531 | case GNUNET_DNSPARSER_TYPE_SOA: | 595 | case GNUNET_DNSPARSER_TYPE_SOA: |
532 | free_soa (r->data.soa); | 596 | free_soa (r->data.soa); |
533 | break; | 597 | break; |
598 | case GNUNET_DNSPARSER_TYPE_SRV: | ||
599 | free_srv (r->data.srv); | ||
600 | break; | ||
534 | case GNUNET_DNSPARSER_TYPE_NS: | 601 | case GNUNET_DNSPARSER_TYPE_NS: |
535 | case GNUNET_DNSPARSER_TYPE_CNAME: | 602 | case GNUNET_DNSPARSER_TYPE_CNAME: |
536 | case GNUNET_DNSPARSER_TYPE_PTR: | 603 | case GNUNET_DNSPARSER_TYPE_PTR: |
@@ -727,6 +794,43 @@ add_soa (char *dst, | |||
727 | 794 | ||
728 | 795 | ||
729 | /** | 796 | /** |
797 | * Add an SRV record to the UDP packet at the given location. | ||
798 | * | ||
799 | * @param dst where to write the SRV record | ||
800 | * @param dst_len number of bytes in dst | ||
801 | * @param off pointer to offset where to write the SRV information (increment by bytes used) | ||
802 | * can also change if there was an error | ||
803 | * @param srv SRV information to write | ||
804 | * @return GNUNET_SYSERR if 'srv' is invalid | ||
805 | * GNUNET_NO if 'srv' did not fit | ||
806 | * GNUNET_OK if 'srv' was added to 'dst' | ||
807 | */ | ||
808 | static int | ||
809 | add_srv (char *dst, | ||
810 | size_t dst_len, | ||
811 | size_t *off, | ||
812 | const struct GNUNET_DNSPARSER_SrvRecord *srv) | ||
813 | { | ||
814 | struct srv_data sd; | ||
815 | int ret; | ||
816 | |||
817 | if (*off + sizeof (struct srv_data) > dst_len) | ||
818 | return GNUNET_NO; | ||
819 | sd.prio = htons (srv->priority); | ||
820 | sd.weight = htons (srv->weight); | ||
821 | sd.port = htons (srv->port); | ||
822 | memcpy (&dst[*off], &sd, sizeof (sd)); | ||
823 | (*off) += sizeof (sd); | ||
824 | if (GNUNET_OK != (ret = add_name (dst, | ||
825 | dst_len, | ||
826 | off, | ||
827 | srv->target))) | ||
828 | return ret; | ||
829 | return GNUNET_OK; | ||
830 | } | ||
831 | |||
832 | |||
833 | /** | ||
730 | * Add a DNS record to the UDP packet at the given location. | 834 | * Add a DNS record to the UDP packet at the given location. |
731 | * | 835 | * |
732 | * @param dst where to write the query | 836 | * @param dst where to write the query |
@@ -748,10 +852,23 @@ add_record (char *dst, | |||
748 | size_t start; | 852 | size_t start; |
749 | size_t pos; | 853 | size_t pos; |
750 | struct record_line rl; | 854 | struct record_line rl; |
751 | 855 | char *name; | |
856 | |||
752 | start = *off; | 857 | start = *off; |
753 | ret = add_name (dst, dst_len - sizeof (struct record_line), off, record->name); | 858 | /* for SRV records, we can create the name from the details |
754 | if (ret != GNUNET_OK) | 859 | of the record if needed */ |
860 | name = record->name; | ||
861 | if ( (GNUNET_DNSPARSER_TYPE_SRV == record->type) && | ||
862 | (NULL == name) ) | ||
863 | GNUNET_asprintf (&name, | ||
864 | "_%s._%s.%s", | ||
865 | record->data.srv->service, | ||
866 | record->data.srv->proto, | ||
867 | record->data.srv->domain_name); | ||
868 | ret = add_name (dst, dst_len - sizeof (struct record_line), off, name); | ||
869 | if (name != record->name) | ||
870 | GNUNET_free (name); | ||
871 | if (GNUNET_OK != ret) | ||
755 | return ret; | 872 | return ret; |
756 | /* '*off' is now the position where we will need to write the record line */ | 873 | /* '*off' is now the position where we will need to write the record line */ |
757 | 874 | ||
@@ -769,6 +886,9 @@ add_record (char *dst, | |||
769 | case GNUNET_DNSPARSER_TYPE_PTR: | 886 | case GNUNET_DNSPARSER_TYPE_PTR: |
770 | ret = add_name (dst, dst_len, &pos, record->data.hostname); | 887 | ret = add_name (dst, dst_len, &pos, record->data.hostname); |
771 | break; | 888 | break; |
889 | case GNUNET_DNSPARSER_TYPE_SRV: | ||
890 | ret = add_srv (dst, dst_len, &pos, record->data.srv); | ||
891 | break; | ||
772 | default: | 892 | default: |
773 | if (pos + record->data.raw.data_len > dst_len) | 893 | if (pos + record->data.raw.data_len > dst_len) |
774 | { | 894 | { |
@@ -780,7 +900,7 @@ add_record (char *dst, | |||
780 | ret = GNUNET_OK; | 900 | ret = GNUNET_OK; |
781 | break; | 901 | break; |
782 | } | 902 | } |
783 | if (ret != GNUNET_OK) | 903 | if (GNUNET_OK != ret) |
784 | { | 904 | { |
785 | *off = start; | 905 | *off = start; |
786 | return GNUNET_NO; | 906 | return GNUNET_NO; |