diff options
author | Hajimu UMEMOTO <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
---|---|---|
committer | Hajimu UMEMOTO <ume@FreeBSD.org> | 2001-06-11 12:39:29 +0000 |
commit | 33841545909f4a4ee94aa148b3a9cbcdc1abb02a (patch) | |
tree | a79fc7ad2b97862c4a404f352f0211ad93a7b5f1 /sys/netinet | |
parent | 52ebde4fbaab8a8b79de6b17892943783abec7be (diff) |
Sync with recent KAME.
This work was based on kame-20010528-freebsd43-snap.tgz and some
critical problem after the snap was out were fixed.
There are many many changes since last KAME merge.
TODO:
- The definitions of SADB_* in sys/net/pfkeyv2.h are still different
from RFC2407/IANA assignment because of binary compatibility
issue. It should be fixed under 5-CURRENT.
- ip6po_m member of struct ip6_pktopts is no longer used. But, it
is still there because of binary compatibility issue. It should
be removed under 5-CURRENT.
Reviewed by: itojun
Obtained from: KAME
MFC after: 3 weeks
Notes
Notes:
svn path=/head/; revision=78064
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/icmp6.h | 117 | ||||
-rw-r--r-- | sys/netinet/in.c | 23 | ||||
-rw-r--r-- | sys/netinet/in_gif.c | 61 | ||||
-rw-r--r-- | sys/netinet/in_pcb.c | 17 | ||||
-rw-r--r-- | sys/netinet/in_pcb.h | 32 | ||||
-rw-r--r-- | sys/netinet/in_proto.c | 27 | ||||
-rw-r--r-- | sys/netinet/ip6.h | 36 | ||||
-rw-r--r-- | sys/netinet/ip_ecn.c | 21 | ||||
-rw-r--r-- | sys/netinet/ip_ecn.h | 10 | ||||
-rw-r--r-- | sys/netinet/ip_encap.c | 14 | ||||
-rw-r--r-- | sys/netinet/ip_icmp.c | 9 | ||||
-rw-r--r-- | sys/netinet/ip_input.c | 66 | ||||
-rw-r--r-- | sys/netinet/ip_output.c | 313 | ||||
-rw-r--r-- | sys/netinet/ip_var.h | 4 | ||||
-rw-r--r-- | sys/netinet/raw_ip.c | 29 | ||||
-rw-r--r-- | sys/netinet/tcp_input.c | 109 | ||||
-rw-r--r-- | sys/netinet/tcp_output.c | 8 | ||||
-rw-r--r-- | sys/netinet/tcp_reass.c | 109 | ||||
-rw-r--r-- | sys/netinet/tcp_subr.c | 65 | ||||
-rw-r--r-- | sys/netinet/tcp_timewait.c | 65 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 13 | ||||
-rw-r--r-- | sys/netinet/udp_usrreq.c | 8 |
22 files changed, 697 insertions, 459 deletions
diff --git a/sys/netinet/icmp6.h b/sys/netinet/icmp6.h index 3625ee48e41e..425495d524b8 100644 --- a/sys/netinet/icmp6.h +++ b/sys/netinet/icmp6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: icmp6.h,v 1.18 2000/07/03 02:51:08 itojun Exp $ */ +/* $KAME: icmp6.h,v 1.46 2001/04/27 15:09:48 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -80,7 +80,7 @@ struct icmp6_hdr { u_int16_t icmp6_un_data16[2]; /* type-specific field */ u_int8_t icmp6_un_data8[4]; /* type-specific field */ } icmp6_dataun; -}; +} __attribute__((__packed__)); #define icmp6_data32 icmp6_dataun.icmp6_un_data32 #define icmp6_data16 icmp6_dataun.icmp6_un_data16 @@ -124,7 +124,10 @@ struct icmp6_hdr { #define MLD6_MTRACE_RESP 141 /* mtrace response(to sender) */ #define MLD6_MTRACE 142 /* mtrace messages */ -#define ICMP6_MAXTYPE 142 +#define ICMP6_HADISCOV_REQUEST 143 /* XXX To be defined */ +#define ICMP6_HADISCOV_REPLY 144 /* XXX To be defined */ + +#define ICMP6_MAXTYPE 144 #define ICMP6_DST_UNREACH_NOROUTE 0 /* no route to destination */ #define ICMP6_DST_UNREACH_ADMIN 1 /* administratively prohibited */ @@ -146,7 +149,7 @@ struct icmp6_hdr { #define ICMP6_NI_SUBJ_FQDN 1 /* Query Subject is a Domain name */ #define ICMP6_NI_SUBJ_IPV4 2 /* Query Subject is an IPv4 address */ -#define ICMP6_NI_SUCESS 0 /* node information successful reply */ +#define ICMP6_NI_SUCCESS 0 /* node information successful reply */ #define ICMP6_NI_REFUSED 1 /* node information request is refused */ #define ICMP6_NI_UNKNOWN 2 /* unknown Qtype */ @@ -164,7 +167,7 @@ struct icmp6_hdr { struct mld6_hdr { struct icmp6_hdr mld6_hdr; struct in6_addr mld6_addr; /* multicast address */ -}; +} __attribute__((__packed__)); #define mld6_type mld6_hdr.icmp6_type #define mld6_code mld6_hdr.icmp6_code @@ -179,7 +182,7 @@ struct mld6_hdr { struct nd_router_solicit { /* router solicitation */ struct icmp6_hdr nd_rs_hdr; /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_rs_type nd_rs_hdr.icmp6_type #define nd_rs_code nd_rs_hdr.icmp6_code @@ -191,7 +194,7 @@ struct nd_router_advert { /* router advertisement */ u_int32_t nd_ra_reachable; /* reachable time */ u_int32_t nd_ra_retransmit; /* retransmit timer */ /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_ra_type nd_ra_hdr.icmp6_type #define nd_ra_code nd_ra_hdr.icmp6_code @@ -200,13 +203,26 @@ struct nd_router_advert { /* router advertisement */ #define nd_ra_flags_reserved nd_ra_hdr.icmp6_data8[1] #define ND_RA_FLAG_MANAGED 0x80 #define ND_RA_FLAG_OTHER 0x40 +#define ND_RA_FLAG_HA 0x20 + +/* + * Router preference values based on draft-draves-ipngwg-router-selection-01. + * These are non-standard definitions. + */ +#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ + +#define ND_RA_FLAG_RTPREF_HIGH 0x08 /* 00001000 */ +#define ND_RA_FLAG_RTPREF_MEDIUM 0x00 /* 00000000 */ +#define ND_RA_FLAG_RTPREF_LOW 0x18 /* 00011000 */ +#define ND_RA_FLAG_RTPREF_RSV 0x10 /* 00010000 */ + #define nd_ra_router_lifetime nd_ra_hdr.icmp6_data16[1] struct nd_neighbor_solicit { /* neighbor solicitation */ struct icmp6_hdr nd_ns_hdr; struct in6_addr nd_ns_target; /*target address */ /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_ns_type nd_ns_hdr.icmp6_type #define nd_ns_code nd_ns_hdr.icmp6_code @@ -217,7 +233,7 @@ struct nd_neighbor_advert { /* neighbor advertisement */ struct icmp6_hdr nd_na_hdr; struct in6_addr nd_na_target; /* target address */ /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_na_type nd_na_hdr.icmp6_type #define nd_na_code nd_na_hdr.icmp6_code @@ -240,7 +256,7 @@ struct nd_redirect { /* redirect */ struct in6_addr nd_rd_target; /* target address */ struct in6_addr nd_rd_dst; /* destination address */ /* could be followed by options */ -}; +} __attribute__((__packed__)); #define nd_rd_type nd_rd_hdr.icmp6_type #define nd_rd_code nd_rd_hdr.icmp6_code @@ -251,13 +267,14 @@ struct nd_opt_hdr { /* Neighbor discovery option header */ u_int8_t nd_opt_type; u_int8_t nd_opt_len; /* followed by option specific data*/ -}; +} __attribute__((__packed__)); #define ND_OPT_SOURCE_LINKADDR 1 #define ND_OPT_TARGET_LINKADDR 2 #define ND_OPT_PREFIX_INFORMATION 3 #define ND_OPT_REDIRECTED_HEADER 4 #define ND_OPT_MTU 5 +#define ND_OPT_ROUTE_INFO 9 /* draft-draves-router-preference, not officially assigned yet */ struct nd_opt_prefix_info { /* prefix information */ u_int8_t nd_opt_pi_type; @@ -268,7 +285,7 @@ struct nd_opt_prefix_info { /* prefix information */ u_int32_t nd_opt_pi_preferred_time; u_int32_t nd_opt_pi_reserved2; struct in6_addr nd_opt_pi_prefix; -}; +} __attribute__((__packed__)); #define ND_OPT_PI_FLAG_ONLINK 0x80 #define ND_OPT_PI_FLAG_AUTO 0x40 @@ -279,15 +296,23 @@ struct nd_opt_rd_hdr { /* redirected header */ u_int16_t nd_opt_rh_reserved1; u_int32_t nd_opt_rh_reserved2; /* followed by IP header and data */ -}; +} __attribute__((__packed__)); struct nd_opt_mtu { /* MTU option */ u_int8_t nd_opt_mtu_type; u_int8_t nd_opt_mtu_len; u_int16_t nd_opt_mtu_reserved; u_int32_t nd_opt_mtu_mtu; -}; - +} __attribute__((__packed__)); + +struct nd_opt_route_info { /* route info */ + u_int8_t nd_opt_rti_type; + u_int8_t nd_opt_rti_len; + u_int8_t nd_opt_rti_prefixlen; + u_int8_t nd_opt_rti_flags; + u_int32_t nd_opt_rti_lifetime; + /* followed by prefix */ +} __attribute__((__packed__)); /* * icmp6 namelookup */ @@ -301,7 +326,7 @@ struct icmp6_namelookup { u_int8_t icmp6_nl_name[3]; #endif /* could be followed by options */ -}; +} __attribute__((__packed__)); /* * icmp6 node information @@ -310,7 +335,7 @@ struct icmp6_nodeinfo { struct icmp6_hdr icmp6_ni_hdr; u_int8_t icmp6_ni_nonce[8]; /* could be followed by reply data */ -}; +} __attribute__((__packed__)); #define ni_type icmp6_ni_hdr.icmp6_type #define ni_code icmp6_ni_hdr.icmp6_code @@ -320,8 +345,10 @@ struct icmp6_nodeinfo { #define NI_QTYPE_NOOP 0 /* NOOP */ #define NI_QTYPE_SUPTYPES 1 /* Supported Qtypes */ -#define NI_QTYPE_FQDN 2 /* FQDN */ -#define NI_QTYPE_NODEADDR 3 /* Node Addresses. XXX: spec says 2, but it may be a typo... */ +#define NI_QTYPE_FQDN 2 /* FQDN (draft 04) */ +#define NI_QTYPE_DNSNAME 2 /* DNS Name */ +#define NI_QTYPE_NODEADDR 3 /* Node Addresses */ +#define NI_QTYPE_IPV4ADDR 4 /* IPv4 Addresses */ #if BYTE_ORDER == BIG_ENDIAN #define NI_SUPTYPE_FLAG_COMPRESS 0x1 @@ -371,7 +398,7 @@ struct ni_reply_fqdn { u_int32_t ni_fqdn_ttl; /* TTL */ u_int8_t ni_fqdn_namelen; /* length in octets of the FQDN */ u_int8_t ni_fqdn_name[3]; /* XXX: alignment */ -}; +} __attribute__((__packed__)); /* * Router Renumbering. as router-renum-08.txt @@ -382,13 +409,13 @@ struct icmp6_router_renum { /* router renumbering header */ u_int8_t rr_flags; u_int16_t rr_maxdelay; u_int32_t rr_reserved; -}; -#define ICMP6_RR_FLAGS_SEGNUM 0x80 -#define ICMP6_RR_FLAGS_TEST 0x40 -#define ICMP6_RR_FLAGS_REQRESULT 0x20 -#define ICMP6_RR_FLAGS_FORCEAPPLY 0x10 -#define ICMP6_RR_FLAGS_SPECSITE 0x08 -#define ICMP6_RR_FLAGS_PREVDONE 0x04 +} __attribute__((__packed__)); + +#define ICMP6_RR_FLAGS_TEST 0x80 +#define ICMP6_RR_FLAGS_REQRESULT 0x40 +#define ICMP6_RR_FLAGS_FORCEAPPLY 0x20 +#define ICMP6_RR_FLAGS_SPECSITE 0x10 +#define ICMP6_RR_FLAGS_PREVDONE 0x08 #define rr_type rr_hdr.icmp6_type #define rr_code rr_hdr.icmp6_code @@ -404,7 +431,7 @@ struct rr_pco_match { /* match prefix part */ u_int8_t rpm_maxlen; u_int16_t rpm_reserved; struct in6_addr rpm_prefix; -}; +} __attribute__((__packed__)); #define RPM_PCO_ADD 1 #define RPM_PCO_CHANGE 2 @@ -420,7 +447,7 @@ struct rr_pco_use { /* use prefix part */ u_int32_t rpu_pltime; u_int32_t rpu_flags; struct in6_addr rpu_prefix; -}; +} __attribute__((__packed__)); #define ICMP6_RR_PCOUSE_RAFLAGS_ONLINK 0x80 #define ICMP6_RR_PCOUSE_RAFLAGS_AUTO 0x40 @@ -438,13 +465,13 @@ struct rr_result { /* router renumbering result message */ u_int8_t rrr_matchedlen; u_int32_t rrr_ifid; struct in6_addr rrr_prefix; -}; +} __attribute__((__packed__)); #if BYTE_ORDER == BIG_ENDIAN #define ICMP6_RR_RESULT_FLAGS_OOB 0x0002 #define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0001 #elif BYTE_ORDER == LITTLE_ENDIAN -#define ICMP6_RR_RESULT_FLAGS_OOB 0x02 -#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x01 +#define ICMP6_RR_RESULT_FLAGS_OOB 0x0200 +#define ICMP6_RR_RESULT_FLAGS_FORBIDDEN 0x0100 #endif /* @@ -534,6 +561,13 @@ struct icmp6stat { #define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option #define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect #define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown + u_quad_t icp6s_pmtuchg; /* path MTU changes */ + u_quad_t icp6s_nd_badopt; /* bad ND options */ + u_quad_t icp6s_badns; /* bad neighbor solicitation */ + u_quad_t icp6s_badna; /* bad neighbor advertisement */ + u_quad_t icp6s_badrs; /* bad router advertisement */ + u_quad_t icp6s_badra; /* bad router advertisement */ + u_quad_t icp6s_badredirect; /* bad redirect message */ }; /* @@ -542,7 +576,9 @@ struct icmp6stat { #define ICMPV6CTL_STATS 1 #define ICMPV6CTL_REDIRACCEPT 2 /* accept/process redirects */ #define ICMPV6CTL_REDIRTIMEOUT 3 /* redirect cache time */ +#if 0 /*obsoleted*/ #define ICMPV6CTL_ERRRATELIMIT 5 /* ICMPv6 error rate limitation */ +#endif #define ICMPV6CTL_ND6_PRUNE 6 #define ICMPV6CTL_ND6_DELAY 8 #define ICMPV6CTL_ND6_UMAXTRIES 9 @@ -552,7 +588,12 @@ struct icmp6stat { #define ICMPV6CTL_NODEINFO 13 #define ICMPV6CTL_ERRPPSLIMIT 14 /* ICMPv6 error pps limitation */ #define ICMPV6CTL_ND6_MAXNUDHINT 15 -#define ICMPV6CTL_MAXID 16 +#define ICMPV6CTL_MTUDISC_HIWAT 16 +#define ICMPV6CTL_MTUDISC_LOWAT 17 +#define ICMPV6CTL_ND6_DEBUG 18 +#define ICMPV6CTL_ND6_DRLIST 19 +#define ICMPV6CTL_ND6_PRLIST 20 +#define ICMPV6CTL_MAXID 21 #define ICMPV6CTL_NAMES { \ { 0, 0 }, \ @@ -560,7 +601,7 @@ struct icmp6stat { { "rediraccept", CTLTYPE_INT }, \ { "redirtimeout", CTLTYPE_INT }, \ { 0, 0 }, \ - { "errratelimit", CTLTYPE_INT }, \ + { 0, 0 }, \ { "nd6_prune", CTLTYPE_INT }, \ { 0, 0 }, \ { "nd6_delay", CTLTYPE_INT }, \ @@ -571,6 +612,11 @@ struct icmp6stat { { "nodeinfo", CTLTYPE_INT }, \ { "errppslimit", CTLTYPE_INT }, \ { "nd6_maxnudhint", CTLTYPE_INT }, \ + { "mtudisc_hiwat", CTLTYPE_INT }, \ + { "mtudisc_lowat", CTLTYPE_INT }, \ + { "nd6_debug", CTLTYPE_INT }, \ + { 0, 0 }, \ + { 0, 0 }, \ } #define RTF_PROBEMTU RTF_PROTO1 @@ -591,6 +637,9 @@ void icmp6_prepare __P((struct mbuf *)); void icmp6_redirect_input __P((struct mbuf *, int)); void icmp6_redirect_output __P((struct mbuf *, struct rtentry *)); +struct ip6ctlparam; +void icmp6_mtudisc_update __P((struct ip6ctlparam *, int)); + /* XXX: is this the right place for these macros? */ #define icmp6_ifstat_inc(ifp, tag) \ do { \ diff --git a/sys/netinet/in.c b/sys/netinet/in.c index 95abe3f21e89..170a34352128 100644 --- a/sys/netinet/in.c +++ b/sys/netinet/in.c @@ -51,11 +51,6 @@ #include <netinet/igmp_var.h> -#include "gif.h" -#if NGIF > 0 -#include <net/if_gif.h> -#endif - static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); static int in_mask2len __P((struct in_addr *)); @@ -200,21 +195,6 @@ in_control(so, cmd, data, ifp, p) int error, hostIsNew, maskIsNew, s; u_long i; -#if NGIF > 0 - if (ifp && ifp->if_type == IFT_GIF) { - switch (cmd) { - case SIOCSIFPHYADDR: - case SIOCDIFPHYADDR: - if (p && - (error = suser(p)) != 0) - return(error); - case SIOCGIFPSRCADDR: - case SIOCGIFPDSTADDR: - return gif_ioctl(ifp, cmd, data); - } - } -#endif - switch (cmd) { case SIOCALIFADDR: case SIOCDLIFADDR: @@ -713,6 +693,9 @@ in_ifinit(ifp, ia, sin, scrub) } if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) ia->ia_flags |= IFA_ROUTE; + /* XXX check if the subnet route points to the same interface */ + if (error == EEXIST) + error = 0; /* * If the interface supports multicast, join the "all hosts" diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c index 17955ade5681..5ad92e1a5c7b 100644 --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: in_gif.c,v 1.44 2000/08/15 07:24:24 itojun Exp $ */ +/* $KAME: in_gif.c,v 1.54 2001/05/14 14:02:16 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -88,7 +88,7 @@ in_gif_output(ifp, family, m, rt) struct mbuf *m; struct rtentry *rt; { - register struct gif_softc *sc = (struct gif_softc*)ifp; + struct gif_softc *sc = (struct gif_softc*)ifp; struct sockaddr_in *dst = (struct sockaddr_in *)&sc->gif_ro.ro_dst; struct sockaddr_in *sin_src = (struct sockaddr_in *)sc->gif_psrc; struct sockaddr_in *sin_dst = (struct sockaddr_in *)sc->gif_pdst; @@ -146,29 +146,12 @@ in_gif_output(ifp, family, m, rt) bzero(&iphdr, sizeof(iphdr)); iphdr.ip_src = sin_src->sin_addr; - if (ifp->if_flags & IFF_LINK0) { - /* multi-destination mode */ - if (sin_dst->sin_addr.s_addr != INADDR_ANY) - iphdr.ip_dst = sin_dst->sin_addr; - else if (rt) { - if (family != AF_INET) { - m_freem(m); - return EINVAL; /*XXX*/ - } - iphdr.ip_dst = ((struct sockaddr_in *) - (rt->rt_gateway))->sin_addr; - } else { - m_freem(m); - return ENETUNREACH; - } - } else { - /* bidirectional configured tunnel mode */ - if (sin_dst->sin_addr.s_addr != INADDR_ANY) - iphdr.ip_dst = sin_dst->sin_addr; - else { - m_freem(m); - return ENETUNREACH; - } + /* bidirectional configured tunnel mode */ + if (sin_dst->sin_addr.s_addr != INADDR_ANY) + iphdr.ip_dst = sin_dst->sin_addr; + else { + m_freem(m); + return ENETUNREACH; } iphdr.ip_p = proto; /* version will be set in ip_output() */ @@ -176,6 +159,8 @@ in_gif_output(ifp, family, m, rt) iphdr.ip_len = m->m_pkthdr.len + sizeof(struct ip); if (ifp->if_flags & IFF_LINK1) ip_ecn_ingress(ECN_ALLOWED, &iphdr.ip_tos, &tos); + else + ip_ecn_ingress(ECN_NOCARE, &iphdr.ip_tos, &tos); /* prepend new IP header */ M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); @@ -272,6 +257,8 @@ in_gif_input(m, va_alist) ip = mtod(m, struct ip *); if (gifp->if_flags & IFF_LINK1) ip_ecn_egress(ECN_ALLOWED, &otos, &ip->ip_tos); + else + ip_ecn_egress(ECN_NOCARE, &otos, &ip->ip_tos); break; } #endif @@ -290,6 +277,8 @@ in_gif_input(m, va_alist) itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; if (gifp->if_flags & IFF_LINK1) ip_ecn_egress(ECN_ALLOWED, &otos, &itos); + else + ip_ecn_egress(ECN_NOCARE, &otos, &itos); ip6->ip6_flow &= ~htonl(0xff << 20); ip6->ip6_flow |= htonl((u_int32_t)itos << 20); break; @@ -335,10 +324,6 @@ gif_encapcheck4(m, off, proto, arg) addrmatch |= 1; if (dst->sin_addr.s_addr == ip.ip_src.s_addr) addrmatch |= 2; - else if ((sc->gif_if.if_flags & IFF_LINK0) != 0 && - dst->sin_addr.s_addr == INADDR_ANY) { - addrmatch |= 2; /* we accept any source */ - } if (addrmatch != 3) return 0; @@ -359,7 +344,8 @@ gif_encapcheck4(m, off, proto, arg) } /* ingress filters on outer source */ - if ((m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { + if ((sc->gif_if.if_flags & IFF_LINK2) == 0 && + (m->m_flags & M_PKTHDR) != 0 && m->m_pkthdr.rcvif) { struct sockaddr_in sin; struct rtentry *rt; @@ -368,15 +354,18 @@ gif_encapcheck4(m, off, proto, arg) sin.sin_len = sizeof(struct sockaddr_in); sin.sin_addr = ip.ip_src; rt = rtalloc1((struct sockaddr *)&sin, 0, 0UL); - if (!rt) - return 0; - if (rt->rt_ifp != m->m_pkthdr.rcvif) { - rtfree(rt); + if (!rt || rt->rt_ifp != m->m_pkthdr.rcvif) { +#if 0 + log(LOG_WARNING, "%s: packet from 0x%x dropped " + "due to ingress filter\n", if_name(&sc->gif_if), + (u_int32_t)ntohl(sin.sin_addr.s_addr)); +#endif + if (rt) + rtfree(rt); return 0; } rtfree(rt); } - /* prioritize: IFF_LINK0 mode is less preferred */ - return (sc->gif_if.if_flags & IFF_LINK0) ? 32 : 32 * 2; + return 32 * 2; } diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index b24b4042628c..ba5f77f13807 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -151,14 +151,16 @@ in_pcballoc(so, pcbinfo, p) inp->inp_pcbinfo = pcbinfo; inp->inp_socket = so; #if defined(INET6) - if (ip6_mapped_addr_on) - inp->inp_flags &= ~IN6P_BINDV6ONLY; - else - inp->inp_flags |= IN6P_BINDV6ONLY; + if (INP_SOCKAF(so) == AF_INET6 && !ip6_mapped_addr_on) + inp->inp_flags |= IN6P_IPV6_V6ONLY; #endif LIST_INSERT_HEAD(pcbinfo->listhead, inp, inp_list); pcbinfo->ipi_count++; so->so_pcb = (caddr_t)inp; +#ifdef INET6 + if (ip6_auto_flowlabel) + inp->inp_flags |= IN6P_AUTOFLOWLABEL; +#endif return (0); } @@ -234,9 +236,7 @@ in_pcbbind(inp, nam, p) (so->so_cred->cr_uid != t->inp_socket->so_cred->cr_uid)) { #if defined(INET6) - if ((inp->inp_flags & - IN6P_BINDV6ONLY) != 0 || - ntohl(sin->sin_addr.s_addr) != + if (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || ntohl(t->inp_laddr.s_addr) != INADDR_ANY || @@ -254,8 +254,7 @@ in_pcbbind(inp, nam, p) if (t && (reuseport & t->inp_socket->so_options) == 0) { #if defined(INET6) - if ((inp->inp_flags & IN6P_BINDV6ONLY) != 0 || - ntohl(sin->sin_addr.s_addr) != + if (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || ntohl(t->inp_laddr.s_addr) != INADDR_ANY || diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index f4abb4d0a440..1ae93d284201 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -226,25 +226,27 @@ struct inpcbinfo { /* XXX documentation, prefixes */ #define INP_RECVIF 0x80 /* receive incoming interface */ #define INP_MTUDISC 0x100 /* user can do MTU discovery */ #define INP_FAITH 0x200 /* accept FAITH'ed connections */ -#define IN6P_PKTINFO 0x010000 -#define IN6P_HOPLIMIT 0x020000 -#define IN6P_NEXTHOP 0x040000 -#define IN6P_HOPOPTS 0x080000 -#define IN6P_DSTOPTS 0x100000 -#define IN6P_RTHDR 0x200000 -#define IN6P_BINDV6ONLY 0x400000 + +#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 */ +#define IN6P_DSTOPTS 0x080000 /* receive dst options after rthdr */ +#define IN6P_RTHDR 0x100000 /* receive routing header */ +#define IN6P_RTHDRDSTOPTS 0x200000 /* receive dstoptions before rthdr */ +#define IN6P_AUTOFLOWLABEL 0x800000 /* attach flowlabel automatically */ +#define IN6P_BINDV6ONLY 0x10000000 /* do not grab IPv4 traffic */ + #define INP_CONTROLOPTS (INP_RECVOPTS|INP_RECVRETOPTS|INP_RECVDSTADDR|\ INP_RECVIF|\ - IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_NEXTHOP|\ - IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR) - -#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR) + IN6P_PKTINFO|IN6P_HOPLIMIT|IN6P_HOPOPTS|\ + IN6P_DSTOPTS|IN6P_RTHDR|IN6P_RTHDRDSTOPTS|\ + IN6P_AUTOFLOWLABEL) +#define INP_UNMAPPABLEOPTS (IN6P_HOPOPTS|IN6P_DSTOPTS|IN6P_RTHDR|\ + IN6P_AUTOFLOWLABEL) /* for KAME src sync over BSD*'s */ -#define IN6P_RECVOPTS INP_RECVOPTS -#define IN6P_RECVRETOPTS INP_RECVRETOPTS -#define IN6P_RECVDSTADDR INP_RECVDSTADDR -#define IN6P_HDRINCL INP_HDRINCL #define IN6P_HIGHPORT INP_HIGHPORT #define IN6P_LOWPORT INP_LOWPORT #define IN6P_ANONPORT INP_ANONPORT diff --git a/sys/netinet/in_proto.c b/sys/netinet/in_proto.c index 02e6313295e8..4c07a04a8f23 100644 --- a/sys/netinet/in_proto.c +++ b/sys/netinet/in_proto.c @@ -75,6 +75,7 @@ #ifdef IPSEC_ESP #include <netinet6/esp.h> #endif +#include <netinet6/ipcomp.h> #endif /* IPSEC */ #include "gif.h" @@ -125,19 +126,19 @@ struct ipprotosw inetsw[] = { 0, 0, 0, 0, &rip_usrreqs }, -{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_ICMP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, icmp_input, 0, 0, rip_ctloutput, 0, 0, 0, 0, 0, &rip_usrreqs }, -{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IGMP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, igmp_input, 0, 0, rip_ctloutput, 0, igmp_init, igmp_fasttimo, igmp_slowtimo, 0, &rip_usrreqs }, -{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_RSVP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, rsvp_input, 0, 0, rip_ctloutput, 0, 0, 0, 0, 0, @@ -158,19 +159,25 @@ struct ipprotosw inetsw[] = { &nousrreqs }, #endif +{ SOCK_RAW, &inetdomain, IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR, + ipcomp4_input, 0, 0, 0, + 0, + 0, 0, 0, 0, + &nousrreqs +}, #endif /* IPSEC */ -{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IPV4, PR_ATOMIC|PR_ADDR|PR_LASTHDR, encap4_input, 0, 0, rip_ctloutput, 0, encap_init, 0, 0, 0, - &nousrreqs + &rip_usrreqs }, # ifdef INET6 -{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IPV6, PR_ATOMIC|PR_ADDR|PR_LASTHDR, encap4_input, 0, 0, rip_ctloutput, 0, - 0, 0, 0, 0, - &nousrreqs + encap_init, 0, 0, 0, + &rip_usrreqs }, #endif #ifdef IPDIVERT @@ -182,7 +189,7 @@ struct ipprotosw inetsw[] = { }, #endif #ifdef IPXIP -{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, ipxip_input, 0, ipxip_ctlinput, 0, 0, 0, 0, 0, 0, @@ -190,7 +197,7 @@ struct ipprotosw inetsw[] = { }, #endif #ifdef NSIP -{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR, +{ SOCK_RAW, &inetdomain, IPPROTO_IDP, PR_ATOMIC|PR_ADDR|PR_LASTHDR, idpip_input, 0, nsip_ctlinput, 0, 0, 0, 0, 0, 0, diff --git a/sys/netinet/ip6.h b/sys/netinet/ip6.h index 77d1ab657612..ec2c21641dc0 100644 --- a/sys/netinet/ip6.h +++ b/sys/netinet/ip6.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip6.h,v 1.9 2000/07/02 21:01:32 itojun Exp $ */ +/* $KAME: ip6.h,v 1.18 2001/03/29 05:34:30 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -85,7 +85,7 @@ struct ip6_hdr { } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ -}; +} __attribute__((__packed__)); #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow @@ -106,18 +106,20 @@ struct ip6_hdr { #define IPV6_FLOWLABEL_MASK 0xffff0f00 /* flow label (20 bits) */ #endif /* LITTLE_ENDIAN */ #endif +#if 1 /* ECN bits proposed by Sally Floyd */ #define IP6TOS_CE 0x01 /* congestion experienced */ #define IP6TOS_ECT 0x02 /* ECN-capable transport */ +#endif /* * Extension Headers */ struct ip6_ext { - u_char ip6e_nxt; - u_char ip6e_len; -}; + u_int8_t ip6e_nxt; + u_int8_t ip6e_len; +} __attribute__((__packed__)); /* Hop-by-Hop options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ @@ -125,7 +127,7 @@ struct ip6_hbh { u_int8_t ip6h_nxt; /* next header */ u_int8_t ip6h_len; /* length in units of 8 octets */ /* followed by options */ -}; +} __attribute__((__packed__)); /* Destination options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ @@ -133,20 +135,28 @@ struct ip6_dest { u_int8_t ip6d_nxt; /* next header */ u_int8_t ip6d_len; /* length in units of 8 octets */ /* followed by options */ -}; +} __attribute__((__packed__)); /* Option types and related macros */ #define IP6OPT_PAD1 0x00 /* 00 0 00000 */ #define IP6OPT_PADN 0x01 /* 00 0 00001 */ #define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ -#define IP6OPT_JUMBO_LEN 6 -#define IP6OPT_RTALERT 0x05 /* 00 0 00101 */ +#define IP6OPT_NSAP_ADDR 0xC3 /* 11 0 00011 */ +#define IP6OPT_TUNNEL_LIMIT 0x04 /* 00 0 00100 */ +#define IP6OPT_RTALERT 0x05 /* 00 0 00101 (KAME definition) */ + #define IP6OPT_RTALERT_LEN 4 #define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ #define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ #define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ #define IP6OPT_MINLEN 2 +#define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ +#define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ +#define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ +#define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ +#define IP6OPT_EID 0x8a /* 10 0 01010 */ + #define IP6OPT_TYPE(o) ((o) & 0xC0) #define IP6OPT_TYPE_SKIP 0x00 #define IP6OPT_TYPE_DISCARD 0x40 @@ -155,6 +165,8 @@ struct ip6_dest { #define IP6OPT_MUTABLE 0x20 +#define IP6OPT_JUMBO_LEN 6 + /* Routing header */ struct ip6_rthdr { u_int8_t ip6r_nxt; /* next header */ @@ -162,7 +174,7 @@ struct ip6_rthdr { u_int8_t ip6r_type; /* routing type */ u_int8_t ip6r_segleft; /* segments left */ /* followed by routing type specific data */ -}; +} __attribute__((__packed__)); /* Type 0 Routing header */ struct ip6_rthdr0 { @@ -173,7 +185,7 @@ struct ip6_rthdr0 { u_int8_t ip6r0_reserved; /* reserved field */ u_int8_t ip6r0_slmap[3]; /* strict/loose bit map */ struct in6_addr ip6r0_addr[1]; /* up to 23 addresses */ -}; +} __attribute__((__packed__)); /* Fragment header */ struct ip6_frag { @@ -181,7 +193,7 @@ struct ip6_frag { u_int8_t ip6f_reserved; /* reserved field */ u_int16_t ip6f_offlg; /* offset, reserved, and flag */ u_int32_t ip6f_ident; /* identification */ -}; +} __attribute__((__packed__)); #if BYTE_ORDER == BIG_ENDIAN #define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */ diff --git a/sys/netinet/ip_ecn.c b/sys/netinet/ip_ecn.c index 047f82e1fb52..3abc3b683212 100644 --- a/sys/netinet/ip_ecn.c +++ b/sys/netinet/ip_ecn.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip_ecn.c,v 1.7 2000/05/05 11:00:56 sumikawa Exp $ */ +/* $KAME: ip_ecn.c,v 1.11 2001/05/03 16:09:29 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -43,16 +43,10 @@ #include <sys/mbuf.h> #include <sys/errno.h> -#ifdef INET #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> -#endif - #ifdef INET6 -#ifndef INET -#include <netinet/in.h> -#endif #include <netinet/ip6.h> #endif @@ -63,17 +57,17 @@ /* * modify outer ECN (TOS) field on ingress operation (tunnel encapsulation). - * call it after you've done the default initialization/copy for the outer. */ void ip_ecn_ingress(mode, outer, inner) int mode; u_int8_t *outer; - u_int8_t *inner; + const u_int8_t *inner; { if (!outer || !inner) panic("NULL pointer passed to ip_ecn_ingress"); + *outer = *inner; switch (mode) { case ECN_ALLOWED: /* ECN allowed */ *outer &= ~IPTOS_CE; @@ -88,12 +82,11 @@ ip_ecn_ingress(mode, outer, inner) /* * modify inner ECN (TOS) field on egress operation (tunnel decapsulation). - * call it after you've done the default initialization/copy for the inner. */ void ip_ecn_egress(mode, outer, inner) int mode; - u_int8_t *outer; + const u_int8_t *outer; u_int8_t *inner; { if (!outer || !inner) @@ -115,14 +108,13 @@ void ip6_ecn_ingress(mode, outer, inner) int mode; u_int32_t *outer; - u_int32_t *inner; + const u_int32_t *inner; { u_int8_t outer8, inner8; if (!outer || !inner) panic("NULL pointer passed to ip6_ecn_ingress"); - outer8 = (ntohl(*outer) >> 20) & 0xff; inner8 = (ntohl(*inner) >> 20) & 0xff; ip_ecn_ingress(mode, &outer8, &inner8); *outer &= ~htonl(0xff << 20); @@ -132,7 +124,7 @@ ip6_ecn_ingress(mode, outer, inner) void ip6_ecn_egress(mode, outer, inner) int mode; - u_int32_t *outer; + const u_int32_t *outer; u_int32_t *inner; { u_int8_t outer8, inner8; @@ -141,7 +133,6 @@ ip6_ecn_egress(mode, outer, inner) panic("NULL pointer passed to ip6_ecn_egress"); outer8 = (ntohl(*outer) >> 20) & 0xff; - inner8 = (ntohl(*inner) >> 20) & 0xff; ip_ecn_egress(mode, &outer8, &inner8); *inner &= ~htonl(0xff << 20); *inner |= htonl((u_int32_t)inner8 << 20); diff --git a/sys/netinet/ip_ecn.h b/sys/netinet/ip_ecn.h index 6445d0f8fce7..9aca7319df4d 100644 --- a/sys/netinet/ip_ecn.h +++ b/sys/netinet/ip_ecn.h @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip_ecn.h,v 1.5 2000/03/27 04:58:38 sumikawa Exp $ */ +/* $KAME: ip_ecn.h,v 1.6 2001/05/03 14:51:48 itojun Exp $ */ /* * Copyright (C) 1999 WIDE Project. @@ -35,11 +35,15 @@ * http://www.aciri.org/floyd/papers/draft-ipsec-ecn-00.txt */ +#if defined(_KERNEL) && !defined(_LKM) +#include "opt_inet.h" +#endif + #define ECN_ALLOWED 1 /* ECN allowed */ #define ECN_FORBIDDEN 0 /* ECN forbidden */ #define ECN_NOCARE (-1) /* no consideration to ECN */ #ifdef _KERNEL -extern void ip_ecn_ingress __P((int, u_int8_t *, u_int8_t *)); -extern void ip_ecn_egress __P((int, u_int8_t *, u_int8_t *)); +extern void ip_ecn_ingress __P((int, u_int8_t *, const u_int8_t *)); +extern void ip_ecn_egress __P((int, const u_int8_t *, u_int8_t *)); #endif diff --git a/sys/netinet/ip_encap.c b/sys/netinet/ip_encap.c index 7d623eab6a2d..746330056f3b 100644 --- a/sys/netinet/ip_encap.c +++ b/sys/netinet/ip_encap.c @@ -1,5 +1,5 @@ /* $FreeBSD$ */ -/* $KAME: ip_encap.c,v 1.36 2000/06/17 20:34:24 itojun Exp $ */ +/* $KAME: ip_encap.c,v 1.41 2001/03/15 08:35:08 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -67,6 +67,7 @@ #include <sys/mbuf.h> #include <sys/errno.h> #include <sys/protosw.h> +#include <sys/queue.h> #include <net/if.h> #include <net/route.h> @@ -100,12 +101,21 @@ static int mask_match __P((const struct encaptab *, const struct sockaddr *, const struct sockaddr *)); static void encap_fillarg __P((struct mbuf *, const struct encaptab *)); +#ifndef LIST_HEAD_INITIALIZER /* rely upon BSS initialization */ LIST_HEAD(, encaptab) encaptab; +#else +LIST_HEAD(, encaptab) encaptab = LIST_HEAD_INITIALIZER(&encaptab); +#endif void encap_init() { + static int initialized = 0; + + if (initialized) + return; + initialized++; #if 0 /* * we cannot use LIST_INIT() here, since drivers may want to call @@ -118,6 +128,7 @@ encap_init() #endif } +#ifdef INET void #if __STDC__ encap4_input(struct mbuf *m, ...) @@ -221,6 +232,7 @@ encap4_input(m, va_alist) /* last resort: inject to raw socket */ rip_input(m, off, proto); } +#endif #ifdef INET6 int diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c index ddb95f01edc0..7e8c722cd821 100644 --- a/sys/netinet/ip_icmp.c +++ b/sys/netinet/ip_icmp.c @@ -296,15 +296,6 @@ icmp_input(m, off, proto) icp->icmp_code); #endif -#ifdef IPSEC - /* drop it if it does not match the policy */ - /* XXX Is there meaning of check in here ? */ - if (ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; - goto freeit; - } -#endif - /* * Message type specific processing. */ diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 7cd856889801..3cf13cf0e6e9 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -350,6 +350,16 @@ ip_input(struct mbuf *m) } ip = mtod(m, struct ip *); } + + /* 127/8 must not appear on wire - RFC1122 */ + if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || + (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { + if ((m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { + ipstat.ips_badaddr++; + goto bad; + } + } + if (m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) { sum = !(m->m_pkthdr.csum_flags & CSUM_IP_VALID); } else { @@ -393,15 +403,10 @@ tooshort: m_adj(m, ip->ip_len - m->m_pkthdr.len); } - /* - * Don't accept packets with a loopback destination address - * unless they arrived via the loopback interface. - */ - if ((ntohl(ip->ip_dst.s_addr) & IN_CLASSA_NET) == - (IN_LOOPBACKNET << IN_CLASSA_NSHIFT) && - (m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) { - goto bad; - } +#ifdef IPSEC + if (ipsec_gethist(m, NULL)) + goto pass; +#endif /* * IpHack's section. @@ -796,6 +801,19 @@ found: } #endif +#ifdef IPSEC + /* + * enforce IPsec policy checking if we are seeing last header. + * note that we do not visit this with protocols with pcb layer + * code - like udp/tcp/raw ip. + */ + if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && + ipsec4_in_reject(m, NULL)) { + ipsecstat.in_polvio++; + goto bad; + } +#endif + /* * Switch out to protocol's input routine. */ @@ -1189,6 +1207,10 @@ ip_dooptions(m) */ case IPOPT_LSRR: case IPOPT_SSRR: + if (optlen < IPOPT_OFFSET + sizeof(*cp)) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; @@ -1308,12 +1330,21 @@ nosourcerouting: case IPOPT_TS: code = cp - (u_char *)ip; ipt = (struct ip_timestamp *)cp; - if (ipt->ipt_len < 5) + if (ipt->ipt_len < 4 || ipt->ipt_len > 40) { + code = (u_char *)&ipt->ipt_len - (u_char *)ip; goto bad; + } + if (ipt->ipt_ptr < 5) { + code = (u_char *)&ipt->ipt_ptr - (u_char *)ip; + goto bad; + } if (ipt->ipt_ptr > ipt->ipt_len - (int)sizeof(int32_t)) { - if (++ipt->ipt_oflw == 0) + if (++ipt->ipt_oflw == 0) { + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip; goto bad; + } break; } sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); @@ -1324,8 +1355,11 @@ nosourcerouting: case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr - 1 + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) + sizeof(struct in_addr) > ipt->ipt_len) { + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip; goto bad; + } ipaddr.sin_addr = dst; ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, m->m_pkthdr.rcvif); @@ -1338,8 +1372,11 @@ nosourcerouting: case IPOPT_TS_PRESPEC: if (ipt->ipt_ptr - 1 + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) + sizeof(struct in_addr) > ipt->ipt_len) { + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip; goto bad; + } (void)memcpy(&ipaddr.sin_addr, sin, sizeof(struct in_addr)); if (ifa_ifwithaddr((SA)&ipaddr) == 0) @@ -1348,6 +1385,9 @@ nosourcerouting: break; default: + /* XXX can't take &ipt->ipt_flg */ + code = (u_char *)&ipt->ipt_ptr - + (u_char *)ip + 1; goto bad; } ntime = iptime(); diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 1025e3764e20..10de694fde10 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -95,6 +95,7 @@ static MALLOC_DEFINE(M_IPMOPTS, "ip_moptions", "internet multicast options"); u_short ip_id; static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *)); +static struct ifnet *ip_multicast_if __P((struct in_addr *, int *)); static void ip_mloopback __P((struct ifnet *, struct mbuf *, struct sockaddr_in *, int)); static int ip_getmoptions @@ -177,7 +178,7 @@ ip_output(m0, opt, ro, flags, imo) m0 = m = m->m_next ; #ifdef IPSEC so = ipsec_getsocket(m); - ipsec_setsocket(m, NULL); + (void)ipsec_setsocket(m, NULL); #endif ip = mtod(m, struct ip *); hlen = IP_VHL_HL(ip->ip_vhl) << 2 ; @@ -188,7 +189,7 @@ ip_output(m0, opt, ro, flags, imo) #endif #ifdef IPSEC so = ipsec_getsocket(m); - ipsec_setsocket(m, NULL); + (void)ipsec_setsocket(m, NULL); #endif #ifdef DIAGNOSTIC @@ -430,6 +431,133 @@ ip_output(m0, opt, ro, flags, imo) } sendit: +#ifdef IPSEC + /* get SP for this packet */ + if (so == NULL) + sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); + else + sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); + + if (sp == NULL) { + ipsecstat.out_inval++; + goto bad; + } + + error = 0; + + /* check policy */ + switch (sp->policy) { + case IPSEC_POLICY_DISCARD: + /* + * This packet is just discarded. + */ + ipsecstat.out_polvio++; + goto bad; + + case IPSEC_POLICY_BYPASS: + case IPSEC_POLICY_NONE: + /* no need to do IPsec. */ + goto skip_ipsec; + + case IPSEC_POLICY_IPSEC: + if (sp->req == NULL) { + /* acquire a policy */ + error = key_spdacquire(sp); + goto bad; + } + break; + + case IPSEC_POLICY_ENTRUST: + default: + printf("ip_output: Invalid policy found. %d\n", sp->policy); + } + { + struct ipsec_output_state state; + bzero(&state, sizeof(state)); + state.m = m; + if (flags & IP_ROUTETOIF) { + state.ro = &iproute; + bzero(&iproute, sizeof(iproute)); + } else + state.ro = ro; + state.dst = (struct sockaddr *)dst; + + ip->ip_sum = 0; + + /* + * XXX + * delayed checksums are not currently compatible with IPsec + */ + if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { + in_delayed_cksum(m); + m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; + } + + HTONS(ip->ip_len); + HTONS(ip->ip_off); + + error = ipsec4_output(&state, sp, flags); + + m = state.m; + if (flags & IP_ROUTETOIF) { + /* + * if we have tunnel mode SA, we may need to ignore + * IP_ROUTETOIF. + */ + if (state.ro != &iproute || state.ro->ro_rt != NULL) { + flags &= ~IP_ROUTETOIF; + ro = state.ro; + } + } else + ro = state.ro; + dst = (struct sockaddr_in *)state.dst; + if (error) { + /* mbuf is already reclaimed in ipsec4_output. */ + m0 = NULL; + switch (error) { + case EHOSTUNREACH: + case ENETUNREACH: + case EMSGSIZE: + case ENOBUFS: + case ENOMEM: + break; + default: + printf("ip4_output (ipsec): error code %d\n", error); + /*fall through*/ + case ENOENT: + /* don't show these error codes to the user */ + error = 0; + break; + } + goto bad; + } + } + + /* be sure to update variables that are affected by ipsec4_output() */ + ip = mtod(m, struct ip *); +#ifdef _IP_VHL + hlen = IP_VHL_HL(ip->ip_vhl) << 2; +#else + hlen = ip->ip_hl << 2; +#endif + if (ro->ro_rt == NULL) { + if ((flags & IP_ROUTETOIF) == 0) { + printf("ip_output: " + "can't update route after IPsec processing\n"); + error = EHOSTUNREACH; /*XXX*/ + goto bad; + } + } else { + ia = ifatoia(ro->ro_rt->rt_ifa); + ifp = ro->ro_rt->rt_ifp; + } + + /* make it flipped, again. */ + NTOHS(ip->ip_len); + NTOHS(ip->ip_off); +skip_ipsec: +#endif /*IPSEC*/ + /* * IpHack's section. * - Xlate: translate packet's addr/port (NAT). @@ -661,134 +789,6 @@ sendit: } pass: -#ifdef IPSEC - /* get SP for this packet */ - if (so == NULL) - sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); - else - sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); - - if (sp == NULL) { - ipsecstat.out_inval++; - goto bad; - } - - error = 0; - - /* check policy */ - switch (sp->policy) { - case IPSEC_POLICY_DISCARD: - /* - * This packet is just discarded. - */ - ipsecstat.out_polvio++; - goto bad; - - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_NONE: - /* no need to do IPsec. */ - goto skip_ipsec; - - case IPSEC_POLICY_IPSEC: - if (sp->req == NULL) { - /* XXX should be panic ? */ - printf("ip_output: No IPsec request specified.\n"); - error = EINVAL; - goto bad; - } - break; - - case IPSEC_POLICY_ENTRUST: - default: - printf("ip_output: Invalid policy found. %d\n", sp->policy); - } - { - struct ipsec_output_state state; - bzero(&state, sizeof(state)); - state.m = m; - if (flags & IP_ROUTETOIF) { - state.ro = &iproute; - bzero(&iproute, sizeof(iproute)); - } else - state.ro = ro; - state.dst = (struct sockaddr *)dst; - - ip->ip_sum = 0; - - /* - * XXX - * delayed checksums are not currently compatible with IPsec - */ - if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { - in_delayed_cksum(m); - m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; - } - - HTONS(ip->ip_len); - HTONS(ip->ip_off); - - error = ipsec4_output(&state, sp, flags); - - m = state.m; - if (flags & IP_ROUTETOIF) { - /* - * if we have tunnel mode SA, we may need to ignore - * IP_ROUTETOIF. - */ - if (state.ro != &iproute || state.ro->ro_rt != NULL) { - flags &= ~IP_ROUTETOIF; - ro = state.ro; - } - } else - ro = state.ro; - dst = (struct sockaddr_in *)state.dst; - if (error) { - /* mbuf is already reclaimed in ipsec4_output. */ - m0 = NULL; - switch (error) { - case EHOSTUNREACH: - case ENETUNREACH: - case EMSGSIZE: - case ENOBUFS: - case ENOMEM: - break; - default: - printf("ip4_output (ipsec): error code %d\n", error); - /*fall through*/ - case ENOENT: - /* don't show these error codes to the user */ - error = 0; - break; - } - goto bad; - } - } - - /* be sure to update variables that are affected by ipsec4_output() */ - ip = mtod(m, struct ip *); -#ifdef _IP_VHL - hlen = IP_VHL_HL(ip->ip_vhl) << 2; -#else - hlen = ip->ip_hl << 2; -#endif - if (ro->ro_rt == NULL) { - if ((flags & IP_ROUTETOIF) == 0) { - printf("ip_output: " - "can't update route after IPsec processing\n"); - error = EHOSTUNREACH; /*XXX*/ - goto bad; - } - } else { - ia = ifatoia(ro->ro_rt->rt_ifa); - ifp = ro->ro_rt->rt_ifp; - } - - /* make it flipped, again. */ - NTOHS(ip->ip_len); - NTOHS(ip->ip_off); -skip_ipsec: -#endif /*IPSEC*/ - m->m_pkthdr.csum_flags |= CSUM_IP; sw_csum = m->m_pkthdr.csum_flags & ~ifp->if_hwassist; if (sw_csum & CSUM_DELAY_DATA) { @@ -820,6 +820,11 @@ skip_ipsec: ia->ia_ifa.if_obytes += m->m_pkthdr.len; } +#ifdef IPSEC + /* clean ipsec history once it goes out of the node */ + ipsec_delaux(m); +#endif + error = (*ifp->if_output)(ifp, m, (struct sockaddr *)dst, ro->ro_rt); goto done; @@ -946,6 +951,10 @@ sendorfree: for (m = m0; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = 0; +#ifdef IPSEC + /* clean ipsec history once it goes out of the node */ + ipsec_delaux(m); +#endif if (error == 0) { /* Record statistics for this interface address. */ ia->ia_ifa.if_opackets++; @@ -1480,6 +1489,33 @@ bad: * transmission, and one (IP_MULTICAST_TTL) totally duplicates a * standard option (IP_TTL). */ + +/* + * following RFC1724 section 3.3, 0.0.0.0/8 is interpreted as interface index. + */ +static struct ifnet * +ip_multicast_if(a, ifindexp) + struct in_addr *a; + int *ifindexp; +{ + int ifindex; + struct ifnet *ifp; + + if (ifindexp) + *ifindexp = 0; + if (ntohl(a->s_addr) >> 24 == 0) { + ifindex = ntohl(a->s_addr) & 0xffffff; + if (ifindex < 0 || if_index < ifindex) + return NULL; + ifp = ifindex2ifnet[ifindex]; + if (ifindexp) + *ifindexp = ifindex; + } else { + INADDR_TO_IFP(*a, ifp); + } + return ifp; +} + /* * Set the IP multicast options in response to user setsockopt(). */ @@ -1496,6 +1532,7 @@ ip_setmoptions(sopt, imop) struct ip_moptions *imo = *imop; struct route ro; struct sockaddr_in *dst; + int ifindex; int s; if (imo == NULL) { @@ -1510,6 +1547,7 @@ ip_setmoptions(sopt, imop) return (ENOBUFS); *imop = imo; imo->imo_multicast_ifp = NULL; + imo->imo_multicast_addr.s_addr = INADDR_ANY; imo->imo_multicast_vif = -1; imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; imo->imo_multicast_loop = IP_DEFAULT_MULTICAST_LOOP; @@ -1555,13 +1593,17 @@ ip_setmoptions(sopt, imop) * it supports multicasting. */ s = splimp(); - INADDR_TO_IFP(addr, ifp); + ifp = ip_multicast_if(&addr, &ifindex); if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) { splx(s); error = EADDRNOTAVAIL; break; } imo->imo_multicast_ifp = ifp; + if (ifindex) + imo->imo_multicast_addr = addr; + else + imo->imo_multicast_addr.s_addr = INADDR_ANY; splx(s); break; @@ -1648,7 +1690,7 @@ ip_setmoptions(sopt, imop) rtfree(ro.ro_rt); } else { - INADDR_TO_IFP(mreq.imr_interface, ifp); + ifp = ip_multicast_if(&mreq.imr_interface, NULL); } /* @@ -1716,7 +1758,7 @@ ip_setmoptions(sopt, imop) if (mreq.imr_interface.s_addr == INADDR_ANY) ifp = NULL; else { - INADDR_TO_IFP(mreq.imr_interface, ifp); + ifp = ip_multicast_if(&mreq.imr_interface, NULL); if (ifp == NULL) { error = EADDRNOTAVAIL; splx(s); @@ -1798,7 +1840,10 @@ ip_getmoptions(sopt, imo) case IP_MULTICAST_IF: if (imo == NULL || imo->imo_multicast_ifp == NULL) addr.s_addr = INADDR_ANY; - else { + else if (imo->imo_multicast_addr.s_addr) { + /* return the value user has set */ + addr = imo->imo_multicast_addr; + } else { IFP_TO_IA(imo->imo_multicast_ifp, ia); addr.s_addr = (ia == NULL) ? INADDR_ANY : IA_SIN(ia)->sin_addr.s_addr; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 6354d84da527..b318a1c001d4 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -37,6 +37,8 @@ #ifndef _NETINET_IP_VAR_H_ #define _NETINET_IP_VAR_H_ +#include <sys/queue.h> + /* * Overlay for ip header used by other protocols (tcp, udp). */ @@ -86,6 +88,7 @@ struct ipoption { */ struct ip_moptions { struct ifnet *imo_multicast_ifp; /* ifp for outgoing multicasts */ + struct in_addr imo_multicast_addr; /* ifindex/addr on MULTICAST_IF */ u_char imo_multicast_ttl; /* TTL for outgoing multicasts */ u_char imo_multicast_loop; /* 1 => hear sends if a member */ u_short imo_num_memberships; /* no. memberships this socket */ @@ -122,6 +125,7 @@ struct ipstat { u_long ips_toolong; /* ip length > max ip packet size */ u_long ips_notmember; /* multicasts for unregistered grps */ u_long ips_nogif; /* no match gif found */ + u_long ips_badaddr; /* invalid address on header */ }; #ifdef _KERNEL diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index 4fdcf9523ade..32c909a1fb2b 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -137,6 +137,15 @@ rip_input(m, off, proto) continue; if (last) { struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); + +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (n && ipsec4_in_reject_so(n, last->inp_socket)) { + m_freem(n); + ipsecstat.in_polvio++; + /* do not inject data to pcb */ + } else +#endif /*IPSEC*/ if (n) { if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) @@ -155,6 +164,15 @@ rip_input(m, off, proto) } last = inp; } +#ifdef IPSEC + /* check AH/ESP integrity. */ + if (last && ipsec4_in_reject_so(m, last->inp_socket)) { + m_freem(m); + ipsecstat.in_polvio++; + ipstat.ips_delivered--; + /* do not inject data to pcb */ + } else +#endif /*IPSEC*/ if (last) { if (last->inp_flags & INP_CONTROLOPTS || last->inp_socket->so_options & SO_TIMESTAMP) @@ -168,9 +186,9 @@ rip_input(m, off, proto) sorwakeup(last->inp_socket); } else { m_freem(m); - ipstat.ips_noproto++; - ipstat.ips_delivered--; - } + ipstat.ips_noproto++; + ipstat.ips_delivered--; + } } /* @@ -232,7 +250,10 @@ rip_output(m, so, dst) } #ifdef IPSEC - ipsec_setsocket(m, so); + if (ipsec_setsocket(m, so) != 0) { + m_freem(m); + return ENOBUFS; + } #endif /*IPSEC*/ return (ip_output(m, inp->inp_options, &inp->inp_route, flags, diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index 34c2006d3d22..3554dae2e9ac 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -305,6 +305,7 @@ tcp6_input(mp, offp, proto) int *offp, proto; { register struct mbuf *m = *mp; + struct in6_ifaddr *ia6; IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE); @@ -312,7 +313,8 @@ tcp6_input(mp, offp, proto) * draft-itojun-ipv6-tcp-to-anycast * better place to put this in? */ - if (m->m_flags & M_ANYCAST6) { + ia6 = ip6_getdstifaddr(m); + if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) { struct ip6_hdr *ip6; ip6 = mtod(m, struct ip6_hdr *); @@ -379,6 +381,19 @@ tcp_input(m, off0, proto) goto drop; } th = (struct tcphdr *)((caddr_t)ip6 + off0); + + /* + * Be proactive about unspecified IPv6 address in source. + * As we use all-zero to indicate unbounded/unconnected pcb, + * unspecified IPv6 address can be used to confuse us. + * + * Note that packets with unspecified IPv6 destination is + * already dropped in ip6_input. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { + /* XXX stat */ + goto drop; + } } else #endif /* INET6 */ { @@ -627,18 +642,6 @@ findpcb: else tiwin = th->th_win; -#ifdef INET6 - /* save packet options if user wanted */ - if (isipv6 && inp->in6p_flags & INP_CONTROLOPTS) { - if (inp->in6p_options) { - m_freem(inp->in6p_options); - inp->in6p_options = 0; - } - ip6_savecontrol(inp, &inp->in6p_options, ip6, m); - } - /* else, should also do ip_srcroute() here? */ -#endif /* INET6 */ - so = inp->inp_socket; if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { #ifdef TCPDEBUG @@ -683,6 +686,50 @@ findpcb: goto drop; } #endif + +#ifdef INET6 + /* + * If deprecated address is forbidden, + * we do not accept SYN to deprecated interface + * address to prevent any new inbound connection from + * getting established. + * When we do not accept SYN, we send a TCP RST, + * with deprecated source address (instead of dropping + * it). We compromise it as it is much better for peer + * to send a RST, and RST will be the final packet + * for the exchange. + * + * If we do not forbid deprecated addresses, we accept + * the SYN packet. RFC2462 does not suggest dropping + * SYN in this case. + * If we decipher RFC2462 5.5.4, it says like this: + * 1. use of deprecated addr with existing + * communication is okay - "SHOULD continue to be + * used" + * 2. use of it with new communication: + * (2a) "SHOULD NOT be used if alternate address + * with sufficient scope is available" + * (2b) nothing mentioned otherwise. + * Here we fall into (2b) case as we have no choice in + * our source address selection - we must obey the peer. + * + * The wording in RFC2462 is confusing, and there are + * multiple description text for deprecated address + * handling - worse, they are not exactly the same. + * I believe 5.5.4 is the best one, so we follow 5.5.4. + */ + if (isipv6 && !ip6_use_deprecated) { + struct in6_ifaddr *ia6; + + if ((ia6 = ip6_getdstifaddr(m)) && + (ia6->ia6_flags & IN6_IFF_DEPRECATED)) { + tp = NULL; + rstreason = BANDLIM_RST_OPENPORT; + goto dropwithreset; + } + } +#endif + so2 = sonewconn(so, 0); if (so2 == 0) { /* @@ -731,10 +778,8 @@ findpcb: if (isipv6) inp->in6p_laddr = ip6->ip6_dst; else { - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) { - inp->inp_vflag &= ~INP_IPV6; - inp->inp_vflag |= INP_IPV4; - } + inp->inp_vflag &= ~INP_IPV6; + inp->inp_vflag |= INP_IPV4; #endif /* INET6 */ inp->inp_laddr = ip->ip_dst; #ifdef INET6 @@ -779,21 +824,25 @@ findpcb: #endif #ifdef INET6 if (isipv6) { - /* - * inherit socket options from the listening - * socket. - */ + /* + * Inherit socket options from the listening + * socket. + * Note that in6p_inputopts are not (even + * should not be) copied, since it stores + * previously received options and is used to + * detect if each new option is different than + * the previous one and hence should be passed + * to a user. + * If we copied in6p_inputopts, a user would + * not be able to receive options just after + * calling the accept system call. + */ inp->inp_flags |= oinp->inp_flags & INP_CONTROLOPTS; - if (inp->inp_flags & INP_CONTROLOPTS) { - if (inp->in6p_options) { - m_freem(inp->in6p_options); - inp->in6p_options = 0; - } - ip6_savecontrol(inp, - &inp->in6p_options, - ip6, m); - } + if (oinp->in6p_outputopts) + inp->in6p_outputopts = + ip6_copypktopts(oinp->in6p_outputopts, + M_NOWAIT); } else #endif /* INET6 */ inp->inp_options = ip_srcroute(); diff --git a/sys/netinet/tcp_output.c b/sys/netinet/tcp_output.c index 286b420ac4ff..a2a2cf370cb6 100644 --- a/sys/netinet/tcp_output.c +++ b/sys/netinet/tcp_output.c @@ -376,7 +376,7 @@ send: * NOTE: we assume that the IP/TCP header plus TCP options * always fit in a single mbuf, leaving room for a maximum * link header, i.e. - * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN + * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MCLBYTES */ optlen = 0; #ifdef INET6 @@ -823,7 +823,11 @@ send: /* TODO: IPv6 IP6TOS_ECT bit on */ #ifdef IPSEC - ipsec_setsocket(m, so); + if (ipsec_setsocket(m, so) != 0) { + m_freem(m); + error = ENOBUFS; + goto out; + } #endif /*IPSEC*/ error = ip6_output(m, tp->t_inpcb->in6p_outputopts, diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index 34c2006d3d22..3554dae2e9ac 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -305,6 +305,7 @@ tcp6_input(mp, offp, proto) int *offp, proto; { register struct mbuf *m = *mp; + struct in6_ifaddr *ia6; IP6_EXTHDR_CHECK(m, *offp, sizeof(struct tcphdr), IPPROTO_DONE); @@ -312,7 +313,8 @@ tcp6_input(mp, offp, proto) * draft-itojun-ipv6-tcp-to-anycast * better place to put this in? */ - if (m->m_flags & M_ANYCAST6) { + ia6 = ip6_getdstifaddr(m); + if (ia6 && (ia6->ia6_flags & IN6_IFF_ANYCAST)) { struct ip6_hdr *ip6; ip6 = mtod(m, struct ip6_hdr *); @@ -379,6 +381,19 @@ tcp_input(m, off0, proto) goto drop; } th = (struct tcphdr *)((caddr_t)ip6 + off0); + + /* + * Be proactive about unspecified IPv6 address in source. + * As we use all-zero to indicate unbounded/unconnected pcb, + * unspecified IPv6 address can be used to confuse us. + * + * Note that packets with unspecified IPv6 destination is + * already dropped in ip6_input. + */ + if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { + /* XXX stat */ + goto drop; + } } else #endif /* INET6 */ { @@ -627,18 +642,6 @@ findpcb: else tiwin = th->th_win; -#ifdef INET6 - /* save packet options if user wanted */ - if (isipv6 && inp->in6p_flags & INP_CONTROLOPTS) { - if (inp->in6p_options) { - m_freem(inp->in6p_options); - inp->in6p_options = 0; - } - ip6_savecontrol(inp, &inp->in6p_options, ip6, m); - } - /* else, should also do ip_srcroute() here? */ -#endif /* INET6 */ - so = inp->inp_socket; if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) { #ifdef TCPDEBUG @@ -683,6 +686,50 @@ findpcb: goto drop; } #endif + +#ifdef INET6 + /* + * If deprecated address is forbidden, + * we do not accept SYN to deprecated interface + * address to prevent any new inbound connection from + * getting established. + * When we do not accept SYN, we send a TCP RST, + * with deprecated source address (instead of dropping + * it). We compromise it as it is much better for peer + * to send a RST, and RST will be the final packet + * for the exchange. + * + * If we do not forbid deprecated addresses, we accept + * the SYN packet. RFC2462 does not suggest dropping + * SYN in this case. + * If we decipher RFC2462 5.5.4, it says like this: + * 1. use of deprecated addr with existing + * communication is okay - "SHOULD continue to be + * used" + * 2. use of it with new communication: + * (2a) "SHOULD NOT be used if alternate address + * with sufficient scope is available" + * (2b) nothing mentioned otherwise. + * Here we fall into (2b) case as we have no choice in + * our source address selection - we must obey the peer. + * + * The wording in RFC2462 is confusing, and there are + * multiple description text for deprecated address + * handling - worse, they are not exactly the same. + * I believe 5.5.4 is the best one, so we follow 5.5.4. + */ + if (isipv6 && !ip6_use_deprecated) { + struct in6_ifaddr *ia6; + + if ((ia6 = ip6_getdstifaddr(m)) && + (ia6->ia6_flags & IN6_IFF_DEPRECATED)) { + tp = NULL; + rstreason = BANDLIM_RST_OPENPORT; + goto dropwithreset; + } + } +#endif + so2 = sonewconn(so, 0); if (so2 == 0) { /* @@ -731,10 +778,8 @@ findpcb: if (isipv6) inp->in6p_laddr = ip6->ip6_dst; else { - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) { - inp->inp_vflag &= ~INP_IPV6; - inp->inp_vflag |= INP_IPV4; - } + inp->inp_vflag &= ~INP_IPV6; + inp->inp_vflag |= INP_IPV4; #endif /* INET6 */ inp->inp_laddr = ip->ip_dst; #ifdef INET6 @@ -779,21 +824,25 @@ findpcb: #endif #ifdef INET6 if (isipv6) { - /* - * inherit socket options from the listening - * socket. - */ + /* + * Inherit socket options from the listening + * socket. + * Note that in6p_inputopts are not (even + * should not be) copied, since it stores + * previously received options and is used to + * detect if each new option is different than + * the previous one and hence should be passed + * to a user. + * If we copied in6p_inputopts, a user would + * not be able to receive options just after + * calling the accept system call. + */ inp->inp_flags |= oinp->inp_flags & INP_CONTROLOPTS; - if (inp->inp_flags & INP_CONTROLOPTS) { - if (inp->in6p_options) { - m_freem(inp->in6p_options); - inp->in6p_options = 0; - } - ip6_savecontrol(inp, - &inp->in6p_options, - ip6, m); - } + if (oinp->in6p_outputopts) + inp->in6p_outputopts = + ip6_copypktopts(oinp->in6p_outputopts, + M_NOWAIT); } else #endif /* INET6 */ inp->inp_options = ip_srcroute(); diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c index 3857b7513029..06849be35acd 100644 --- a/sys/netinet/tcp_subr.c +++ b/sys/netinet/tcp_subr.c @@ -443,7 +443,10 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); #endif #ifdef IPSEC - ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL); + if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) { + m_freem(m); + return; + } #endif #ifdef INET6 if (isipv6) { @@ -1020,13 +1023,17 @@ tcp6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - register struct tcphdr *thp; struct tcphdr th; void (*notify) __P((struct inpcb *, int)) = tcp_notify; - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; int off; + struct tcp_portonly { + u_int16_t th_sport; + u_int16_t th_dport; + } *thp; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) @@ -1042,56 +1049,36 @@ tcp6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; off = 0; /* fool gcc */ + sa6_src = &sa6_any; } - /* - * Translate addresses into internal form. - * Sa check if it is AF_INET6 is done at the top of this funciton. - */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) != 0 && m != NULL && - m->m_pkthdr.rcvif != NULL) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - if (ip6) { /* * XXX: We assume that when IPV6 is non NULL, * M and OFF are valid. */ - struct in6_addr s; - - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s) != 0 && m != NULL && - m->m_pkthdr.rcvif != NULL) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); /* check if we can safely examine src and dst ports */ - if (m->m_pkthdr.len < off + sizeof(th)) + if (m->m_pkthdr.len < off + sizeof(*thp)) return; - if (m->m_len < off + sizeof(th)) { - /* - * this should be rare case - * because now MINCLSIZE is "(MHLEN + 1)", - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(th), (caddr_t)&th); - thp = &th; - } else - thp = (struct tcphdr *)(mtod(m, caddr_t) + off); - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, thp->th_dport, - &s, thp->th_sport, cmd, notify); + bzero(&th, sizeof(th)); + m_copydata(m, off, sizeof(*thp), (caddr_t)&th); + + in6_pcbnotify(&tcb, sa, th.th_dport, + (struct sockaddr *)ip6cp->ip6c_src, + th.th_sport, cmd, notify); } else - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, 0, &zeroin6_addr, + in6_pcbnotify(&tcb, sa, 0, (struct sockaddr *)sa6_src, 0, cmd, notify); } #endif /* INET6 */ @@ -1323,9 +1310,12 @@ tcp_rtlookup6(inp) if (rt == NULL || !(rt->rt_flags & RTF_UP)) { /* No route yet, so try to acquire one */ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { - ro6->ro_dst.sin6_family = AF_INET6; - ro6->ro_dst.sin6_len = sizeof(ro6->ro_dst); - ro6->ro_dst.sin6_addr = inp->in6p_faddr; + struct sockaddr_in6 *dst6; + + dst6 = (struct sockaddr_in6 *)&ro6->ro_dst; + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(ro6->ro_dst); + dst6->sin6_addr = inp->in6p_faddr; rtalloc((struct route *)ro6); rt = ro6->ro_rt; } @@ -1376,6 +1366,7 @@ ipsec_hdrsiz_tcp(tp) sizeof(struct ip)); bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, sizeof(struct tcphdr)); + ip->ip_vhl = IP_VHL_BORING; hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); } diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index 3857b7513029..06849be35acd 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -443,7 +443,10 @@ tcp_respond(tp, ipgen, th, m, ack, seq, flags) tcp_trace(TA_OUTPUT, 0, tp, mtod(m, void *), th, 0); #endif #ifdef IPSEC - ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL); + if (ipsec_setsocket(m, tp ? tp->t_inpcb->inp_socket : NULL) != 0) { + m_freem(m); + return; + } #endif #ifdef INET6 if (isipv6) { @@ -1020,13 +1023,17 @@ tcp6_ctlinput(cmd, sa, d) struct sockaddr *sa; void *d; { - register struct tcphdr *thp; struct tcphdr th; void (*notify) __P((struct inpcb *, int)) = tcp_notify; - struct sockaddr_in6 sa6; struct ip6_hdr *ip6; struct mbuf *m; + struct ip6ctlparam *ip6cp = NULL; + const struct sockaddr_in6 *sa6_src = NULL; int off; + struct tcp_portonly { + u_int16_t th_sport; + u_int16_t th_dport; + } *thp; if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) @@ -1042,56 +1049,36 @@ tcp6_ctlinput(cmd, sa, d) /* if the parameter is from icmp6, decode it. */ if (d != NULL) { - struct ip6ctlparam *ip6cp = (struct ip6ctlparam *)d; + ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; + sa6_src = ip6cp->ip6c_src; } else { m = NULL; ip6 = NULL; off = 0; /* fool gcc */ + sa6_src = &sa6_any; } - /* - * Translate addresses into internal form. - * Sa check if it is AF_INET6 is done at the top of this funciton. - */ - sa6 = *(struct sockaddr_in6 *)sa; - if (IN6_IS_ADDR_LINKLOCAL(&sa6.sin6_addr) != 0 && m != NULL && - m->m_pkthdr.rcvif != NULL) - sa6.sin6_addr.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); - if (ip6) { /* * XXX: We assume that when IPV6 is non NULL, * M and OFF are valid. */ - struct in6_addr s; - - /* translate addresses into internal form */ - memcpy(&s, &ip6->ip6_src, sizeof(s)); - if (IN6_IS_ADDR_LINKLOCAL(&s) != 0 && m != NULL && - m->m_pkthdr.rcvif != NULL) - s.s6_addr16[1] = htons(m->m_pkthdr.rcvif->if_index); /* check if we can safely examine src and dst ports */ - if (m->m_pkthdr.len < off + sizeof(th)) + if (m->m_pkthdr.len < off + sizeof(*thp)) return; - if (m->m_len < off + sizeof(th)) { - /* - * this should be rare case - * because now MINCLSIZE is "(MHLEN + 1)", - * so we compromise on this copy... - */ - m_copydata(m, off, sizeof(th), (caddr_t)&th); - thp = &th; - } else - thp = (struct tcphdr *)(mtod(m, caddr_t) + off); - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, thp->th_dport, - &s, thp->th_sport, cmd, notify); + bzero(&th, sizeof(th)); + m_copydata(m, off, sizeof(*thp), (caddr_t)&th); + + in6_pcbnotify(&tcb, sa, th.th_dport, + (struct sockaddr *)ip6cp->ip6c_src, + th.th_sport, cmd, notify); } else - in6_pcbnotify(&tcb, (struct sockaddr *)&sa6, 0, &zeroin6_addr, + in6_pcbnotify(&tcb, sa, 0, (struct sockaddr *)sa6_src, 0, cmd, notify); } #endif /* INET6 */ @@ -1323,9 +1310,12 @@ tcp_rtlookup6(inp) if (rt == NULL || !(rt->rt_flags & RTF_UP)) { /* No route yet, so try to acquire one */ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr)) { - ro6->ro_dst.sin6_family = AF_INET6; - ro6->ro_dst.sin6_len = sizeof(ro6->ro_dst); - ro6->ro_dst.sin6_addr = inp->in6p_faddr; + struct sockaddr_in6 *dst6; + + dst6 = (struct sockaddr_in6 *)&ro6->ro_dst; + dst6->sin6_family = AF_INET6; + dst6->sin6_len = sizeof(ro6->ro_dst); + dst6->sin6_addr = inp->in6p_faddr; rtalloc((struct route *)ro6); rt = ro6->ro_rt; } @@ -1376,6 +1366,7 @@ ipsec_hdrsiz_tcp(tp) sizeof(struct ip)); bcopy((caddr_t)&tp->t_template->tt_t, (caddr_t)th, sizeof(struct tcphdr)); + ip->ip_vhl = IP_VHL_BORING; hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); } diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 25834d412812..aea92c0d33cc 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -240,8 +240,7 @@ tcp6_usr_bind(struct socket *so, struct sockaddr *nam, struct proc *p) } inp->inp_vflag &= ~INP_IPV4; inp->inp_vflag |= INP_IPV6; - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) { - + if (ip6_mapped_addr_on && (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) { if (IN6_IS_ADDR_UNSPECIFIED(&sin6p->sin6_addr)) inp->inp_vflag |= INP_IPV4; else if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { @@ -292,7 +291,8 @@ tcp6_usr_listen(struct socket *so, struct proc *p) COMMON_START(); if (inp->inp_lport == 0) { inp->inp_vflag &= ~INP_IPV4; - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0) + if (ip6_mapped_addr_on && + (inp->inp_flags & IN6P_IPV6_V6ONLY) == 0) inp->inp_vflag |= INP_IPV4; error = in6_pcbbind(inp, (struct sockaddr *)0, p); } @@ -361,10 +361,13 @@ tcp6_usr_connect(struct socket *so, struct sockaddr *nam, struct proc *p) goto out; } - if ((inp->inp_flags & IN6P_BINDV6ONLY) == 0 && - IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { + if (IN6_IS_ADDR_V4MAPPED(&sin6p->sin6_addr)) { struct sockaddr_in sin; + if (!ip6_mapped_addr_on || + (inp->inp_flags & IN6P_IPV6_V6ONLY)) + return(EINVAL); + in6_sin6_2_sin(&sin, sin6p); inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 350a3842b39b..d546b1f30917 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -392,8 +392,7 @@ udp_input(m, off, proto) #endif ip_savecontrol(inp, &opts, ip, m); } - iphlen += sizeof(struct udphdr); - m_adj(m, iphlen); + m_adj(m, iphlen + sizeof(struct udphdr)); #ifdef INET6 if (inp->inp_vflag & INP_IPV6) { in6_sin_2_v4mapsin6(&udp_in, &udp_in6.uin6_sin); @@ -744,7 +743,10 @@ udp_output(inp, m, addr, control, p) udpstat.udps_opackets++; #ifdef IPSEC - ipsec_setsocket(m, inp->inp_socket); + if (ipsec_setsocket(m, inp->inp_socket) != 0) { + error = ENOBUFS; + goto release; + } #endif /*IPSEC*/ error = ip_output(m, inp->inp_options, &inp->inp_route, (inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST)), |