1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1999 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <syslog.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/sockio.h>
33 #include <arpa/inet.h>
34 #include <net/if.h>
35 #include <unistd.h>
36 #include <netdb.h>
37 #include <nss_dbdefs.h>
38 #include <slp-internal.h>
39 #include <slp_net_utils.h>
40
41 typedef struct slp_ifinfo {
42 struct sockaddr_in addr;
43 struct sockaddr_in netmask;
44 struct sockaddr_in bc_addr;
45 short flags;
46 } slp_ifinfo_t;
47
48 typedef struct slp_handle_ifinfo {
49 slp_ifinfo_t *all_ifs;
50 int numifs;
51 } slp_handle_ifinfo_t;
52
53
54 static SLPError get_all_interfaces(slp_handle_ifinfo_t *info);
55
56 /*
57 * Obtains the broadcast addresses for all local interfaces given in
58 * addrs.
59 *
60 * hp IN / OUT holds cached-per-handle if info
61 * given_ifs IN an array of local interfaces
62 * num_givenifs IN number of addresses in given_ifs
63 * bc_addrs OUT an array of broadcast addresses for local interfaces
64 * num_addrs OUT number of addrs returned in bc_addrs
65 *
66 * Returns SLP_OK if at least one broadcast address was found; if none
67 * were found, returns err != SLP_OK and *bc_addrs = NULL;
68 * Caller must free *bc_addrs when done.
69 */
slp_broadcast_addrs(slp_handle_impl_t * hp,struct in_addr * given_ifs,int num_givenifs,struct sockaddr_in * bc_addrs[],int * num_addrs)70 SLPError slp_broadcast_addrs(slp_handle_impl_t *hp, struct in_addr *given_ifs,
71 int num_givenifs,
72 struct sockaddr_in *bc_addrs[],
73 int *num_addrs) {
74
75 SLPError err;
76 int i, j;
77 slp_ifinfo_t *all_ifs;
78 slp_handle_ifinfo_t *ifinfo;
79 int numifs;
80
81 if (!hp->ifinfo) {
82 if (!(ifinfo = malloc(sizeof (*ifinfo)))) {
83 slp_err(LOG_CRIT, 0, "slp_broadcast_addrs",
84 "out of memory");
85 return (SLP_MEMORY_ALLOC_FAILED);
86 }
87 if ((err = get_all_interfaces(ifinfo)) != SLP_OK) {
88 free(ifinfo);
89 return (err);
90 }
91 hp->ifinfo = ifinfo;
92 }
93 all_ifs = ((slp_handle_ifinfo_t *)hp->ifinfo)->all_ifs;
94 numifs = ((slp_handle_ifinfo_t *)hp->ifinfo)->numifs;
95
96 /* allocate memory for reply */
97 if (!(*bc_addrs = calloc(num_givenifs, sizeof (**bc_addrs)))) {
98 slp_err(LOG_CRIT, 0, "slp_broadcast_addrs", "out of memory");
99 return (SLP_MEMORY_ALLOC_FAILED);
100 }
101
102 /* copy bc addrs for all desired interfaces which are bc-enabled */
103 *num_addrs = 0;
104 for (j = 0; j < num_givenifs; j++) {
105 for (i = 0; i < numifs; i++) {
106
107 if (!(all_ifs[i].flags & IFF_BROADCAST)) {
108 continue;
109 }
110
111 if (memcmp(&(all_ifs[i].addr.sin_addr.s_addr),
112 &(given_ifs[j].s_addr),
113 sizeof (given_ifs[j].s_addr)) == 0 &&
114 all_ifs[i].bc_addr.sin_addr.s_addr != 0) {
115
116 /* got it, so copy it to bc_addrs */
117 (void) memcpy(
118 *bc_addrs + *num_addrs,
119 &(all_ifs[i].bc_addr),
120 sizeof (all_ifs[i].bc_addr));
121 (*num_addrs)++;
122
123 break;
124 }
125 }
126 }
127
128 if (*num_addrs == 0) {
129 /* none found */
130 free (*bc_addrs);
131 bc_addrs = NULL;
132 return (SLP_INTERNAL_SYSTEM_ERROR);
133 }
134 return (SLP_OK);
135 }
136
137 /*
138 * Returns true if addr is on a subnet local to the local host.
139 */
slp_on_subnet(slp_handle_impl_t * hp,struct in_addr addr)140 SLPBoolean slp_on_subnet(slp_handle_impl_t *hp, struct in_addr addr) {
141 int i;
142 struct in_addr netmask, net_addr, masked_addr;
143 slp_ifinfo_t *all_ifs;
144 slp_handle_ifinfo_t *ifinfo;
145 int numifs;
146
147 if (!hp->ifinfo) {
148 if (!(ifinfo = malloc(sizeof (*ifinfo)))) {
149 slp_err(LOG_CRIT, 0, "slp_broadcast_addrs",
150 "out of memory");
151 return (SLP_FALSE);
152 }
153 if (get_all_interfaces(ifinfo) != SLP_OK) {
154 free(ifinfo);
155 return (SLP_FALSE);
156 }
157 hp->ifinfo = ifinfo;
158 }
159 all_ifs = ((slp_handle_ifinfo_t *)hp->ifinfo)->all_ifs;
160 numifs = ((slp_handle_ifinfo_t *)hp->ifinfo)->numifs;
161
162 for (i = 0; i < numifs; i++) {
163 /* get netmask */
164 netmask.s_addr = all_ifs[i].netmask.sin_addr.s_addr;
165 /* get network address */
166 net_addr.s_addr =
167 all_ifs[i].addr.sin_addr.s_addr & netmask.s_addr;
168 /* apply netmask to input addr */
169 masked_addr.s_addr = addr.s_addr & netmask.s_addr;
170
171 if (memcmp(&(masked_addr.s_addr), &(net_addr.s_addr),
172 sizeof (net_addr.s_addr)) == 0) {
173 return (SLP_TRUE);
174 }
175 }
176
177 return (SLP_FALSE);
178 }
179
180 /*
181 * Returns true if any local interface if configured with addr.
182 */
slp_on_localhost(slp_handle_impl_t * hp,struct in_addr addr)183 SLPBoolean slp_on_localhost(slp_handle_impl_t *hp, struct in_addr addr) {
184 int i;
185 slp_ifinfo_t *all_ifs;
186 slp_handle_ifinfo_t *ifinfo;
187 int numifs;
188
189 if (!hp->ifinfo) {
190 if (!(ifinfo = malloc(sizeof (*ifinfo)))) {
191 slp_err(LOG_CRIT, 0, "slp_broadcast_addrs",
192 "out of memory");
193 return (SLP_FALSE);
194 }
195 if (get_all_interfaces(ifinfo) != SLP_OK) {
196 free(ifinfo);
197 return (SLP_FALSE);
198 }
199 hp->ifinfo = ifinfo;
200 }
201 all_ifs = ((slp_handle_ifinfo_t *)hp->ifinfo)->all_ifs;
202 numifs = ((slp_handle_ifinfo_t *)hp->ifinfo)->numifs;
203
204 for (i = 0; i < numifs; i++) {
205 if (memcmp(&(addr.s_addr), &(all_ifs[i].addr.sin_addr.s_addr),
206 sizeof (addr)) == 0) {
207
208 return (SLP_TRUE);
209 }
210 }
211
212 return (SLP_FALSE);
213 }
214
slp_free_ifinfo(void * hi)215 void slp_free_ifinfo(void *hi) {
216 free(((slp_handle_ifinfo_t *)hi)->all_ifs);
217 }
218
219 /*
220 * Populates all_ifs.
221 */
get_all_interfaces(slp_handle_ifinfo_t * info)222 static SLPError get_all_interfaces(slp_handle_ifinfo_t *info) {
223 int i, n, s = 0;
224 int numifs;
225 char *buf = NULL;
226 size_t bufsize;
227 struct ifconf ifc;
228 struct ifreq *ifrp, ifr;
229 slp_ifinfo_t *all_ifs = NULL;
230 SLPError err = SLP_OK;
231
232 /* create a socket with which to get interface info */
233 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
234 goto cleanup;
235 }
236
237 /* how many interfaces are configured? */
238 if (ioctl(s, SIOCGIFNUM, (char *)&numifs) < 0) {
239 goto cleanup;
240 }
241
242 /* allocate memory for ifinfo_t array */
243 if (!(all_ifs = calloc(numifs, sizeof (*all_ifs)))) {
244 slp_err(LOG_CRIT, 0, "get_all_interfaces", "out of memory");
245 err = SLP_MEMORY_ALLOC_FAILED;
246 goto cleanup;
247 }
248
249 /* allocate memory for interface info */
250 bufsize = numifs * sizeof (struct ifreq);
251 if (!(buf = malloc(bufsize))) {
252 slp_err(LOG_CRIT, 0, "get_all_interfaces", "out of memory");
253 err = SLP_MEMORY_ALLOC_FAILED;
254 goto cleanup;
255 }
256
257 /* get if info */
258 ifc.ifc_len = bufsize;
259 ifc.ifc_buf = buf;
260 if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) {
261 goto cleanup;
262 }
263
264 ifrp = ifc.ifc_req;
265 i = 0;
266 for (n = ifc.ifc_len / sizeof (struct ifreq); n > 0; n--, ifrp++) {
267
268 /* ignore if interface is not up */
269 (void) memset((char *)&ifr, 0, sizeof (ifr));
270 (void) strncpy(ifr.ifr_name, ifrp->ifr_name, sizeof (ifr.ifr_name));
271 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
272 continue;
273 }
274 if (!(ifr.ifr_flags & IFF_UP)) {
275 continue;
276 }
277
278 all_ifs[i].flags = ifr.ifr_flags;
279
280 /* get the interface's address */
281 if (ioctl(s, SIOCGIFADDR, (caddr_t)&ifr) < 0) {
282 continue;
283 }
284
285 (void) memcpy(&(all_ifs[i].addr), &ifr.ifr_addr,
286 sizeof (all_ifs[i].addr));
287
288 /* get the interface's broadcast address */
289 if (ioctl(s, SIOCGIFBRDADDR, (caddr_t)&ifr) < 0) {
290 (void) memset(&(all_ifs[i].bc_addr), 0,
291 sizeof (all_ifs[i].bc_addr));
292 } else {
293 (void) memcpy(&(all_ifs[i].bc_addr), &ifr.ifr_addr,
294 sizeof (all_ifs[i].bc_addr));
295 }
296
297 /* get the interface's subnet mask */
298 if (ioctl(s, SIOCGIFNETMASK, (caddr_t)&ifr) < 0) {
299 (void) memset(&(all_ifs[i].netmask), 0,
300 sizeof (all_ifs[i].netmask));
301 } else {
302 (void) memcpy(&(all_ifs[i].netmask), &ifr.ifr_addr,
303 sizeof (all_ifs[i].netmask));
304 }
305
306 i++;
307 }
308
309 /* i contains the number we actually got info on */
310 info->numifs = i;
311 info->all_ifs = all_ifs;
312
313 if (i == 0) {
314 err = SLP_INTERNAL_SYSTEM_ERROR;
315 free(all_ifs);
316 info->all_ifs = NULL;
317 }
318
319 cleanup:
320 if (s) (void) close(s);
321 if (buf) free(buf);
322
323 return (err);
324 }
325
326 /*
327 * Converts a SLPSrvURL to a network address. 'sa' must have been
328 * allocated by the caller.
329 * Assumes that addresses are given as specified in the protocol spec,
330 * i.e. as IP addresses and not host names.
331 */
slp_surl2sin(SLPSrvURL * surl,struct sockaddr_in * sa)332 SLPError slp_surl2sin(SLPSrvURL *surl, struct sockaddr_in *sa) {
333 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
334
335 if (slp_pton(surl->s_pcHost, &(sin->sin_addr)) < 1)
336 return (SLP_PARAMETER_BAD);
337 sin->sin_family = AF_INET;
338 /* port number */
339 sin->sin_port = htons(
340 (surl->s_iPort == 0 ? SLP_PORT : surl->s_iPort));
341
342 return (SLP_OK);
343 }
344
345 /*
346 * A wrapper around gethostbyaddr_r. This checks the useGetXXXbyYYY
347 * property first to determine whether a name service lookup should
348 * be used. If not, it converts the address in 'addr' to a string
349 * and just returns that.
350 *
351 * The core functionality herein will be replaced with getaddrinfo
352 * when it becomes available.
353 */
354
slp_gethostbyaddr(const char * addr,int size)355 char *slp_gethostbyaddr(const char *addr, int size) {
356 char storebuf[SLP_NETDB_BUFSZ], addrbuf[INET6_ADDRSTRLEN], *cname;
357 const char *use_xbyy;
358 struct hostent namestruct[1], *name;
359 int herrno;
360
361 /* default: copy in the IP address */
362 cname = slp_ntop(addrbuf, INET6_ADDRSTRLEN, (const void *) addr);
363 if (cname && !(cname = strdup(cname))) {
364 slp_err(LOG_CRIT, 0, "slp_gethostbyaddr", "out of memory");
365 return (NULL);
366 }
367
368 if ((use_xbyy = SLPGetProperty(SLP_CONFIG_USEGETXXXBYYYY)) != NULL &&
369 strcasecmp(use_xbyy, "false") == 0) {
370 return (cname);
371 }
372
373 while (!(name = gethostbyaddr_r(addr, size,
374 AF_INET,
375 namestruct,
376 storebuf,
377 SLP_NETDB_BUFSZ,
378 &herrno))) {
379 switch (herrno) {
380 case NO_RECOVERY:
381 case NO_DATA:
382 return (cname);
383 case TRY_AGAIN:
384 continue;
385 default:
386 return (cname); /* IP address */
387 }
388 }
389
390 free(cname);
391 if (!(cname = strdup(name->h_name))) {
392 slp_err(LOG_CRIT, 0, "slp_gethostbyaddr", "out of memory");
393 return (NULL);
394 }
395
396 return (cname);
397 }
398
399 /* @@@ currently getting these from libresolv2 -> change? */
400
401 /*
402 * Converts the address pointed to by 'addr' to a string. Currently
403 * just calls inet_ntoa, but is structured to be a wrapper to
404 * inet_ntop. Returns NULL on failure.
405 *
406 * This wrapper allows callers to be protocol agnostic. Right now it
407 * only handles IPv4.
408 */
409 /*ARGSUSED*/
slp_ntop(char * buf,int buflen,const void * addr)410 char *slp_ntop(char *buf, int buflen, const void *addr) {
411 return (inet_ntoa(*(struct in_addr *)addr));
412 }
413
414 /*
415 * convert from presentation format (which usually means ASCII printable)
416 * to network format (which is usually some kind of binary format).
417 * return:
418 * 1 if the address was valid for the specified address family
419 * 0 if the address wasn't valid (`dst' is untouched in this case)
420 * -1 if some other error occurred (`dst' is untouched in this case, too)
421 *
422 * This wrapper allows callers to be protocol agnostic. Right now it
423 * only handles IPv4.
424 */
slp_pton(const char * addrstr,void * addr)425 int slp_pton(const char *addrstr, void *addr) {
426 return (inet_pton(AF_INET, addrstr, addr));
427 }
428