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 */ 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 */ 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 */ 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 215 void slp_free_ifinfo(void *hi) { 216 free(((slp_handle_ifinfo_t *)hi)->all_ifs); 217 } 218 219 /* 220 * Populates all_ifs. 221 */ 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 */ 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 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*/ 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 */ 425 int slp_pton(const char *addrstr, void *addr) { 426 return (inet_pton(AF_INET, addrstr, addr)); 427 } 428