From 91498ffec5686a7ff51b568cb9c67682c85ebb68 Mon Sep 17 00:00:00 2001 From: itojun Date: Mon, 15 Oct 2001 09:51:15 +0000 Subject: [PATCH] implement IPV6_V6ONLY socket option from draft-ietf-ipngwg-rfc2553bis-03.txt. IPV6_BINDV6ONLY (netbsd only) is deprecated, but still work just like before. --- share/man/man4/ip6.4 | 9 +-- sys/netinet/udp_usrreq.c | 10 +-- sys/netinet6/in6.h | 6 +- sys/netinet6/in6_pcb.c | 56 ++++++------- sys/netinet6/in6_pcb.h | 5 +- sys/netinet6/in6_proto.c | 6 +- sys/netinet6/ip6_input.c | 11 +-- sys/netinet6/ip6_output.c | 156 +++++++++++++++++++------------------ sys/netinet6/ip6_var.h | 6 +- sys/netinet6/udp6_output.c | 137 ++++++++++++++++++++++++++------ sys/netinet6/udp6_usrreq.c | 6 +- sys/netinet6/udp6_var.h | 4 +- 12 files changed, 252 insertions(+), 160 deletions(-) diff --git a/share/man/man4/ip6.4 b/share/man/man4/ip6.4 index 511afe92294e..281cced3b34d 100644 --- a/share/man/man4/ip6.4 +++ b/share/man/man4/ip6.4 @@ -1,4 +1,4 @@ -.\" $NetBSD: ip6.4,v 1.8 2001/09/22 00:57:41 wiz Exp $ +.\" $NetBSD: ip6.4,v 1.9 2001/10/15 09:51:16 itojun Exp $ .\" $KAME: ip6.4,v 1.11 2000/05/07 06:21:41 itojun Exp $ .\" .\" Copyright (C) 1999 WIDE Project. @@ -240,14 +240,14 @@ int range = IPV6_PORTRANGE_LOW; /* see */ setsockopt(s, IPPROTO_IPV6, IPV6_PORTRANGE, &range, sizeof(range)); .Ed .Pp -.Dv IPV6_BINDV6ONLY +.Dv IPV6_V6ONLY controls behavior of .Dv AF_INET6 wildcard listening socket. The following example sets the option to 1: .Bd -literal -offset indent int on = 1; -setsockopt(s, IPPROTO_IPV6, IPV6_BINDV6ONLY, &on, sizeof(on)); +setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); .Ed .Pp If set to 1, @@ -684,8 +684,7 @@ The ancillary data items were improperly formed, or option name was unknown. .Sh STANDARDS Most of the socket options are defined in RFC2292 and/or RFC2553. -.Dv IPV6_PORTRANGE , -.Dv IPV6_BINDV6ONLY +.Dv IPV6_PORTRANGE and conflict resolution rule are not defined in the RFCs and should be considered implementation dependent. diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index e86776365ac8..16914c486d19 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp_usrreq.c,v 1.84 2001/09/17 17:27:01 thorpej Exp $ */ +/* $NetBSD: udp_usrreq.c,v 1.85 2001/10/15 09:51:15 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -778,25 +778,21 @@ udp6_realinput(af, src, dst, m, off) !in6_mcmatch(in6p, &dst6, m->m_pkthdr.rcvif)) continue; } -#ifndef INET6_BINDV6ONLY else { if (IN6_IS_ADDR_V4MAPPED(&dst6) && - (in6p->in6p_flags & IN6P_BINDV6ONLY)) + (in6p->in6p_flags & IN6P_IPV6_V6ONLY)) continue; } -#endif if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_faddr, &src6) || in6p->in6p_fport != sport) continue; } -#ifndef INET6_BINDV6ONLY else { if (IN6_IS_ADDR_V4MAPPED(&src6) && - (in6p->in6p_flags & IN6P_BINDV6ONLY)) + (in6p->in6p_flags & IN6P_IPV6_V6ONLY)) continue; } -#endif last = in6p; udp6_sendup(m, off, (struct sockaddr *)src, diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h index 33d92b86e372..c4624f1a75c1 100644 --- a/sys/netinet6/in6.h +++ b/sys/netinet6/in6.h @@ -1,4 +1,4 @@ -/* $NetBSD: in6.h,v 1.27 2001/07/24 00:44:36 itojun Exp $ */ +/* $NetBSD: in6.h,v 1.28 2001/10/15 09:51:16 itojun Exp $ */ /* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */ /* @@ -402,7 +402,7 @@ struct route_in6 { #define IPV6_RTHDR 24 /* bool; routing header */ #define IPV6_PKTOPTIONS 25 /* buf/cmsghdr; set/get IPv6 options */ #define IPV6_CHECKSUM 26 /* int; checksum offset for raw socket */ -#define IPV6_BINDV6ONLY 27 /* bool; only bind INET6 at null bind */ +#define IPV6_V6ONLY 27 /* bool; only bind INET6 at null bind */ #if 1 /*IPSEC*/ #define IPV6_IPSEC_POLICY 28 /* struct; get/set security policy */ @@ -527,7 +527,7 @@ struct in6_pktinfo { #define IPV6CTL_KAME_VERSION 20 #define IPV6CTL_USE_DEPRECATED 21 /* use deprecated addr (RFC2462 5.5.4) */ #define IPV6CTL_RR_PRUNE 22 /* walk timer for router renumbering */ -#define IPV6CTL_BINDV6ONLY 24 +#define IPV6CTL_V6ONLY 24 /* 25 to 27: reserved */ #define IPV6CTL_ANONPORTMIN 28 /* minimum ephemeral port */ #define IPV6CTL_ANONPORTMAX 29 /* maximum ephemeral port */ diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index 1eb0e2b4797c..8d07a0f3def7 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6_pcb.c,v 1.40 2001/08/06 10:25:01 itojun Exp $ */ +/* $NetBSD: in6_pcb.c,v 1.41 2001/10/15 09:51:16 itojun Exp $ */ /* $KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $ */ /* @@ -137,12 +137,8 @@ in6_pcballoc(so, head) head->in6p_next = in6p; in6p->in6p_prev = head; in6p->in6p_next->in6p_prev = in6p; -#ifndef INET6_BINDV6ONLY - if (ip6_bindv6only) - in6p->in6p_flags |= IN6P_BINDV6ONLY; -#else - in6p->in6p_flags |= IN6P_BINDV6ONLY; /*just for safety*/ -#endif + if (ip6_v6only) + in6p->in6p_flags |= IN6P_IPV6_V6ONLY; so->so_pcb = (caddr_t)in6p; return(0); } @@ -201,7 +197,8 @@ in6_pcbbind(in6p, nam, p) */ if (so->so_options & SO_REUSEADDR) reuseport = SO_REUSEADDR|SO_REUSEPORT; - } else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + } + else if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { struct sockaddr_in sin; bzero(&sin, sizeof(sin)); @@ -211,7 +208,8 @@ in6_pcbbind(in6p, nam, p) sizeof(sin.sin_addr)); if (ifa_ifwithaddr((struct sockaddr *)&sin) == 0) return EADDRNOTAVAIL; - } else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + } + else if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { struct ifaddr *ia = NULL; sin6->sin6_port = 0; /* yech... */ @@ -310,11 +308,14 @@ in6_pcbconnect(in6p, nam) /* sanity check for mapped address case */ if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY) != 0) + return EINVAL; if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) in6p->in6p_laddr.s6_addr16[5] = htons(0xffff); if (!IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)) return EINVAL; - } else { + } else + { if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)) return EINVAL; } @@ -352,7 +353,8 @@ in6_pcbconnect(in6p, nam) #else return EADDRNOTAVAIL; #endif - } else { + } else + { /* * XXX: in6_selectsrc might replace the bound local address * with the address specified by setsockopt(IPV6_PKTINFO). @@ -383,7 +385,14 @@ in6_pcbconnect(in6p, nam) return(EADDRINUSE); if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) || (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) - && in6p->in6p_laddr.s6_addr32[3] == 0)) { + && in6p->in6p_laddr.s6_addr32[3] == 0)) + { + /* + * XXX in IPv4 mapped address case, we should grab fresh + * local port number by in_pcbbind, not in6_pcbbind. + * if we are in bad luck, we may assign conflicting port number + * between IPv4 and IPv6 unwillingly. + */ if (in6p->in6p_lport == 0) { (void)in6_pcbbind(in6p, (struct mbuf *)0, (struct proc *)0); @@ -758,14 +767,10 @@ in6_pcblookup(head, faddr6, fport_arg, laddr6, lport_arg, flags) } else { if (IN6_IS_ADDR_V4MAPPED(laddr6)) { -#ifndef INET6_BINDV6ONLY - if (in6p->in6p_flags & IN6P_BINDV6ONLY) + if (in6p->in6p_flags & IN6P_IPV6_V6ONLY) continue; else wildcard++; -#else - continue; -#endif } else if (!IN6_IS_ADDR_UNSPECIFIED(laddr6)) wildcard++; } @@ -787,14 +792,10 @@ in6_pcblookup(head, faddr6, fport_arg, laddr6, lport_arg, flags) } else { if (IN6_IS_ADDR_V4MAPPED(faddr6)) { -#ifndef INET6_BINDV6ONLY - if (in6p->in6p_flags & IN6P_BINDV6ONLY) + if (in6p->in6p_flags & IN6P_IPV6_V6ONLY) continue; else wildcard++; -#else - continue; -#endif } else if (!IN6_IS_ADDR_UNSPECIFIED(faddr6)) wildcard++; } @@ -860,6 +861,10 @@ in6_pcblookup_connect(head, faddr6, fport_arg, laddr6, lport_arg, faith) continue; if (!IN6_ARE_ADDR_EQUAL(&in6p->in6p_laddr, laddr6)) continue; + if ((IN6_IS_ADDR_V4MAPPED(laddr6) || + IN6_IS_ADDR_V4MAPPED(faddr6)) && + (in6p->in6p_flags & IN6P_IPV6_V6ONLY)) + continue; return in6p; } return NULL; @@ -889,18 +894,15 @@ in6_pcblookup_bind(head, laddr6, lport_arg, faith) continue; if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { if (IN6_IS_ADDR_V4MAPPED(laddr6)) { -#ifndef INET6_BINDV6ONLY - if (in6p->in6p_flags & IN6P_BINDV6ONLY) + if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) continue; else match = in6p; -#else - continue; -#endif } else match = in6p; } else if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr) && + !(in6p->in6p_flags & IN6P_IPV6_V6ONLY) && in6p->in6p_laddr.s6_addr32[3] == 0) { if (IN6_IS_ADDR_V4MAPPED(laddr6) && laddr6->s6_addr32[3] != 0) diff --git a/sys/netinet6/in6_pcb.h b/sys/netinet6/in6_pcb.h index 615e1ebaa91b..6e3e0b940f40 100644 --- a/sys/netinet6/in6_pcb.h +++ b/sys/netinet6/in6_pcb.h @@ -1,4 +1,4 @@ -/* $NetBSD: in6_pcb.h,v 1.17 2001/07/02 15:25:36 itojun Exp $ */ +/* $NetBSD: in6_pcb.h,v 1.18 2001/10/15 09:51:16 itojun Exp $ */ /* $KAME: in6_pcb.h,v 1.45 2001/02/09 05:59:46 itojun Exp $ */ /* @@ -122,6 +122,7 @@ struct in6pcb { #define IN6P_RECVOPTS 0x001000 /* receive incoming IP6 options */ #define IN6P_RECVRETOPTS 0x002000 /* receive IP6 options for reply */ #define IN6P_RECVDSTADDR 0x004000 /* receive IP6 dst address */ +#define IN6P_IPV6_V6ONLY 0x008000 /* restrict AF_INET6 socket for v6 */ #define IN6P_PKTINFO 0x010000 /* receive IP6 dst and I/F */ #define IN6P_HOPLIMIT 0x020000 /* receive hoplimit */ #define IN6P_HOPOPTS 0x040000 /* receive hop-by-hop options */ @@ -133,7 +134,9 @@ struct in6pcb { #define IN6P_LOWPORT 0x2000000 /* user wants "low" port binding */ #define IN6P_ANONPORT 0x4000000 /* port chosen for user */ #define IN6P_FAITH 0x8000000 /* accept FAITH'ed connections */ +#if 0 /* obsoleted */ #define IN6P_BINDV6ONLY 0x10000000 /* do not grab IPv4 traffic */ +#endif #define IN6P_CONTROLOPTS (IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\ IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS) diff --git a/sys/netinet6/in6_proto.c b/sys/netinet6/in6_proto.c index 32472df1ddf7..e6987ed21db7 100644 --- a/sys/netinet6/in6_proto.c +++ b/sys/netinet6/in6_proto.c @@ -1,4 +1,4 @@ -/* $NetBSD: in6_proto.c,v 1.29 2001/03/21 19:22:28 thorpej Exp $ */ +/* $NetBSD: in6_proto.c,v 1.30 2001/10/15 09:51:17 itojun Exp $ */ /* $KAME: in6_proto.c,v 1.66 2000/10/10 15:35:47 itojun Exp $ */ /* @@ -292,9 +292,7 @@ int ip6_gif_hlim = 0; int ip6_use_deprecated = 1; /* allow deprecated addr (RFC2462 5.5.4) */ int ip6_rr_prune = 5; /* router renumbering prefix * walk list every 5 sec. */ -#ifndef INET6_BINDV6ONLY -int ip6_bindv6only = 1; -#endif +int ip6_v6only = 1; u_int32_t ip6_id = 0UL; int ip6_keepfaith = 0; diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 114b80cfbe4f..be64fdbe82e8 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.42 2001/08/06 10:25:01 itojun Exp $ */ +/* $NetBSD: ip6_input.c,v 1.43 2001/10/15 09:51:17 itojun Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -1453,10 +1453,11 @@ ip6_sysctl(name, namelen, oldp, oldlenp, newp, newlen) &ip6_use_deprecated); case IPV6CTL_RR_PRUNE: return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_rr_prune); -#ifndef INET6_BINDV6ONLY - case IPV6CTL_BINDV6ONLY: - return sysctl_int(oldp, oldlenp, newp, newlen, - &ip6_bindv6only); + case IPV6CTL_V6ONLY: +#ifdef INET6_BINDV6ONLY + return sysctl_rdint(oldp, oldlenp, newp, ip6_v6only); +#else + return sysctl_int(oldp, oldlenp, newp, newlen, &ip6_v6only); #endif case IPV6CTL_ANONPORTMIN: old = ip6_anonportmin; diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 93e4642cf9f6..87766a74e71b 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_output.c,v 1.36 2001/06/11 13:49:18 itojun Exp $ */ +/* $NetBSD: ip6_output.c,v 1.37 2001/10/15 09:51:17 itojun Exp $ */ /* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */ /* @@ -1257,75 +1257,87 @@ ip6_ctloutput(op, so, level, optname, mp) case IPV6_RTHDR: case IPV6_CHECKSUM: case IPV6_FAITH: -#ifndef INET6_BINDV6ONLY - case IPV6_BINDV6ONLY: -#endif - if (!m || m->m_len != sizeof(int)) + case IPV6_V6ONLY: + if (!m || m->m_len != sizeof(int)) { error = EINVAL; - else { - optval = *mtod(m, int *); - switch (optname) { + break; + } + optval = *mtod(m, int *); + switch (optname) { - case IPV6_UNICAST_HOPS: - if (optval < -1 || optval >= 256) - error = EINVAL; - else { - /* -1 = kernel default */ - in6p->in6p_hops = optval; - } - break; -#define OPTSET(bit) \ - if (optval) \ - in6p->in6p_flags |= bit; \ - else \ - in6p->in6p_flags &= ~bit; - - case IPV6_RECVOPTS: - OPTSET(IN6P_RECVOPTS); - break; - - case IPV6_RECVRETOPTS: - OPTSET(IN6P_RECVRETOPTS); - break; - - case IPV6_RECVDSTADDR: - OPTSET(IN6P_RECVDSTADDR); - break; - - case IPV6_PKTINFO: - OPTSET(IN6P_PKTINFO); - break; - - case IPV6_HOPLIMIT: - OPTSET(IN6P_HOPLIMIT); - break; - - case IPV6_HOPOPTS: - OPTSET(IN6P_HOPOPTS); - break; - - case IPV6_DSTOPTS: - OPTSET(IN6P_DSTOPTS); - break; - - case IPV6_RTHDR: - OPTSET(IN6P_RTHDR); - break; - - case IPV6_CHECKSUM: - in6p->in6p_cksum = optval; - break; - - case IPV6_FAITH: - OPTSET(IN6P_FAITH); - break; - -#ifndef INET6_BINDV6ONLY - case IPV6_BINDV6ONLY: - OPTSET(IN6P_BINDV6ONLY); - break; -#endif + case IPV6_UNICAST_HOPS: + if (optval < -1 || optval >= 256) + error = EINVAL; + else { + /* -1 = kernel default */ + in6p->in6p_hops = optval; } + break; +#define OPTSET(bit) \ +if (optval) \ + in6p->in6p_flags |= bit; \ +else \ + in6p->in6p_flags &= ~bit; + + case IPV6_RECVOPTS: + OPTSET(IN6P_RECVOPTS); + break; + + case IPV6_RECVRETOPTS: + OPTSET(IN6P_RECVRETOPTS); + break; + + case IPV6_RECVDSTADDR: + OPTSET(IN6P_RECVDSTADDR); + break; + + case IPV6_PKTINFO: + OPTSET(IN6P_PKTINFO); + break; + + case IPV6_HOPLIMIT: + OPTSET(IN6P_HOPLIMIT); + break; + + case IPV6_HOPOPTS: + OPTSET(IN6P_HOPOPTS); + break; + + case IPV6_DSTOPTS: + OPTSET(IN6P_DSTOPTS); + break; + + case IPV6_RTHDR: + OPTSET(IN6P_RTHDR); + break; + + case IPV6_CHECKSUM: + in6p->in6p_cksum = optval; + break; + + case IPV6_FAITH: + OPTSET(IN6P_FAITH); + break; + + case IPV6_V6ONLY: + /* + * make setsockopt(IPV6_V6ONLY) + * available only prior to bind(2). + * see ipng mailing list, Jun 22 2001. + */ + if (in6p->in6p_lport || + !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) + { + error = EINVAL; + break; + } +#ifdef INET6_BINDV6ONLY + if (!optval) + error = EINVAL; +#else + OPTSET(IN6P_IPV6_V6ONLY); +#endif + break; } break; #undef OPTSET @@ -1439,9 +1451,7 @@ ip6_ctloutput(op, so, level, optname, mp) case IPV6_RTHDR: case IPV6_CHECKSUM: case IPV6_FAITH: -#ifndef INET6_BINDV6ONLY - case IPV6_BINDV6ONLY: -#endif + case IPV6_V6ONLY: *mp = m = m_get(M_WAIT, MT_SOOPTS); m->m_len = sizeof(int); switch (optname) { @@ -1505,11 +1515,9 @@ ip6_ctloutput(op, so, level, optname, mp) optval = OPTBIT(IN6P_FAITH); break; -#ifndef INET6_BINDV6ONLY - case IPV6_BINDV6ONLY: - optval = OPTBIT(IN6P_BINDV6ONLY); + case IPV6_V6ONLY: + optval = OPTBIT(IN6P_IPV6_V6ONLY); break; -#endif } *mtod(m, int *) = optval; break; diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index 4596fcd05732..85c8b627c169 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_var.h,v 1.15 2000/08/26 11:03:46 itojun Exp $ */ +/* $NetBSD: ip6_var.h,v 1.16 2001/10/15 09:51:17 itojun Exp $ */ /* $KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $ */ /* @@ -214,9 +214,7 @@ extern int ip6_gif_hlim; /* Hop limit for gif encap packet */ extern int ip6_use_deprecated; /* allow deprecated addr as source */ extern int ip6_rr_prune; /* router renumbering prefix * walk list every 5 sec. */ -#ifndef INET6_BINDV6ONLY -extern int ip6_bindv6only; -#endif +extern int ip6_v6only; extern struct socket *ip6_mrouter; /* multicast routing daemon */ extern int ip6_sendredirects; /* send IP redirects when forwarding? */ diff --git a/sys/netinet6/udp6_output.c b/sys/netinet6/udp6_output.c index 011a5eb0d517..2c260f904ac9 100644 --- a/sys/netinet6/udp6_output.c +++ b/sys/netinet6/udp6_output.c @@ -1,5 +1,5 @@ -/* $NetBSD: udp6_output.c,v 1.1 2001/02/08 16:48:02 itojun Exp $ */ -/* $KAME: udp6_output.c,v 1.21 2001/02/07 11:51:54 itojun Exp $ */ +/* $NetBSD: udp6_output.c,v 1.2 2001/10/15 09:51:17 itojun Exp $ */ +/* $KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -123,14 +123,16 @@ udp6_output(in6p, m, addr6, control, p) u_int32_t plen = sizeof(struct udphdr) + ulen; struct ip6_hdr *ip6; struct udphdr *udp6; - struct in6_addr *laddr, *faddr; + struct in6_addr *laddr, *faddr; + struct in6_addr laddr_mapped; /* XXX ugly */ u_short fport; int error = 0; struct ip6_pktopts opt, *stickyopt = in6p->in6p_outputopts; int priv; - int af, hlen; + int af = AF_INET6, hlen = sizeof(struct ip6_hdr); #ifdef INET struct ip *ip; + struct udpiphdr *ui; #endif int flags; struct sockaddr_in6 tmp; @@ -169,6 +171,7 @@ udp6_output(in6p, m, addr6, control, p) } if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + /* how about ::ffff:0.0.0.0 case? */ error = EISCONN; goto release; } @@ -180,6 +183,37 @@ udp6_output(in6p, m, addr6, control, p) faddr = &sin6->sin6_addr; fport = sin6->sin6_port; /* allow 0 port */ + if (IN6_IS_ADDR_V4MAPPED(faddr)) { + if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) + { + /* + * I believe we should explicitly discard the + * packet when mapped addresses are disabled, + * rather than send the packet as an IPv6 one. + * If we chose the latter approach, the packet + * might be sent out on the wire based on the + * default route, the situation which we'd + * probably want to avoid. + * (20010421 jinmei@kame.net) + */ + error = EINVAL; + goto release; + } + if (!IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr) + && !IN6_IS_ADDR_V4MAPPED(&in6p->in6p_laddr)) { + /* + * when remote addr is an IPv4-mapped address, + * local addr should not be an IPv6 address, + * since you cannot determine how to map IPv6 + * source address to IPv4. + */ + error = EINVAL; + goto release; + } + + af = AF_INET; + } + /* KAME hack: embed scopeid */ if (in6_embedscope(&sin6->sin6_addr, sin6, in6p, NULL) != 0) { error = EINVAL; @@ -191,8 +225,41 @@ udp6_output(in6p, m, addr6, control, p) in6p->in6p_moptions, &in6p->in6p_route, &in6p->in6p_laddr, &error); - } else - laddr = &in6p->in6p_laddr; /*XXX*/ + } else { + /* + * XXX: freebsd[34] does not have in_selectsrc, but + * we can omit the whole part because freebsd4 calls + * udp_output() directly in this case, and thus we'll + * never see this path. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_laddr)) { + struct sockaddr_in *sinp, sin_dst; + + bzero(&sin_dst, sizeof(sin_dst)); + sin_dst.sin_family = AF_INET; + sin_dst.sin_len = sizeof(sin_dst); + bcopy(&faddr->s6_addr[12], &sin_dst.sin_addr, + sizeof(sin_dst.sin_addr)); + sinp = in_selectsrc(&sin_dst, + (struct route *)&in6p->in6p_route, + in6p->in6p_socket->so_options, + NULL, &error); + if (sinp == NULL) { + if (error == 0) + error = EADDRNOTAVAIL; + goto release; + } + bzero(&laddr_mapped, sizeof(laddr_mapped)); + laddr_mapped.s6_addr16[5] = 0xffff; /* ugly */ + bcopy(&sinp->sin_addr, + &laddr_mapped.s6_addr[12], + sizeof(sinp->sin_addr)); + laddr = &laddr_mapped; + } else + { + laddr = &in6p->in6p_laddr; /* XXX */ + } + } if (laddr == NULL) { if (error == 0) error = EADDRNOTAVAIL; @@ -206,18 +273,30 @@ udp6_output(in6p, m, addr6, control, p) error = ENOTCONN; goto release; } + if (IN6_IS_ADDR_V4MAPPED(&in6p->in6p_faddr)) { + if ((in6p->in6p_flags & IN6P_IPV6_V6ONLY)) + { + /* + * XXX: this case would happen when the + * application sets the V6ONLY flag after + * connecting the foreign address. + * Such applications should be fixed, + * so we bark here. + */ + log(LOG_INFO, "udp6_output: IPV6_V6ONLY " + "option was set for a connected socket\n"); + error = EINVAL; + goto release; + } else + af = AF_INET; + } laddr = &in6p->in6p_laddr; faddr = &in6p->in6p_faddr; fport = in6p->in6p_fport; } - if (!IN6_IS_ADDR_V4MAPPED(faddr)) { - af = AF_INET6; - hlen = sizeof(struct ip6_hdr); - } else { - af = AF_INET; + if (af == AF_INET) hlen = sizeof(struct ip); - } /* * Calculate data length and get a mbuf @@ -274,7 +353,7 @@ udp6_output(in6p, m, addr6, control, p) error = ENOBUFS; goto release; } -#endif /*IPSEC*/ +#endif /* IPSEC */ error = ip6_output(m, in6p->in6p_outputopts, &in6p->in6p_route, flags, in6p->in6p_moptions, NULL); break; @@ -287,23 +366,31 @@ udp6_output(in6p, m, addr6, control, p) } ip = mtod(m, struct ip *); + ui = (struct udpiphdr *)ip; + bzero(ui->ui_x1, sizeof ui->ui_x1); + ui->ui_pr = IPPROTO_UDP; + ui->ui_len = htons(plen); + bcopy(&faddr->s6_addr[12], &ui->ui_dst, sizeof(ui->ui_dst)); + ui->ui_ulen = ui->ui_len; - ip->ip_len = plen; - ip->ip_p = IPPROTO_UDP; - ip->ip_ttl = in6_selecthlim(in6p, NULL); /*XXX*/ - ip->ip_tos = 0; /*XXX*/ - bcopy(&laddr->s6_addr[12], &ip->ip_src, sizeof(ip->ip_src)); - bcopy(&faddr->s6_addr[12], &ip->ip_dst, sizeof(ip->ip_dst)); - - udp6->uh_sum = 0; - if ((udp6->uh_sum = in_cksum(m, ulen)) == 0) + flags = (in6p->in6p_socket->so_options & + (SO_DONTROUTE | SO_BROADCAST)); + bcopy(&laddr->s6_addr[12], &ui->ui_src, sizeof(ui->ui_src)); + udp6->uh_sum = in_cksum(m, hlen + plen); + if (udp6->uh_sum == 0) udp6->uh_sum = 0xffff; + ip->ip_len = hlen + plen; + ip->ip_ttl = in6_selecthlim(in6p, NULL); /* XXX */ + ip->ip_tos = 0; /* XXX */ + + ip->ip_len = hlen + plen; /* XXX */ + udpstat.udps_opackets++; #ifdef IPSEC - (void)ipsec_setsocket(m, NULL); /*XXX*/ -#endif /*IPSEC*/ - error = ip_output(m, NULL, &in6p->in6p_route, 0 /*XXX*/); + (void)ipsec_setsocket(m, NULL); /* XXX */ +#endif /* IPSEC */ + error = ip_output(m, NULL, &in6p->in6p_route, flags /* XXX */); break; #else error = EAFNOSUPPORT; diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c index 5e0c961df11d..93b8c46e1f2a 100644 --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_usrreq.c,v 1.45 2001/07/25 23:28:04 itojun Exp $ */ +/* $NetBSD: udp6_usrreq.c,v 1.46 2001/10/15 09:51:17 itojun Exp $ */ /* $KAME: udp6_usrreq.c,v 1.86 2001/05/27 17:33:00 itojun Exp $ */ /* @@ -266,7 +266,7 @@ udp6_input(mp, offp, proto) m->m_pkthdr.rcvif); /* - * KAME note: usually we drop udphdr from mbuf here. + * KAME note: traditionally we dropped udpiphdr from mbuf here. * We need udphdr for IPsec processing so we do that later. */ @@ -557,7 +557,7 @@ udp6_ctlinput(cmd, sa, d) /* * Depending on the value of "valid" and routing table * size (mtudisc_{hi,lo}wat), we will: - * - recalcurate the new MTU and create the + * - recalculate the new MTU and create the * corresponding routing entry, or * - ignore the MTU change notification. */ diff --git a/sys/netinet6/udp6_var.h b/sys/netinet6/udp6_var.h index 43754e8ced2d..b8a0ef4468cd 100644 --- a/sys/netinet6/udp6_var.h +++ b/sys/netinet6/udp6_var.h @@ -1,4 +1,4 @@ -/* $NetBSD: udp6_var.h,v 1.9 2000/06/05 06:38:23 itojun Exp $ */ +/* $NetBSD: udp6_var.h,v 1.10 2001/10/15 09:51:17 itojun Exp $ */ /* $KAME: udp6_var.h,v 1.11 2000/06/05 00:14:31 itojun Exp $ */ /* @@ -114,4 +114,4 @@ int udp6_usrreq __P((struct socket *, struct proc *)); #endif /* _KERNEL */ -#endif /*_NETINET6_UDP6_VAR_H_*/ +#endif /* _NETINET6_UDP6_VAR_H_ */