]> git.saurik.com Git - apple/network_cmds.git/blame - racoon.tproj/sockmisc.c
network_cmds-245.19.tar.gz
[apple/network_cmds.git] / racoon.tproj / sockmisc.c
CommitLineData
ac2f15b3 1/* $KAME: sockmisc.c,v 1.36 2002/04/15 06:20:08 sakane Exp $ */
7ba0088d
A
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
61const int niflags = 0;
62
63/*
64 * compare two sockaddr without port number.
65 * OUT: 0: equal.
66 * 1: not equal.
67 */
68int
69cmpsaddrwop(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 */
115int
116cmpsaddrwild(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 */
174int
175cmpsaddrstrict(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. */
225struct sockaddr *
226getlocaladdr(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 */
274int
275recvfromto(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. */
396int
397sendfromto(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));
ac2f15b3 534 close(sendsock);
7ba0088d
A
535 return -1;
536 }
537#ifdef IPV6_USE_MIN_MTU
538 if (src->sa_family == AF_INET6 &&
539 setsockopt(sendsock, IPPROTO_IPV6, IPV6_USE_MIN_MTU,
540 (void *)&yes, sizeof(yes)) < 0) {
541 plog(LLV_ERROR, LOCATION, NULL,
542 "setsockopt (%s)\n", strerror(errno));
ac2f15b3 543 close(sendsock);
7ba0088d
A
544 return -1;
545 }
546#endif
ac2f15b3
A
547 if (setsockopt_bypass(sendsock, src->sa_family) < 0) {
548 close(sendsock);
7ba0088d 549 return -1;
ac2f15b3 550 }
7ba0088d
A
551
552 if (bind(sendsock, (struct sockaddr *)src, src->sa_len) < 0) {
553 plog(LLV_ERROR, LOCATION, NULL,
554 "bind 1 (%s)\n", strerror(errno));
ac2f15b3 555 close(sendsock);
7ba0088d
A
556 return -1;
557 }
558 needclose = 1;
559 }
560
561 for (i = 0; i < cnt; i++) {
562 len = sendto(sendsock, buf, buflen, 0, dst, dst->sa_len);
563 if (len < 0) {
564 plog(LLV_ERROR, LOCATION, NULL,
565 "sendto (%s)\n", strerror(errno));
ac2f15b3
A
566 if (needclose)
567 close(sendsock);
7ba0088d
A
568 return len;
569 }
570 plog(LLV_DEBUG, LOCATION, NULL,
571 "%d times of %d bytes message will be sent "
572 "to %s\n",
573 i + 1, len, saddr2str(src));
574 }
575 plogdump(LLV_DEBUG, (char *)buf, buflen);
576
577 if (needclose)
578 close(sendsock);
579
580 return len;
581 }
582 }
583}
584
585int
586setsockopt_bypass(so, family)
587 int so, family;
588{
589 int level;
590 char *buf;
591 char *policy;
592
593 switch (family) {
594 case AF_INET:
595 level = IPPROTO_IP;
596 break;
597#ifdef INET6
598 case AF_INET6:
599 level = IPPROTO_IPV6;
600 break;
601#endif
602 default:
603 plog(LLV_ERROR, LOCATION, NULL,
604 "unsupported address family %d\n", family);
605 return -1;
606 }
607
608 policy = "in bypass";
609 buf = ipsec_set_policy(policy, strlen(policy));
610 if (buf == NULL) {
611 plog(LLV_ERROR, LOCATION, NULL,
612 "ipsec_set_policy (%s)\n",
613 ipsec_strerror());
614 return -1;
615 }
616 if (setsockopt(so, level,
617 (level == IPPROTO_IP ?
618 IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
619 buf, ipsec_get_policylen(buf)) < 0) {
620 plog(LLV_ERROR, LOCATION, NULL,
621 "setsockopt (%s)\n",
622 strerror(errno));
623 return -1;
624 }
625 racoon_free(buf);
626
627 policy = "out bypass";
628 buf = ipsec_set_policy(policy, strlen(policy));
629 if (buf == NULL) {
630 plog(LLV_ERROR, LOCATION, NULL,
631 "ipsec_set_policy (%s)\n",
632 ipsec_strerror());
633 return -1;
634 }
635 if (setsockopt(so, level,
636 (level == IPPROTO_IP ?
637 IP_IPSEC_POLICY : IPV6_IPSEC_POLICY),
638 buf, ipsec_get_policylen(buf)) < 0) {
639 plog(LLV_ERROR, LOCATION, NULL,
640 "setsockopt (%s)\n",
641 strerror(errno));
642 return -1;
643 }
644 racoon_free(buf);
645
646 return 0;
647}
648
649struct sockaddr *
650newsaddr(len)
651 int len;
652{
653 struct sockaddr *new;
654
655 new = racoon_calloc(1, len);
656 if (new == NULL)
657 plog(LLV_ERROR, LOCATION, NULL,
658 "%s\n", strerror(errno));
659
660 /* initial */
661 new->sa_len = len;
662
663 return new;
664}
665
666struct sockaddr *
667dupsaddr(src)
668 struct sockaddr *src;
669{
670 struct sockaddr *dst;
671
672 dst = racoon_calloc(1, src->sa_len);
673 if (dst == NULL) {
674 plog(LLV_ERROR, LOCATION, NULL,
675 "%s\n", strerror(errno));
676 return NULL;
677 }
678
679 memcpy(dst, src, src->sa_len);
680
681 return dst;
682}
683
684char *
685saddr2str(saddr)
686 const struct sockaddr *saddr;
687{
688 static char buf[NI_MAXHOST + NI_MAXSERV + 10];
689 char addr[NI_MAXHOST], port[NI_MAXSERV];
690
691 if (saddr == NULL)
692 return NULL;
693
694 GETNAMEINFO(saddr, addr, port);
695 snprintf(buf, sizeof(buf), "%s[%s]", addr, port);
696
697 return buf;
698}
699
700char *
701saddrwop2str(saddr)
702 struct sockaddr *saddr;
703{
704 static char buf[NI_MAXHOST + NI_MAXSERV + 10];
705 char addr[NI_MAXHOST];
706
707 if (saddr == NULL)
708 return NULL;
709
710 GETNAMEINFO(saddr, addr, NULL);
711 snprintf(buf, sizeof(buf), "%s", addr);
712
713 return buf;
714}
715
716struct sockaddr *
717str2saddr(host, port)
718 char *host;
719 char *port;
720{
721 struct addrinfo hints, *res;
722 struct sockaddr *saddr;
723 int error;
724
725 memset(&hints, 0, sizeof(hints));
726 hints.ai_family = PF_UNSPEC;
727 hints.ai_socktype = SOCK_DGRAM;
728 hints.ai_flags = AI_NUMERICHOST;
729 error = getaddrinfo(host, port, &hints, &res);
730 if (error != 0) {
731 plog(LLV_ERROR, LOCATION, NULL,
732 "getaddrinfo(%s%s%s): %s",
733 host, port ? "," : "", port ? port : "",
734 gai_strerror(error));
735 return NULL;
736 }
737 if (res->ai_next != NULL) {
738 plog(LLV_ERROR, LOCATION, NULL,
739 "getaddrinfo(%s%s%s): "
740 "resolved to multiple address, "
741 "taking the first one",
742 host, port ? "," : "", port ? port : "");
743 }
744 saddr = racoon_malloc(res->ai_addrlen);
745 if (saddr == NULL) {
746 plog(LLV_ERROR, LOCATION, NULL,
747 "failed to allocate buffer.\n");
748 freeaddrinfo(res);
749 return NULL;
750 }
751 memcpy(saddr, res->ai_addr, res->ai_addrlen);
ac2f15b3 752 freeaddrinfo(res);
7ba0088d
A
753
754 return saddr;
755}
756
757void
758mask_sockaddr(a, b, l)
759 struct sockaddr *a;
760 const struct sockaddr *b;
761 size_t l;
762{
763 size_t i;
764 u_int8_t *p, alen;
765
766 switch (b->sa_family) {
767 case AF_INET:
768 alen = sizeof(struct in_addr);
769 p = (u_int8_t *)&((struct sockaddr_in *)a)->sin_addr;
770 break;
771#ifdef INET6
772 case AF_INET6:
773 alen = sizeof(struct in6_addr);
774 p = (u_int8_t *)&((struct sockaddr_in6 *)a)->sin6_addr;
775 break;
776#endif
777 default:
778 plog(LLV_ERROR, LOCATION, NULL,
779 "invalid family: %d\n", b->sa_family);
780 exit(1);
781 }
782
783 if ((alen << 3) < l) {
784 plog(LLV_ERROR, LOCATION, NULL,
785 "unexpected inconsistency: %d %d\n", b->sa_family, l);
786 exit(1);
787 }
788
789 memcpy(a, b, b->sa_len);
790 p[l / 8] &= (0xff00 >> (l % 8)) & 0xff;
791 for (i = l / 8 + 1; i < alen; i++)
792 p[i] = 0x00;
793}