blob: 5b4a4a10b7b41c7cdc8aae43d37219a93bda8f24
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * stolen from net-tools-1.59 and stripped down for busybox by |
4 | * Erik Andersen <andersen@codepoet.org> |
5 | * |
6 | * Heavily modified by Manuel Novoa III Mar 12, 2001 |
7 | * |
8 | * Licensed under GPLv2, see file LICENSE in this source tree. |
9 | */ |
10 | |
11 | #include "libbb.h" |
12 | #include "inet_common.h" |
13 | |
14 | int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst) |
15 | { |
16 | struct hostent *hp; |
17 | #if ENABLE_FEATURE_ETC_NETWORKS |
18 | struct netent *np; |
19 | #endif |
20 | |
21 | /* Grmpf. -FvK */ |
22 | s_in->sin_family = AF_INET; |
23 | s_in->sin_port = 0; |
24 | |
25 | /* Default is special, meaning 0.0.0.0. */ |
26 | if (strcmp(name, "default") == 0) { |
27 | s_in->sin_addr.s_addr = INADDR_ANY; |
28 | return 1; |
29 | } |
30 | /* Look to see if it's a dotted quad. */ |
31 | if (inet_aton(name, &s_in->sin_addr)) { |
32 | return 0; |
33 | } |
34 | /* If we expect this to be a hostname, try hostname database first */ |
35 | if (hostfirst) { |
36 | #ifdef DEBUG |
37 | bb_error_msg("gethostbyname(%s)", name); |
38 | #endif |
39 | hp = gethostbyname(name); |
40 | if (hp) { |
41 | memcpy(&s_in->sin_addr, hp->h_addr_list[0], |
42 | sizeof(struct in_addr)); |
43 | return 0; |
44 | } |
45 | } |
46 | #if ENABLE_FEATURE_ETC_NETWORKS |
47 | /* Try the NETWORKS database to see if this is a known network. */ |
48 | #ifdef DEBUG |
49 | bb_error_msg("getnetbyname(%s)", name); |
50 | #endif |
51 | np = getnetbyname(name); |
52 | if (np) { |
53 | s_in->sin_addr.s_addr = htonl(np->n_net); |
54 | return 1; |
55 | } |
56 | #endif |
57 | if (hostfirst) { |
58 | /* Don't try again */ |
59 | return -1; |
60 | } |
61 | #ifdef DEBUG |
62 | res_init(); |
63 | _res.options |= RES_DEBUG; |
64 | bb_error_msg("gethostbyname(%s)", name); |
65 | #endif |
66 | hp = gethostbyname(name); |
67 | if (!hp) { |
68 | return -1; |
69 | } |
70 | memcpy(&s_in->sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); |
71 | return 0; |
72 | } |
73 | |
74 | |
75 | /* numeric: & 0x8000: "default" instead of "*", |
76 | * & 0x4000: host instead of net, |
77 | * & 0x0fff: don't resolve |
78 | */ |
79 | char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t netmask) |
80 | { |
81 | /* addr-to-name cache */ |
82 | struct addr { |
83 | struct addr *next; |
84 | uint32_t nip; |
85 | smallint is_host; |
86 | char name[1]; |
87 | }; |
88 | static struct addr *cache = NULL; |
89 | |
90 | struct addr *pn; |
91 | char *name; |
92 | uint32_t nip; |
93 | smallint is_host; |
94 | |
95 | if (s_in->sin_family != AF_INET) { |
96 | #ifdef DEBUG |
97 | bb_error_msg("rresolve: unsupported address family %d!", |
98 | s_in->sin_family); |
99 | #endif |
100 | errno = EAFNOSUPPORT; |
101 | return NULL; |
102 | } |
103 | nip = s_in->sin_addr.s_addr; |
104 | #ifdef DEBUG |
105 | bb_error_msg("rresolve: %08x mask:%08x num:%08x", (unsigned)nip, netmask, numeric); |
106 | #endif |
107 | if (numeric & 0x0FFF) |
108 | return xmalloc_sockaddr2dotted_noport((void*)s_in); |
109 | if (nip == INADDR_ANY) { |
110 | if (numeric & 0x8000) |
111 | return xstrdup("default"); |
112 | return xstrdup("*"); |
113 | } |
114 | |
115 | is_host = ((nip & (~netmask)) != 0 || (numeric & 0x4000)); |
116 | |
117 | pn = cache; |
118 | while (pn) { |
119 | if (pn->nip == nip && pn->is_host == is_host) { |
120 | #ifdef DEBUG |
121 | bb_error_msg("rresolve: found %s %08x in cache", |
122 | (is_host ? "host" : "net"), (unsigned)nip); |
123 | #endif |
124 | return xstrdup(pn->name); |
125 | } |
126 | pn = pn->next; |
127 | } |
128 | |
129 | name = NULL; |
130 | if (is_host) { |
131 | #ifdef DEBUG |
132 | bb_error_msg("sockaddr2host_noport(%08x)", (unsigned)nip); |
133 | #endif |
134 | name = xmalloc_sockaddr2host_noport((void*)s_in); |
135 | } else if (ENABLE_FEATURE_ETC_NETWORKS) { |
136 | struct netent *np; |
137 | #ifdef DEBUG |
138 | bb_error_msg("getnetbyaddr(%08x)", (unsigned)ntohl(nip)); |
139 | #endif |
140 | np = getnetbyaddr(ntohl(nip), AF_INET); |
141 | if (np) |
142 | name = xstrdup(np->n_name); |
143 | } |
144 | if (!name) |
145 | name = xmalloc_sockaddr2dotted_noport((void*)s_in); |
146 | |
147 | pn = xmalloc(sizeof(*pn) + strlen(name)); /* no '+ 1', it's already accounted for */ |
148 | pn->next = cache; |
149 | pn->nip = nip; |
150 | pn->is_host = is_host; |
151 | strcpy(pn->name, name); |
152 | cache = pn; |
153 | |
154 | return name; |
155 | } |
156 | |
157 | #if ENABLE_FEATURE_IPV6 |
158 | |
159 | int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6) |
160 | { |
161 | struct addrinfo req, *ai = NULL; |
162 | int s; |
163 | |
164 | memset(&req, 0, sizeof(req)); |
165 | req.ai_family = AF_INET6; |
166 | s = getaddrinfo(name, NULL, &req, &ai); |
167 | if (s != 0) { |
168 | bb_error_msg("getaddrinfo: %s: %d", name, s); |
169 | return -1; |
170 | } |
171 | memcpy(sin6, ai->ai_addr, sizeof(*sin6)); |
172 | freeaddrinfo(ai); |
173 | return 0; |
174 | } |
175 | |
176 | #ifndef IN6_IS_ADDR_UNSPECIFIED |
177 | # define IN6_IS_ADDR_UNSPECIFIED(a) \ |
178 | (((uint32_t *) (a))[0] == 0 && ((uint32_t *) (a))[1] == 0 && \ |
179 | ((uint32_t *) (a))[2] == 0 && ((uint32_t *) (a))[3] == 0) |
180 | #endif |
181 | |
182 | |
183 | char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric) |
184 | { |
185 | if (sin6->sin6_family != AF_INET6) { |
186 | #ifdef DEBUG |
187 | bb_error_msg("rresolve: unsupported address family %d!", |
188 | sin6->sin6_family); |
189 | #endif |
190 | errno = EAFNOSUPPORT; |
191 | return NULL; |
192 | } |
193 | if (numeric & 0x7FFF) { |
194 | return xmalloc_sockaddr2dotted_noport((void*)sin6); |
195 | } |
196 | if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
197 | if (numeric & 0x8000) |
198 | return xstrdup("default"); |
199 | return xstrdup("*"); |
200 | } |
201 | |
202 | return xmalloc_sockaddr2host_noport((void*)sin6); |
203 | } |
204 | |
205 | #endif /* CONFIG_FEATURE_IPV6 */ |
206 |