# HG changeset patch # User asl # Date 1053934430 0 # Node ID 1aaed612fe59e024d946fc235496fdfeb553d5a0 # Parent 13e9f49a7dcb4fea9cfe7d0f8e2f825c57930206 * src/dns.c: (cyg_dns_res_start) New: Allow IPv6 to be used to transport queries to the DNS server. This requires a new API function to start the client which if protocol family independent. * tests/dns1.c: Added a test which uses IPv6 as the transport to the DNS server. * doc/dns.sgml: Documentation of new API function for IPv6. * cdl/dns.cdl: Comment that the default DNS server can be an IPv6 address. diff --git a/packages/net/ns/dns/current/ChangeLog b/packages/net/ns/dns/current/ChangeLog --- a/packages/net/ns/dns/current/ChangeLog +++ b/packages/net/ns/dns/current/ChangeLog @@ -1,3 +1,15 @@ +2003-05-22 Andrew Lunn + + * src/dns.c: (cyg_dns_res_start) New: Allow IPv6 to be used to + transport queries to the DNS server. This requires a new API + function to start the client which if protocol family + independent. + * tests/dns1.c: Added a test which uses IPv6 as the transport to + the DNS server. + * doc/dns.sgml: Documentation of new API function for IPv6. + * cdl/dns.cdl: Comment that the default DNS server can be an IPv6 + address. + 2003-05-14 Mark Salter * include/dns_impl.inl: Use strrchr instead of rindex. diff --git a/packages/net/ns/dns/current/cdl/dns.cdl b/packages/net/ns/dns/current/cdl/dns.cdl --- a/packages/net/ns/dns/current/cdl/dns.cdl +++ b/packages/net/ns/dns/current/cdl/dns.cdl @@ -77,8 +77,8 @@ cdl_package CYGPKG_NS_DNS { default_value 0 description " This option controls the use of a default, hard coded DNS - server. When this is enabled, the IP address in the CDL - option CYGDAT_NS_DNS_DEFAULT_SERVER is used in + server. When this is enabled, the IPv4 or IPv6 address in + the CDL option CYGDAT_NS_DNS_DEFAULT_SERVER is used in init_all_network_interfaces() to start the resolver using the specified server. The DHCP client or user code may override this by restarting the resolver." diff --git a/packages/net/ns/dns/current/doc/dns.sgml b/packages/net/ns/dns/current/doc/dns.sgml --- a/packages/net/ns/dns/current/doc/dns.sgml +++ b/packages/net/ns/dns/current/doc/dns.sgml @@ -67,11 +67,10 @@ is not safe is one thread using both and gethostbyaddr(). A call to one will destroy the results from the previous call -to the other function. getaddrinfo() is thread -safe and so is the preferred interface. - - -The client only uses IPv4 to access the DNS server. +to the other function. getaddrinfo() and +getnameinfo() are thread +safe and so these are the preferred interfaces. They are also address +family independent so making it easier to port code to IPv6. The DNS client will only return IPv4 addresses to RedBoot. At the moment this is not really a limitation, @@ -81,9 +80,21 @@ since RedBoot only supports IPv4 and not To initialise the DNS client the following function must be called: #include <network.h> +int cyg_dns_res_start(char * dns_server) + +Where dns_server is the address of the DNS server. The address +must be in numeric form and can be either an IPv4 or an IPv6 address. + +There also exists a deprecated function to start the DNS +client: + int cyg_dns_res_init(struct in_addr *dns_server) where dns_server is the address of the DNS server -the client should query. On Error this function returns -1, otherwise +the client should query. The address should be in network order and +can only be an IPv4 address. + + + On error both this function returns -1, otherwise 0 for success. If lookups are attemped before this function has been called, they will fail and return NULL, unless numeric host addresses are passed. In this cause, the address will be converted and returned @@ -189,7 +200,8 @@ and the domain name is taken from information: struct test_info_s { - char * dns_server; + char * dns_server_v4; + char * dns_server_v6; char * domain_name; char * hostname_v4; char * cname_v4; diff --git a/packages/net/ns/dns/current/include/dns.h b/packages/net/ns/dns/current/include/dns.h --- a/packages/net/ns/dns/current/include/dns.h +++ b/packages/net/ns/dns/current/include/dns.h @@ -11,6 +11,7 @@ // ------------------------------------------- // This file is part of eCos, the Embedded Configurable Operating System. // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Andrew Lunn // // eCos is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free @@ -54,8 +55,14 @@ #include #ifndef _POSIX_SOURCE -/* Initialise the DNS client with the address of the server */ +/* Initialise the DNS client with the address of the server. The + address should be a IPv4 or IPv6 numeric address */ +externC int cyg_dns_res_start(char * server); + +/* Old interface which is depricated */ externC int cyg_dns_res_init(struct in_addr *dns_server); + +/* Functions to manipulate the domainname */ externC int getdomainname(char *name, size_t len); externC int setdomainname(const char *name, size_t len); #endif diff --git a/packages/net/ns/dns/current/src/dns.c b/packages/net/ns/dns/current/src/dns.c --- a/packages/net/ns/dns/current/src/dns.c +++ b/packages/net/ns/dns/current/src/dns.c @@ -250,22 +250,21 @@ send_recv(char * msg, int len, int msgle /* Include the DNS client implementation code */ #include -/* Initialise the resolver. Open a socket and bind it to the address - of the server. return -1 if something goes wrong, otherwise 0. If - we are being called a second time we have to be careful to allow - any ongoing lookups to finish before we close the socket and - connect to a different DNS server. The danger here is that we may - have to wait for upto 32 seconds if the DNS server is down. - */ -int -cyg_dns_res_init(struct in_addr *dns_server) -{ - struct sockaddr_in server; - struct servent *sent; +/* (re)Start the DNS client. This opens a socket to the DNS server + who's address is passed in. This address can be either an IPv4 or + IPv6 address. This function can be called multiple times. Each + invocation will close any previous connection and make a new + connection to the new server. Note the address of the server must + be in numeric form since its not possible to do a DNS lookup! */ + +int cyg_dns_res_start(char * dns_server) { + static int init =0; + struct addrinfo * res; + int err; - CYG_REPORT_FUNCNAMETYPE( "cyg_dns_res_init", "returning %d" ); - CYG_REPORT_FUNCARG1( "dns_server=%08x", dns_server ); + CYG_REPORT_FUNCNAMETYPE( "cyg_dns_res_start", "returning %d" ); + CYG_REPORT_FUNCARG1( "dns_server=%s", dns_server ); CYG_CHECK_DATA_PTR( dns_server, "dns_server is not a valid pointer!" ); @@ -281,41 +280,63 @@ cyg_dns_res_init(struct in_addr *dns_ser cyg_drv_mutex_lock(&dns_mutex); } - - s = socket(PF_INET, SOCK_DGRAM, 0); - if (s < 0) { + err = getaddrinfo(dns_server,"domain", NULL, &res); + if (err != 0) { cyg_drv_mutex_unlock(&dns_mutex); CYG_REPORT_RETVAL( -1 ); return -1; } - sent = getservbyname("domain", "udp"); - if (sent == (struct servent *)0) { - s = -1; + s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (s == -1) { cyg_drv_mutex_unlock(&dns_mutex); + freeaddrinfo(res); CYG_REPORT_RETVAL( -1 ); return -1; } - - memcpy((char *)&server.sin_addr, dns_server, sizeof(server.sin_addr)); - server.sin_port = sent->s_port; - server.sin_family = AF_INET; - server.sin_len = sizeof(server); - if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) { + if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { s = -1; cyg_drv_mutex_unlock(&dns_mutex); + freeaddrinfo(res); CYG_REPORT_RETVAL( -1 ); return -1; } ptdindex = cyg_thread_new_data_index(); cyg_drv_mutex_unlock(&dns_mutex); - + freeaddrinfo(res); CYG_REPORT_RETVAL( 0 ); return 0; } +/* This is the old interface to start the resolver. It is only IPv4 + capable and so is now depricated in favor of cyg_dns_res_start(). + Initialise the resolver. Open a socket and bind it to the + address of the server. return -1 if something goes wrong, + otherwise 0. If we are being called a second time we have to be + careful to allow any ongoing lookups to finish before we close the + socket and connect to a different DNS server. The danger here is + that we may have to wait for upto 32 seconds if the DNS server is + down. */ +int +cyg_dns_res_init(struct in_addr *dns_server) +{ + char name[20]; + unsigned char *bytes = (unsigned char *)dns_server; + int ret; + + CYG_REPORT_FUNCNAMETYPE( "cyg_dns_res_init", "returning %d" ); + CYG_REPORT_FUNCARG1( "dns_server=%08x", dns_server ); + + diag_sprintf(name, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]); + + ret = cyg_dns_res_start(name); + + CYG_REPORT_RETVAL( ret ); + return ret; +} + /* add_answer checks to see if we already have this answer and if not, adds it to the answers. */ static int diff --git a/packages/net/ns/dns/current/tests/dns1.c b/packages/net/ns/dns/current/tests/dns1.c --- a/packages/net/ns/dns/current/tests/dns1.c +++ b/packages/net/ns/dns/current/tests/dns1.c @@ -70,7 +70,8 @@ static cyg_handle_t thread_handle; #define NELEM(x) (sizeof(x) / sizeof(x[0])) struct test_info_s { - char * dns_server; + char * dns_server_v4; + char * dns_server_v6; char * domain_name; char * hostname_v4; char * cname_v4; @@ -87,6 +88,7 @@ struct test_info_s { struct test_info_s test_info[] = { { "192.168.10.1", + "fe80::2ff:8eff:fe04:a18d", "lunn.org.", "hostnamev4", "cnamev4", @@ -134,7 +136,7 @@ void dns_test(struct test_info_s *info) #endif int error; - if (inet_pton(AF_INET, info->dns_server, (void *)&addr) < 0) { + if (inet_pton(AF_INET, info->dns_server_v4, (void *)&addr) < 0) { CYG_TEST_FAIL_FINISH("Error with DNS server address"); } cyg_dns_res_init(&addr); @@ -815,6 +817,64 @@ void dns_test(struct test_info_s *info) gai_strerror(error)); CYG_TEST_FAIL(buffer); } + + if (info->dns_server_v6) { + cyg_dns_res_start(info->dns_server_v6); + // Lookup the IPv4 and IPv6 FQDN cname + error = getaddrinfo(cname, NULL, &hints, &res); + + if (error == EAI_NONE) { +#ifdef CYGOPT_NS_DNS_FIRST_FAMILY_AF_INET6 + ai6 = res; + ai4 = res->ai_next; + CYG_TEST_PASS_FAIL((NULL != ai6->ai_next), + "[IPv6] IPv6 FQDN hostname not one result"); + CYG_TEST_PASS_FAIL((NULL == ai4->ai_next), + "[IPv6] IPv4 & IPv6 FQDN hostname two results"); +#else + ai4 = res; + ai6 = res->ai_next; + CYG_TEST_PASS_FAIL((NULL != ai4->ai_next), + "[IPv6] IPv6 FQDN hostname not one result"); + CYG_TEST_PASS_FAIL((NULL == ai6->ai_next), + "[IPv6] IPv4 & IPv6 FQDN hostname two results"); +#endif + getnameinfo(ai4->ai_addr, ai4->ai_addrlen, + buff, sizeof(buff), + NULL,0,NI_NUMERICHOST); + diag_sprintf(buffer,"[IPv6] Lookup %s: Result <%s is %s %s>", + cname, + ai4->ai_canonname, + familytoa(ai4->ai_family), + buff); + CYG_TEST_INFO(buffer); + CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa4, + (void*)ai4->ai_addr, + sizeof(sa4))) && + (ai4->ai_family == AF_INET), + "[IPv6] IPv4 & IPv6 FQDN cname address IPv4"); + CYG_TEST_PASS_FAIL((0 == strcmp(name, ai4->ai_canonname)), + "[IPv6] IPv4 & IPv6 FQDN cname name"); + getnameinfo(ai6->ai_addr, ai6->ai_addrlen, + buff, sizeof(buff), + NULL,0,NI_NUMERICHOST); + diag_sprintf(buffer,"[IPv6] Lookup %s: Result <%s %s>", + cname, + familytoa(ai6->ai_family), + buff); + CYG_TEST_INFO(buffer); + CYG_TEST_PASS_FAIL((0 == memcmp((void *)&sa6, + (void*)ai6->ai_addr, + sizeof(sa6))) && + (ai6->ai_family == AF_INET6), + "[IPv6] IPv4 & IPv6 FQDN cname address IPv6"); + freeaddrinfo(res); + } else { + diag_sprintf(buffer,"[IPv6] IPv4 & IPv6 FQDN cname: error %s", + gai_strerror(error)); + CYG_TEST_FAIL(buffer); + } + } #endif }