1 /*
2 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008,
3 * 2009, 2010, 2011, 2012, 2013, 2014, 2019, 2020
4 * Inferno Nettverk A/S, Norway. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. The above copyright notice, this list of conditions and the following
10 * disclaimer must appear in all copies of the software, derivative works
11 * or modified versions, and any portions thereof, aswell as in all
12 * supporting documentation.
13 * 2. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by
16 * Inferno Nettverk A/S, Norway.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 *
31 * Inferno Nettverk A/S requests users of this software to return to
32 *
33 * Software Distribution Coordinator or sdc@inet.no
34 * Inferno Nettverk A/S
35 * Oslo Research Park
36 * Gaustadall�en 21
37 * NO-0349 Oslo
38 * Norway
39 *
40 * any improvements or extensions that they make and grant Inferno Nettverk A/S
41 * the rights to redistribute these changes.
42 *
43 */
44
45 #include "common.h"
46
47 #include "vis_compat.h"
48
49 static const char rcsid[] =
50 "$Id: util.c,v 1.416.4.5.6.5 2020/11/11 17:02:26 karls Exp $";
51
52 const char *
strcheck(string)53 strcheck(string)
54 const char *string;
55 {
56 return string == NULL ? NOMEM : string;
57 }
58
59 unsigned int
sockscode(version,code)60 sockscode(version, code)
61 const int version;
62 const int code;
63 {
64
65 SASSERTX(code >= 0);
66
67 switch (version) {
68 case PROXY_SOCKS_V4:
69 case PROXY_SOCKS_V4REPLY_VERSION:
70 switch (code) {
71 case SOCKS_SUCCESS:
72 return SOCKSV4_SUCCESS;
73
74 default:
75 return SOCKSV4_FAIL; /* v4 is not very specific. */
76 }
77 /* NOTREACHED */
78
79 case PROXY_SOCKS_V5:
80 return (unsigned char)code; /* current codes are all V5. */
81
82 case PROXY_HTTP_10:
83 case PROXY_HTTP_11:
84 switch (code) {
85 case SOCKS_SUCCESS:
86 return HTTP_SUCCESS;
87
88 case SOCKS_FAILURE:
89 return HTTP_FAILURE;
90
91 case SOCKS_NOTALLOWED:
92 return HTTP_NOTALLOWED;
93
94 case SOCKS_NETUNREACH:
95 case SOCKS_HOSTUNREACH:
96 case SOCKS_CONNREFUSED:
97 return HTTP_HOSTUNREACH;
98
99 default:
100 return HTTP_FAILURE;
101 }
102 /* NOTREACHED */
103
104 case PROXY_UPNP:
105 switch (code) {
106 case SOCKS_SUCCESS:
107 return UPNP_SUCCESS;
108
109 case SOCKS_FAILURE:
110 return UPNP_FAILURE;
111
112 default:
113 return UPNP_FAILURE;
114 }
115 /* NOTREACHED */
116
117
118 default:
119 SERRX(version);
120 }
121
122 /* NOTREACHED */
123 }
124
125 unsigned int
errno2reply(errnum,version)126 errno2reply(errnum, version)
127 int errnum;
128 int version;
129 {
130
131 switch (errnum) {
132 case ENETDOWN:
133 case ENETUNREACH:
134 return sockscode(version, SOCKS_NETUNREACH);
135
136 case EHOSTDOWN:
137 case EHOSTUNREACH:
138 return sockscode(version, SOCKS_HOSTUNREACH);
139
140 case ECONNREFUSED:
141 case ECONNRESET:
142 return sockscode(version, SOCKS_CONNREFUSED);
143
144 case ETIMEDOUT:
145 return sockscode(version, SOCKS_TTLEXPIRED);
146 }
147
148 return sockscode(version, SOCKS_FAILURE);
149 }
150
151 struct sockaddr_storage *
int_sockshost2sockaddr2(host,addr,addrlen,gaierr,emsg,emsglen)152 int_sockshost2sockaddr2(host, addr, addrlen, gaierr, emsg, emsglen)
153 const sockshost_t *host;
154 struct sockaddr_storage *addr;
155 size_t addrlen;
156 int *gaierr;
157 char *emsg;
158 size_t emsglen;
159 {
160 const char *function = "int_sockshost2sockaddr2()";
161 char emsgmem[1024 + MAXHOSTNAMELEN * 4];
162
163 if (emsg == NULL || emsglen == 0) {
164 emsg = emsgmem;
165 emsglen = sizeof(emsgmem);
166 }
167
168 *emsg = NUL;
169 *gaierr = 0;
170
171 if (addr == NULL) {
172 static struct sockaddr_storage addrmem;
173
174 addr = &addrmem;
175 addrlen = sizeof(addrmem);
176 }
177
178 bzero(addr, addrlen);
179
180 switch (host->atype) {
181 case SOCKS_ADDR_IPV4:
182 case SOCKS_ADDR_IPV6: {
183 struct sockaddr_storage ss;
184
185 bzero(&ss, sizeof(ss));
186
187 if (host->atype == SOCKS_ADDR_IPV4) {
188 SET_SOCKADDR(&ss, AF_INET);
189 TOIN(&ss)->sin_addr = host->addr.ipv4;
190 }
191 else {
192 SET_SOCKADDR(&ss, AF_INET6);
193 TOIN6(&ss)->sin6_addr = host->addr.ipv6.ip;
194 TOIN6(&ss)->sin6_scope_id = host->addr.ipv6.scopeid;
195 }
196
197 sockaddrcpy(addr, &ss, salen(ss.ss_family));
198 SET_SOCKADDRPORT(addr, host->port);
199 break;
200 }
201
202 case SOCKS_ADDR_DOMAIN: {
203 struct addrinfo hints, *res;
204 dnsinfo_t resmem;
205
206 bzero(&hints, sizeof(hints));
207
208 set_hints_ai_family(&hints.ai_family);
209
210 *gaierr = cgetaddrinfo(host->addr.domain, NULL, &hints, &res, &resmem);
211
212 if (*gaierr == 0) {
213 if (res->ai_addrlen <= addrlen) {
214 sockaddrcpy(addr, TOSS(res->ai_addr), addrlen);
215 SET_SOCKADDRPORT(addr, host->port);
216 }
217 else {
218 snprintf(emsg, emsglen,
219 "strange dns reply. res->ai_addrlen (%lu) > "
220 "addrlen (%lu)",
221 (unsigned long)res->ai_addrlen,
222 (unsigned long)addrlen);
223
224 swarnx("%s: %s", function, emsg);
225 addr->ss_family = AF_UNSPEC;
226 }
227 }
228 else {
229 char visbuf[MAXHOSTNAMELEN * 4];
230
231 snprintf(emsg, emsglen,
232 "could not resolve hostname \"%s\": %s",
233 str2vis(host->addr.domain,
234 strlen(host->addr.domain),
235 visbuf,
236 sizeof(visbuf)),
237 gai_strerror(*gaierr));
238
239 slog(LOG_NEGOTIATE, "%s: %s", function, emsg);
240 addr->ss_family = AF_UNSPEC;
241 }
242
243 break;
244 }
245
246 case SOCKS_ADDR_IFNAME: {
247 struct sockaddr_storage a, m;
248
249 if (ifname2sockaddr(host->addr.ifname, 0, &a, &m) != NULL) {
250 sockaddrcpy(addr, &a, addrlen);
251 SET_SOCKADDRPORT(addr, host->port);
252 }
253 else {
254 snprintf(emsg, emsglen,
255 "could not resolve %s to IP-address",
256 sockshost2string2(host, ADDRINFO_ATYPE, NULL, 0));
257
258 slog(LOG_NEGOTIATE, "%s: %s", function, emsg);
259
260 addr->ss_family = AF_UNSPEC;
261 }
262
263 break;
264 }
265
266 case SOCKS_ADDR_URL:
267 urlstring2sockaddr(host->addr.urlname, addr, gaierr, emsg, emsglen);
268 break;
269
270 default:
271 SERRX(host->atype);
272 }
273
274 SASSERTX(addr->ss_family == AF_UNSPEC
275 || addr->ss_family == AF_INET
276 || addr->ss_family == AF_INET6);
277
278 return addr;
279 }
280
281 struct sockaddr_storage *
int_sockshost2sockaddr(host,addr,addrlen)282 int_sockshost2sockaddr(host, addr, addrlen)
283 const sockshost_t *host;
284 struct sockaddr_storage *addr;
285 size_t addrlen;
286 {
287 int p;
288
289 return int_sockshost2sockaddr2(host, addr, addrlen, &p, NULL, 0);
290 }
291
292
293 sockshost_t *
sockaddr2sockshost(addr,host)294 sockaddr2sockshost(addr, host)
295 const struct sockaddr_storage *addr;
296 sockshost_t *host;
297 {
298
299 if (host == NULL) {
300 static sockshost_t _host;
301
302 host = &_host;
303 }
304
305 switch (addr->ss_family) {
306 case AF_INET:
307 host->atype = SOCKS_ADDR_IPV4;
308 host->addr.ipv4 = TOCIN(addr)->sin_addr;
309 host->port = TOCIN(addr)->sin_port;
310 break;
311
312 case AF_INET6:
313 host->atype = SOCKS_ADDR_IPV6;
314 host->addr.ipv6.ip = TOCIN6(addr)->sin6_addr;
315 host->addr.ipv6.scopeid = TOCIN6(addr)->sin6_scope_id;
316 host->port = TOCIN6(addr)->sin6_port;
317 break;
318
319 default:
320 SERRX(addr->ss_family);
321 }
322
323 return host;
324 }
325
326 int
sockaddr2hostname(sa,hostname,hostnamelen)327 sockaddr2hostname(sa, hostname, hostnamelen)
328 const struct sockaddr_storage *sa;
329 char *hostname;
330 const size_t hostnamelen;
331 {
332 const char *function = "sockaddr2hostname()";
333 char vbuf[MAXHOSTNAMELEN * 4];
334 int rc;
335
336 rc = getnameinfo(TOCSA(sa),
337 salen(sa->ss_family),
338 hostname,
339 hostnamelen,
340 NULL,
341 0,
342 NI_NAMEREQD);
343
344 if (rc != 0) {
345 slog(LOG_DEBUG, "%s: getnameinfo(%s) failed: %s",
346 function,
347 sockaddr2string2(sa, 0, NULL, 0),
348 gai_strerror(rc));
349
350 return rc;
351 }
352
353 slog(LOG_DEBUG, "%s: %s resolved to \"%s\"",
354 function,
355 sockaddr2string2(sa, 0, NULL, 0),
356 str2vis(hostname, strlen(hostname), vbuf, sizeof(vbuf)));
357
358 return rc;
359 }
360
361
362 struct sockaddr_storage *
int_ruleaddr2sockaddr2(address,sa,len,protocol,gaierr,emsg,emsglen)363 int_ruleaddr2sockaddr2(address, sa, len, protocol, gaierr, emsg, emsglen)
364 const ruleaddr_t *address;
365 struct sockaddr_storage *sa;
366 size_t len;
367 const int protocol;
368 int *gaierr;
369 char *emsg;
370 const size_t emsglen;
371 {
372 sockshost_t host;
373
374 if (sa == NULL) {
375 static struct sockaddr_storage samem;
376
377 sa = &samem;
378 len = sizeof(samem);
379 }
380
381 ruleaddr2sockshost(address, &host, protocol);
382 return int_sockshost2sockaddr2(&host, sa, len, gaierr, emsg, emsglen);
383 }
384
385 struct sockaddr_storage *
int_ruleaddr2sockaddr(address,sa,len,protocol)386 int_ruleaddr2sockaddr(address, sa, len, protocol)
387 const ruleaddr_t *address;
388 struct sockaddr_storage *sa;
389 size_t len;
390 const int protocol;
391 {
392 int gaierr;
393
394 return int_ruleaddr2sockaddr2(address, sa, len, protocol, &gaierr, NULL, 0);
395 }
396
397 sockshost_t *
ruleaddr2sockshost(address,host,protocol)398 ruleaddr2sockshost(address, host, protocol)
399 const ruleaddr_t *address;
400 sockshost_t *host;
401 int protocol;
402 {
403 const char *function = "ruleaddr2sockshost()";
404
405 if (host == NULL) {
406 static sockshost_t hostmem;
407
408 host = &hostmem;
409 }
410
411 switch (host->atype = address->atype) {
412 case SOCKS_ADDR_IPV4:
413 host->addr.ipv4 = address->addr.ipv4.ip;
414 break;
415
416 case SOCKS_ADDR_IPV6:
417 host->addr.ipv6.ip = address->addr.ipv6.ip;
418 host->addr.ipv6.scopeid = address->addr.ipv6.scopeid;
419 break;
420
421 case SOCKS_ADDR_DOMAIN:
422 STRCPY_ASSERTSIZE(host->addr.domain, address->addr.domain);
423 break;
424
425 case SOCKS_ADDR_IFNAME: {
426 struct sockaddr_storage addr, p;
427
428 if (ifname2sockaddr(address->addr.ifname, 0, &addr, &p) == NULL){
429 swarnx("%s: cannot find interface named %s with IP configured. "
430 "Using address %d instead",
431 function, address->addr.ifname, INADDR_ANY);
432
433 host->atype = SOCKS_ADDR_IPV4;
434 host->addr.ipv4.s_addr = htonl(INADDR_ANY);
435 }
436 else {
437 switch (addr.ss_family) {
438 case AF_INET:
439 host->addr.ipv4 = TOIN(&addr)->sin_addr;
440 break;
441
442 case AF_INET6:
443 host->addr.ipv6.ip = TOIN6(&addr)->sin6_addr;
444 host->addr.ipv6.scopeid = TOIN6(&addr)->sin6_scope_id;
445 break;
446
447 default:
448 SERRX(addr.ss_family);
449
450 }
451
452 host->atype = safamily2atype(addr.ss_family);
453 }
454
455 break;
456 }
457
458 default:
459 SERRX(address->atype);
460 }
461
462 switch (protocol) {
463 case SOCKS_TCP:
464 host->port = address->port.tcp;
465 break;
466
467 case SOCKS_UDP:
468 host->port = address->port.udp;
469 break;
470
471 default:
472 SERRX(protocol);
473 }
474
475 return host;
476 }
477
478 ruleaddr_t *
sockshost2ruleaddr(host,addr)479 sockshost2ruleaddr(host, addr)
480 const sockshost_t *host;
481 ruleaddr_t *addr;
482 {
483
484 if (addr == NULL) {
485 static ruleaddr_t addrmem;
486
487 addr = &addrmem;
488 }
489
490 switch (addr->atype = host->atype) {
491 case SOCKS_ADDR_IPV4:
492 addr->addr.ipv4.ip = host->addr.ipv4;
493 addr->addr.ipv4.mask.s_addr = htonl(IPV4_FULLNETMASK);
494 break;
495
496 case SOCKS_ADDR_IPV6:
497 addr->addr.ipv6.ip = host->addr.ipv6.ip;
498 addr->addr.ipv6.maskbits = IPV6_NETMASKBITS;
499 addr->addr.ipv6.scopeid = host->addr.ipv6.scopeid;
500 break;
501
502 case SOCKS_ADDR_DOMAIN:
503 STRCPY_ASSERTSIZE(addr->addr.domain, host->addr.domain);
504 break;
505
506 default:
507 SERRX(host->atype);
508 }
509
510
511 if (host->port == htons(0)) {
512 addr->operator = none;
513 addr->port.tcp = addr->port.udp = addr->portend = htons(0);
514 }
515 else {
516 addr->operator = eq;
517 addr->port.tcp = host->port;
518 addr->port.udp = host->port;
519 addr->portend = host->port;
520 }
521
522 return addr;
523 }
524
525 ruleaddr_t *
sockaddr2ruleaddr(addr,ruleaddr)526 sockaddr2ruleaddr(addr, ruleaddr)
527 const struct sockaddr_storage *addr;
528 ruleaddr_t *ruleaddr;
529 {
530 sockshost_t host;
531
532 sockaddr2sockshost(addr, &host);
533 sockshost2ruleaddr(&host, ruleaddr);
534
535 return ruleaddr;
536 }
537
538 struct sockaddr_storage *
int_hostname2sockaddr(name,index,addr,addrlen)539 int_hostname2sockaddr(name, index, addr, addrlen)
540 const char *name;
541 size_t index;
542 struct sockaddr_storage *addr;
543 size_t addrlen;
544 {
545 int rc;
546
547 return int_hostname2sockaddr2(name, index, addr, addrlen, &rc, NULL, 0);
548 }
549
550
551 struct sockaddr_storage *
int_hostname2sockaddr2(name,index,addr,addrlen,gaierr,emsg,emsglen)552 int_hostname2sockaddr2(name, index, addr, addrlen, gaierr, emsg, emsglen)
553 const char *name;
554 size_t index;
555 struct sockaddr_storage *addr;
556 size_t addrlen;
557 int *gaierr;
558 char *emsg;
559 size_t emsglen;
560 {
561 const char *function = "int_hostname2sockaddr()";
562 struct addrinfo *ai, hints;
563 dnsinfo_t aimem;
564 size_t i;
565 char emsgmem[1024 + MAXHOSTNAMELEN * 4];
566
567 if (emsg == NULL || emsglen == 0) {
568 emsg = emsgmem;
569 emsglen = sizeof(emsgmem);
570 }
571
572 *emsg = NUL;
573 *gaierr = 0;
574
575 bzero(addr, addrlen);
576 SET_SOCKADDR(addr, AF_UNSPEC);
577
578 bzero(&hints, sizeof(hints));
579 if ((*gaierr = cgetaddrinfo(name, NULL, &hints, &ai, &aimem)) != 0) {
580 char visbuf[MAXHOSTNAMELEN * 4];
581
582 snprintf(emsg, emsglen, "could not resolve hostname \"%s\": %s",
583 str2vis(name, strlen(name), visbuf, sizeof(visbuf)),
584 gai_strerror(*gaierr));
585
586 slog(LOG_DEBUG, "%s: could not resolve hostname \"%s\": %s",
587 function, visbuf, gai_strerror(*gaierr));
588
589 return NULL;
590 }
591
592 i = 0;
593 do {
594 SASSERTX(ai->ai_addr != NULL);
595
596 if (i == index) {
597 sockaddrcpy(addr, TOSS(ai->ai_addr), addrlen);
598 return addr;
599 }
600
601 ++i;
602 ai = ai->ai_next;
603 } while (ai != NULL);
604
605 return NULL;
606 }
607
608
609 struct sockaddr_storage *
int_ifname2sockaddr(ifname,index,addr,addrlen,mask,masklen)610 int_ifname2sockaddr(ifname, index, addr, addrlen, mask, masklen)
611 const char *ifname;
612 size_t index;
613 struct sockaddr_storage *addr;
614 size_t addrlen;
615 struct sockaddr_storage *mask;
616 size_t masklen;
617 {
618 const char *function = "int_ifname2sockaddr()";
619 struct ifaddrs ifa, *ifap = &ifa, *iface;
620 size_t i, realindex;
621 int foundifname, foundaddr;
622
623 if (getifaddrs(&ifap) != 0) {
624 swarn("%s: getifaddrs() failed", function);
625 return NULL;
626 }
627
628 for (iface = ifap, i = 0, realindex = 0, foundifname = foundaddr = 0;
629 i <= index && iface != NULL;
630 iface = iface->ifa_next, ++realindex) {
631 if (strcmp(iface->ifa_name, ifname) != 0)
632 continue;
633
634 foundifname = 1;
635
636 if (iface->ifa_addr == NULL) {
637 slog(LOG_DEBUG,
638 "%s: interface %s missing address on index %lu ... skipping",
639 function, iface->ifa_name, (unsigned long)realindex);
640
641 continue;
642 }
643
644 if (iface->ifa_netmask == NULL) {
645 slog(LOG_DEBUG,
646 "%s: interface %s missing netmask for address %s, skipping",
647 function,
648 iface->ifa_name,
649 sockaddr2string(TOSS(iface->ifa_addr), NULL, 0));
650
651 continue;
652 }
653
654 if (iface->ifa_addr->sa_family != AF_INET
655 && iface->ifa_addr->sa_family != AF_INET6) {
656 slog(LOG_DEBUG,
657 "%s: interface %s has neither AF_INET nor AF_INET6 configured "
658 "at index %lu, skipping",
659 function, iface->ifa_name, (unsigned long)index);
660
661 continue;
662 }
663
664 /*
665 * this address-index looks usable. Does it match the requested
666 * index?
667 */
668 if (i != index) {
669 ++i; /* we only count usable indexes. */
670 continue;
671 }
672
673 foundaddr = 1;
674
675 sockaddrcpy(addr, TOSS(iface->ifa_addr), addrlen);
676
677 if (mask != NULL)
678 sockaddrcpy(mask, TOSS(iface->ifa_netmask), masklen);
679
680 break;
681 }
682
683 freeifaddrs(ifap);
684
685 if (!foundifname) {
686 slog(LOG_DEBUG, "%s: no interface with the name \"%s\" found",
687 function, ifname);
688
689 return NULL;
690 }
691
692 if (!foundaddr) {
693 if (index == 0) {
694 char visbuf[MAXIFNAMELEN * 4];
695
696 swarnx("%s: interface \"%s\" has no usable IP-addresses configured",
697 function,
698 str2vis(ifname, strlen(ifname), visbuf, sizeof(visbuf)));
699
700 }
701
702 return NULL;
703 }
704
705 return addr;
706 }
707
708 const char *
sockaddr2ifname(addr,ifname,iflen)709 sockaddr2ifname(addr, ifname, iflen)
710 struct sockaddr_storage *addr;
711 char *ifname;
712 size_t iflen;
713 {
714 const char *function = "sockaddr2ifname()";
715 struct ifaddrs ifa, *ifap = &ifa, *iface;
716 size_t nocompare;
717
718 if (ifname == NULL || iflen == 0) {
719 static char ifname_mem[MAXIFNAMELEN];
720
721 ifname = ifname_mem;
722 iflen = sizeof(ifname_mem);
723 }
724
725 /*
726 * port is irrelevant as far as an interface-address is concerned,
727 * so make a copy of the address and zero it before we start
728 * comparing.
729 */
730 nocompare = ADDRINFO_PORT;
731
732 if (addr->ss_family == AF_INET6
733 && TOIN6(addr)->sin6_scope_id == 0)
734 /*
735 * no particular scope requested, match all.
736 */
737 nocompare |= ADDRINFO_SCOPEID;
738
739 if (getifaddrs(&ifap) != 0)
740 return NULL;
741
742 for (iface = ifap; iface != NULL; iface = iface->ifa_next) {
743 if (iface->ifa_addr != NULL
744 && sockaddrareeq(TOSS(iface->ifa_addr), addr, nocompare)) {
745 strncpy(ifname, iface->ifa_name, iflen - 1);
746 ifname[iflen - 1] = NUL;
747
748 slog(LOG_DEBUG, "%s: address %s belongs to interface %s (af: %s)",
749 function,
750 sockaddr2string(addr, NULL, 0),
751 ifname,
752 safamily2string(iface->ifa_addr->sa_family));
753
754 freeifaddrs(ifap);
755 return ifname;
756 }
757 else
758 slog(LOG_DEBUG,
759 "%s: address %s does not belong to interface %s (af: %s)",
760 function,
761 sockaddr2string(addr, NULL, 0),
762 iface->ifa_name,
763 iface->ifa_addr == NULL ?
764 "<no address>" : safamily2string(iface->ifa_addr->sa_family));
765 }
766
767 freeifaddrs(ifap);
768 return NULL;
769 }
770
771 int
sockshostareeq(a,b)772 sockshostareeq(a, b)
773 const sockshost_t *a;
774 const sockshost_t *b;
775 {
776
777 if (a->atype != b->atype)
778 return 0;
779
780 if (a->port != b->port)
781 return 0;
782
783 switch (a->atype) {
784 case SOCKS_ADDR_IPV4:
785 if (memcmp(&a->addr.ipv4, &b->addr.ipv4, sizeof(a->addr.ipv4)) != 0)
786 return 0;
787 break;
788
789 case SOCKS_ADDR_IPV6:
790 if (memcmp(&a->addr.ipv6, &b->addr.ipv6, sizeof(a->addr.ipv6)) != 0)
791 return 0;
792 break;
793
794 case SOCKS_ADDR_DOMAIN:
795 if (strcmp(a->addr.domain, b->addr.domain) != 0)
796 return 0;
797 break;
798
799 default:
800 SERRX(a->atype);
801 }
802
803 return 1;
804 }
805
806 int
fdsetop(highestfd,op,a,b,result)807 fdsetop(highestfd, op, a, b, result)
808 int highestfd;
809 int op;
810 const fd_set *a;
811 const fd_set *b;
812 fd_set *result;
813 {
814 int i, bits;
815
816 bits = -1;
817 switch (op) {
818 case '&':
819 FD_ZERO(result);
820 for (i = 0; i <= highestfd; ++i)
821 if (FD_ISSET(i, a) && FD_ISSET(i, b)) {
822 FD_SET(i, result);
823 bits = MAX(i, bits);
824 }
825
826 break;
827
828 case '^':
829 FD_ZERO(result);
830 for (i = 0; i <= highestfd; ++i)
831 if (FD_ISSET(i, a) != FD_ISSET(i, b)) {
832 FD_SET(i, result);
833 bits = MAX(i, bits);
834 }
835 else
836 FD_CLR(i, result);
837
838 break;
839
840 case '|':
841 /*
842 * no FD_ZERO() required. Allows caller to call us without using
843 * a temporary object for result if he wants to do result = a | b.
844 */
845 for (i = 0; i <= highestfd; ++i)
846 if (FD_ISSET(i, a) || FD_ISSET(i, b)) {
847 FD_SET(i, result);
848 bits = MAX(i, bits);
849 }
850 break;
851
852 default:
853 SERRX(op);
854 }
855
856 return bits;
857 }
858
859 int
methodisset(method,methodv,methodc)860 methodisset(method, methodv, methodc)
861 int method;
862 const int *methodv;
863 size_t methodc;
864 {
865 const char *function = "methodisset()";
866 size_t i;
867
868 if (sockscf.option.debug)
869 slog(LOG_DEBUG,
870 "%s: checking if method %s is set in the list (%lu) \"%s\"",
871 function,
872 method2string(method),
873 (unsigned long)methodc,
874 methods2string(methodc, methodv, NULL, 0));
875
876 for (i = 0; i < methodc; ++i)
877 if (methodv[i] == method)
878 return 1;
879
880 return 0;
881 }
882
883 char *
str2vis(string,len,visstring,vislen)884 str2vis(string, len, visstring, vislen)
885 const char *string;
886 size_t len;
887 char *visstring;
888 size_t vislen;
889 {
890 const int visflag = VIS_SP | VIS_TAB | VIS_NL | VIS_CSTYLE | VIS_OCTAL;
891
892 if (visstring == NULL) {
893 SERRX(0); /* should never be used. */
894
895 /* see vis(3) for "* 4" */
896 if ((visstring = malloc((sizeof(*visstring) * len * 4) + 1)) == NULL)
897 return NULL;
898
899 vislen = len * 4 + 1;
900 }
901
902 len = MIN(len, (vislen / 4) - 1);
903 strvisx(visstring, string, len, visflag);
904
905 return visstring;
906 }
907
908 int
socks_mklock(template,newname,newnamelen)909 socks_mklock(template, newname, newnamelen)
910 const char *template;
911 char *newname;
912 const size_t newnamelen;
913 {
914 const char *function = "socks_mklock()";
915 static char newtemplate[PATH_MAX];
916 size_t len;
917 char *prefix;
918 int s, flag;
919
920 if ((prefix = socks_getenv(ENV_TMPDIR, dontcare)) != NULL)
921 if (*prefix == NUL)
922 prefix = NULL;
923
924 if (prefix == NULL)
925 prefix = "/tmp";
926
927 len = strlen(prefix) + strlen("/") + strlen(template) + 1;
928 if (len > sizeof(newtemplate))
929 serr("%s: the combination of \"%s\" and \"%s\""
930 "is longer than the system max path length of %lu",
931 function, prefix, template, (unsigned long)sizeof(newtemplate));
932
933 if (newnamelen != 0 && len > newnamelen)
934 serr("%s: the combination of \"%s\" and \"%s\""
935 "is longer than the passed maxlength length of %lu",
936 function, prefix, template, (unsigned long)newnamelen);
937
938 if (*prefix != NUL)
939 snprintf(newtemplate, len, "%s/%s", prefix, template);
940 else
941 snprintf(newtemplate, len, "%s", template);
942
943 if (sockscf.option.debug >= DEBUG_VERBOSE)
944 slog(LOG_DEBUG, "%s: newtemplate = \"%s\", prefix = \"%s\" "
945 "uid = %d, euid = %d, gid = %d, egid = %d",
946 function, newtemplate, prefix,
947 (int)getuid(), (int)geteuid(), (int)getgid(), (int)getegid());
948
949 if (strstr(newtemplate, "XXXXXX") != NULL) {
950 const mode_t oldumask = umask(S_IWGRP | S_IWOTH);
951
952 if ((s = mkstemp(newtemplate)) == -1)
953 swarn("%s: mkstemp(%s) using euid/egid %d/%d failed",
954 function, newtemplate, (int)geteuid(), (int)getegid());
955
956 (void)umask(oldumask);
957
958 #if HAVE_SOLARIS_BUGS
959 if (s == -1 && *newtemplate == NUL) {
960 /*
961 * Solaris 5.11 sometimes loses the template on failure. :-/
962 */
963 if (*prefix != NUL)
964 snprintf(newtemplate, len, "%s/%s", prefix, template);
965 else
966 snprintf(newtemplate, len, "%s", template);
967 }
968 #endif /* HAVE_SOLARIS_BUGS */
969 }
970 else {
971 s = open(newtemplate, O_RDWR | O_CREAT | O_EXCL, 0600);
972 swarn("%s: open(%s)", function, newtemplate);
973 }
974
975 if (s == -1) {
976 if (*prefix == NUL) {
977 slog(LOG_DEBUG, "%s: failed to create \"%s\" (%s) and TMPDIR is not "
978 "set. Trying again with TMPDIR set to \"/tmp\"",
979 function, newtemplate, strerror(errno));
980
981 if (setenv("TMPDIR", "/tmp", 1) != 0)
982 serr("%s: could not setenv(\"TMPDIR\", \"/tmp\")", function);
983
984 SASSERT(socks_getenv(ENV_TMPDIR, dontcare) != NULL);
985
986 return socks_mklock(template, newname, newnamelen);
987 }
988
989 return -1;
990 }
991 else
992 if (sockscf.option.debug >= DEBUG_VERBOSE)
993 slog(LOG_DEBUG, "%s: created file %s", function, newtemplate);
994
995 if (newnamelen == 0) {
996 if (unlink(newtemplate) == -1) {
997 swarn("%s: unlink(%s)", function, newtemplate);
998 close(s);
999
1000 return -1;
1001 }
1002 }
1003 else
1004 strcpy(newname, newtemplate);
1005
1006 if ((flag = fcntl(s, F_GETFD, 0)) == -1
1007 || fcntl(s, F_SETFD, flag | FD_CLOEXEC) == -1)
1008 swarn("%s: fcntl(F_GETFD/F_SETFD)", function);
1009
1010 return s;
1011 }
1012
1013 int
socks_lock(d,offset,len,exclusive,wait)1014 socks_lock(d, offset, len, exclusive, wait)
1015 const int d;
1016 const off_t offset;
1017 const off_t len;
1018 const int exclusive;
1019 const int wait;
1020 {
1021 const char *function = "socks_lock()";
1022 struct flock lock;
1023 int rc;
1024
1025 /* slog(LOG_DEBUG, "%s: %d", function, d); */
1026
1027 if (d == -1)
1028 return 0;
1029
1030 lock.l_start = offset;
1031 lock.l_len = len;
1032 lock.l_whence = SEEK_SET;
1033 lock.l_type = exclusive ? F_WRLCK : F_RDLCK;
1034
1035 #if DIAGNOSTIC && 0
1036 {
1037 struct flock diaginfo = lock;
1038
1039 if (d != sockscf.loglock && fcntl(d, F_GETLK, &diaginfo) != -1)
1040 if (diaginfo.l_type != F_UNLCK)
1041 slog(LOG_DEBUG, "%s: lock %d is currently held by pid %ld",
1042 function, d, (long)diaginfo.l_pid);
1043 }
1044 #endif /* DIAGNOSTIC && 0*/
1045
1046 do
1047 rc = fcntl(d, wait ? F_SETLKW : F_SETLK, &lock);
1048 while (rc == -1 && wait && (ERRNOISTMP(errno) || errno == EACCES));
1049
1050 if (rc == -1) {
1051 if (!sockscf.state.inited
1052 && sockscf.loglock == d
1053 && sockscf.loglock == 0) { /* have not yet inited lockfile. */
1054 sockscf.loglock = -1;
1055 return 0;
1056 }
1057
1058 SASSERT(ERRNOISTMP(errno) || errno == EACCES);
1059 SASSERT(!wait);
1060 }
1061
1062 return rc;
1063 }
1064
1065 void
socks_unlock(d,offset,len)1066 socks_unlock(d, offset, len)
1067 int d;
1068 const off_t offset;
1069 const off_t len;
1070 {
1071 /* const char *function = "socks_unlock()"; */
1072 struct flock lock;
1073
1074 /* slog(LOG_DEBUG, "%s: %d", function, d); */
1075
1076 if (d == -1)
1077 return;
1078
1079 lock.l_start = offset;
1080 lock.l_len = len;
1081 lock.l_type = F_UNLCK;
1082 lock.l_whence = SEEK_SET;
1083
1084 if (fcntl(d, F_SETLK, &lock) == -1)
1085 SERR(errno);
1086 }
1087
1088 int
fdisopen(fd)1089 fdisopen(fd)
1090 const int fd;
1091 {
1092 const int errno_s = errno;
1093 const int rc = fcntl(fd, F_GETFD, 0);
1094
1095 errno = errno_s;
1096 return rc != -1;
1097 }
1098
1099 int
fdisblocking(fd)1100 fdisblocking(fd)
1101 const int fd;
1102 {
1103 const char *function = "fdisblocking()";
1104 int p;
1105
1106 if ((p = fcntl(fd, F_GETFL, 0)) == -1) {
1107 swarn("%s: fcntl(F_GETFL)", function);
1108 return 1;
1109 }
1110
1111 return !(p & O_NONBLOCK);
1112 }
1113
1114 void
closev(ic,iv)1115 closev(ic, iv)
1116 size_t ic;
1117 int *iv;
1118 {
1119 size_t i;
1120
1121 for (i = 0; i < ic; ++i)
1122 if (iv[i] >= 0)
1123 if (close(iv[i]) != 0)
1124 SWARN(iv[i]);
1125 }
1126
1127 /*
1128 * Posted by Kien Ha (Kien_Ha@Mitel.COM) in comp.lang.c once upon a
1129 * time.
1130 */
1131 int
bitcount(number)1132 bitcount(number)
1133 unsigned long number;
1134 {
1135 int bitsset;
1136
1137 for (bitsset = 0; number > 0; number >>= 1)
1138 if (number & 1)
1139 ++bitsset;
1140
1141 return bitsset;
1142 }
1143
1144 int
bitcount_in6addr(in6addr)1145 bitcount_in6addr(in6addr)
1146 const struct in6_addr *in6addr;
1147 {
1148 size_t i;
1149 int bitsset;
1150
1151 for (i = 0, bitsset = 0; i < ELEMENTS(in6addr->s6_addr); ++i)
1152 bitsset += bitcount((unsigned long)in6addr->s6_addr[i]);
1153
1154 return bitsset;
1155 }
1156
1157
1158 fd_set *
allocate_maxsize_fdset(void)1159 allocate_maxsize_fdset(void)
1160 {
1161 const char *function = "allocate_maxsize_fdset()";
1162 fd_set *set;
1163
1164 #if SOCKS_CLIENT
1165 sockscf.state.maxopenfiles = getmaxofiles(hardlimit);
1166 if (sockscf.state.maxopenfiles == (rlim_t)RLIM_INFINITY)
1167 /*
1168 * In the client the softlimit can vary at any time, so this is not
1169 * 100%, but see no other practical solution at the moment.
1170 */
1171 sockscf.state.maxopenfiles = getmaxofiles(softlimit);
1172 #endif /* !SOCKS_CLIENT */
1173
1174 SASSERTX(sockscf.state.maxopenfiles < (rlim_t)RLIM_INFINITY);
1175 SASSERTX(sockscf.state.maxopenfiles > 0);
1176
1177 if ((set = malloc(MAX(sizeof(fd_set), SOCKD_FD_SIZE()))) == NULL)
1178 serr("%s: malloc() of %lu bytes for fd_set failed",
1179 function, (unsigned long)MAX(sizeof(fd_set), SOCKD_FD_SIZE()));
1180
1181 #if DEBUG
1182 if (sockscf.option.debug >= DEBUG_VERBOSE)
1183 slog(LOG_DEBUG, "%s: allocated %lu bytes",
1184 function, (unsigned long)SOCKD_FD_SIZE());
1185 #endif /* DEBUG */
1186
1187 return set;
1188 }
1189
1190 rlim_t
getmaxofiles(limittype_t type)1191 getmaxofiles(limittype_t type)
1192 {
1193 const char *function = "getmaxofiles()";
1194 struct rlimit rlimit;
1195 rlim_t limit;
1196
1197 if (getrlimit(RLIMIT_OFILE, &rlimit) != 0)
1198 serr("%s: getrlimit(RLIMIT_OFILE)", function);
1199
1200 if (type == softlimit)
1201 limit = rlimit.rlim_cur;
1202 else if (type == hardlimit)
1203 #if HAVE_DARWIN /* documented os x bug. What on earth are they thinking? */
1204 limit = MIN(rlimit.rlim_max, OPEN_MAX);
1205 #else /* !HAVE_DARWIN */
1206 limit = rlimit.rlim_max;
1207 #endif /* !HAVE_DARWIN */
1208 else
1209 SERRX(type);
1210 /* NOTREACHED */
1211
1212 #if !SOCKS_CLIENT && FD_SETSIZE_LIMITS_SELECT
1213 /*
1214 * we don't mess with the clients limits. Not our business whether
1215 * select(2) will work or not if a fd has a index that would overflow
1216 * FD_SETSIZE.
1217 */
1218 if (limit >= FD_SETSIZE) {
1219 static int logged;
1220
1221 if (!logged) {
1222 slog(LOG_INFO,
1223 "%s: max open file limit is %lu, but we need to shrink it "
1224 "down to below FD_SETSIZE (%lu) for select(2) to work",
1225 function, (unsigned long)limit, (unsigned long)FD_SETSIZE);
1226
1227 logged = 1;
1228 }
1229
1230 limit = FD_SETSIZE - 1;
1231 }
1232 #endif /* !SOCKS_CLIENT && FD_SETSIZE_LIMITS_SELECT */
1233
1234 if (type == softlimit && limit == (rlim_t)RLIM_INFINITY) {
1235 static int logged;
1236 const rlim_t reduced = 65356;
1237
1238 if (!logged) {
1239 slog(LOG_INFO,
1240 "%s: maxopenfiles is RLIM_INFINITY (%lu), reducing to %lu",
1241 function, (unsigned long)RLIM_INFINITY, (unsigned long)reduced);
1242
1243 logged = 1;
1244 }
1245
1246 limit = reduced;
1247 }
1248
1249 return limit;
1250 }
1251
1252 void
socks_sigblock(sig,oldset)1253 socks_sigblock(sig, oldset)
1254 const int sig;
1255 sigset_t *oldset;
1256 {
1257 const char *function = "socks_sigblock()";
1258 sigset_t newmask;
1259
1260 if (sig == -1)
1261 (void)sigfillset(&newmask);
1262 else {
1263 (void)sigemptyset(&newmask);
1264 (void)sigaddset(&newmask, sig);
1265 }
1266
1267 if (sigprocmask(SIG_BLOCK, &newmask, oldset) != 0)
1268 swarn("%s: sigprocmask()", function);
1269 }
1270
1271 void
socks_sigunblock(oldset)1272 socks_sigunblock(oldset)
1273 const sigset_t *oldset;
1274 {
1275 const char *function = "socks_sigunblock()";
1276
1277 if (sigprocmask(SIG_SETMASK, oldset, NULL) != 0)
1278 swarn("%s: sigprocmask()", function);
1279 }
1280
1281 int
socks_msghaserrors(prefix,msg)1282 socks_msghaserrors(prefix, msg)
1283 const char *prefix;
1284 const struct msghdr *msg;
1285 {
1286 if (msg->msg_flags & MSG_TRUNC) {
1287 swarnx("%s: msg is truncated ... message discarded", prefix);
1288
1289 if (CMSG_TOTLEN(*msg) > 0)
1290 swarnx("%s: XXX should close received descriptors", prefix);
1291
1292 return 1;
1293 }
1294
1295 if (msg->msg_flags & MSG_CTRUNC) {
1296 swarnx("%s: cmsg was truncated ... message discarded", prefix);
1297 return 1;
1298 }
1299
1300 return 0;
1301 }
1302
1303 void
seconds2days(seconds,days,hours,minutes)1304 seconds2days(seconds, days, hours, minutes)
1305 unsigned long *seconds;
1306 unsigned long *days;
1307 unsigned long *hours;
1308 unsigned long *minutes;
1309 {
1310
1311 if (*seconds >= 3600 * 24) {
1312 *days = *seconds / (3600 * 24);
1313 *seconds -= (time_t)(*days * 3600 * 24);
1314 }
1315 else
1316 *days = 0;
1317
1318 if (*seconds >= 3600) {
1319 *hours = *seconds / 3600;
1320 *seconds -= (time_t)(*hours * 3600);
1321 }
1322 else
1323 *hours = 0;
1324
1325 if (*seconds >= 60) {
1326 *minutes = *seconds / 60;
1327 *seconds -= (time_t)(*minutes * 60);
1328 }
1329 else
1330 *minutes = 0;
1331
1332 #if DIAGNOSTIC
1333 SASSERTX(*seconds < 60);
1334 SASSERTX(*minutes < 60);
1335 SASSERTX(*hours < 24);
1336 #endif /* DIAGNOSTIC */
1337
1338 }
1339
1340 struct sockaddr_storage *
int_urlstring2sockaddr(string,saddr,saddrlen,gaierr,emsg,emsglen)1341 int_urlstring2sockaddr(string, saddr, saddrlen, gaierr, emsg, emsglen)
1342 const char *string;
1343 struct sockaddr_storage *saddr;
1344 size_t saddrlen;
1345 int *gaierr;
1346 char *emsg;
1347 size_t emsglen;
1348 {
1349 const char *function = "int_urlstring2sockaddr()";
1350 const char *httpprefix = "http://";
1351 char buf[1024], vbuf[sizeof(buf) * 4], vstring[sizeof(vbuf)],
1352 emsgmem[1024], *port, *s;
1353 long portnumber;
1354 int haveportsep;
1355
1356 *gaierr = 0;
1357
1358 bzero(saddr, saddrlen);
1359 SET_SOCKADDR(saddr, AF_UNSPEC);
1360
1361 if (emsg == NULL) {
1362 emsg = emsgmem;
1363 emsglen = sizeof(emsgmem);
1364 }
1365
1366 slog(LOG_DEBUG, "%s: string to parse is \"%s\"",
1367 function, str2vis(string, strlen(string), vstring, sizeof(vstring)));
1368
1369 if (strstr(string, httpprefix) == NULL) {
1370 snprintf(emsg, emsglen,
1371 "could not find http prefix (%s) in http address \"%s\"",
1372 httpprefix, vstring);
1373
1374 slog(LOG_DEBUG, "%s: %s", function, emsg);
1375 return NULL;
1376 }
1377
1378 string += strlen(httpprefix);
1379
1380 snprintf(buf, sizeof(buf), "%s", string);
1381
1382 if ((s = strchr(buf, ':')) == NULL) {
1383 slog(LOG_DEBUG, "%s: could not find port separator in \"%s\"",
1384 function, vstring);
1385
1386 haveportsep = 0;
1387 }
1388 else {
1389 haveportsep = 1;
1390 *s = NUL;
1391 }
1392
1393 if (*buf == NUL) {
1394 snprintf(emsg, emsglen,
1395 "could not find address string in \"%s\"", vstring);
1396
1397 slog(LOG_DEBUG, "%s: %s", function, emsg);
1398 return NULL;
1399 }
1400
1401 slog(LOG_DEBUG, "%s: pre-portnumber string (%s): \"%s\"",
1402 function,
1403 haveportsep ? "portnumber comes later" : "no portnumber given",
1404 str2vis(buf, strlen(buf), vbuf, sizeof(vbuf)));
1405
1406 if (socks_inet_pton(saddr->ss_family, buf, &(TOIN(saddr)->sin_addr), NULL)
1407 != 1) {
1408 struct hostent *hostent;
1409 char *ep;
1410
1411 errno = 0;
1412 (void)strtol(buf, &ep, 10);
1413
1414 if (*ep == NUL || errno == ERANGE) {
1415 /* only digits, but inet_pton() failed. */
1416 snprintf(emsg, emsglen,
1417 "\"%s\" does not appear to be a valid IP address",
1418 str2vis(buf, strlen(buf), vbuf, sizeof(vbuf)));
1419
1420 slog(LOG_DEBUG, "%s: %s", function, emsg);
1421 return NULL;
1422 }
1423
1424 if ((hostent = gethostbyname(buf)) == NULL
1425 || hostent->h_addr == NULL) {
1426 snprintf(emsg, emsglen, "could not resolve hostname \"%s\"",
1427 str2vis(buf, strlen(buf), vbuf, sizeof(vbuf)));
1428
1429 slog(LOG_DEBUG, "%s: %s", function, emsg);
1430 return NULL;
1431 }
1432
1433 SET_SOCKADDR(saddr, (uint8_t)hostent->h_addrtype);
1434 memcpy(&TOIN(saddr)->sin_addr,
1435 hostent->h_addr_list[0],
1436 (size_t)hostent->h_length);
1437 }
1438
1439
1440 if (haveportsep) {
1441 if ((port = strchr(string, ':')) == NULL) {
1442 snprintf(emsg, emsglen,
1443 "could not find start of port number in \"%s\"",
1444 str2vis(string, strlen(string), vbuf, sizeof(vbuf)));
1445
1446 return NULL;
1447 }
1448 ++port; /* skip ':' */
1449
1450 if ((portnumber = string2portnumber(port, emsg, emsglen)) == -1)
1451 return NULL;
1452 }
1453 else
1454 portnumber = SOCKD_HTTP_PORT;
1455
1456 TOIN(saddr)->sin_port = htons((in_port_t)portnumber);
1457
1458 slog(LOG_DEBUG, "%s: returning addr %s",
1459 function, sockaddr2string(saddr, NULL, 0));
1460
1461 return saddr;
1462 }
1463
1464 #undef snprintf
1465 size_t
snprintfn(char * str,size_t size,const char * format,...)1466 snprintfn(char *str, size_t size, const char *format, ...)
1467 {
1468 const int errno_s = errno;
1469 va_list ap;
1470 ssize_t rc;
1471
1472 if (size <= 0 || str == NULL)
1473 return 0;
1474
1475 va_start(ap, format);
1476 rc = vsnprintf(str, size, format, ap);
1477 va_end(ap);
1478
1479 errno = errno_s; /* don't want snprintf(3) to change errno. */
1480
1481 if (rc <= 0) {
1482 *str = NUL;
1483 rc = 0;
1484 }
1485 else if (rc >= (ssize_t)size) {
1486 rc = (ssize_t)(size - 1);
1487 str[rc] = NUL; /* we never return non-terminated strings. */
1488 }
1489
1490 if (size > 0)
1491 SASSERTX(str[rc] == NUL);
1492
1493 return (size_t)rc;
1494 }
1495
1496 /*
1497 * NOTE: close() macro undefined; closen() function needs to be at the
1498 * end of the file.
1499 */
1500 int
closen(d)1501 closen(d)
1502 int d;
1503 {
1504 int rc;
1505
1506 #undef close /* we redefine close() to closen() for convenience. */
1507 while ((rc = close(d)) == -1 && errno == EINTR)
1508 ; /* LINTED empty */
1509
1510 if (rc == -1 && errno != EBADF) {
1511 /*
1512 * Some people don't understand one should not introduce random
1513 * extra return codes into standard system calls without thinking
1514 * about it carefully first.
1515 * E.g. FreeBSD seems to think it's perfectly ok to let close(2)
1516 * close the socket, yet return -1 and set errno to ECONNRESET.
1517 * Never mind this breaks all sort of applications who keep track
1518 * of their fd's well enough to consider a failure from close(2)
1519 * an indication of something being wrong in their code, rather
1520 * than a TCP connection being reset.
1521 */
1522 errno = 0;
1523 rc = 0;
1524 }
1525
1526 return rc;
1527 }
1528
1529 int
linkednamesareeq(a,b)1530 linkednamesareeq(a, b)
1531 const linkedname_t *a;
1532 const linkedname_t *b;
1533 {
1534
1535 /*
1536 * Check that they have the same contents and in the same order.
1537 */
1538 while (1) {
1539 if (a == b)
1540 return 1;
1541
1542 if (a == NULL || b == NULL)
1543 return 0;
1544
1545 if (strcmp(a->name, b->name) != 0)
1546 return 0;
1547
1548 a = a->next;
1549 b = b->next;
1550 }
1551
1552 /* NOTREACHED */
1553 SERRX(0);
1554 }
1555