• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* Copyright 1998 by the Massachusetts Institute of Technology.
3  * Copyright (C) 2008-2013 by Daniel Stenberg
4  *
5  * Permission to use, copy, modify, and distribute this
6  * software and its documentation for any purpose and without
7  * fee is hereby granted, provided that the above copyright
8  * notice appear in all copies and that both that copyright
9  * notice and this permission notice appear in supporting
10  * documentation, and that the name of M.I.T. not be used in
11  * advertising or publicity pertaining to distribution of the
12  * software without specific, written prior permission.
13  * M.I.T. makes no representations about the suitability of
14  * this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  */
17 
18 
19 #include "ares_setup.h"
20 
21 #ifdef HAVE_ARPA_INET_H
22 #  include <arpa/inet.h>
23 #endif
24 
25 #include "ares.h"
26 #include "ares_data.h"
27 #include "ares_inet_net_pton.h"
28 #include "ares_private.h"
29 
30 
ares_get_servers(ares_channel channel,struct ares_addr_node ** servers)31 int ares_get_servers(ares_channel channel,
32                      struct ares_addr_node **servers)
33 {
34   struct ares_addr_node *srvr_head = NULL;
35   struct ares_addr_node *srvr_last = NULL;
36   struct ares_addr_node *srvr_curr;
37   int status = ARES_SUCCESS;
38   int i;
39 
40   if (!channel)
41     return ARES_ENODATA;
42 
43   for (i = 0; i < channel->nservers; i++)
44     {
45       /* Allocate storage for this server node appending it to the list */
46       srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_NODE);
47       if (!srvr_curr)
48         {
49           status = ARES_ENOMEM;
50           break;
51         }
52       if (srvr_last)
53         {
54           srvr_last->next = srvr_curr;
55         }
56       else
57         {
58           srvr_head = srvr_curr;
59         }
60       srvr_last = srvr_curr;
61 
62       /* Fill this server node data */
63       srvr_curr->family = channel->servers[i].addr.family;
64       if (srvr_curr->family == AF_INET)
65         memcpy(&srvr_curr->addrV4, &channel->servers[i].addr.addrV4,
66                sizeof(srvr_curr->addrV4));
67       else
68         memcpy(&srvr_curr->addrV6, &channel->servers[i].addr.addrV6,
69                sizeof(srvr_curr->addrV6));
70     }
71 
72   if (status != ARES_SUCCESS)
73     {
74       if (srvr_head)
75         {
76           ares_free_data(srvr_head);
77           srvr_head = NULL;
78         }
79     }
80 
81   *servers = srvr_head;
82 
83   return status;
84 }
85 
ares_get_servers_ports(ares_channel channel,struct ares_addr_port_node ** servers)86 int ares_get_servers_ports(ares_channel channel,
87                            struct ares_addr_port_node **servers)
88 {
89   struct ares_addr_port_node *srvr_head = NULL;
90   struct ares_addr_port_node *srvr_last = NULL;
91   struct ares_addr_port_node *srvr_curr;
92   int status = ARES_SUCCESS;
93   int i;
94 
95   if (!channel)
96     return ARES_ENODATA;
97 
98   for (i = 0; i < channel->nservers; i++)
99     {
100       /* Allocate storage for this server node appending it to the list */
101       srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_PORT_NODE);
102       if (!srvr_curr)
103         {
104           status = ARES_ENOMEM;
105           break;
106         }
107       if (srvr_last)
108         {
109           srvr_last->next = srvr_curr;
110         }
111       else
112         {
113           srvr_head = srvr_curr;
114         }
115       srvr_last = srvr_curr;
116 
117       /* Fill this server node data */
118       srvr_curr->family = channel->servers[i].addr.family;
119       srvr_curr->udp_port = ntohs((unsigned short)channel->servers[i].addr.udp_port);
120       srvr_curr->tcp_port = ntohs((unsigned short)channel->servers[i].addr.tcp_port);
121       if (srvr_curr->family == AF_INET)
122         memcpy(&srvr_curr->addrV4, &channel->servers[i].addr.addrV4,
123                sizeof(srvr_curr->addrV4));
124       else
125         memcpy(&srvr_curr->addrV6, &channel->servers[i].addr.addrV6,
126                sizeof(srvr_curr->addrV6));
127     }
128 
129   if (status != ARES_SUCCESS)
130     {
131       if (srvr_head)
132         {
133           ares_free_data(srvr_head);
134           srvr_head = NULL;
135         }
136     }
137 
138   *servers = srvr_head;
139 
140   return status;
141 }
142 
ares_set_servers(ares_channel channel,struct ares_addr_node * servers)143 int ares_set_servers(ares_channel channel,
144                      struct ares_addr_node *servers)
145 {
146   struct ares_addr_node *srvr;
147   int num_srvrs = 0;
148   int i;
149 
150   if (ares_library_initialized() != ARES_SUCCESS)
151     return ARES_ENOTINITIALIZED;  /* LCOV_EXCL_LINE: n/a on non-WinSock */
152 
153   if (!channel)
154     return ARES_ENODATA;
155 
156   if (!ares__is_list_empty(&channel->all_queries))
157     return ARES_ENOTIMP;
158 
159   ares__destroy_servers_state(channel);
160 
161   for (srvr = servers; srvr; srvr = srvr->next)
162     {
163       num_srvrs++;
164     }
165 
166   if (num_srvrs > 0)
167     {
168       /* Allocate storage for servers state */
169       channel->servers = ares_malloc(num_srvrs * sizeof(struct server_state));
170       if (!channel->servers)
171         {
172           return ARES_ENOMEM;
173         }
174       channel->nservers = num_srvrs;
175       /* Fill servers state address data */
176       for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
177         {
178           channel->servers[i].addr.family = srvr->family;
179           channel->servers[i].addr.udp_port = 0;
180           channel->servers[i].addr.tcp_port = 0;
181           if (srvr->family == AF_INET)
182             memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
183                    sizeof(srvr->addrV4));
184           else
185             memcpy(&channel->servers[i].addr.addrV6, &srvr->addrV6,
186                    sizeof(srvr->addrV6));
187         }
188       /* Initialize servers state remaining data */
189       ares__init_servers_state(channel);
190     }
191 
192   return ARES_SUCCESS;
193 }
194 
ares_set_servers_ports(ares_channel channel,struct ares_addr_port_node * servers)195 int ares_set_servers_ports(ares_channel channel,
196                            struct ares_addr_port_node *servers)
197 {
198   struct ares_addr_port_node *srvr;
199   int num_srvrs = 0;
200   int i;
201 
202   if (ares_library_initialized() != ARES_SUCCESS)
203     return ARES_ENOTINITIALIZED;  /* LCOV_EXCL_LINE: n/a on non-WinSock */
204 
205   if (!channel)
206     return ARES_ENODATA;
207 
208   if (!ares__is_list_empty(&channel->all_queries))
209     return ARES_ENOTIMP;
210 
211   ares__destroy_servers_state(channel);
212 
213   for (srvr = servers; srvr; srvr = srvr->next)
214     {
215       num_srvrs++;
216     }
217 
218   if (num_srvrs > 0)
219     {
220       /* Allocate storage for servers state */
221       channel->servers = ares_malloc(num_srvrs * sizeof(struct server_state));
222       if (!channel->servers)
223         {
224           return ARES_ENOMEM;
225         }
226       channel->nservers = num_srvrs;
227       /* Fill servers state address data */
228       for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
229         {
230           channel->servers[i].addr.family = srvr->family;
231           channel->servers[i].addr.udp_port = htons((unsigned short)srvr->udp_port);
232           channel->servers[i].addr.tcp_port = htons((unsigned short)srvr->tcp_port);
233           if (srvr->family == AF_INET)
234             memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
235                    sizeof(srvr->addrV4));
236           else
237             memcpy(&channel->servers[i].addr.addrV6, &srvr->addrV6,
238                    sizeof(srvr->addrV6));
239         }
240       /* Initialize servers state remaining data */
241       ares__init_servers_state(channel);
242     }
243 
244   return ARES_SUCCESS;
245 }
246 
247 /* Incomming string format: host[:port][,host[:port]]... */
248 /* IPv6 addresses with ports require square brackets [fe80::1%lo0]:53 */
set_servers_csv(ares_channel channel,const char * _csv,int use_port)249 static int set_servers_csv(ares_channel channel,
250                            const char* _csv, int use_port)
251 {
252   size_t i;
253   char* csv = NULL;
254   char* ptr;
255   char* start_host;
256   int cc = 0;
257   int rv = ARES_SUCCESS;
258   struct ares_addr_port_node *servers = NULL;
259   struct ares_addr_port_node *last = NULL;
260 
261   if (ares_library_initialized() != ARES_SUCCESS)
262     return ARES_ENOTINITIALIZED;  /* LCOV_EXCL_LINE: n/a on non-WinSock */
263 
264   if (!channel)
265     return ARES_ENODATA;
266 
267   i = strlen(_csv);
268   if (i == 0)
269      return ARES_SUCCESS; /* blank all servers */
270 
271   csv = ares_malloc(i + 2);
272   if (!csv)
273     return ARES_ENOMEM;
274 
275   strcpy(csv, _csv);
276   if (csv[i-1] != ',') { /* make parsing easier by ensuring ending ',' */
277     csv[i] = ',';
278     csv[i+1] = 0;
279   }
280 
281   start_host = csv;
282   for (ptr = csv; *ptr; ptr++) {
283     if (*ptr == ':') {
284       /* count colons to determine if we have an IPv6 number or IPv4 with
285          port */
286       cc++;
287     }
288     else if (*ptr == '[') {
289       /* move start_host if an open square bracket is found wrapping an IPv6
290          address */
291       start_host = ptr + 1;
292     }
293     else if (*ptr == ',') {
294       char* pp = ptr - 1;
295       char* p = ptr;
296       int port = 0;
297       struct in_addr in4;
298       struct ares_in6_addr in6;
299       struct ares_addr_port_node *s = NULL;
300 
301       *ptr = 0; /* null terminate host:port string */
302       /* Got an entry..see if the port was specified. */
303       if (cc > 0) {
304         while (pp > start_host) {
305           /* a single close square bracket followed by a colon, ']:' indicates
306              an IPv6 address with port */
307           if ((*pp == ']') && (*p == ':'))
308             break; /* found port */
309           /* a single colon, ':' indicates an IPv4 address with port */
310           if ((*pp == ':') && (cc == 1))
311             break; /* found port */
312           if (!(ISDIGIT(*pp) || (*pp == ':'))) {
313             /* Found end of digits before we found :, so wasn't a port */
314             /* must allow ':' for IPv6 case of ']:' indicates we found a port */
315             pp = p = ptr;
316             break;
317           }
318           pp--;
319           p--;
320         }
321         if ((pp != start_host) && ((pp + 1) < ptr)) {
322           /* Found it. Parse over the port number */
323           /* when an IPv6 address is wrapped with square brackets the port
324              starts at pp + 2 */
325           if (*pp == ']')
326             p++; /* move p before ':' */
327           /* p will point to the start of the port */
328           port = (int)strtol(p, NULL, 10);
329           *pp = 0; /* null terminate host */
330         }
331       }
332       /* resolve host, try ipv4 first, rslt is in network byte order */
333       rv = ares_inet_pton(AF_INET, start_host, &in4);
334       if (!rv) {
335         /* Ok, try IPv6 then */
336         rv = ares_inet_pton(AF_INET6, start_host, &in6);
337         if (!rv) {
338           rv = ARES_EBADSTR;
339           goto out;
340         }
341         /* was ipv6, add new server */
342         s = ares_malloc(sizeof(*s));
343         if (!s) {
344           rv = ARES_ENOMEM;
345           goto out;
346         }
347         s->family = AF_INET6;
348         memcpy(&s->addr, &in6, sizeof(struct ares_in6_addr));
349       }
350       else {
351         /* was ipv4, add new server */
352         s = ares_malloc(sizeof(*s));
353         if (!s) {
354           rv = ARES_ENOMEM;
355           goto out;
356         }
357         s->family = AF_INET;
358         memcpy(&s->addr, &in4, sizeof(struct in_addr));
359       }
360       if (s) {
361         s->udp_port = use_port ? port: 0;
362         s->tcp_port = s->udp_port;
363         s->next = NULL;
364         if (last) {
365           last->next = s;
366           /* need to move last to maintain the linked list */
367           last = last->next;
368         }
369         else {
370           servers = s;
371           last = s;
372         }
373       }
374 
375       /* Set up for next one */
376       start_host = ptr + 1;
377       cc = 0;
378     }
379   }
380 
381   rv = ares_set_servers_ports(channel, servers);
382 
383   out:
384   if (csv)
385     ares_free(csv);
386   while (servers) {
387     struct ares_addr_port_node *s = servers;
388     servers = servers->next;
389     ares_free(s);
390   }
391 
392   return rv;
393 }
394 
ares_set_servers_csv(ares_channel channel,const char * _csv)395 int ares_set_servers_csv(ares_channel channel,
396                          const char* _csv)
397 {
398   return set_servers_csv(channel, _csv, FALSE);
399 }
400 
ares_set_servers_ports_csv(ares_channel channel,const char * _csv)401 int ares_set_servers_ports_csv(ares_channel channel,
402                                const char* _csv)
403 {
404   return set_servers_csv(channel, _csv, TRUE);
405 }
406 
407