]>
git.saurik.com Git - apple/network_cmds.git/blob - racoon.tproj/sockmisc.c
1 /* $KAME: sockmisc.c,v 1.34 2001/12/07 21:35:46 sakane Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
32 #include <sys/types.h>
33 #include <sys/param.h>
34 #include <sys/socket.h>
37 #include <netinet/in.h>
38 #ifdef IPV6_INRIA_VERSION
39 #include <netinet/ipsec.h>
40 #define IPV6_RECVDSTADDR IP_RECVDSTADDR
42 #include <netinet6/ipsec.h>
44 #include <netkey/key_var.h>
61 const int niflags
= 0;
64 * compare two sockaddr without port number.
69 cmpsaddrwop(addr1
, addr2
)
70 struct sockaddr
*addr1
;
71 struct sockaddr
*addr2
;
75 if (addr1
== 0 && addr2
== 0)
77 if (addr1
== 0 || addr2
== 0)
80 if (addr1
->sa_len
!= addr2
->sa_len
81 || addr1
->sa_family
!= addr2
->sa_family
)
84 switch (addr1
->sa_family
) {
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)
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)
97 if (((struct sockaddr_in6
*)addr1
)->sin6_scope_id
!=
98 ((struct sockaddr_in6
*)addr2
)->sin6_scope_id
)
110 * compare two sockaddr with port, taking care wildcard.
111 * addr1 is a subject address, addr2 is in a database entry.
116 cmpsaddrwild(addr1
, addr2
)
117 struct sockaddr
*addr1
;
118 struct sockaddr
*addr2
;
121 u_short port1
, port2
;
123 if (addr1
== 0 && addr2
== 0)
125 if (addr1
== 0 || addr2
== 0)
128 if (addr1
->sa_len
!= addr2
->sa_len
129 || addr1
->sa_family
!= addr2
->sa_family
)
132 switch (addr1
->sa_family
) {
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
||
142 if (memcmp(sa1
, sa2
, sizeof(struct in_addr
)) != 0)
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
||
155 if (memcmp(sa1
, sa2
, sizeof(struct in6_addr
)) != 0)
157 if (((struct sockaddr_in6
*)addr1
)->sin6_scope_id
!=
158 ((struct sockaddr_in6
*)addr2
)->sin6_scope_id
)
170 * compare two sockaddr with strict match on port.
175 cmpsaddrstrict(addr1
, addr2
)
176 struct sockaddr
*addr1
;
177 struct sockaddr
*addr2
;
180 u_short port1
, port2
;
182 if (addr1
== 0 && addr2
== 0)
184 if (addr1
== 0 || addr2
== 0)
187 if (addr1
->sa_len
!= addr2
->sa_len
188 || addr1
->sa_family
!= addr2
->sa_family
)
191 switch (addr1
->sa_family
) {
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
;
199 if (memcmp(sa1
, sa2
, sizeof(struct in_addr
)) != 0)
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
;
210 if (memcmp(sa1
, sa2
, sizeof(struct in6_addr
)) != 0)
212 if (((struct sockaddr_in6
*)addr1
)->sin6_scope_id
!=
213 ((struct sockaddr_in6
*)addr2
)->sin6_scope_id
)
224 /* get local address against the destination. */
227 struct sockaddr
*remote
;
229 struct sockaddr
*local
;
230 int local_len
= sizeof(struct sockaddr_storage
);
231 int s
; /* for dummy connection */
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");
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
));
247 if (connect(s
, remote
, remote
->sa_len
) < 0) {
248 plog(LLV_ERROR
, LOCATION
, NULL
,
249 "connect (%s)\n", strerror(errno
));
254 if (getsockname(s
, local
, &local_len
) < 0) {
255 plog(LLV_ERROR
, LOCATION
, NULL
,
256 "getsockname (%s)\n", strerror(errno
));
271 * Receive packet, with src/dst information. It is assumed that necessary
272 * setsockopt() have already performed on socket.
275 recvfromto(s
, buf
, buflen
, flags
, from
, fromlen
, to
, tolen
)
280 struct sockaddr
*from
;
287 struct sockaddr_storage ss
;
292 #if defined(INET6) && defined(ADVAPI)
293 struct in6_pktinfo
*pi
;
295 struct sockaddr_in
*sin
;
297 struct sockaddr_in6
*sin6
;
301 if (getsockname(s
, (struct sockaddr
*)&ss
, &len
) < 0) {
302 plog(LLV_ERROR
, LOCATION
, NULL
,
303 "getsockname (%s)\n", strerror(errno
));
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
;
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
));
322 *fromlen
= m
.msg_namelen
;
326 for (cm
= (struct cmsghdr
*)CMSG_FIRSTHDR(&m
);
327 m
.msg_controllen
!= 0 && cm
;
328 cm
= (struct cmsghdr
*)CMSG_NXTHDR(&m
, cm
)) {
330 plog(LLV_ERROR
, LOCATION
, NULL
,
331 "cmsg %d %d\n", cm
->cmsg_level
, cm
->cmsg_type
);)
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
;
350 sin6
->sin6_scope_id
= 0;
352 ((struct sockaddr_in6
*)&ss
)->sin6_port
;
353 otolen
= -1; /* "to" already set */
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
));
370 ((struct sockaddr_in6
*)&ss
)->sin6_port
;
371 otolen
= -1; /* "to" already set */
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 */
395 /* send packet, with fixing src/dst address pair. */
397 sendfromto(s
, buf
, buflen
, src
, dst
, cnt
)
401 struct sockaddr
*src
;
402 struct sockaddr
*dst
;
404 struct sockaddr_storage ss
;
408 if (src
->sa_family
!= dst
->sa_family
) {
409 plog(LLV_ERROR
, LOCATION
, NULL
,
410 "address family mismatch\n");
415 if (getsockname(s
, (struct sockaddr
*)&ss
, &len
) < 0) {
416 plog(LLV_ERROR
, LOCATION
, NULL
,
417 "getsockname (%s)\n", strerror(errno
));
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
));
428 if (src
->sa_family
!= ss
.ss_family
) {
429 plog(LLV_ERROR
, LOCATION
, NULL
,
430 "address family mismatch\n");
434 switch (src
->sa_family
) {
435 #if defined(INET6) && defined(ADVAPI) && !defined(IPV6_INRIA_VERSION)
442 struct in6_pktinfo
*pi
;
444 struct sockaddr_in6 src6
, dst6
;
446 memcpy(&src6
, src
, sizeof(src6
));
447 memcpy(&dst6
, dst
, sizeof(dst6
));
449 /* XXX take care of other cases, such as site-local */
451 if (IN6_IS_ADDR_LINKLOCAL(&src6
.sin6_addr
)
452 || IN6_IS_ADDR_MULTICAST(&src6
.sin6_addr
)) {
453 ifindex
= src6
.sin6_scope_id
; /*???*/
456 /* XXX some sanity check on dst6.sin6_scope_id */
458 /* flowinfo for IKE? mmm, maybe useful but for now make it 0 */
459 src6
.sin6_flowinfo
= dst6
.sin6_flowinfo
= 0;
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
;
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
));
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
;
481 plog(LLV_DEBUG
, LOCATION
, NULL
,
483 saddr2str((struct sockaddr
*)&src6
),
485 plog(LLV_DEBUG
, LOCATION
, NULL
,
487 saddr2str((struct sockaddr
*)&dst6
),
490 for (i
= 0; i
< cnt
; i
++) {
491 len
= sendmsg(s
, &m
, 0 /*MSG_DONTROUTE*/);
493 plog(LLV_ERROR
, LOCATION
, NULL
,
494 "sendmsg (%s)\n", strerror(errno
));
497 plog(LLV_DEBUG
, LOCATION
, NULL
,
498 "%d times of %d bytes message will be sent "
500 i
+ 1, len
, saddr2str(src
));
502 plogdump(LLV_DEBUG
, (char *)buf
, buflen
);
512 if (ss
.ss_family
== src
->sa_family
&& memcmp(&ss
, src
, src
->sa_len
) == 0) {
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.
524 sendsock
= socket(src
->sa_family
, SOCK_DGRAM
, 0);
526 plog(LLV_ERROR
, LOCATION
, NULL
,
527 "socket (%s)\n", strerror(errno
));
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
));
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
));
545 if (setsockopt_bypass(sendsock
, src
->sa_family
) < 0)
548 if (bind(sendsock
, (struct sockaddr
*)src
, src
->sa_len
) < 0) {
549 plog(LLV_ERROR
, LOCATION
, NULL
,
550 "bind 1 (%s)\n", strerror(errno
));
556 for (i
= 0; i
< cnt
; i
++) {
557 len
= sendto(sendsock
, buf
, buflen
, 0, dst
, dst
->sa_len
);
559 plog(LLV_ERROR
, LOCATION
, NULL
,
560 "sendto (%s)\n", strerror(errno
));
563 plog(LLV_DEBUG
, LOCATION
, NULL
,
564 "%d times of %d bytes message will be sent "
566 i
+ 1, len
, saddr2str(src
));
568 plogdump(LLV_DEBUG
, (char *)buf
, buflen
);
579 setsockopt_bypass(so
, family
)
592 level
= IPPROTO_IPV6
;
596 plog(LLV_ERROR
, LOCATION
, NULL
,
597 "unsupported address family %d\n", family
);
601 policy
= "in bypass";
602 buf
= ipsec_set_policy(policy
, strlen(policy
));
604 plog(LLV_ERROR
, LOCATION
, NULL
,
605 "ipsec_set_policy (%s)\n",
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
,
620 policy
= "out bypass";
621 buf
= ipsec_set_policy(policy
, strlen(policy
));
623 plog(LLV_ERROR
, LOCATION
, NULL
,
624 "ipsec_set_policy (%s)\n",
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
,
646 struct sockaddr
*new;
648 new = racoon_calloc(1, len
);
650 plog(LLV_ERROR
, LOCATION
, NULL
,
651 "%s\n", strerror(errno
));
661 struct sockaddr
*src
;
663 struct sockaddr
*dst
;
665 dst
= racoon_calloc(1, src
->sa_len
);
667 plog(LLV_ERROR
, LOCATION
, NULL
,
668 "%s\n", strerror(errno
));
672 memcpy(dst
, src
, src
->sa_len
);
679 const struct sockaddr
*saddr
;
681 static char buf
[NI_MAXHOST
+ NI_MAXSERV
+ 10];
682 char addr
[NI_MAXHOST
], port
[NI_MAXSERV
];
687 GETNAMEINFO(saddr
, addr
, port
);
688 snprintf(buf
, sizeof(buf
), "%s[%s]", addr
, port
);
695 struct sockaddr
*saddr
;
697 static char buf
[NI_MAXHOST
+ NI_MAXSERV
+ 10];
698 char addr
[NI_MAXHOST
];
703 GETNAMEINFO(saddr
, addr
, NULL
);
704 snprintf(buf
, sizeof(buf
), "%s", addr
);
710 str2saddr(host
, port
)
714 struct addrinfo hints
, *res
;
715 struct sockaddr
*saddr
;
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
);
724 plog(LLV_ERROR
, LOCATION
, NULL
,
725 "getaddrinfo(%s%s%s): %s",
726 host
, port
? "," : "", port
? port
: "",
727 gai_strerror(error
));
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
: "");
737 saddr
= racoon_malloc(res
->ai_addrlen
);
739 plog(LLV_ERROR
, LOCATION
, NULL
,
740 "failed to allocate buffer.\n");
744 memcpy(saddr
, res
->ai_addr
, res
->ai_addrlen
);
750 mask_sockaddr(a
, b
, l
)
752 const struct sockaddr
*b
;
758 switch (b
->sa_family
) {
760 alen
= sizeof(struct in_addr
);
761 p
= (u_int8_t
*)&((struct sockaddr_in
*)a
)->sin_addr
;
765 alen
= sizeof(struct in6_addr
);
766 p
= (u_int8_t
*)&((struct sockaddr_in6
*)a
)->sin6_addr
;
770 plog(LLV_ERROR
, LOCATION
, NULL
,
771 "invalid family: %d\n", b
->sa_family
);
775 if ((alen
<< 3) < l
) {
776 plog(LLV_ERROR
, LOCATION
, NULL
,
777 "unexpected inconsistency: %d %d\n", b
->sa_family
, l
);
781 memcpy(a
, b
, b
->sa_len
);
782 p
[l
/ 8] &= (0xff00 >> (l
% 8)) & 0xff;
783 for (i
= l
/ 8 + 1; i
< alen
; i
++)