diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-11-06 20:30:18 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-11-06 20:30:18 +0000 |
commit | cc846ca686a7e2e894801b731630cfa50408b7e2 (patch) | |
tree | 50a773c27a807ed3db684de31cd39ce3ec609131 /src/gns/gnunet-service-gns_resolver.c | |
parent | 1ffbb120d6a59a9aceb875b3960101b37bbafd06 (diff) | |
download | gnunet-cc846ca686a7e2e894801b731630cfa50408b7e2.tar.gz gnunet-cc846ca686a7e2e894801b731630cfa50408b7e2.zip |
-improve testcase to actually test #3093
Diffstat (limited to 'src/gns/gnunet-service-gns_resolver.c')
-rw-r--r-- | src/gns/gnunet-service-gns_resolver.c | 384 |
1 files changed, 265 insertions, 119 deletions
diff --git a/src/gns/gnunet-service-gns_resolver.c b/src/gns/gnunet-service-gns_resolver.c index c881b6b83..28ec58430 100644 --- a/src/gns/gnunet-service-gns_resolver.c +++ b/src/gns/gnunet-service-gns_resolver.c | |||
@@ -214,6 +214,30 @@ struct VpnContext | |||
214 | 214 | ||
215 | 215 | ||
216 | /** | 216 | /** |
217 | * Information we keep during the resolution of an | ||
218 | * IP address for a DNS server while handling a | ||
219 | * GNS2DNS record. | ||
220 | */ | ||
221 | struct Gns2DnsContext | ||
222 | { | ||
223 | |||
224 | /** | ||
225 | * DNS domain in which the resolution will continue | ||
226 | * (first part of the GNS2DNS record). | ||
227 | */ | ||
228 | char *ns; | ||
229 | |||
230 | /** | ||
231 | * Handle for the resolution of the IP part of the | ||
232 | * GNS2DNS record. Will return to us the addresses | ||
233 | * of the DNS resolver to use. | ||
234 | */ | ||
235 | struct GNS_ResolverHandle *rh; | ||
236 | |||
237 | }; | ||
238 | |||
239 | |||
240 | /** | ||
217 | * Handle to a currenty pending resolution. On result (positive or | 241 | * Handle to a currenty pending resolution. On result (positive or |
218 | * negative) the #GNS_ResultProcessor is called. | 242 | * negative) the #GNS_ResultProcessor is called. |
219 | */ | 243 | */ |
@@ -241,11 +265,17 @@ struct GNS_ResolverHandle | |||
241 | GNS_ResultProcessor proc; | 265 | GNS_ResultProcessor proc; |
242 | 266 | ||
243 | /** | 267 | /** |
244 | * closure passed to proc | 268 | * closure passed to @e proc |
245 | */ | 269 | */ |
246 | void* proc_cls; | 270 | void* proc_cls; |
247 | 271 | ||
248 | /** | 272 | /** |
273 | * Handle used during GNS2DNS resolution for looking up the | ||
274 | * IP address of the DNS server. | ||
275 | */ | ||
276 | struct Gns2DnsContext *g2dc; | ||
277 | |||
278 | /** | ||
249 | * Handle for DHT lookups. should be NULL if no lookups are in progress | 279 | * Handle for DHT lookups. should be NULL if no lookups are in progress |
250 | */ | 280 | */ |
251 | struct GNUNET_DHT_GetHandle *get_handle; | 281 | struct GNUNET_DHT_GetHandle *get_handle; |
@@ -1145,6 +1175,135 @@ vpn_allocation_cb (void *cls, | |||
1145 | 1175 | ||
1146 | 1176 | ||
1147 | /** | 1177 | /** |
1178 | * We've resolved the IP address for the DNS resolver to use | ||
1179 | * after encountering a GNS2DNS record. | ||
1180 | * | ||
1181 | * TODO: Right now we only foward the request to ONE DNS resolver, | ||
1182 | * even if we get multiple IP addresses back; a correct implementation | ||
1183 | * should try all DNS resolvers. | ||
1184 | * | ||
1185 | * @param cls the `struct GNS_ResolverHandle` where we encountered | ||
1186 | * the GNS2DNS record | ||
1187 | * @param rd_count number of records in @a rd | ||
1188 | * @param rd addresses for the DNS resolver (presumably) | ||
1189 | */ | ||
1190 | static void | ||
1191 | handle_gns2dns_result (void *cls, | ||
1192 | unsigned int rd_count, | ||
1193 | const struct GNUNET_GNSRECORD_Data *rd) | ||
1194 | { | ||
1195 | struct GNS_ResolverHandle *rh = cls; | ||
1196 | struct AuthorityChain *ac; | ||
1197 | unsigned int j; | ||
1198 | struct sockaddr *sa; | ||
1199 | struct sockaddr_in v4; | ||
1200 | struct sockaddr_in6 v6; | ||
1201 | size_t sa_len; | ||
1202 | |||
1203 | /* find suitable A/AAAA record */ | ||
1204 | rh->g2dc->rh = NULL; | ||
1205 | sa = NULL; | ||
1206 | sa_len = 0; | ||
1207 | for (j=0;j<rd_count;j++) | ||
1208 | { | ||
1209 | switch (rd[j].record_type) | ||
1210 | { | ||
1211 | case GNUNET_DNSPARSER_TYPE_A: | ||
1212 | if (sizeof (struct in_addr) != rd[j].data_size) | ||
1213 | { | ||
1214 | GNUNET_break_op (0); | ||
1215 | rh->proc (rh->proc_cls, 0, NULL); | ||
1216 | GNS_resolver_lookup_cancel (rh); | ||
1217 | return; | ||
1218 | } | ||
1219 | /* FIXME: might want to check if we support IPv4 here, | ||
1220 | and otherwise skip this one and hope we find another */ | ||
1221 | memset (&v4, 0, sizeof (v4)); | ||
1222 | sa_len = sizeof (v4); | ||
1223 | v4.sin_family = AF_INET; | ||
1224 | v4.sin_port = htons (53); | ||
1225 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1226 | v4.sin_len = (u_char) sa_len; | ||
1227 | #endif | ||
1228 | memcpy (&v4.sin_addr, | ||
1229 | rd[j].data, | ||
1230 | sizeof (struct in_addr)); | ||
1231 | sa = (struct sockaddr *) &v4; | ||
1232 | break; | ||
1233 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
1234 | if (sizeof (struct in6_addr) != rd[j].data_size) | ||
1235 | { | ||
1236 | GNUNET_break_op (0); | ||
1237 | rh->proc (rh->proc_cls, 0, NULL); | ||
1238 | GNS_resolver_lookup_cancel (rh); | ||
1239 | return; | ||
1240 | } | ||
1241 | /* FIXME: might want to check if we support IPv6 here, | ||
1242 | and otherwise skip this one and hope we find another */ | ||
1243 | memset (&v6, 0, sizeof (v6)); | ||
1244 | sa_len = sizeof (v6); | ||
1245 | v6.sin6_family = AF_INET6; | ||
1246 | v6.sin6_port = htons (53); | ||
1247 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1248 | v6.sin6_len = (u_char) sa_len; | ||
1249 | #endif | ||
1250 | memcpy (&v6.sin6_addr, | ||
1251 | rd[j].data, | ||
1252 | sizeof (struct in6_addr)); | ||
1253 | sa = (struct sockaddr *) &v6; | ||
1254 | break; | ||
1255 | default: | ||
1256 | break; | ||
1257 | } | ||
1258 | if (NULL != sa) | ||
1259 | break; | ||
1260 | } | ||
1261 | if (NULL == sa) | ||
1262 | { | ||
1263 | /* we cannot continue; NS without A/AAAA */ | ||
1264 | rh->proc (rh->proc_cls, 0, NULL); | ||
1265 | GNS_resolver_lookup_cancel (rh); | ||
1266 | return; | ||
1267 | } | ||
1268 | /* expand authority chain */ | ||
1269 | ac = GNUNET_new (struct AuthorityChain); | ||
1270 | ac->rh = rh; | ||
1271 | strcpy (ac->authority_info.dns_authority.name, | ||
1272 | rh->g2dc->ns); | ||
1273 | memcpy (&ac->authority_info.dns_authority.dns_ip, | ||
1274 | sa, | ||
1275 | sa_len); | ||
1276 | /* for DNS recursion, the label is the full DNS name, | ||
1277 | created from the remainder of the GNS name and the | ||
1278 | name in the NS record */ | ||
1279 | GNUNET_asprintf (&ac->label, | ||
1280 | "%.*s%s%s", | ||
1281 | (int) rh->name_resolution_pos, | ||
1282 | rh->name, | ||
1283 | (0 != rh->name_resolution_pos) ? "." : "", | ||
1284 | rh->g2dc->ns); | ||
1285 | GNUNET_free (rh->g2dc->ns); | ||
1286 | GNUNET_free (rh->g2dc); | ||
1287 | rh->g2dc = NULL; | ||
1288 | GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head, | ||
1289 | rh->ac_tail, | ||
1290 | ac); | ||
1291 | if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH) | ||
1292 | { | ||
1293 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1294 | _("GNS lookup resulted in DNS name that is too long (`%s')\n"), | ||
1295 | ac->label); | ||
1296 | rh->proc (rh->proc_cls, 0, NULL); | ||
1297 | GNS_resolver_lookup_cancel (rh); | ||
1298 | return; | ||
1299 | } | ||
1300 | /* recurse */ | ||
1301 | rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution, | ||
1302 | rh); | ||
1303 | } | ||
1304 | |||
1305 | |||
1306 | /** | ||
1148 | * Process a records that were decrypted from a block. | 1307 | * Process a records that were decrypted from a block. |
1149 | * | 1308 | * |
1150 | * @param cls closure with the `struct GNS_ResolverHandle` | 1309 | * @param cls closure with the `struct GNS_ResolverHandle` |
@@ -1159,11 +1318,6 @@ handle_gns_resolution_result (void *cls, | |||
1159 | struct GNS_ResolverHandle *rh = cls; | 1318 | struct GNS_ResolverHandle *rh = cls; |
1160 | struct AuthorityChain *ac; | 1319 | struct AuthorityChain *ac; |
1161 | unsigned int i; | 1320 | unsigned int i; |
1162 | unsigned int j; | ||
1163 | struct sockaddr *sa; | ||
1164 | struct sockaddr_in v4; | ||
1165 | struct sockaddr_in6 v6; | ||
1166 | size_t sa_len; | ||
1167 | char *cname; | 1321 | char *cname; |
1168 | struct VpnContext *vpn_ctx; | 1322 | struct VpnContext *vpn_ctx; |
1169 | const struct GNUNET_TUN_GnsVpnRecord *vpn; | 1323 | const struct GNUNET_TUN_GnsVpnRecord *vpn; |
@@ -1532,126 +1686,67 @@ handle_gns_resolution_result (void *cls, | |||
1532 | return; | 1686 | return; |
1533 | case GNUNET_GNSRECORD_TYPE_GNS2DNS: | 1687 | case GNUNET_GNSRECORD_TYPE_GNS2DNS: |
1534 | { | 1688 | { |
1535 | char *ns; | ||
1536 | /* resolution continues within DNS */ | 1689 | /* resolution continues within DNS */ |
1537 | if (GNUNET_DNSPARSER_MAX_NAME_LENGTH < rd[i].data_size) | 1690 | struct Gns2DnsContext *g2dc; |
1691 | char *ip; | ||
1692 | char *at; | ||
1693 | char *cp; | ||
1694 | char *ns; | ||
1695 | |||
1696 | cp = GNUNET_strndup (rd[i].data, | ||
1697 | rd[i].data_size); | ||
1698 | at = strchr (cp, '@'); | ||
1699 | if (NULL == at) | ||
1538 | { | 1700 | { |
1539 | GNUNET_break_op (0); | 1701 | GNUNET_break_op (0); |
1540 | rh->proc (rh->proc_cls, 0, NULL); | 1702 | rh->proc (rh->proc_cls, 0, NULL); |
1541 | GNS_resolver_lookup_cancel (rh); | 1703 | GNS_resolver_lookup_cancel (rh); |
1542 | return; | 1704 | return; |
1543 | } | 1705 | } |
1544 | /* find associated A/AAAA record */ | 1706 | *at = '\0'; |
1545 | sa = NULL; | 1707 | off = 0; |
1546 | sa_len = 0; | 1708 | ns = GNUNET_DNSPARSER_parse_name (cp, |
1547 | for (j=0;j<rd_count;j++) | 1709 | strlen (cp), |
1548 | { | 1710 | &off); |
1549 | switch (rd[j].record_type) | 1711 | if ( (NULL == ns) || |
1550 | { | 1712 | (off != strlen (cp)) ) |
1551 | case GNUNET_DNSPARSER_TYPE_A: | 1713 | { |
1552 | if (sizeof (struct in_addr) != rd[j].data_size) | 1714 | GNUNET_break_op (0); /* record not well-formed */ |
1553 | { | 1715 | rh->proc (rh->proc_cls, 0, NULL); |
1554 | GNUNET_break_op (0); | 1716 | GNS_resolver_lookup_cancel (rh); |
1555 | rh->proc (rh->proc_cls, 0, NULL); | 1717 | GNUNET_free (cp); |
1556 | GNS_resolver_lookup_cancel (rh); | 1718 | return; |
1557 | return; | 1719 | } |
1558 | } | 1720 | off++; /* skip '@' */ |
1559 | /* FIXME: might want to check if we support IPv4 here, | 1721 | ip = GNUNET_DNSPARSER_parse_name (cp, |
1560 | and otherwise skip this one and hope we find another */ | 1722 | strlen (at + 1), |
1561 | memset (&v4, 0, sizeof (v4)); | 1723 | &off); |
1562 | sa_len = sizeof (v4); | 1724 | if ( (NULL == ip) || |
1563 | v4.sin_family = AF_INET; | 1725 | (off != rd[i].data_size) ) |
1564 | v4.sin_port = htons (53); | 1726 | { |
1565 | #if HAVE_SOCKADDR_IN_SIN_LEN | 1727 | GNUNET_break_op (0); /* record not well-formed */ |
1566 | v4.sin_len = (u_char) sa_len; | 1728 | rh->proc (rh->proc_cls, 0, NULL); |
1567 | #endif | 1729 | GNS_resolver_lookup_cancel (rh); |
1568 | memcpy (&v4.sin_addr, | 1730 | GNUNET_free (ns); |
1569 | rd[j].data, | 1731 | GNUNET_free (cp); |
1570 | sizeof (struct in_addr)); | 1732 | return; |
1571 | sa = (struct sockaddr *) &v4; | 1733 | } |
1572 | break; | 1734 | GNUNET_free (cp); |
1573 | case GNUNET_DNSPARSER_TYPE_AAAA: | 1735 | /* resolve 'ip' to determine the IP(s) of the DNS |
1574 | if (sizeof (struct in6_addr) != rd[j].data_size) | 1736 | resolver to use */ |
1575 | { | 1737 | g2dc = GNUNET_new (struct Gns2DnsContext); |
1576 | GNUNET_break_op (0); | 1738 | g2dc->ns = ns; |
1577 | rh->proc (rh->proc_cls, 0, NULL); | 1739 | g2dc->rh = GNUNET_new (struct GNS_ResolverHandle); |
1578 | GNS_resolver_lookup_cancel (rh); | 1740 | g2dc->rh->authority_zone = rh->ac_tail->authority_info.gns_authority; |
1579 | return; | 1741 | g2dc->rh->name = ip; |
1580 | } | 1742 | g2dc->rh->name_resolution_pos = strlen (ip); |
1581 | /* FIXME: might want to check if we support IPv6 here, | 1743 | g2dc->rh->proc = &handle_gns2dns_result; |
1582 | and otherwise skip this one and hope we find another */ | 1744 | g2dc->rh->proc_cls = rh; |
1583 | memset (&v6, 0, sizeof (v6)); | 1745 | g2dc->rh->record_type = GNUNET_GNSRECORD_TYPE_ANY; |
1584 | sa_len = sizeof (v6); | 1746 | g2dc->rh->only_cached = GNUNET_NO; |
1585 | v6.sin6_family = AF_INET6; | 1747 | g2dc->rh->loop_limiter = rh->loop_limiter + 1; |
1586 | v6.sin6_port = htons (53); | 1748 | rh->g2dc = g2dc; |
1587 | #if HAVE_SOCKADDR_IN_SIN_LEN | 1749 | start_resolver_lookup (g2dc->rh); |
1588 | v6.sin6_len = (u_char) sa_len; | ||
1589 | #endif | ||
1590 | memcpy (&v6.sin6_addr, | ||
1591 | rd[j].data, | ||
1592 | sizeof (struct in6_addr)); | ||
1593 | sa = (struct sockaddr *) &v6; | ||
1594 | break; | ||
1595 | default: | ||
1596 | break; | ||
1597 | } | ||
1598 | if (NULL != sa) | ||
1599 | break; | ||
1600 | } | ||
1601 | if (NULL == sa) | ||
1602 | { | ||
1603 | /* we cannot continue; NS without A/AAAA */ | ||
1604 | rh->proc (rh->proc_cls, 0, NULL); | ||
1605 | GNS_resolver_lookup_cancel (rh); | ||
1606 | return; | ||
1607 | } | ||
1608 | /* expand authority chain */ | ||
1609 | ac = GNUNET_new (struct AuthorityChain); | ||
1610 | ac->rh = rh; | ||
1611 | off = 0; | ||
1612 | ns = GNUNET_DNSPARSER_parse_name (rd[i].data, | ||
1613 | rd[i].data_size, | ||
1614 | &off); | ||
1615 | if ( (NULL == ns) || | ||
1616 | (off != rd[i].data_size) ) | ||
1617 | { | ||
1618 | GNUNET_break_op (0); /* record not well-formed */ | ||
1619 | rh->proc (rh->proc_cls, 0, NULL); | ||
1620 | GNS_resolver_lookup_cancel (rh); | ||
1621 | GNUNET_free_non_null (ns); | ||
1622 | GNUNET_free (ac); | ||
1623 | return; | ||
1624 | } | ||
1625 | strcpy (ac->authority_info.dns_authority.name, | ||
1626 | ns); | ||
1627 | memcpy (&ac->authority_info.dns_authority.dns_ip, | ||
1628 | sa, | ||
1629 | sa_len); | ||
1630 | /* for DNS recursion, the label is the full DNS name, | ||
1631 | created from the remainder of the GNS name and the | ||
1632 | name in the NS record */ | ||
1633 | GNUNET_asprintf (&ac->label, | ||
1634 | "%.*s%s%s", | ||
1635 | (int) rh->name_resolution_pos, | ||
1636 | rh->name, | ||
1637 | (0 != rh->name_resolution_pos) ? "." : "", | ||
1638 | ns); | ||
1639 | GNUNET_free (ns); | ||
1640 | GNUNET_CONTAINER_DLL_insert_tail (rh->ac_head, | ||
1641 | rh->ac_tail, | ||
1642 | ac); | ||
1643 | if (strlen (ac->label) > GNUNET_DNSPARSER_MAX_NAME_LENGTH) | ||
1644 | { | ||
1645 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1646 | _("GNS lookup resulted in DNS name that is too long (`%s')\n"), | ||
1647 | ac->label); | ||
1648 | rh->proc (rh->proc_cls, 0, NULL); | ||
1649 | GNS_resolver_lookup_cancel (rh); | ||
1650 | return; | ||
1651 | } | ||
1652 | /* recurse */ | ||
1653 | rh->task_id = GNUNET_SCHEDULER_add_now (&recursive_resolution, | ||
1654 | rh); | ||
1655 | return; | 1750 | return; |
1656 | } | 1751 | } |
1657 | case GNUNET_DNSPARSER_TYPE_CNAME: | 1752 | case GNUNET_DNSPARSER_TYPE_CNAME: |
@@ -2000,7 +2095,41 @@ start_resolver_lookup (struct GNS_ResolverHandle *rh) | |||
2000 | { | 2095 | { |
2001 | struct AuthorityChain *ac; | 2096 | struct AuthorityChain *ac; |
2002 | char *y; | 2097 | char *y; |
2098 | struct in_addr v4; | ||
2099 | struct in6_addr v6; | ||
2003 | 2100 | ||
2101 | if (1 == inet_pton (AF_INET, | ||
2102 | rh->name, | ||
2103 | &v4)) | ||
2104 | { | ||
2105 | /* name is IPv4 address, pretend it's an A record */ | ||
2106 | struct GNUNET_GNSRECORD_Data rd; | ||
2107 | |||
2108 | rd.data = &v4; | ||
2109 | rd.data_size = sizeof (v4); | ||
2110 | rd.expiration_time = UINT64_MAX; | ||
2111 | rd.record_type = GNUNET_DNSPARSER_TYPE_A; | ||
2112 | rd.flags = 0; | ||
2113 | rh->proc (rh->proc_cls, 1, &rd); | ||
2114 | GNS_resolver_lookup_cancel (rh); | ||
2115 | return; | ||
2116 | } | ||
2117 | if (1 == inet_pton (AF_INET6, | ||
2118 | rh->name, | ||
2119 | &v6)) | ||
2120 | { | ||
2121 | /* name is IPv6 address, pretend it's an AAAA record */ | ||
2122 | struct GNUNET_GNSRECORD_Data rd; | ||
2123 | |||
2124 | rd.data = &v6; | ||
2125 | rd.data_size = sizeof (v6); | ||
2126 | rd.expiration_time = UINT64_MAX; | ||
2127 | rd.record_type = GNUNET_DNSPARSER_TYPE_AAAA; | ||
2128 | rd.flags = 0; | ||
2129 | rh->proc (rh->proc_cls, 1, &rd); | ||
2130 | GNS_resolver_lookup_cancel (rh); | ||
2131 | return; | ||
2132 | } | ||
2004 | if ( ( (GNUNET_YES == is_canonical (rh->name)) && | 2133 | if ( ( (GNUNET_YES == is_canonical (rh->name)) && |
2005 | (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) || | 2134 | (0 != strcmp (GNUNET_GNS_TLD, rh->name)) ) || |
2006 | ( (GNUNET_YES != is_gnu_tld (rh->name)) && | 2135 | ( (GNUNET_YES != is_gnu_tld (rh->name)) && |
@@ -2143,6 +2272,23 @@ GNS_resolver_lookup_cancel (struct GNS_ResolverHandle *rh) | |||
2143 | GNUNET_free (ac->label); | 2272 | GNUNET_free (ac->label); |
2144 | GNUNET_free (ac); | 2273 | GNUNET_free (ac); |
2145 | } | 2274 | } |
2275 | if (NULL != rh->g2dc) | ||
2276 | { | ||
2277 | /* rh->g2dc->rh is NOT in the DLL yet, so to enable us | ||
2278 | using GNS_resolver_lookup_cancel here, we need to | ||
2279 | add it first... */ | ||
2280 | if (NULL != rh->g2dc->rh) | ||
2281 | { | ||
2282 | GNUNET_CONTAINER_DLL_insert (rlh_head, | ||
2283 | rlh_tail, | ||
2284 | rh->g2dc->rh); | ||
2285 | GNS_resolver_lookup_cancel (rh->g2dc->rh); | ||
2286 | rh->g2dc->rh = NULL; | ||
2287 | } | ||
2288 | GNUNET_free (rh->g2dc->ns); | ||
2289 | GNUNET_free (rh->g2dc); | ||
2290 | rh->g2dc = NULL; | ||
2291 | } | ||
2146 | if (GNUNET_SCHEDULER_NO_TASK != rh->task_id) | 2292 | if (GNUNET_SCHEDULER_NO_TASK != rh->task_id) |
2147 | { | 2293 | { |
2148 | GNUNET_SCHEDULER_cancel (rh->task_id); | 2294 | GNUNET_SCHEDULER_cancel (rh->task_id); |