summaryrefslogtreecommitdiff
path: root/src/gns/gnunet-service-gns_resolver.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-11-06 20:30:18 +0000
committerChristian Grothoff <christian@grothoff.org>2013-11-06 20:30:18 +0000
commitcc846ca686a7e2e894801b731630cfa50408b7e2 (patch)
tree50a773c27a807ed3db684de31cd39ce3ec609131 /src/gns/gnunet-service-gns_resolver.c
parent1ffbb120d6a59a9aceb875b3960101b37bbafd06 (diff)
downloadgnunet-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.c384
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 */
221struct 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 */
1190static void
1191handle_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);