1 1.48 joerg /* $NetBSD: bootparamd.c,v 1.48 2020/04/22 23:47:02 joerg Exp $ */ 2 1.7 thorpej 3 1.1 deraadt /* 4 1.1 deraadt * This code is not copyright, and is placed in the public domain. 5 1.1 deraadt * Feel free to use and modify. Please send modifications and/or 6 1.1 deraadt * suggestions + bug fixes to Klas Heggemann <klas (at) nada.kth.se> 7 1.2 deraadt * 8 1.1 deraadt * Various small changes by Theo de Raadt <deraadt (at) fsa.ca> 9 1.2 deraadt * Parser rewritten (adding YP support) by Roland McGrath <roland (at) frob.com> 10 1.1 deraadt */ 11 1.1 deraadt 12 1.12 thorpej #include <sys/cdefs.h> 13 1.12 thorpej #ifndef lint 14 1.48 joerg __RCSID("$NetBSD: bootparamd.c,v 1.48 2020/04/22 23:47:02 joerg Exp $"); 15 1.12 thorpej #endif 16 1.12 thorpej 17 1.1 deraadt #include <sys/types.h> 18 1.1 deraadt #include <sys/ioctl.h> 19 1.1 deraadt #include <sys/stat.h> 20 1.1 deraadt #include <sys/socket.h> 21 1.10 mycroft 22 1.34 thorpej #include <assert.h> 23 1.10 mycroft #include <ctype.h> 24 1.21 christos #include <errno.h> 25 1.10 mycroft #include <err.h> 26 1.34 thorpej #include <fnmatch.h> 27 1.10 mycroft #include <netdb.h> 28 1.12 thorpej #include <stdlib.h> 29 1.1 deraadt #include <stdio.h> 30 1.10 mycroft #include <string.h> 31 1.1 deraadt #include <syslog.h> 32 1.12 thorpej #include <unistd.h> 33 1.20 thorpej #include <util.h> 34 1.22 itojun #include <ifaddrs.h> 35 1.10 mycroft 36 1.23 itojun #include <net/if.h> 37 1.23 itojun 38 1.10 mycroft #include <netinet/in.h> 39 1.9 cgd #include <arpa/inet.h> 40 1.10 mycroft 41 1.10 mycroft #include <rpc/rpc.h> 42 1.12 thorpej #include <rpc/pmap_clnt.h> 43 1.10 mycroft #include <rpcsvc/bootparam_prot.h> 44 1.40 thorpej #ifdef YP 45 1.12 thorpej #include <rpcsvc/ypclnt.h> 46 1.40 thorpej #endif 47 1.10 mycroft 48 1.2 deraadt #include "pathnames.h" 49 1.1 deraadt 50 1.1 deraadt #define MAXLEN 800 51 1.1 deraadt 52 1.1 deraadt static char hostname[MAX_MACHINE_NAME]; 53 1.1 deraadt static char askname[MAX_MACHINE_NAME]; 54 1.1 deraadt static char domain_name[MAX_MACHINE_NAME]; 55 1.1 deraadt 56 1.46 joerg extern void bootparamprog_1(struct svc_req *, SVCXPRT *); 57 1.1 deraadt 58 1.47 kamil extern int _rpcsvcdirty; 59 1.48 joerg extern int _rpcpmstart; 60 1.1 deraadt int debug = 0; 61 1.1 deraadt int dolog = 0; 62 1.12 thorpej struct in_addr route_addr; 63 1.1 deraadt struct sockaddr_in my_addr; 64 1.45 lukem const char *bootpfile = _PATH_BOOTPARAMS; 65 1.41 itojun char *iface = NULL; 66 1.1 deraadt 67 1.46 joerg static int lookup_bootparam(char *, char *, char *, char **, char **); 68 1.46 joerg __dead static void usage(void); 69 1.46 joerg static int get_localaddr(const char *, struct sockaddr_in *); 70 1.1 deraadt 71 1.1 deraadt 72 1.1 deraadt /* 73 1.1 deraadt * ever familiar 74 1.1 deraadt */ 75 1.1 deraadt int 76 1.46 joerg main(int argc, char *argv[]) 77 1.1 deraadt { 78 1.1 deraadt SVCXPRT *transp; 79 1.1 deraadt struct hostent *he; 80 1.1 deraadt struct stat buf; 81 1.6 mark int c; 82 1.1 deraadt 83 1.41 itojun while ((c = getopt(argc, argv, "di:sr:f:")) != -1) 84 1.1 deraadt switch (c) { 85 1.1 deraadt case 'd': 86 1.1 deraadt debug = 1; 87 1.1 deraadt break; 88 1.41 itojun case 'i': 89 1.41 itojun iface = optarg; 90 1.41 itojun break; 91 1.1 deraadt case 'r': 92 1.44 dsl if (isdigit((unsigned char)*optarg)) { 93 1.12 thorpej if (inet_aton(optarg, &route_addr) != 0) 94 1.12 thorpej break; 95 1.1 deraadt } 96 1.1 deraadt he = gethostbyname(optarg); 97 1.12 thorpej if (he == 0) { 98 1.13 mikel warnx("no such host: %s", optarg); 99 1.1 deraadt usage(); 100 1.1 deraadt } 101 1.15 lukem memmove(&route_addr.s_addr, he->h_addr, he->h_length); 102 1.1 deraadt break; 103 1.1 deraadt case 'f': 104 1.1 deraadt bootpfile = optarg; 105 1.1 deraadt break; 106 1.1 deraadt case 's': 107 1.1 deraadt dolog = 1; 108 1.1 deraadt #ifndef LOG_DAEMON 109 1.37 lukem openlog("rpc.bootparamd", 0, 0); 110 1.1 deraadt #else 111 1.37 lukem openlog("rpc.bootparamd", 0, LOG_DAEMON); 112 1.1 deraadt setlogmask(LOG_UPTO(LOG_NOTICE)); 113 1.1 deraadt #endif 114 1.1 deraadt break; 115 1.1 deraadt default: 116 1.1 deraadt usage(); 117 1.1 deraadt } 118 1.1 deraadt 119 1.10 mycroft if (stat(bootpfile, &buf)) 120 1.10 mycroft err(1, "%s", bootpfile); 121 1.10 mycroft 122 1.12 thorpej if (route_addr.s_addr == 0) { 123 1.22 itojun if (get_localaddr(NULL, &my_addr) != 0) 124 1.22 itojun errx(1, "router address not found"); 125 1.12 thorpej route_addr.s_addr = my_addr.sin_addr.s_addr; 126 1.1 deraadt } 127 1.10 mycroft if (!debug) { 128 1.10 mycroft if (daemon(0, 0)) 129 1.10 mycroft err(1, "can't detach from terminal"); 130 1.10 mycroft } 131 1.20 thorpej pidfile(NULL); 132 1.1 deraadt 133 1.1 deraadt (void) pmap_unset(BOOTPARAMPROG, BOOTPARAMVERS); 134 1.1 deraadt 135 1.1 deraadt transp = svcudp_create(RPC_ANYSOCK); 136 1.10 mycroft if (transp == NULL) 137 1.10 mycroft errx(1, "can't create udp service"); 138 1.10 mycroft 139 1.10 mycroft if (!svc_register(transp, BOOTPARAMPROG, BOOTPARAMVERS, bootparamprog_1, 140 1.10 mycroft IPPROTO_UDP)) 141 1.33 tron /* 142 1.33 tron * Do NOT change the "%u" in the format string below to "%lu". If your 143 1.33 tron * build fails update the "rpcgen" program and use "make cleandir" and 144 1.33 tron * "make includes" in "src/lib/librpcsvc" afterwards. 145 1.33 tron */ 146 1.32 explorer errx(1, "unable to register BOOTPARAMPROG version %u, udp", 147 1.1 deraadt BOOTPARAMVERS); 148 1.10 mycroft 149 1.1 deraadt svc_run(); 150 1.10 mycroft errx(1, "svc_run returned"); 151 1.1 deraadt } 152 1.1 deraadt 153 1.1 deraadt bp_whoami_res * 154 1.46 joerg bootparamproc_whoami_1_svc(bp_whoami_arg *whoami, struct svc_req *rqstp) 155 1.1 deraadt { 156 1.9 cgd static bp_whoami_res res; 157 1.9 cgd struct hostent *he; 158 1.18 nathanw struct in_addr haddr; 159 1.21 christos int e; 160 1.2 deraadt 161 1.1 deraadt if (debug) 162 1.13 mikel warnx("whoami got question for %d.%d.%d.%d", 163 1.1 deraadt 255 & whoami->client_address.bp_address_u.ip_addr.net, 164 1.1 deraadt 255 & whoami->client_address.bp_address_u.ip_addr.host, 165 1.1 deraadt 255 & whoami->client_address.bp_address_u.ip_addr.lh, 166 1.1 deraadt 255 & whoami->client_address.bp_address_u.ip_addr.impno); 167 1.1 deraadt if (dolog) 168 1.13 mikel syslog(LOG_NOTICE, "whoami got question for %d.%d.%d.%d", 169 1.1 deraadt 255 & whoami->client_address.bp_address_u.ip_addr.net, 170 1.1 deraadt 255 & whoami->client_address.bp_address_u.ip_addr.host, 171 1.1 deraadt 255 & whoami->client_address.bp_address_u.ip_addr.lh, 172 1.1 deraadt 255 & whoami->client_address.bp_address_u.ip_addr.impno); 173 1.1 deraadt 174 1.15 lukem memmove((char *) &haddr, 175 1.15 lukem (char *) &whoami->client_address.bp_address_u.ip_addr, 176 1.15 lukem sizeof(haddr)); 177 1.1 deraadt he = gethostbyaddr((char *) &haddr, sizeof(haddr), AF_INET); 178 1.14 mrg if (he) { 179 1.43 jrf (void)strlcpy(askname, he->h_name, sizeof(askname)); 180 1.14 mrg } else { 181 1.43 jrf (void)strlcpy(askname, inet_ntoa(haddr), sizeof(askname)); 182 1.9 cgd } 183 1.1 deraadt 184 1.1 deraadt if (debug) 185 1.13 mikel warnx("This is host %s", askname); 186 1.1 deraadt if (dolog) 187 1.13 mikel syslog(LOG_NOTICE, "This is host %s", askname); 188 1.1 deraadt 189 1.21 christos if ((e = lookup_bootparam(askname, hostname, NULL, NULL, NULL)) == 0) { 190 1.1 deraadt res.client_name = hostname; 191 1.1 deraadt getdomainname(domain_name, MAX_MACHINE_NAME); 192 1.1 deraadt res.domain_name = domain_name; 193 1.1 deraadt 194 1.1 deraadt if (res.router_address.address_type != IP_ADDR_TYPE) { 195 1.1 deraadt res.router_address.address_type = IP_ADDR_TYPE; 196 1.15 lukem memmove(&res.router_address.bp_address_u.ip_addr, 197 1.15 lukem &route_addr.s_addr,4); 198 1.1 deraadt } 199 1.1 deraadt if (debug) 200 1.13 mikel warnx("Returning %s %s %d.%d.%d.%d", 201 1.1 deraadt res.client_name, res.domain_name, 202 1.1 deraadt 255 & res.router_address.bp_address_u.ip_addr.net, 203 1.1 deraadt 255 & res.router_address.bp_address_u.ip_addr.host, 204 1.1 deraadt 255 & res.router_address.bp_address_u.ip_addr.lh, 205 1.14 mrg 255 &res.router_address.bp_address_u.ip_addr.impno); 206 1.1 deraadt if (dolog) 207 1.13 mikel syslog(LOG_NOTICE, "Returning %s %s %d.%d.%d.%d", 208 1.1 deraadt res.client_name, res.domain_name, 209 1.1 deraadt 255 & res.router_address.bp_address_u.ip_addr.net, 210 1.1 deraadt 255 & res.router_address.bp_address_u.ip_addr.host, 211 1.1 deraadt 255 & res.router_address.bp_address_u.ip_addr.lh, 212 1.14 mrg 255 &res.router_address.bp_address_u.ip_addr.impno); 213 1.1 deraadt 214 1.1 deraadt return (&res); 215 1.1 deraadt } 216 1.21 christos errno = e; 217 1.1 deraadt if (debug) 218 1.21 christos warn("whoami failed"); 219 1.1 deraadt if (dolog) 220 1.21 christos syslog(LOG_NOTICE, "whoami failed %m"); 221 1.1 deraadt return (NULL); 222 1.1 deraadt } 223 1.1 deraadt 224 1.1 deraadt 225 1.1 deraadt bp_getfile_res * 226 1.46 joerg bootparamproc_getfile_1_svc(bp_getfile_arg *getfile, struct svc_req *rqstp) 227 1.1 deraadt { 228 1.1 deraadt static bp_getfile_res res; 229 1.9 cgd struct hostent *he; 230 1.45 lukem int error; 231 1.1 deraadt 232 1.1 deraadt if (debug) 233 1.13 mikel warnx("getfile got question for \"%s\" and file \"%s\"", 234 1.1 deraadt getfile->client_name, getfile->file_id); 235 1.1 deraadt 236 1.1 deraadt if (dolog) 237 1.13 mikel syslog(LOG_NOTICE, 238 1.13 mikel "getfile got question for \"%s\" and file \"%s\"", 239 1.1 deraadt getfile->client_name, getfile->file_id); 240 1.1 deraadt 241 1.1 deraadt he = NULL; 242 1.1 deraadt he = gethostbyname(getfile->client_name); 243 1.39 jhawk if (!he) { 244 1.39 jhawk if (debug) 245 1.39 jhawk warnx("getfile can't resolve client %s", 246 1.39 jhawk getfile->client_name); 247 1.39 jhawk if (dolog) 248 1.39 jhawk syslog(LOG_NOTICE, "getfile can't resolve client %s", 249 1.39 jhawk getfile->client_name); 250 1.39 jhawk return (NULL); 251 1.39 jhawk } 252 1.1 deraadt 253 1.43 jrf (void)strlcpy(askname, he->h_name, sizeof(askname)); 254 1.45 lukem error = lookup_bootparam(askname, NULL, getfile->file_id, 255 1.2 deraadt &res.server_name, &res.server_path); 256 1.45 lukem if (error == 0) { 257 1.2 deraadt he = gethostbyname(res.server_name); 258 1.39 jhawk if (!he) { 259 1.39 jhawk if (debug) 260 1.39 jhawk warnx("getfile can't resolve server %s for %s", 261 1.39 jhawk res.server_name, getfile->client_name); 262 1.39 jhawk if (dolog) 263 1.39 jhawk syslog(LOG_NOTICE, 264 1.39 jhawk "getfile can't resolve server %s for %s", 265 1.39 jhawk res.server_name, getfile->client_name); 266 1.39 jhawk return (NULL); 267 1.39 jhawk 268 1.39 jhawk } 269 1.15 lukem memmove(&res.server_address.bp_address_u.ip_addr, 270 1.15 lukem he->h_addr, 4); 271 1.2 deraadt res.server_address.address_type = IP_ADDR_TYPE; 272 1.45 lukem } else if (error == ENOENT && !strcmp(getfile->file_id, "dump")) { 273 1.2 deraadt /* Special for dump, answer with null strings. */ 274 1.2 deraadt res.server_name[0] = '\0'; 275 1.2 deraadt res.server_path[0] = '\0'; 276 1.15 lukem memset(&res.server_address.bp_address_u.ip_addr, 0, 4); 277 1.2 deraadt } else { 278 1.1 deraadt if (debug) 279 1.39 jhawk warnx("getfile lookup failed for %s", 280 1.2 deraadt getfile->client_name); 281 1.1 deraadt if (dolog) 282 1.1 deraadt syslog(LOG_NOTICE, 283 1.39 jhawk "getfile lookup failed for %s", 284 1.39 jhawk getfile->client_name); 285 1.2 deraadt return (NULL); 286 1.1 deraadt } 287 1.2 deraadt 288 1.1 deraadt if (debug) 289 1.10 mycroft warnx( 290 1.13 mikel "returning server:%s path:%s address: %d.%d.%d.%d", 291 1.2 deraadt res.server_name, res.server_path, 292 1.2 deraadt 255 & res.server_address.bp_address_u.ip_addr.net, 293 1.2 deraadt 255 & res.server_address.bp_address_u.ip_addr.host, 294 1.2 deraadt 255 & res.server_address.bp_address_u.ip_addr.lh, 295 1.2 deraadt 255 & res.server_address.bp_address_u.ip_addr.impno); 296 1.1 deraadt if (dolog) 297 1.1 deraadt syslog(LOG_NOTICE, 298 1.13 mikel "returning server:%s path:%s address: %d.%d.%d.%d", 299 1.2 deraadt res.server_name, res.server_path, 300 1.2 deraadt 255 & res.server_address.bp_address_u.ip_addr.net, 301 1.2 deraadt 255 & res.server_address.bp_address_u.ip_addr.host, 302 1.2 deraadt 255 & res.server_address.bp_address_u.ip_addr.lh, 303 1.2 deraadt 255 & res.server_address.bp_address_u.ip_addr.impno); 304 1.2 deraadt return (&res); 305 1.1 deraadt } 306 1.1 deraadt 307 1.1 deraadt 308 1.46 joerg static int 309 1.46 joerg lookup_bootparam(char *client, char *client_canonical, char *id, 310 1.46 joerg char **server, char **path) 311 1.1 deraadt { 312 1.2 deraadt FILE *f = fopen(bootpfile, "r"); 313 1.2 deraadt #ifdef YP 314 1.2 deraadt static char *ypbuf = NULL; 315 1.2 deraadt static int ypbuflen = 0; 316 1.2 deraadt #endif 317 1.2 deraadt static char buf[BUFSIZ]; 318 1.34 thorpej char *canon = NULL, *bp, *word = NULL; 319 1.2 deraadt size_t idlen = id == NULL ? 0 : strlen(id); 320 1.2 deraadt int contin = 0; 321 1.2 deraadt int found = 0; 322 1.2 deraadt 323 1.2 deraadt if (f == NULL) 324 1.2 deraadt return EINVAL; /* ? */ 325 1.2 deraadt 326 1.2 deraadt while (fgets(buf, sizeof buf, f)) { 327 1.2 deraadt int wascontin = contin; 328 1.2 deraadt contin = buf[strlen(buf) - 2] == '\\'; 329 1.2 deraadt bp = buf + strspn(buf, " \t\n"); 330 1.2 deraadt 331 1.2 deraadt switch (wascontin) { 332 1.2 deraadt case -1: 333 1.2 deraadt /* Continuation of uninteresting line */ 334 1.2 deraadt contin *= -1; 335 1.2 deraadt continue; 336 1.2 deraadt case 0: 337 1.2 deraadt /* New line */ 338 1.2 deraadt contin *= -1; 339 1.2 deraadt if (*bp == '#') 340 1.2 deraadt continue; 341 1.2 deraadt if ((word = strsep(&bp, " \t\n")) == NULL) 342 1.2 deraadt continue; 343 1.2 deraadt #ifdef YP 344 1.2 deraadt /* A + in the file means try YP now */ 345 1.2 deraadt if (!strcmp(word, "+")) { 346 1.2 deraadt char *ypdom; 347 1.2 deraadt 348 1.2 deraadt if (yp_get_default_domain(&ypdom) || 349 1.2 deraadt yp_match(ypdom, "bootparams", client, 350 1.2 deraadt strlen(client), &ypbuf, &ypbuflen)) 351 1.2 deraadt continue; 352 1.2 deraadt bp = ypbuf; 353 1.2 deraadt word = client; 354 1.2 deraadt contin *= -1; 355 1.2 deraadt break; 356 1.2 deraadt } 357 1.2 deraadt #endif 358 1.21 christos if (debug) 359 1.21 christos warnx("match %s with %s", word, client); 360 1.34 thorpej 361 1.34 thorpej #define HASGLOB(str) \ 362 1.34 thorpej (strchr(str, '*') != NULL || \ 363 1.34 thorpej strchr(str, '?') != NULL || \ 364 1.34 thorpej strchr(str, '[') != NULL || \ 365 1.34 thorpej strchr(str, ']') != NULL) 366 1.34 thorpej 367 1.2 deraadt /* See if this line's client is the one we are 368 1.2 deraadt * looking for */ 369 1.34 thorpej if (fnmatch(word, client, FNM_CASEFOLD) == 0) { 370 1.34 thorpej /* 371 1.34 thorpej * Match. The token may be globbed, we 372 1.34 thorpej * can't just return that as the canonical 373 1.34 thorpej * name. Check to see if the token has any 374 1.34 thorpej * globbing characters in it (*, ?, [, ]). 375 1.34 thorpej * If so, just return the name we already 376 1.34 thorpej * have. Otherwise, return the token. 377 1.34 thorpej */ 378 1.34 thorpej if (HASGLOB(word)) 379 1.34 thorpej canon = client; 380 1.34 thorpej else 381 1.34 thorpej canon = word; 382 1.34 thorpej } else { 383 1.36 thorpej struct hostent *hp; 384 1.2 deraadt /* 385 1.2 deraadt * If it didn't match, try getting the 386 1.2 deraadt * canonical host name of the client 387 1.36 thorpej * on this line, if it's not a glob, 388 1.36 thorpej * and comparing it to the client we 389 1.36 thorpej * are looking up. 390 1.2 deraadt */ 391 1.36 thorpej if (HASGLOB(word)) { 392 1.36 thorpej if (debug) 393 1.36 thorpej warnx("Skipping non-match: %s", 394 1.36 thorpej word); 395 1.36 thorpej continue; 396 1.36 thorpej } 397 1.36 thorpej if ((hp = gethostbyname(word)) == NULL) { 398 1.19 abs if (debug) 399 1.19 abs warnx( 400 1.36 thorpej "Unknown bootparams host %s", 401 1.36 thorpej word); 402 1.19 abs if (dolog) 403 1.19 abs syslog(LOG_NOTICE, 404 1.36 thorpej "Unknown bootparams host %s", 405 1.36 thorpej word); 406 1.19 abs continue; 407 1.19 abs } 408 1.36 thorpej if (strcasecmp(hp->h_name, client) != 0) 409 1.35 enami continue; 410 1.36 thorpej canon = hp->h_name; 411 1.1 deraadt } 412 1.34 thorpej 413 1.34 thorpej #undef HASGLOB 414 1.34 thorpej 415 1.2 deraadt contin *= -1; 416 1.2 deraadt break; 417 1.2 deraadt case 1: 418 1.2 deraadt /* Continued line we want to parse below */ 419 1.1 deraadt break; 420 1.1 deraadt } 421 1.1 deraadt 422 1.34 thorpej assert(canon != NULL); 423 1.2 deraadt if (client_canonical) 424 1.34 thorpej strncpy(client_canonical, canon, MAX_MACHINE_NAME); 425 1.1 deraadt 426 1.2 deraadt /* We have found a line for CLIENT */ 427 1.4 glass if (id == NULL) { 428 1.4 glass (void) fclose(f); 429 1.2 deraadt return 0; 430 1.4 glass } 431 1.2 deraadt 432 1.2 deraadt /* Look for a value for the parameter named by ID */ 433 1.2 deraadt while ((word = strsep(&bp, " \t\n")) != NULL) { 434 1.2 deraadt if (!strncmp(word, id, idlen) && word[idlen] == '=') { 435 1.2 deraadt /* We have found the entry we want */ 436 1.2 deraadt *server = &word[idlen + 1]; 437 1.2 deraadt *path = strchr(*server, ':'); 438 1.2 deraadt if (*path == NULL) 439 1.2 deraadt /* Malformed entry */ 440 1.2 deraadt continue; 441 1.2 deraadt *(*path)++ = '\0'; 442 1.2 deraadt (void) fclose(f); 443 1.2 deraadt return 0; 444 1.2 deraadt } 445 1.1 deraadt } 446 1.2 deraadt 447 1.2 deraadt found = 1; 448 1.1 deraadt } 449 1.1 deraadt 450 1.2 deraadt (void) fclose(f); 451 1.2 deraadt return found ? ENOENT : EPERM; 452 1.12 thorpej } 453 1.12 thorpej 454 1.46 joerg static void 455 1.46 joerg usage(void) 456 1.12 thorpej { 457 1.12 thorpej fprintf(stderr, 458 1.42 wiz "usage: %s [-ds] [-i interface] [-r router] [-f bootparamsfile]\n", 459 1.38 cgd getprogname()); 460 1.12 thorpej exit(1); 461 1.22 itojun } 462 1.22 itojun 463 1.22 itojun static int 464 1.46 joerg get_localaddr(const char *ifname, struct sockaddr_in *sin) 465 1.22 itojun { 466 1.22 itojun struct ifaddrs *ifap, *ifa; 467 1.22 itojun 468 1.22 itojun if (getifaddrs(&ifap) != 0) 469 1.22 itojun return -1; 470 1.22 itojun 471 1.22 itojun for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 472 1.22 itojun if (ifname && strcmp(ifname, ifa->ifa_name) != 0) 473 1.22 itojun continue; 474 1.22 itojun if (ifa->ifa_addr->sa_family != AF_INET) 475 1.22 itojun continue; 476 1.22 itojun if (ifa->ifa_addr->sa_len != sizeof(*sin)) 477 1.22 itojun continue; 478 1.22 itojun 479 1.22 itojun /* no loopback please */ 480 1.22 itojun #ifdef IFF_LOOPBACK 481 1.22 itojun if (ifa->ifa_flags & IFF_LOOPBACK) 482 1.22 itojun continue; 483 1.22 itojun #else 484 1.23 itojun if (strncmp(ifa->ifa_name, "lo", 2) == 0 && 485 1.23 itojun (isdigit(ifa->ifa_name[2]) || ifa->ifa_name[2] == '\0')) 486 1.22 itojun continue; 487 1.22 itojun #endif 488 1.22 itojun 489 1.41 itojun if (!iface || strcmp(ifa->ifa_name, iface) == 0) 490 1.41 itojun ; 491 1.41 itojun else 492 1.41 itojun continue; 493 1.22 itojun 494 1.22 itojun /* candidate found */ 495 1.22 itojun memcpy(sin, ifa->ifa_addr, ifa->ifa_addr->sa_len); 496 1.22 itojun freeifaddrs(ifap); 497 1.22 itojun return 0; 498 1.22 itojun } 499 1.22 itojun 500 1.22 itojun /* no candidate */ 501 1.22 itojun freeifaddrs(ifap); 502 1.22 itojun return -1; 503 1.1 deraadt } 504