Revert "Imported Upstream version 1.17.1"
[platform/upstream/c-ares.git] / ares_options.c
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
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
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
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   ares__destroy_servers_state(channel);
157
158   for (srvr = servers; srvr; srvr = srvr->next)
159     {
160       num_srvrs++;
161     }
162
163   if (num_srvrs > 0)
164     {
165       /* Allocate storage for servers state */
166       channel->servers = ares_malloc(num_srvrs * sizeof(struct server_state));
167       if (!channel->servers)
168         {
169           return ARES_ENOMEM;
170         }
171       channel->nservers = num_srvrs;
172       /* Fill servers state address data */
173       for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
174         {
175           channel->servers[i].addr.family = srvr->family;
176           channel->servers[i].addr.udp_port = 0;
177           channel->servers[i].addr.tcp_port = 0;
178           if (srvr->family == AF_INET)
179             memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
180                    sizeof(srvr->addrV4));
181           else
182             memcpy(&channel->servers[i].addr.addrV6, &srvr->addrV6,
183                    sizeof(srvr->addrV6));
184         }
185       /* Initialize servers state remaining data */
186       ares__init_servers_state(channel);
187     }
188
189   return ARES_SUCCESS;
190 }
191
192 int ares_set_servers_ports(ares_channel channel,
193                            struct ares_addr_port_node *servers)
194 {
195   struct ares_addr_port_node *srvr;
196   int num_srvrs = 0;
197   int i;
198
199   if (ares_library_initialized() != ARES_SUCCESS)
200     return ARES_ENOTINITIALIZED;  /* LCOV_EXCL_LINE: n/a on non-WinSock */
201
202   if (!channel)
203     return ARES_ENODATA;
204
205   ares__destroy_servers_state(channel);
206
207   for (srvr = servers; srvr; srvr = srvr->next)
208     {
209       num_srvrs++;
210     }
211
212   if (num_srvrs > 0)
213     {
214       /* Allocate storage for servers state */
215       channel->servers = ares_malloc(num_srvrs * sizeof(struct server_state));
216       if (!channel->servers)
217         {
218           return ARES_ENOMEM;
219         }
220       channel->nservers = num_srvrs;
221       /* Fill servers state address data */
222       for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
223         {
224           channel->servers[i].addr.family = srvr->family;
225           channel->servers[i].addr.udp_port = htons((unsigned short)srvr->udp_port);
226           channel->servers[i].addr.tcp_port = htons((unsigned short)srvr->tcp_port);
227           if (srvr->family == AF_INET)
228             memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
229                    sizeof(srvr->addrV4));
230           else
231             memcpy(&channel->servers[i].addr.addrV6, &srvr->addrV6,
232                    sizeof(srvr->addrV6));
233         }
234       /* Initialize servers state remaining data */
235       ares__init_servers_state(channel);
236     }
237
238   return ARES_SUCCESS;
239 }
240
241 /* Incomming string format: host[:port][,host[:port]]... */
242 /* IPv6 addresses with ports require square brackets [fe80::1%lo0]:53 */
243 static int set_servers_csv(ares_channel channel,
244                            const char* _csv, int use_port)
245 {
246   size_t i;
247   char* csv = NULL;
248   char* ptr;
249   char* start_host;
250   int cc = 0;
251   int rv = ARES_SUCCESS;
252   struct ares_addr_port_node *servers = NULL;
253   struct ares_addr_port_node *last = NULL;
254
255   if (ares_library_initialized() != ARES_SUCCESS)
256     return ARES_ENOTINITIALIZED;  /* LCOV_EXCL_LINE: n/a on non-WinSock */
257
258   if (!channel)
259     return ARES_ENODATA;
260
261   ares__destroy_servers_state(channel);
262
263   i = strlen(_csv);
264   if (i == 0)
265      return ARES_SUCCESS; /* blank all servers */
266
267   csv = ares_malloc(i + 2);
268   if (!csv)
269     return ARES_ENOMEM;
270
271   strcpy(csv, _csv);
272   if (csv[i-1] != ',') { /* make parsing easier by ensuring ending ',' */
273     csv[i] = ',';
274     csv[i+1] = 0;
275   }
276
277   start_host = csv;
278   for (ptr = csv; *ptr; ptr++) {
279     if (*ptr == ':') {
280       /* count colons to determine if we have an IPv6 number or IPv4 with
281          port */
282       cc++;
283     }
284     else if (*ptr == '[') {
285       /* move start_host if an open square bracket is found wrapping an IPv6
286          address */
287       start_host = ptr + 1;
288     }
289     else if (*ptr == ',') {
290       char* pp = ptr - 1;
291       char* p = ptr;
292       int port = 0;
293       struct in_addr in4;
294       struct ares_in6_addr in6;
295       struct ares_addr_port_node *s = NULL;
296
297       *ptr = 0; /* null terminate host:port string */
298       /* Got an entry..see if the port was specified. */
299       if (cc > 0) {
300         while (pp > start_host) {
301           /* a single close square bracket followed by a colon, ']:' indicates
302              an IPv6 address with port */
303           if ((*pp == ']') && (*p == ':'))
304             break; /* found port */
305           /* a single colon, ':' indicates an IPv4 address with port */
306           if ((*pp == ':') && (cc == 1))
307             break; /* found port */
308           if (!(ISDIGIT(*pp) || (*pp == ':'))) {
309             /* Found end of digits before we found :, so wasn't a port */
310             /* must allow ':' for IPv6 case of ']:' indicates we found a port */
311             pp = p = ptr;
312             break;
313           }
314           pp--;
315           p--;
316         }
317         if ((pp != start_host) && ((pp + 1) < ptr)) {
318           /* Found it. Parse over the port number */
319           /* when an IPv6 address is wrapped with square brackets the port
320              starts at pp + 2 */
321           if (*pp == ']')
322             p++; /* move p before ':' */
323           /* p will point to the start of the port */
324           port = (int)strtol(p, NULL, 10);
325           *pp = 0; /* null terminate host */
326         }
327       }
328       /* resolve host, try ipv4 first, rslt is in network byte order */
329       rv = ares_inet_pton(AF_INET, start_host, &in4);
330       if (!rv) {
331         /* Ok, try IPv6 then */
332         rv = ares_inet_pton(AF_INET6, start_host, &in6);
333         if (!rv) {
334           rv = ARES_EBADSTR;
335           goto out;
336         }
337         /* was ipv6, add new server */
338         s = ares_malloc(sizeof(*s));
339         if (!s) {
340           rv = ARES_ENOMEM;
341           goto out;
342         }
343         s->family = AF_INET6;
344         memcpy(&s->addr, &in6, sizeof(struct ares_in6_addr));
345       }
346       else {
347         /* was ipv4, add new server */
348         s = ares_malloc(sizeof(*s));
349         if (!s) {
350           rv = ARES_ENOMEM;
351           goto out;
352         }
353         s->family = AF_INET;
354         memcpy(&s->addr, &in4, sizeof(struct in_addr));
355       }
356       if (s) {
357         s->udp_port = use_port ? port: 0;
358         s->tcp_port = s->udp_port;
359         s->next = NULL;
360         if (last) {
361           last->next = s;
362           /* need to move last to maintain the linked list */
363           last = last->next;
364         }
365         else {
366           servers = s;
367           last = s;
368         }
369       }
370
371       /* Set up for next one */
372       start_host = ptr + 1;
373       cc = 0;
374     }
375   }
376
377   rv = ares_set_servers_ports(channel, servers);
378
379   out:
380   if (csv)
381     ares_free(csv);
382   while (servers) {
383     struct ares_addr_port_node *s = servers;
384     servers = servers->next;
385     ares_free(s);
386   }
387
388   return rv;
389 }
390
391 int ares_set_servers_csv(ares_channel channel,
392                          const char* _csv)
393 {
394   return set_servers_csv(channel, _csv, FALSE);
395 }
396
397 int ares_set_servers_ports_csv(ares_channel channel,
398                                const char* _csv)
399 {
400   return set_servers_csv(channel, _csv, TRUE);
401 }
402