]> git.saurik.com Git - apple/network_cmds.git/blob - racoon.tproj/sockmisc.c
network_cmds-115.tar.gz
[apple/network_cmds.git] / racoon.tproj / sockmisc.c
1 /* $KAME: sockmisc.c,v 1.34 2001/12/07 21:35:46 sakane Exp $ */
2
3 /*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
35 #include <sys/uio.h>
36
37 #include <netinet/in.h>
38 #ifdef IPV6_INRIA_VERSION
39 #include <netinet/ipsec.h>
40 #define IPV6_RECVDSTADDR IP_RECVDSTADDR
41 #else
42 #include <netinet6/ipsec.h>
43 #endif
44 #include <netkey/key_var.h>
45
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <errno.h>
50 #ifdef HAVE_UNISTD_H
51 #include <unistd.h>
52 #endif
53
54 #include "var.h"
55 #include "misc.h"
56 #include "plog.h"
57 #include "sockmisc.h"
58 #include "debug.h"
59 #include "gcmalloc.h"
60
61 const int niflags = 0;
62
63 /*
64 * compare two sockaddr without port number.
65 * OUT: 0: equal.
66 * 1: not equal.
67 */
68 int
69 cmpsaddrwop(addr1, addr2)
70 struct sockaddr *addr1;
71 struct sockaddr *addr2;
72 {
73 caddr_t sa1, sa2;
74
75 if (addr1 == 0 && addr2 == 0)
76 return 0;
77 if (addr1 == 0 || addr2 == 0)
78 return 1;
79
80 if (addr1->sa_len != addr2->sa_len
81 || addr1->sa_family != addr2->sa_family)
82 return 1;
83
84 switch (addr1->sa_family) {
85 case AF_INET:
86 sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
87 sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
88 if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
89 return 1;
90 break;
91 #ifdef INET6
92 case AF_INET6:
93 sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
94 sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
95 if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
96 return 1;
97 if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
98 ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
99 return 1;
100 break;
101 #endif
102 default:
103 return 1;
104 }
105
106 return 0;
107 }
108
109 /*
110 * compare two sockaddr with port, taking care wildcard.
111 * addr1 is a subject address, addr2 is in a database entry.
112 * OUT: 0: equal.
113 * 1: not equal.
114 */
115 int
116 cmpsaddrwild(addr1, addr2)
117 struct sockaddr *addr1;
118 struct sockaddr *addr2;
119 {
120 caddr_t sa1, sa2;
121 u_short port1, port2;
122
123 if (addr1 == 0 && addr2 == 0)
124 return 0;
125 if (addr1 == 0 || addr2 == 0)
126 return 1;
127
128 if (addr1->sa_len != addr2->sa_len
129 || addr1->sa_family != addr2->sa_family)
130 return 1;
131
132 switch (addr1->sa_family) {
133 case AF_INET:
134 sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
135 sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
136 port1 = ((struct sockaddr_in *)addr1)->sin_port;
137 port2 = ((struct sockaddr_in *)addr2)->sin_port;
138 if (!(port1 == IPSEC_PORT_ANY ||
139 port2 == IPSEC_PORT_ANY ||
140 port1 == port2))
141 return 1;
142 if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
143 return 1;
144 break;
145 #ifdef INET6
146 case AF_INET6:
147 sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
148 sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
149 port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
150 port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
151 if (!(port1 == IPSEC_PORT_ANY ||
152 port2 == IPSEC_PORT_ANY ||
153 port1 == port2))
154 return 1;
155 if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
156 return 1;
157 if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
158 ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
159 return 1;
160 break;
161 #endif
162 default:
163 return 1;
164 }
165
166 return 0;
167 }
168
169 /*
170 * compare two sockaddr with strict match on port.
171 * OUT: 0: equal.
172 * 1: not equal.
173 */
174 int
175 cmpsaddrstrict(addr1, addr2)
176 struct sockaddr *addr1;
177 struct sockaddr *addr2;
178 {
179 caddr_t sa1, sa2;
180 u_short port1, port2;
181
182 if (addr1 == 0 && addr2 == 0)
183 return 0;
184 if (addr1 == 0 || addr2 == 0)
185 return 1;
186
187 if (addr1->sa_len != addr2->sa_len
188 || addr1->sa_family != addr2->sa_family)
189 return 1;
190
191 switch (addr1->sa_family) {
192 case AF_INET:
193 sa1 = (caddr_t)&((struct sockaddr_in *)addr1)->sin_addr;
194 sa2 = (caddr_t)&((struct sockaddr_in *)addr2)->sin_addr;
195 port1 = ((struct sockaddr_in *)addr1)->sin_port;
196 port2 = ((struct sockaddr_in *)addr2)->sin_port;
197 if (port1 != port2)
198 return 1;
199 if (memcmp(sa1, sa2, sizeof(struct in_addr)) != 0)
200 return 1;
201 break;
202 #ifdef INET6
203 case AF_INET6:
204 sa1 = (caddr_t)&((struct sockaddr_in6 *)addr1)->sin6_addr;
205 sa2 = (caddr_t)&((struct sockaddr_in6 *)addr2)->sin6_addr;
206 port1 = ((struct sockaddr_in6 *)addr1)->sin6_port;
207 port2 = ((struct sockaddr_in6 *)addr2)->sin6_port;
208 if (port1 != port2)
209 return 1;
210 if (memcmp(sa1, sa2, sizeof(struct in6_addr)) != 0)
211 return 1;
212 if (((struct sockaddr_in6 *)addr1)->sin6_scope_id !=
213 ((struct sockaddr_in6 *)addr2)->sin6_scope_id)
214 return 1;
215 break;
216 #endif
217 default:
218 return 1;
219 }
220
221 return 0;
222 }
223
224 /* get local address against the destination. */
225 struct sockaddr *
226 getlocaladdr(remote)
227 struct sockaddr *remote;
228 {
229 struct sockaddr *local;
230 int local_len = sizeof(struct sockaddr_storage);
231 int s; /* for dummy connection */
232
233 /* allocate buffer */
234 if ((local = racoon_calloc(1, local_len)) == NULL) {
235 plog(LLV_ERROR, LOCATION, NULL,
236 "failed to get address buffer.\n");
237 goto err;
238 }
239
240 /* get real interface received packet */
241 if ((s = socket(remote->sa_family, SOCK_DGRAM, 0)) < 0) {
242 plog(LLV_ERROR, LOCATION, NULL,
243 "socket (%s)\n", strerror(errno));
244 goto err;
245 }
246
247 if (connect(s, remote, remote->sa_len) < 0) {
248 plog(LLV_ERROR, LOCATION, NULL,
249 "connect (%s)\n", strerror(errno));
250 close(s);
251 goto err;
252 }
253
254 if (getsockname(s, local, &local_len) < 0) {
255 plog(LLV_ERROR, LOCATION, NULL,
256 "getsockname (%s)\n", strerror(errno));
257 close(s);
258 return NULL;
259 }
260
261 close(s);
262 return local;
263
264 err:
265 if (local != NULL)
266 racoon_free(local);
267 return NULL;
268 }
269
270 /*
271 * Receive packet, with src/dst information. It is assumed that necessary
272 * setsockopt() have already performed on socket.
273 */
274 int
275 recvfromto(s, buf, buflen, flags, from, fromlen, to, tolen)
276 int s;
277 void *buf;
278 size_t buflen;
279 int flags;
280 struct sockaddr *from;
281 int *fromlen;
282 struct sockaddr *to;
283 int *tolen;
284 {
285 int otolen;
286 int len;
287 struct sockaddr_storage ss;
288 struct msghdr m;
289 struct cmsghdr *cm;
290 struct iovec iov[2];
291 u_char cmsgbuf[256];
292 #if defined(INET6) && defined(ADVAPI)
293 struct in6_pktinfo *pi;
294 #endif /*ADVAPI*/
295 struct sockaddr_in *sin;
296 #ifdef INET6
297 struct sockaddr_in6 *sin6;
298 #endif
299
300 len = sizeof(ss);
301 if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
302 plog(LLV_ERROR, LOCATION, NULL,
303 "getsockname (%s)\n", strerror(errno));
304 return -1;
305 }
306
307 m.msg_name = (caddr_t)from;
308 m.msg_namelen = *fromlen;
309 iov[0].iov_base = (caddr_t)buf;
310 iov[0].iov_len = buflen;
311 m.msg_iov = iov;
312 m.msg_iovlen = 1;
313 memset(cmsgbuf, 0, sizeof(cmsgbuf));
314 cm = (struct cmsghdr *)cmsgbuf;
315 m.msg_control = (caddr_t)cm;
316 m.msg_controllen = sizeof(cmsgbuf);
317 if ((len = recvmsg(s, &m, flags)) < 0) {
318 plog(LLV_ERROR, LOCATION, NULL,
319 "recvmsg (%s)\n", strerror(errno));
320 return -1;
321 }
322 *fromlen = m.msg_namelen;
323
324 otolen = *tolen;
325 *tolen = 0;
326 for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(&m);
327 m.msg_controllen != 0 && cm;
328 cm = (struct cmsghdr *)CMSG_NXTHDR(&m, cm)) {
329 #if 0
330 plog(LLV_ERROR, LOCATION, NULL,
331 "cmsg %d %d\n", cm->cmsg_level, cm->cmsg_type);)
332 #endif
333 #if defined(INET6) && defined(ADVAPI)
334 if (ss.ss_family == AF_INET6
335 && cm->cmsg_level == IPPROTO_IPV6
336 && cm->cmsg_type == IPV6_PKTINFO
337 && otolen >= sizeof(*sin6)) {
338 pi = (struct in6_pktinfo *)(CMSG_DATA(cm));
339 *tolen = sizeof(*sin6);
340 sin6 = (struct sockaddr_in6 *)to;
341 memset(sin6, 0, sizeof(*sin6));
342 sin6->sin6_family = AF_INET6;
343 sin6->sin6_len = sizeof(*sin6);
344 memcpy(&sin6->sin6_addr, &pi->ipi6_addr,
345 sizeof(sin6->sin6_addr));
346 /* XXX other cases, such as site-local? */
347 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
348 sin6->sin6_scope_id = pi->ipi6_ifindex;
349 else
350 sin6->sin6_scope_id = 0;
351 sin6->sin6_port =
352 ((struct sockaddr_in6 *)&ss)->sin6_port;
353 otolen = -1; /* "to" already set */
354 continue;
355 }
356 #endif
357 #if defined(INET6) && defined(IPV6_RECVDSTADDR)
358 if (ss.ss_family == AF_INET6
359 && cm->cmsg_level == IPPROTO_IPV6
360 && cm->cmsg_type == IPV6_RECVDSTADDR
361 && otolen >= sizeof(*sin6)) {
362 *tolen = sizeof(*sin6);
363 sin6 = (struct sockaddr_in6 *)to;
364 memset(sin6, 0, sizeof(*sin6));
365 sin6->sin6_family = AF_INET6;
366 sin6->sin6_len = sizeof(*sin6);
367 memcpy(&sin6->sin6_addr, CMSG_DATA(cm),
368 sizeof(sin6->sin6_addr));
369 sin6->sin6_port =
370 ((struct sockaddr_in6 *)&ss)->sin6_port;
371 otolen = -1; /* "to" already set */
372 continue;
373 }
374 #endif
375 if (ss.ss_family == AF_INET
376 && cm->cmsg_level == IPPROTO_IP
377 && cm->cmsg_type == IP_RECVDSTADDR
378 && otolen >= sizeof(*sin)) {
379 *tolen = sizeof(*sin);
380 sin = (struct sockaddr_in *)to;
381 memset(sin, 0, sizeof(*sin));
382 sin->sin_family = AF_INET;
383 sin->sin_len = sizeof(*sin);
384 memcpy(&sin->sin_addr, CMSG_DATA(cm),
385 sizeof(sin->sin_addr));
386 sin->sin_port = ((struct sockaddr_in *)&ss)->sin_port;
387 otolen = -1; /* "to" already set */
388 continue;
389 }
390 }
391
392 return len;
393 }
394
395 /* send packet, with fixing src/dst address pair. */
396 int
397 sendfromto(s, buf, buflen, src, dst, cnt)
398 int s, cnt;
399 const void *buf;
400 size_t buflen;
401 struct sockaddr *src;
402 struct sockaddr *dst;
403 {
404 struct sockaddr_storage ss;
405 int len;
406 int i;
407
408 if (src->sa_family != dst->sa_family) {
409 plog(LLV_ERROR, LOCATION, NULL,
410 "address family mismatch\n");
411 return -1;
412 }
413
414 len = sizeof(ss);
415 if (getsockname(s, (struct sockaddr *)&ss, &len) < 0) {
416 plog(LLV_ERROR, LOCATION, NULL,
417 "getsockname (%s)\n", strerror(errno));
418 return -1;
419 }
420
421 plog(LLV_DEBUG, LOCATION, NULL,
422 "sockname %s\n", saddr2str((struct sockaddr *)&ss));
423 plog(LLV_DEBUG, LOCATION, NULL,
424 "send packet from %s\n", saddr2str(src));
425 plog(LLV_DEBUG, LOCATION, NULL,
426 "send packet to %s\n", saddr2str(dst));
427
428 if (src->sa_family != ss.ss_family) {
429 plog(LLV_ERROR, LOCATION, NULL,
430 "address family mismatch\n");
431 return -1;
432 }
433
434 switch (src->sa_family) {
435 #if defined(INET6) && defined(ADVAPI) && !defined(IPV6_INRIA_VERSION)
436 case AF_INET6:
437 {
438 struct msghdr m;
439 struct cmsghdr *cm;
440 struct iovec iov[2];
441 u_char cmsgbuf[256];
442 struct in6_pktinfo *pi;
443 int ifindex;
444 struct sockaddr_in6 src6, dst6;
445
446 memcpy(&src6, src, sizeof(src6));
447 memcpy(&dst6, dst, sizeof(dst6));
448
449 /* XXX take care of other cases, such as site-local */
450 ifindex = 0;
451 if (IN6_IS_ADDR_LINKLOCAL(&src6.sin6_addr)
452 || IN6_IS_ADDR_MULTICAST(&src6.sin6_addr)) {
453 ifindex = src6.sin6_scope_id; /*???*/
454 }
455
456 /* XXX some sanity check on dst6.sin6_scope_id */
457
458 /* flowinfo for IKE? mmm, maybe useful but for now make it 0 */
459 src6.sin6_flowinfo = dst6.sin6_flowinfo = 0;
460
461 memset(&m, 0, sizeof(m));
462 m.msg_name = (caddr_t)&dst6;
463 m.msg_namelen = sizeof(dst6);
464 iov[0].iov_base = (char *)buf;
465 iov[0].iov_len = buflen;
466 m.msg_iov = iov;
467 m.msg_iovlen = 1;
468
469 memset(cmsgbuf, 0, sizeof(cmsgbuf));
470 cm = (struct cmsghdr *)cmsgbuf;
471 m.msg_control = (caddr_t)cm;
472 m.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
473
474 cm->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
475 cm->cmsg_level = IPPROTO_IPV6;
476 cm->cmsg_type = IPV6_PKTINFO;
477 pi = (struct in6_pktinfo *)CMSG_DATA(cm);
478 memcpy(&pi->ipi6_addr, &src6.sin6_addr, sizeof(src6.sin6_addr));
479 pi->ipi6_ifindex = ifindex;
480
481 plog(LLV_DEBUG, LOCATION, NULL,
482 "src6 %s %d\n",
483 saddr2str((struct sockaddr *)&src6),
484 src6.sin6_scope_id);
485 plog(LLV_DEBUG, LOCATION, NULL,
486 "dst6 %s %d\n",
487 saddr2str((struct sockaddr *)&dst6),
488 dst6.sin6_scope_id);
489
490 for (i = 0; i < cnt; i++) {
491 len = sendmsg(s, &m, 0 /*MSG_DONTROUTE*/);
492 if (len < 0) {
493 plog(LLV_ERROR, LOCATION, NULL,
494 "sendmsg (%s)\n", strerror(errno));
495 return -1;
496 }
497 plog(LLV_DEBUG, LOCATION, NULL,
498 "%d times of %d bytes message will be sent "
499 "to %s\n",
500 i + 1, len, saddr2str(src));
501 }
502 plogdump(LLV_DEBUG, (char *)buf, buflen);
503
504 return len;
505 }
506 #endif
507 default:
508 {
509 int needclose = 0;
510 int sendsock;
511
512 if (ss.ss_family == src->sa_family && memcmp(&ss, src, src->sa_len) == 0) {
513 sendsock = s;
514 needclose = 0;
515 } else {
516 int yes = 1;
517 /*
518 * Use newly opened socket for sending packets.
519 * NOTE: this is unsafe, because if the peer is quick enough
520 * the packet from the peer may be queued into sendsock.
521 * Better approach is to prepare bind'ed udp sockets for
522 * each of the interface addresses.
523 */
524 sendsock = socket(src->sa_family, SOCK_DGRAM, 0);
525 if (sendsock < 0) {
526 plog(LLV_ERROR, LOCATION, NULL,
527 "socket (%s)\n", strerror(errno));
528 return -1;
529 }
530 if (setsockopt(sendsock, SOL_SOCKET, SO_REUSEPORT,
531 (void *)&yes, sizeof(yes)) < 0) {
532 plog(LLV_ERROR, LOCATION, NULL,
533 "setsockopt (%s)\n", strerror(errno));
534 return -1;
535 }
536 #ifdef IPV6_USE_MIN_MTU
537 if (src->sa_family == AF_INET6 &&
538 setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
539 (void *)&yes, sizeof(yes)) < 0) {
540 plog(LLV_ERROR, LOCATION, NULL,
541 "setsockopt (%s)\n", strerror(errno));
542 return -1;
543 }
544 #endif
545 if (setsockopt_bypass(sendsock, src->sa_family) < 0)
546 return -1;
547
548 if (bind(sendsock, (struct sockaddr *)src, src->sa_len) < 0) {
549 plog(LLV_ERROR, LOCATION, NULL,
550 "bind 1 (%s)\n", strerror(errno));
551 return -1;
552 }
553 needclose = 1;
554 }
555
556 for (i = 0; i < cnt; i++) {
557 len = sendto(sendsock, buf, buflen, 0, dst, dst->sa_len);
558 if (len < 0) {
559 plog(LLV_ERROR, LOCATION, NULL,
560 "sendto (%s)\n", strerror(errno));
561 return len;
562 }
563 plog(LLV_DEBUG, LOCATION, NULL,
564 "%d times of %d bytes message will be sent "
565 "to %s\n",
566 i + 1, len, saddr2str(src));
567 }
568 plogdump(LLV_DEBUG, (char *)buf, buflen);
569
570 if (needclose)
571 close(sendsock);
572
573 return len;
574 }
575 }
576 }
577
578 int
579 setsockopt_bypass(so, family)
580 int so, family;
581 {
582 int level;
583 char *buf;
584 char *policy;
585
586 switch (family) {
587 case AF_INET:
588 level = IPPROTO_IP;
589 break;
590 #ifdef INET6
591 case AF_INET6:
592 level = IPPROTO_IPV6;
593 break;
594 #endif
595 default:
596 plog(LLV_ERROR, LOCATION, NULL,
597 "unsupported address family %d\n", family);
598 return -1;
599 }
600
601 policy = "in bypass";
602 buf = ipsec_set_policy(policy, strlen(policy));
603 if (buf == NULL) {
604 plog(LLV_ERROR, LOCATION, NULL,
605 "ipsec_set_policy (%s)\n",
606 ipsec_strerror());
607 return -1;
608 }
609 if (setsockopt(so, level,
610 (level == IPPROTO_IP ?
611 IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
612 buf, ipsec_get_policylen(buf)) < 0) {
613 plog(LLV_ERROR, LOCATION, NULL,
614 "setsockopt (%s)\n",
615 strerror(errno));
616 return -1;
617 }
618 racoon_free(buf);
619
620 policy = "out bypass";
621 buf = ipsec_set_policy(policy, strlen(policy));
622 if (buf == NULL) {
623 plog(LLV_ERROR, LOCATION, NULL,
624 "ipsec_set_policy (%s)\n",
625 ipsec_strerror());
626 return -1;
627 }
628 if (setsockopt(so, level,
629 (level == IPPROTO_IP ?
630 IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
631 buf, ipsec_get_policylen(buf)) < 0) {
632 plog(LLV_ERROR, LOCATION, NULL,
633 "setsockopt (%s)\n",
634 strerror(errno));
635 return -1;
636 }
637 racoon_free(buf);
638
639 return 0;
640 }
641
642 struct sockaddr *
643 newsaddr(len)
644 int len;
645 {
646 struct sockaddr *new;
647
648 new = racoon_calloc(1, len);
649 if (new == NULL)
650 plog(LLV_ERROR, LOCATION, NULL,
651 "%s\n", strerror(errno));
652
653 /* initial */
654 new->sa_len = len;
655
656 return new;
657 }
658
659 struct sockaddr *
660 dupsaddr(src)
661 struct sockaddr *src;
662 {
663 struct sockaddr *dst;
664
665 dst = racoon_calloc(1, src->sa_len);
666 if (dst == NULL) {
667 plog(LLV_ERROR, LOCATION, NULL,
668 "%s\n", strerror(errno));
669 return NULL;
670 }
671
672 memcpy(dst, src, src->sa_len);
673
674 return dst;
675 }
676
677 char *
678 saddr2str(saddr)
679 const struct sockaddr *saddr;
680 {
681 static char buf[NI_MAXHOST + NI_MAXSERV + 10];
682 char addr[NI_MAXHOST], port[NI_MAXSERV];
683
684 if (saddr == NULL)
685 return NULL;
686
687 GETNAMEINFO(saddr, addr, port);
688 snprintf(buf, sizeof(buf), "%s[%s]", addr, port);
689
690 return buf;
691 }
692
693 char *
694 saddrwop2str(saddr)
695 struct sockaddr *saddr;
696 {
697 static char buf[NI_MAXHOST + NI_MAXSERV + 10];
698 char addr[NI_MAXHOST];
699
700 if (saddr == NULL)
701 return NULL;
702
703 GETNAMEINFO(saddr, addr, NULL);
704 snprintf(buf, sizeof(buf), "%s", addr);
705
706 return buf;
707 }
708
709 struct sockaddr *
710 str2saddr(host, port)
711 char *host;
712 char *port;
713 {
714 struct addrinfo hints, *res;
715 struct sockaddr *saddr;
716 int error;
717
718 memset(&hints, 0, sizeof(hints));
719 hints.ai_family = PF_UNSPEC;
720 hints.ai_socktype = SOCK_DGRAM;
721 hints.ai_flags = AI_NUMERICHOST;
722 error = getaddrinfo(host, port, &hints, &res);
723 if (error != 0) {
724 plog(LLV_ERROR, LOCATION, NULL,
725 "getaddrinfo(%s%s%s): %s",
726 host, port ? "," : "", port ? port : "",
727 gai_strerror(error));
728 return NULL;
729 }
730 if (res->ai_next != NULL) {
731 plog(LLV_ERROR, LOCATION, NULL,
732 "getaddrinfo(%s%s%s): "
733 "resolved to multiple address, "
734 "taking the first one",
735 host, port ? "," : "", port ? port : "");
736 }
737 saddr = racoon_malloc(res->ai_addrlen);
738 if (saddr == NULL) {
739 plog(LLV_ERROR, LOCATION, NULL,
740 "failed to allocate buffer.\n");
741 freeaddrinfo(res);
742 return NULL;
743 }
744 memcpy(saddr, res->ai_addr, res->ai_addrlen);
745
746 return saddr;
747 }
748
749 void
750 mask_sockaddr(a, b, l)
751 struct sockaddr *a;
752 const struct sockaddr *b;
753 size_t l;
754 {
755 size_t i;
756 u_int8_t *p, alen;
757
758 switch (b->sa_family) {
759 case AF_INET:
760 alen = sizeof(struct in_addr);
761 p = (u_int8_t *)&((struct sockaddr_in *)a)->sin_addr;
762 break;
763 #ifdef INET6
764 case AF_INET6:
765 alen = sizeof(struct in6_addr);
766 p = (u_int8_t *)&((struct sockaddr_in6 *)a)->sin6_addr;
767 break;
768 #endif
769 default:
770 plog(LLV_ERROR, LOCATION, NULL,
771 "invalid family: %d\n", b->sa_family);
772 exit(1);
773 }
774
775 if ((alen << 3) < l) {
776 plog(LLV_ERROR, LOCATION, NULL,
777 "unexpected inconsistency: %d %d\n", b->sa_family, l);
778 exit(1);
779 }
780
781 memcpy(a, b, b->sa_len);
782 p[l / 8] &= (0xff00 >> (l % 8)) & 0xff;
783 for (i = l / 8 + 1; i < alen; i++)
784 p[i] = 0x00;
785 }