ares__readaddrinfo.c
Go to the documentation of this file.
1 /* Copyright (C) 2019 by Andrew Selivanov
2  *
3  * Permission to use, copy, modify, and distribute this
4  * software and its documentation for any purpose and without
5  * fee is hereby granted, provided that the above copyright
6  * notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting
8  * documentation, and that the name of M.I.T. not be used in
9  * advertising or publicity pertaining to distribution of the
10  * software without specific, written prior permission.
11  * M.I.T. makes no representations about the suitability of
12  * this software for any purpose. It is provided "as is"
13  * without express or implied warranty.
14  */
15 
16 #include "ares_setup.h"
17 
18 #ifdef HAVE_NETINET_IN_H
19 # include <netinet/in.h>
20 #endif
21 #ifdef HAVE_NETDB_H
22 # include <netdb.h>
23 #endif
24 #ifdef HAVE_ARPA_INET_H
25 # include <arpa/inet.h>
26 #endif
27 
28 #include "ares.h"
29 #include "ares_inet_net_pton.h"
30 #include "ares_nowarn.h"
31 #include "ares_private.h"
32 
33 #define MAX_ALIASES 40
34 
36  const char *name,
37  unsigned short port,
38  const struct ares_addrinfo_hints *hints,
39  struct ares_addrinfo *ai)
40 {
41  char *line = NULL, *p, *q;
42  char *txtaddr, *txthost, *txtalias;
43  char *aliases[MAX_ALIASES];
44  unsigned int i, alias_count;
45  int status;
46  size_t linesize;
48  struct ares_addrinfo_cname *cname = NULL, *cnames = NULL;
49  struct ares_addrinfo_node *node = NULL, *nodes = NULL;
50  int match_with_alias, match_with_canonical;
51  int want_cname = hints->ai_flags & ARES_AI_CANONNAME;
52 
53  /* Validate family */
54  switch (hints->ai_family) {
55  case AF_INET:
56  case AF_INET6:
57  case AF_UNSPEC:
58  break;
59  default:
60  return ARES_EBADFAMILY;
61  }
62 
63 
64  while ((status = ares__read_line(fp, &line, &linesize)) == ARES_SUCCESS)
65  {
66  match_with_alias = 0;
67  match_with_canonical = 0;
68  alias_count = 0;
69  /* Trim line comment. */
70  p = line;
71  while (*p && (*p != '#'))
72  p++;
73  *p = '\0';
74 
75  /* Trim trailing whitespace. */
76  q = p - 1;
77  while ((q >= line) && ISSPACE(*q))
78  q--;
79  *++q = '\0';
80 
81  /* Skip leading whitespace. */
82  p = line;
83  while (*p && ISSPACE(*p))
84  p++;
85  if (!*p)
86  /* Ignore line if empty. */
87  continue;
88 
89  /* Pointer to start of IPv4 or IPv6 address part. */
90  txtaddr = p;
91 
92  /* Advance past address part. */
93  while (*p && !ISSPACE(*p))
94  p++;
95  if (!*p)
96  /* Ignore line if reached end of line. */
97  continue;
98 
99  /* Null terminate address part. */
100  *p = '\0';
101 
102  /* Advance to host name */
103  p++;
104  while (*p && ISSPACE(*p))
105  p++;
106  if (!*p)
107  /* Ignore line if reached end of line. */
108  continue; /* LCOV_EXCL_LINE: trailing whitespace already stripped */
109 
110  /* Pointer to start of host name. */
111  txthost = p;
112 
113  /* Advance past host name. */
114  while (*p && !ISSPACE(*p))
115  p++;
116 
117  /* Pointer to start of first alias. */
118  txtalias = NULL;
119  if (*p)
120  {
121  q = p + 1;
122  while (*q && ISSPACE(*q))
123  q++;
124  if (*q)
125  txtalias = q;
126  }
127 
128  /* Null terminate host name. */
129  *p = '\0';
130 
131  /* Find out if host name matches with canonical host name. */
132  if (strcasecmp(txthost, name) == 0)
133  {
134  match_with_canonical = 1;
135  }
136 
137  /* Find out if host name matches with one of the aliases. */
138  while (txtalias)
139  {
140  p = txtalias;
141  while (*p && !ISSPACE(*p))
142  p++;
143  q = p;
144  while (*q && ISSPACE(*q))
145  q++;
146  *p = '\0';
147  if (strcasecmp(txtalias, name) == 0)
148  {
149  match_with_alias = 1;
150  if (!want_cname)
151  break;
152  }
153  if (alias_count < MAX_ALIASES)
154  {
155  aliases[alias_count++] = txtalias;
156  }
157  txtalias = *q ? q : NULL;
158  }
159 
160  /* Try next line if host does not match. */
161  if (!match_with_alias && !match_with_canonical)
162  {
163  continue;
164  }
165 
166  /* Zero-out 'addr' struct, as there are members that we may not set, especially
167  * for ipv6. We don't want garbage data */
168  memset(&addr, 0, sizeof(addr));
169 
170  /*
171  * Convert address string to network address for the requested families.
172  * Actual address family possible values are AF_INET and AF_INET6 only.
173  */
174  if ((hints->ai_family == AF_INET) || (hints->ai_family == AF_UNSPEC))
175  {
176  addr.sa4.sin_port = htons(port);
177  if (ares_inet_pton(AF_INET, txtaddr, &addr.sa4.sin_addr) > 0)
178  {
179  node = ares__append_addrinfo_node(&nodes);
180  if(!node)
181  {
182  goto enomem;
183  }
184 
185  node->ai_family = addr.sa.sa_family = AF_INET;
186  node->ai_addrlen = sizeof(addr.sa4);
187  node->ai_addr = ares_malloc(sizeof(addr.sa4));
188  if (!node->ai_addr)
189  {
190  goto enomem;
191  }
192  memcpy(node->ai_addr, &addr.sa4, sizeof(addr.sa4));
193  }
194  }
195  if ((hints->ai_family == AF_INET6) || (hints->ai_family == AF_UNSPEC))
196  {
197  addr.sa6.sin6_port = htons(port);
198  if (ares_inet_pton(AF_INET6, txtaddr, &addr.sa6.sin6_addr) > 0)
199  {
200  node = ares__append_addrinfo_node(&nodes);
201  if (!node)
202  {
203  goto enomem;
204  }
205 
206  node->ai_family = addr.sa.sa_family = AF_INET6;
207  node->ai_addrlen = sizeof(addr.sa6);
208  node->ai_addr = ares_malloc(sizeof(addr.sa6));
209  if (!node->ai_addr)
210  {
211  goto enomem;
212  }
213  memcpy(node->ai_addr, &addr.sa6, sizeof(addr.sa6));
214  }
215  }
216  if (!node)
217  /* Ignore line if invalid address string for the requested family. */
218  continue;
219 
220  if (want_cname)
221  {
222  for (i = 0; i < alias_count; ++i)
223  {
224  cname = ares__append_addrinfo_cname(&cnames);
225  if (!cname)
226  {
227  goto enomem;
228  }
229  cname->alias = ares_strdup(aliases[i]);
230  cname->name = ares_strdup(txthost);
231  }
232  /* No aliases, cname only. */
233  if(!alias_count)
234  {
235  cname = ares__append_addrinfo_cname(&cnames);
236  if (!cname)
237  {
238  goto enomem;
239  }
240  cname->name = ares_strdup(txthost);
241  }
242  }
243  }
244 
245  /* Last read failed. */
246  if (status == ARES_ENOMEM)
247  {
248  goto enomem;
249  }
250 
251  /* Free line buffer. */
252  ares_free(line);
253 
254  ares__addrinfo_cat_cnames(&ai->cnames, cnames);
255  ares__addrinfo_cat_nodes(&ai->nodes, nodes);
256 
257  return node ? ARES_SUCCESS : ARES_ENOTFOUND;
258 
259 enomem:
260  ares_free(line);
263  return ARES_ENOMEM;
264 }
ares__freeaddrinfo_nodes
void ares__freeaddrinfo_nodes(struct ares_addrinfo_node *head)
Definition: ares_freeaddrinfo.c:40
ARES_ENOMEM
#define ARES_ENOMEM
Definition: ares.h:117
ares_inet_pton
CARES_EXTERN int ares_inet_pton(int af, const char *src, void *dst)
Definition: inet_net_pton.c:418
ares_addrinfo_node
Definition: ares.h:593
ares_addrinfo_node::ai_addrlen
ares_socklen_t ai_addrlen
Definition: ares.h:599
ares__freeaddrinfo_cnames
void ares__freeaddrinfo_cnames(struct ares_addrinfo_cname *head)
Definition: ares_freeaddrinfo.c:27
AF_INET6
#define AF_INET6
Definition: ares_setup.h:208
ares_addrinfo
Definition: ares.h:616
memset
return memset(p, 0, total)
ares__addrinfo_cat_cnames
void ares__addrinfo_cat_cnames(struct ares_addrinfo_cname **head, struct ares_addrinfo_cname *tail)
Definition: ares_getaddrinfo.c:142
ares.h
ares_addrinfo_hints
Definition: ares.h:621
ares_strdup
char * ares_strdup(const char *s1)
Definition: ares_strdup.c:23
ares_inet_net_pton.h
ares_addrinfo_node::ai_addr
struct sockaddr * ai_addr
Definition: ares.h:600
ares__append_addrinfo_node
struct ares_addrinfo_node * ares__append_addrinfo_node(struct ares_addrinfo_node **head)
Definition: ares_getaddrinfo.c:182
ares_addrinfo_cname::alias
char * alias
Definition: ares.h:611
ares_addrinfo_node::ai_family
int ai_family
Definition: ares.h:596
status
absl::Status status
Definition: rls.cc:251
setup.name
name
Definition: setup.py:542
xds_manager.p
p
Definition: xds_manager.py:60
ares__read_line
int ares__read_line(FILE *fp, char **buf, size_t *bufsize)
Definition: ares__read_line.c:31
ARES_AI_CANONNAME
#define ARES_AI_CANONNAME
Definition: ares.h:191
ares__append_addrinfo_cname
struct ares_addrinfo_cname * ares__append_addrinfo_cname(struct ares_addrinfo_cname **head)
Definition: ares_getaddrinfo.c:123
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
ARES_ENOTFOUND
#define ARES_ENOTFOUND
Definition: ares.h:104
ares_addrinfo_hints::ai_family
int ai_family
Definition: ares.h:623
ares_malloc
void *(* ares_malloc)(size_t size)=default_malloc
Definition: ares_library_init.c:58
ARES_EBADFAMILY
#define ARES_EBADFAMILY
Definition: ares.h:111
ares_sockaddr
Definition: ares_ipv6.h:35
MAX_ALIASES
#define MAX_ALIASES
Definition: ares__readaddrinfo.c:33
ARES_SUCCESS
#define ARES_SUCCESS
Definition: ares.h:98
ares__addrinfo_cat_nodes
void ares__addrinfo_cat_nodes(struct ares_addrinfo_node **head, struct ares_addrinfo_node *tail)
Definition: ares_getaddrinfo.c:201
ares_setup.h
tests.unit._exit_scenarios.port
port
Definition: _exit_scenarios.py:179
ares_addrinfo::nodes
struct ares_addrinfo_node * nodes
Definition: ares.h:618
ares_addrinfo_cname
Definition: ares.h:609
ares_addrinfo::cnames
struct ares_addrinfo_cname * cnames
Definition: ares.h:617
benchmark.FILE
FILE
Definition: benchmark.py:21
ares_addrinfo_hints::ai_flags
int ai_flags
Definition: ares.h:622
ares_free
void(* ares_free)(void *ptr)=default_free
Definition: ares_library_init.c:60
regen-readme.line
line
Definition: regen-readme.py:30
ares_private.h
ares_addrinfo_cname::name
char * name
Definition: ares.h:612
ares_nowarn.h
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10
ares__readaddrinfo
int ares__readaddrinfo(FILE *fp, const char *name, unsigned short port, const struct ares_addrinfo_hints *hints, struct ares_addrinfo *ai)
Definition: ares__readaddrinfo.c:35
strcasecmp
#define strcasecmp(p1, p2)
Definition: ares_private.h:114
ISSPACE
#define ISSPACE(x)
Definition: setup_once.h:275
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:43