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