Mercurial > illumos > illumos-gate
changeset 2733:fcaf8e865e03
4963362 routing socket is not zone-aware
6391685 Source interface selection is flawed when sending via default route within a zone.
6423486 Solaris should include an option to disable loopback traffic routing between non-global zones.
6426172 ICMP Destination unreachable from global zone instead non-global
6453678 TCP RST are routed as if they were sent by the global zone
6453732 zones routing check for "next hop reachable from zone" for default routes is flawed
line wrap: on
line diff
--- a/usr/src/uts/common/inet/ip.h Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip.h Thu Sep 14 18:05:27 2006 -0700 @@ -2885,8 +2885,9 @@ #define ip_max_defend ip_param_arr[52].ip_param_value #define ip_defend_interval ip_param_arr[53].ip_param_value #define ip_dup_recovery ip_param_arr[54].ip_param_value +#define ip_restrict_interzone_loopback ip_param_arr[55].ip_param_value #ifdef DEBUG -#define ipv6_drop_inbound_icmpv6 ip_param_arr[55].ip_param_value +#define ipv6_drop_inbound_icmpv6 ip_param_arr[56].ip_param_value #else #define ipv6_drop_inbound_icmpv6 0 #endif @@ -2979,8 +2980,8 @@ extern const char *mac_colon_addr(const uint8_t *, size_t, char *, size_t); extern void ip_lwput(queue_t *, mblk_t *); extern boolean_t icmp_err_rate_limit(void); -extern void icmp_time_exceeded(queue_t *, mblk_t *, uint8_t); -extern void icmp_unreachable(queue_t *, mblk_t *, uint8_t); +extern void icmp_time_exceeded(queue_t *, mblk_t *, uint8_t, zoneid_t); +extern void icmp_unreachable(queue_t *, mblk_t *, uint8_t, zoneid_t); extern mblk_t *ip_add_info(mblk_t *, ill_t *, uint_t); extern mblk_t *ip_bind_v4(queue_t *, mblk_t *, conn_t *); extern int ip_bind_connected(conn_t *, mblk_t *, ipaddr_t *, uint16_t, @@ -3018,10 +3019,11 @@ extern void ip_output(void *, mblk_t *, void *, int); extern void ip_wput_md(queue_t *, mblk_t *, conn_t *); -extern void ip_wput_ire(queue_t *, mblk_t *, ire_t *, conn_t *, int); +extern void ip_wput_ire(queue_t *, mblk_t *, ire_t *, conn_t *, int, + zoneid_t); extern void ip_wput_local(queue_t *, ill_t *, ipha_t *, mblk_t *, ire_t *, - int, zoneid_t); -extern void ip_wput_multicast(queue_t *, mblk_t *, ipif_t *); + int, zoneid_t); +extern void ip_wput_multicast(queue_t *, mblk_t *, ipif_t *, zoneid_t); extern void ip_wput_nondata(ipsq_t *, queue_t *, mblk_t *, void *); extern void ip_wsrv(queue_t *); extern char *ip_nv_lookup(nv_t *, int); @@ -3029,7 +3031,8 @@ extern boolean_t ip_remote_addr_ok_v6(const in6_addr_t *, const in6_addr_t *); extern ipaddr_t ip_massage_options(ipha_t *); extern ipaddr_t ip_net_mask(ipaddr_t); -extern void ip_newroute(queue_t *, mblk_t *, ipaddr_t, ill_t *, conn_t *); +extern void ip_newroute(queue_t *, mblk_t *, ipaddr_t, ill_t *, conn_t *, + zoneid_t); extern ipxmit_state_t ip_xmit_v4(mblk_t *, ire_t *, struct ipsec_out_s *, boolean_t); extern int ip_hdr_complete(ipha_t *, zoneid_t);
--- a/usr/src/uts/common/inet/ip/igmp.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/igmp.c Thu Sep 14 18:05:27 2006 -0700 @@ -1952,7 +1952,7 @@ ASSERT(ill->ill_rq != NULL); ip_multicast_loopback(ill->ill_rq, ill, first_mp, 0, ilm->ilm_zoneid); - ip_wput_multicast(ill->ill_wq, first_mp, ipif); + ip_wput_multicast(ill->ill_wq, first_mp, ipif, zoneid); ++igmpstat.igps_snd_reports; } @@ -2135,7 +2135,7 @@ ASSERT(ill->ill_rq != NULL); ip_multicast_loopback(ill->ill_rq, ill, mp, 0, ipif->ipif_zoneid); - ip_wput_multicast(ill->ill_wq, first_mp, ipif); + ip_wput_multicast(ill->ill_wq, first_mp, ipif, zoneid); ++igmpstat.igps_snd_reports;
--- a/usr/src/uts/common/inet/ip/ip.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/ip.c Thu Sep 14 18:05:27 2006 -0700 @@ -632,7 +632,7 @@ * -------- ---------------- * IRE_BROADCAST Exclusive * IRE_DEFAULT (default routes) Shared (*) - * IRE_LOCAL Exclusive + * IRE_LOCAL Exclusive (x) * IRE_LOOPBACK Exclusive * IRE_PREFIX (net routes) Shared (*) * IRE_CACHE Exclusive @@ -644,6 +644,22 @@ * directly reachable from the zone, that is, if the gateway's address matches * one of the zone's logical interfaces. * + * (x) IRE_LOCAL are handled a bit differently, since for all other entries + * in ire_ctable and IRE_INTERFACE, ire_src_addr is what can be used as source + * when sending packets using the IRE. For IRE_LOCAL ire_src_addr is the IP + * address of the zone itself (the destination). Since IRE_LOCAL is used + * for communication between zones, ip_wput_ire has special logic to set + * the right source address when sending using an IRE_LOCAL. + * + * Furthermore, when ip_restrict_interzone_loopback is set (the default), + * ire_cache_lookup restricts loopback using an IRE_LOCAL + * between zone to the case when L2 would have conceptually looped the packet + * back, i.e. the loopback which is required since neither Ethernet drivers + * nor Ethernet hardware loops them back. This is the case when the normal + * routes (ignoring IREs with different zoneids) would send out the packet on + * the same ill (or ill group) as the ill with which is IRE_LOCAL is + * associated. + * * Multiple zones can share a common broadcast address; typically all zones * share the 255.255.255.255 address. Incoming as well as locally originated * broadcast packets must be dispatched to all the zones on the broadcast @@ -689,7 +705,7 @@ static mblk_t *ip_wput_attach_llhdr(mblk_t *, ire_t *, ip_proc_t, uint32_t); static void ip_ipsec_out_prepend(mblk_t *, mblk_t *, ill_t *); -static void icmp_frag_needed(queue_t *, mblk_t *, int); +static void icmp_frag_needed(queue_t *, mblk_t *, int, zoneid_t); static void icmp_inbound(queue_t *, mblk_t *, boolean_t, ill_t *, int, uint32_t, boolean_t, boolean_t, ill_t *, zoneid_t); static ipaddr_t icmp_get_nexthop_addr(ipha_t *, ill_t *, zoneid_t, mblk_t *mp); @@ -699,8 +715,9 @@ icmph_t *, ipha_t *, int, int, boolean_t, boolean_t, ill_t *, zoneid_t); static void icmp_options_update(ipha_t *); -static void icmp_param_problem(queue_t *, mblk_t *, uint8_t); -static void icmp_pkt(queue_t *, mblk_t *, void *, size_t, boolean_t); +static void icmp_param_problem(queue_t *, mblk_t *, uint8_t, zoneid_t); +static void icmp_pkt(queue_t *, mblk_t *, void *, size_t, boolean_t, + zoneid_t zoneid); static mblk_t *icmp_pkt_err_ok(mblk_t *); static void icmp_redirect(mblk_t *); static void icmp_send_redirect(queue_t *, mblk_t *, ipaddr_t); @@ -722,9 +739,10 @@ ipaddr_t ip_massage_options(ipha_t *); static void ip_mrtun_forward(ire_t *, ill_t *, mblk_t *); ipaddr_t ip_net_mask(ipaddr_t); -void ip_newroute(queue_t *, mblk_t *, ipaddr_t, ill_t *, conn_t *); +void ip_newroute(queue_t *, mblk_t *, ipaddr_t, ill_t *, conn_t *, + zoneid_t); static void ip_newroute_ipif(queue_t *, mblk_t *, ipif_t *, ipaddr_t, - conn_t *, uint32_t); + conn_t *, uint32_t, zoneid_t); char *ip_nv_lookup(nv_t *, int); static boolean_t ip_check_for_ipsec_opt(queue_t *, mblk_t *); static int ip_param_get(queue_t *, mblk_t *, caddr_t, cred_t *); @@ -766,11 +784,12 @@ static boolean_t ip_source_routed(ipha_t *); static boolean_t ip_source_route_included(ipha_t *); -static void ip_wput_frag(ire_t *, mblk_t *, ip_pkt_t, uint32_t, uint32_t); +static void ip_wput_frag(ire_t *, mblk_t *, ip_pkt_t, uint32_t, uint32_t, + zoneid_t); static mblk_t *ip_wput_frag_copyhdr(uchar_t *, int, int); static void ip_wput_local_options(ipha_t *); static int ip_wput_options(queue_t *, mblk_t *, ipha_t *, boolean_t, - zoneid_t); + zoneid_t); static void conn_drain_init(void); static void conn_drain_fini(void); @@ -962,6 +981,7 @@ { 0, 1000, 3, "ip_max_defend" }, { 0, 999999, 30, "ip_defend_interval" }, { 0, 3600000, 300000, "ip_dup_recovery" }, + { 0, 1, 1, "ip_restrict_interzone_loopback" }, #ifdef DEBUG { 0, 1, 0, "ip6_drop_inbound_icmpv6" }, #endif @@ -1495,6 +1515,38 @@ #ifdef DEBUG static boolean_t skip_sctp_cksum = B_FALSE; #endif + +/* + * Prepend the zoneid using an ipsec_out_t for later use by functions like + * ip_rput_v6(), ip_output(), etc. If the message + * block already has a M_CTL at the front of it, then simply set the zoneid + * appropriately. + */ +mblk_t * +ip_prepend_zoneid(mblk_t *mp, zoneid_t zoneid) +{ + mblk_t *first_mp; + ipsec_out_t *io; + + ASSERT(zoneid != ALL_ZONES); + if (mp->b_datap->db_type == M_CTL) { + io = (ipsec_out_t *)mp->b_rptr; + ASSERT(io->ipsec_out_type == IPSEC_OUT); + io->ipsec_out_zoneid = zoneid; + return (mp); + } + + first_mp = ipsec_alloc_ipsec_out(); + if (first_mp == NULL) + return (NULL); + io = (ipsec_out_t *)first_mp->b_rptr; + /* This is not a secure packet */ + io->ipsec_out_secure = B_FALSE; + io->ipsec_out_zoneid = zoneid; + first_mp->b_cont = mp; + return (first_mp); +} + /* * Copy an M_CTL-tagged message, preserving reference counts appropriately. */ @@ -1527,7 +1579,7 @@ /* Generate an ICMP fragmentation needed message. */ static void -icmp_frag_needed(queue_t *q, mblk_t *mp, int mtu) +icmp_frag_needed(queue_t *q, mblk_t *mp, int mtu, zoneid_t zoneid) { icmph_t icmph; mblk_t *first_mp; @@ -1547,7 +1599,7 @@ icmph.icmph_du_mtu = htons((uint16_t)mtu); BUMP_MIB(&icmp_mib, icmpOutFragNeeded); BUMP_MIB(&icmp_mib, icmpOutDestUnreachs); - icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present); + icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present, zoneid); } /* @@ -3261,7 +3313,7 @@ * Generate an ICMP parameter problem message. */ static void -icmp_param_problem(queue_t *q, mblk_t *mp, uint8_t ptr) +icmp_param_problem(queue_t *q, mblk_t *mp, uint8_t ptr, zoneid_t zoneid) { icmph_t icmph; boolean_t mctl_present; @@ -3279,7 +3331,7 @@ icmph.icmph_type = ICMP_PARAM_PROBLEM; icmph.icmph_pp_ptr = ptr; BUMP_MIB(&icmp_mib, icmpOutParmProbs); - icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present); + icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present, zoneid); } /* @@ -3296,7 +3348,7 @@ */ static void icmp_pkt(queue_t *q, mblk_t *mp, void *stuff, size_t len, - boolean_t mctl_present) + boolean_t mctl_present, zoneid_t zoneid) { ipaddr_t dst; icmph_t *icmph; @@ -3309,7 +3361,6 @@ mblk_t *ipsec_mp; ipsec_out_t *io = NULL; boolean_t xmit_if_on = B_FALSE; - zoneid_t zoneid; if (mctl_present) { /* @@ -3354,7 +3405,7 @@ */ io->ipsec_out_proc_begin = B_FALSE; } - zoneid = io->ipsec_out_zoneid; + ASSERT(zoneid == io->ipsec_out_zoneid); ASSERT(zoneid != ALL_ZONES); } else { /* @@ -3376,13 +3427,14 @@ /* This is not a secure packet */ ii->ipsec_in_secure = B_FALSE; - if (CONN_Q(q)) { - zoneid = Q_TO_CONN(q)->conn_zoneid; - } else { - zoneid = GLOBAL_ZONEID; - } - ii->ipsec_in_zoneid = zoneid; - ASSERT(zoneid != ALL_ZONES); + /* + * For trusted extensions using a shared IP address we can + * send using any zoneid. + */ + if (zoneid == ALL_ZONES) + ii->ipsec_in_zoneid = GLOBAL_ZONEID; + else + ii->ipsec_in_zoneid = zoneid; ipsec_mp->b_cont = mp; ipha = (ipha_t *)mp->b_rptr; /* @@ -3679,14 +3731,15 @@ icmph.icmph_code = 1; icmph.icmph_rd_gateway = gateway; BUMP_MIB(&icmp_mib, icmpOutRedirects); - icmp_pkt(q, mp, &icmph, sizeof (icmph_t), B_FALSE); + /* Redirects sent by router, and router is global zone */ + icmp_pkt(q, mp, &icmph, sizeof (icmph_t), B_FALSE, GLOBAL_ZONEID); } /* * Generate an ICMP time exceeded message. */ void -icmp_time_exceeded(queue_t *q, mblk_t *mp, uint8_t code) +icmp_time_exceeded(queue_t *q, mblk_t *mp, uint8_t code, zoneid_t zoneid) { icmph_t icmph; boolean_t mctl_present; @@ -3704,14 +3757,14 @@ icmph.icmph_type = ICMP_TIME_EXCEEDED; icmph.icmph_code = code; BUMP_MIB(&icmp_mib, icmpOutTimeExcds); - icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present); + icmp_pkt(q, first_mp, &icmph, sizeof (icmph_t), mctl_present, zoneid); } /* * Generate an ICMP unreachable message. */ void -icmp_unreachable(queue_t *q, mblk_t *mp, uint8_t code) +icmp_unreachable(queue_t *q, mblk_t *mp, uint8_t code, zoneid_t zoneid) { icmph_t icmph; mblk_t *first_mp; @@ -3730,7 +3783,8 @@ icmph.icmph_code = code; BUMP_MIB(&icmp_mib, icmpOutDestUnreachs); ip2dbg(("send icmp destination unreachable code %d\n", code)); - icmp_pkt(q, first_mp, (char *)&icmph, sizeof (icmph_t), mctl_present); + icmp_pkt(q, first_mp, (char *)&icmph, sizeof (icmph_t), mctl_present, + zoneid); } /* @@ -5968,7 +6022,7 @@ } switch (icmp_type) { case ICMP_DEST_UNREACHABLE: - icmp_unreachable(WR(q), first_mp, icmp_code); + icmp_unreachable(WR(q), first_mp, icmp_code, zoneid); break; default: freemsg(first_mp); @@ -6382,7 +6436,7 @@ BUMP_MIB(&ip_mib, ipInDelivers); ip2dbg(("ip_fanout_tcp: no listener; send reset to zone %d\n", zoneid)); - tcp_xmit_listeners_reset(first_mp, ip_hdr_len); + tcp_xmit_listeners_reset(first_mp, ip_hdr_len, zoneid); return; } @@ -6426,7 +6480,7 @@ return; } if (flags & TH_ACK) { - tcp_xmit_listeners_reset(first_mp, ip_hdr_len); + tcp_xmit_listeners_reset(first_mp, ip_hdr_len, zoneid); CONN_DEC_REF(connp); return; } @@ -7197,8 +7251,9 @@ goto drop_pkt; } ip_ipsec_out_prepend(first_mp, mp, in_ill); - icmp_time_exceeded(q, first_mp, ICMP_TTL_EXCEEDED); - + /* Sent by forwarding path, and router is global zone */ + icmp_time_exceeded(q, first_mp, ICMP_TTL_EXCEEDED, + GLOBAL_ZONEID); return; } @@ -7241,7 +7296,7 @@ ip_ipsec_out_prepend(first_mp, mp, in_ill); mp = first_mp; - ip_wput_frag(ire, mp, IB_PKT, max_frag, 0); + ip_wput_frag(ire, mp, IB_PKT, max_frag, 0, GLOBAL_ZONEID); return; } @@ -7424,7 +7479,8 @@ * are not NULL. */ void -ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp) +ip_newroute(queue_t *q, mblk_t *mp, ipaddr_t dst, ill_t *in_ill, conn_t *connp, + zoneid_t zoneid) { areq_t *areq; ipaddr_t gw = 0; @@ -7453,7 +7509,6 @@ boolean_t multirt_resolve_next; boolean_t do_attach_ill = B_FALSE; boolean_t ip_nexthop = B_FALSE; - zoneid_t zoneid; tsol_ire_gw_secattr_t *attrp = NULL; tsol_gcgrp_t *gcgrp = NULL; tsol_gcgrp_addr_t ga; @@ -7466,12 +7521,9 @@ EXTRACT_PKT_MP(mp, first_mp, mctl_present); if (mctl_present) { io = (ipsec_out_t *)first_mp->b_rptr; - zoneid = io->ipsec_out_zoneid; + ASSERT(io->ipsec_out_type == IPSEC_OUT); + ASSERT(zoneid == io->ipsec_out_zoneid); ASSERT(zoneid != ALL_ZONES); - } else if (connp != NULL) { - zoneid = connp->conn_zoneid; - } else { - zoneid = GLOBAL_ZONEID; } ipha = (ipha_t *)mp->b_rptr; @@ -8654,10 +8706,11 @@ ire_refrele(ire); } if (ip_source_routed(ipha)) { - icmp_unreachable(q, first_mp, ICMP_SOURCE_ROUTE_FAILED); - return; - } - icmp_unreachable(q, first_mp, ICMP_HOST_UNREACHABLE); + icmp_unreachable(q, first_mp, ICMP_SOURCE_ROUTE_FAILED, + zoneid); + return; + } + icmp_unreachable(q, first_mp, ICMP_HOST_UNREACHABLE, zoneid); } /* @@ -8688,7 +8741,7 @@ */ static void ip_newroute_ipif(queue_t *q, mblk_t *mp, ipif_t *ipif, ipaddr_t dst, - conn_t *connp, uint32_t flags) + conn_t *connp, uint32_t flags, zoneid_t zoneid) { areq_t *areq; ire_t *ire = NULL; @@ -8709,7 +8762,6 @@ mblk_t *copy_mp = NULL; boolean_t multirt_resolve_next; ipaddr_t ipha_dst; - zoneid_t zoneid = (connp != NULL ? connp->conn_zoneid : ALL_ZONES); /* * CGTP goes in a loop which looks up a new ipif, do an ipif_refhold @@ -9352,7 +9404,7 @@ } ire_refrele(ire); } - icmp_unreachable(q, first_mp, ICMP_HOST_UNREACHABLE); + icmp_unreachable(q, first_mp, ICMP_HOST_UNREACHABLE, zoneid); } /* Name/Value Table Lookup Routine */ @@ -12787,7 +12839,7 @@ return (NULL); } if (flags & TH_ACK) { - tcp_xmit_listeners_reset(first_mp, ip_hdr_len); + tcp_xmit_listeners_reset(first_mp, ip_hdr_len, zoneid); CONN_DEC_REF(connp); return (NULL); } @@ -12892,7 +12944,7 @@ } } BUMP_MIB(&ip_mib, ipInDelivers); - tcp_xmit_listeners_reset(first_mp, IPH_HDR_LENGTH(mp->b_rptr)); + tcp_xmit_listeners_reset(first_mp, IPH_HDR_LENGTH(mp->b_rptr), zoneid); return (NULL); ipoptions: if (!ip_options_cksum(q, first_mp, ipha, ire)) { @@ -13302,7 +13354,7 @@ /* * Now hand the packet to ip_newroute. */ - ip_newroute(q, mp, dst, in_ill, NULL); + ip_newroute(q, mp, dst, in_ill, NULL, GLOBAL_ZONEID); return (NULL); } ire = ire_forward(dst, &check_multirt, NULL, NULL, @@ -13310,7 +13362,7 @@ if (ire == NULL && check_multirt) { /* Let ip_newroute handle CGTP */ - ip_newroute(q, mp, dst, in_ill, NULL); + ip_newroute(q, mp, dst, in_ill, NULL, GLOBAL_ZONEID); return (NULL); } @@ -13320,10 +13372,13 @@ mp->b_prev = mp->b_next = 0; /* send icmp unreachable */ q = WR(q); - if (ip_source_routed(ipha)) - icmp_unreachable(q, mp, ICMP_SOURCE_ROUTE_FAILED); - else - icmp_unreachable(q, mp, ICMP_HOST_UNREACHABLE); + /* Sent by forwarding path, and router is global zone */ + if (ip_source_routed(ipha)) { + icmp_unreachable(q, mp, ICMP_SOURCE_ROUTE_FAILED, + GLOBAL_ZONEID); + } else { + icmp_unreachable(q, mp, ICMP_HOST_UNREACHABLE, GLOBAL_ZONEID); + } return (NULL); @@ -13504,12 +13559,13 @@ BUMP_MIB(&ip_mib, ipInDiscards); mp->b_prev = mp->b_next = 0; /* send icmp unreachable */ + /* Sent by forwarding path, and router is global zone */ if (ip_source_routed(ipha)) { icmp_unreachable(ill->ill_wq, mp, - ICMP_SOURCE_ROUTE_FAILED); + ICMP_SOURCE_ROUTE_FAILED, GLOBAL_ZONEID); } else { icmp_unreachable(ill->ill_wq, mp, - ICMP_HOST_UNREACHABLE); + ICMP_HOST_UNREACHABLE, GLOBAL_ZONEID); } return (ire); } @@ -13633,8 +13689,9 @@ * hardware checksum as we are not using it. */ DB_CKSUMFLAGS(mp) = 0; + /* Sent by forwarding path, and router is global zone */ icmp_unreachable(q, mp, - ICMP_SOURCE_ROUTE_FAILED); + ICMP_SOURCE_ROUTE_FAILED, GLOBAL_ZONEID); return; } goto drop_pkt; @@ -16014,9 +16071,11 @@ * multicast packets. */ q = ire->ire_stq; - if (q) - icmp_time_exceeded(q, mp, ICMP_TTL_EXCEEDED); - else + if (q != NULL) { + /* Sent by forwarding path, and router is global zone */ + icmp_time_exceeded(q, mp, ICMP_TTL_EXCEEDED, + GLOBAL_ZONEID); + } else freemsg(mp); return; } @@ -16081,7 +16140,7 @@ return; } } - ip_wput_frag(ire, mp, IB_PKT, max_frag, 0); + ip_wput_frag(ire, mp, IB_PKT, max_frag, 0, GLOBAL_ZONEID); ip2dbg(("ip_rput_forward:sent to ip_wput_frag\n")); return; } @@ -16122,7 +16181,7 @@ mp->b_prev = NULL; mp->b_next = mp; ip_newroute_ipif(ipif->ipif_ill->ill_wq, mp, ipif, dst, - NULL, 0); + NULL, 0, GLOBAL_ZONEID); } else { ip_rput_forward(ire, (ipha_t *)mp->b_rptr, mp, NULL); IRE_REFRELE(ire); @@ -16160,10 +16219,15 @@ /* Check if adminstratively disabled */ if (!ip_forward_src_routed) { BUMP_MIB(&ip_mib, ipForwProhibits); - if (ire->ire_stq) + if (ire->ire_stq != NULL) { + /* + * Sent by forwarding path, and router + * is global zone + */ icmp_unreachable(ire->ire_stq, mp, - ICMP_SOURCE_ROUTE_FAILED); - else { + ICMP_SOURCE_ROUTE_FAILED, + GLOBAL_ZONEID); + } else { ip0dbg(("ip_rput_forward_options: " "unable to send unreach\n")); freemsg(mp); @@ -17089,6 +17153,8 @@ uint32_t ts; ire_t *dst_ire; timestruc_t now; + zoneid_t zoneid; + ill_t *ill; ASSERT(ire->ire_ipversion == IPV4_VERSION); @@ -17213,9 +17279,18 @@ bad_src_route: q = WR(q); + if (q->q_next != NULL) + ill = q->q_ptr; + else + ill = NULL; + /* make sure we clear any indication of a hardware checksum */ DB_CKSUMFLAGS(mp) = 0; - icmp_unreachable(q, mp, ICMP_SOURCE_ROUTE_FAILED); + zoneid = ipif_lookup_addr_zoneid(ipha->ipha_dst, ill); + if (zoneid == ALL_ZONES) + freemsg(mp); + else + icmp_unreachable(q, mp, ICMP_SOURCE_ROUTE_FAILED, zoneid); return (B_FALSE); } @@ -17236,6 +17311,8 @@ ipaddr_t dst; intptr_t code = 0; ire_t *ire = NULL; + zoneid_t zoneid; + ill_t *ill; ip2dbg(("ip_rput_options\n")); dst = ipha->ipha_dst; @@ -17397,16 +17474,35 @@ param_prob: q = WR(q); + if (q->q_next != NULL) + ill = q->q_ptr; + else + ill = NULL; + /* make sure we clear any indication of a hardware checksum */ DB_CKSUMFLAGS(mp) = 0; - icmp_param_problem(q, mp, (uint8_t)code); + /* Don't know whether this is for non-global or global/forwarding */ + zoneid = ipif_lookup_addr_zoneid(dst, ill); + if (zoneid == ALL_ZONES) + freemsg(mp); + else + icmp_param_problem(q, mp, (uint8_t)code, zoneid); return (-1); bad_src_route: q = WR(q); + if (q->q_next != NULL) + ill = q->q_ptr; + else + ill = NULL; + /* make sure we clear any indication of a hardware checksum */ DB_CKSUMFLAGS(mp) = 0; - icmp_unreachable(q, mp, ICMP_SOURCE_ROUTE_FAILED); + zoneid = ipif_lookup_addr_zoneid(dst, ill); + if (zoneid == ALL_ZONES) + freemsg(mp); + else + icmp_unreachable(q, mp, ICMP_SOURCE_ROUTE_FAILED, zoneid); return (-1); } @@ -17756,7 +17852,8 @@ rw_enter(&ill_g_lock, RW_READER); ill = ILL_START_WALK_V6(&ctx); for (; ill != NULL; ill = ill_next(&ctx, ill)) { - for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { + for (ipif = ill->ill_ipif; ipif != NULL; + ipif = ipif->ipif_next) { if (ipif->ipif_zoneid != zoneid && ipif->ipif_zoneid != ALL_ZONES) continue; @@ -19181,6 +19278,11 @@ /* * Write side put procedure. Outbound data, IOCTLs, responses from * resolvers, etc, come down through here. + * + * arg2 is always a queue_t *. + * When that queue is an ill_t (i.e. q_next != NULL), then arg must be + * the zoneid. + * When that queue is not an ill_t, then arg must be a conn_t pointer. */ void ip_output(void *arg, mblk_t *mp, void *arg2, int caller) @@ -19227,11 +19329,14 @@ */ /* is packet from ARP ? */ - if (q->q_next != NULL) + if (q->q_next != NULL) { + zoneid = (zoneid_t)(uintptr_t)arg; goto qnext; + } connp = (conn_t *)arg; - zoneid = (connp != NULL ? connp->conn_zoneid : ALL_ZONES); + ASSERT(connp != NULL); + zoneid = connp->conn_zoneid; /* is queue flow controlled? */ if ((q->q_first != NULL || connp->conn_draining) && @@ -19468,14 +19573,14 @@ } } - ip_wput_ire(q, first_mp, ire, connp, caller); + ip_wput_ire(q, first_mp, ire, connp, caller, zoneid); /* * Try to resolve another multiroute if * ire_multirt_need_resolve() deemed it necessary. */ if (copy_mp != NULL) { - ip_newroute(q, copy_mp, dst, NULL, connp); + ip_newroute(q, copy_mp, dst, NULL, connp, zoneid); } if (need_decref) CONN_DEC_REF(connp); @@ -19597,14 +19702,14 @@ } } - ip_wput_ire(q, first_mp, ire, connp, caller); + ip_wput_ire(q, first_mp, ire, connp, caller, zoneid); /* * Try to resolve another multiroute if * ire_multirt_resolvable() deemed it necessary */ if (copy_mp != NULL) { - ip_newroute(q, copy_mp, dst, NULL, connp); + ip_newroute(q, copy_mp, dst, NULL, connp, zoneid); } if (need_decref) CONN_DEC_REF(connp); @@ -19899,7 +20004,7 @@ ill_refrele(attach_ill); if (need_decref) mp->b_flag |= MSGHASREF; - (void) ip_output_v6(connp, first_mp, q, caller); + (void) ip_output_v6(arg, first_mp, arg2, caller); return; } @@ -20207,7 +20312,7 @@ if (xmit_ill == NULL || xmit_ill->ill_ipif_up_count > 0) { ip_newroute_ipif(q, first_mp, ipif, dst, connp, - setsrc | RTF_MULTIRT); + setsrc | RTF_MULTIRT, zoneid); TRACE_2(TR_FAC_IP, TR_IP_WPUT_END, "ip_wput_end: q %p (%S)", q, "noire"); } else { @@ -20382,7 +20487,7 @@ ipif = ipif_get_next_ipif(NULL, xmit_ill); if (ipif != NULL) { ip_newroute_ipif(q, first_mp, ipif, - dst, connp, 0); + dst, connp, 0, zoneid); ipif_refrele(ipif); ip1dbg(("ip_wput: ip_unicast_if\n")); } @@ -20463,7 +20568,7 @@ */ mp->b_prev = NULL; mp->b_next = NULL; - ip_newroute(q, first_mp, dst, NULL, connp); + ip_newroute(q, first_mp, dst, NULL, connp, zoneid); TRACE_2(TR_FAC_IP, TR_IP_WPUT_END, "ip_wput_end: q %p (%S)", q, "newroute"); if (attach_ill != NULL) @@ -20522,7 +20627,7 @@ } } - ip_wput_ire(q, first_mp, ire, connp, caller); + ip_wput_ire(q, first_mp, ire, connp, caller, zoneid); /* * Try to resolve another multiroute if * ire_multirt_resolvable() deemed it necessary. @@ -20536,7 +20641,7 @@ ipif_t *ipif = ipif_lookup_group(dst, zoneid); if (ipif) { ip_newroute_ipif(q, copy_mp, ipif, dst, connp, - RTF_SETSRC | RTF_MULTIRT); + RTF_SETSRC | RTF_MULTIRT, zoneid); ipif_refrele(ipif); } else { MULTIRT_DEBUG_UNTAG(copy_mp); @@ -20544,7 +20649,7 @@ copy_mp = NULL; } } else { - ip_newroute(q, copy_mp, dst, NULL, connp); + ip_newroute(q, copy_mp, dst, NULL, connp, zoneid); } } if (attach_ill != NULL) @@ -20561,7 +20666,7 @@ if (ip_hdr_complete(ipha, zoneid) == 0) { BUMP_MIB(&ip_mib, ipOutNoRoutes); /* it's the IP header length that's in trouble */ - icmp_param_problem(q, first_mp, 0); + icmp_param_problem(q, first_mp, 0, zoneid); first_mp = NULL; } @@ -20580,10 +20685,20 @@ "ip_wput_end: q %p (%S)", q, "droppkt"); } +/* + * If this is a conn_t queue, then we pass in the conn. This includes the + * zoneid. + * Otherwise, this is a message coming back from ARP or for an ill_t queue, + * in which case we use the global zoneid since those are all part of + * the global zone. + */ void ip_wput(queue_t *q, mblk_t *mp) { - ip_output(Q_TO_CONN(q), mp, q, IP_WPUT); + if (CONN_Q(q)) + ip_output(Q_TO_CONN(q), mp, q, IP_WPUT); + else + ip_output(GLOBAL_ZONEID, mp, q, IP_WPUT); } /* @@ -20693,7 +20808,7 @@ * NOTE : This function does not ire_refrele the ire argument passed in. */ static void -ip_wput_ire_fragmentit(mblk_t *ipsec_mp, ire_t *ire) +ip_wput_ire_fragmentit(mblk_t *ipsec_mp, ire_t *ire, zoneid_t zoneid) { ipha_t *ipha; mblk_t *mp; @@ -20751,7 +20866,7 @@ ip_source_route_included(ipha)) || CLASSD(ipha->ipha_dst)); ip_wput_frag(ire, ipsec_mp, OB_PKT, max_frag, - (dont_use ? 0 : frag_flag)); + (dont_use ? 0 : frag_flag), zoneid); } /* @@ -20863,7 +20978,7 @@ mblk_t * ip_wput_ire_parse_ipsec_out(mblk_t *mp, ipha_t *ipha, ip6_t *ip6h, ire_t *ire, - conn_t *connp, boolean_t unspec_src) + conn_t *connp, boolean_t unspec_src, zoneid_t zoneid) { ipsec_out_t *io; mblk_t *first_mp; @@ -20897,7 +21012,7 @@ if ((io->ipsec_out_latch == NULL) && (io->ipsec_out_use_global_policy)) { return (ip_wput_attach_policy(first_mp, ipha, ip6h, - ire, connp, unspec_src)); + ire, connp, unspec_src, zoneid)); } if (!io->ipsec_out_secure) { /* @@ -20956,7 +21071,8 @@ if (!policy_present) return (mp); - return (ip_wput_attach_policy(mp, ipha, ip6h, ire, connp, unspec_src)); + return (ip_wput_attach_policy(mp, ipha, ip6h, ire, connp, unspec_src, + zoneid)); } ire_t * @@ -21061,7 +21177,8 @@ * */ void -ip_wput_ire(queue_t *q, mblk_t *mp, ire_t *ire, conn_t *connp, int caller) +ip_wput_ire(queue_t *q, mblk_t *mp, ire_t *ire, conn_t *connp, int caller, + zoneid_t zoneid) { ipha_t *ipha; #define rptr ((uchar_t *)ipha) @@ -21094,7 +21211,6 @@ uint32_t ill_index = 0; boolean_t multirt_send = B_FALSE; int err; - zoneid_t zoneid; ipxmit_state_t pktxmit_state; TRACE_1(TR_FAC_IP, TR_IP_WPUT_IRE_START, @@ -21177,11 +21293,10 @@ if (mp->b_datap->db_type != M_CTL) { ipha = (ipha_t *)mp->b_rptr; - zoneid = (connp != NULL ? connp->conn_zoneid : ALL_ZONES); } else { io = (ipsec_out_t *)mp->b_rptr; ASSERT(io->ipsec_out_type == IPSEC_OUT); - zoneid = io->ipsec_out_zoneid; + ASSERT(zoneid == io->ipsec_out_zoneid); ASSERT(zoneid != ALL_ZONES); ipha = (ipha_t *)mp->b_cont->b_rptr; dst = ipha->ipha_dst; @@ -21216,12 +21331,24 @@ * matching route in the forwarding table. * RTF_REJECT and RTF_BLACKHOLE are handled just like * ip_newroute() does. - */ - ire_t *src_ire = ire_ftable_lookup(ipha->ipha_dst, 0, 0, 0, + * Note that IRE_LOCAL are special, since they are used + * when the zoneid doesn't match in some cases. This means that + * we need to handle ipha_src differently since ire_src_addr + * belongs to the receiving zone instead of the sending zone. + * When ip_restrict_interzone_loopback is set, then + * ire_cache_lookup() ensures that IRE_LOCAL are only used + * for loopback between zones when the logical "Ethernet" would + * have looped them back. + */ + ire_t *src_ire; + + src_ire = ire_ftable_lookup(ipha->ipha_dst, 0, 0, 0, NULL, NULL, zoneid, 0, NULL, (MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT | MATCH_IRE_RJ_BHOLE)); if (src_ire != NULL && - !(src_ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE))) { + !(src_ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE)) && + (!ip_restrict_interzone_loopback || + ire_local_same_ill_group(ire, src_ire))) { if (ipha->ipha_src == INADDR_ANY && !unspec_src) ipha->ipha_src = src_ire->ire_src_addr; ire_refrele(src_ire); @@ -21243,7 +21370,7 @@ freemsg(mp); return; } - icmp_unreachable(q, mp, ICMP_HOST_UNREACHABLE); + icmp_unreachable(q, mp, ICMP_HOST_UNREACHABLE, zoneid); return; } } @@ -21251,7 +21378,7 @@ if (mp->b_datap->db_type == M_CTL || ipsec_outbound_v4_policy_present) { mp = ip_wput_ire_parse_ipsec_out(mp, ipha, NULL, ire, connp, - unspec_src); + unspec_src, zoneid); if (mp == NULL) { ire_refrele(ire); if (conn_outgoing_ill != NULL) @@ -21269,7 +21396,8 @@ mp = first_mp->b_cont; ipsec_len = ipsec_out_extra_length(first_mp); ASSERT(ipsec_len >= 0); - zoneid = io->ipsec_out_zoneid; + /* We already picked up the zoneid from the M_CTL above */ + ASSERT(zoneid == io->ipsec_out_zoneid); ASSERT(zoneid != ALL_ZONES); /* @@ -22260,7 +22388,7 @@ ipha->ipha_hdr_checksum = (uint16_t)ip_csum_hdr(ipha); icmp_frag_needed(ire->ire_stq, first_mp, - max_frag); + max_frag, zoneid); if (!next_mp) { ire_refrele(ire); if (conn_outgoing_ill != NULL) { @@ -22331,13 +22459,14 @@ TRACE_2(TR_FAC_IP, TR_IP_WPUT_IRE_END, "ip_wput_ire_end: q %p (%S)", q, "last fragmentation"); - ip_wput_ire_fragmentit(mp, ire); + ip_wput_ire_fragmentit(mp, ire, + zoneid); ire_refrele(ire); if (conn_outgoing_ill != NULL) ill_refrele(conn_outgoing_ill); return; } - ip_wput_ire_fragmentit(mp, ire); + ip_wput_ire_fragmentit(mp, ire, zoneid); } } } else { @@ -22899,7 +23028,7 @@ */ static void ip_wput_frag(ire_t *ire, mblk_t *mp_orig, ip_pkt_t pkt_type, uint32_t max_frag, - uint32_t frag_flag) + uint32_t frag_flag, zoneid_t zoneid) { int i1; mblk_t *ll_hdr_mp; @@ -22979,7 +23108,7 @@ */ ipha->ipha_hdr_checksum = 0; ipha->ipha_hdr_checksum = ip_csum_hdr(ipha); - icmp_frag_needed(ire->ire_stq, first_mp, max_frag); + icmp_frag_needed(ire->ire_stq, first_mp, max_frag, zoneid); TRACE_1(TR_FAC_IP, TR_IP_WPUT_FRAG_END, "ip_wput_frag_end:(%S)", "don't fragment"); @@ -24078,7 +24207,7 @@ * Caller verifies that this isn't a PHYI_LOOPBACK. */ void -ip_wput_multicast(queue_t *q, mblk_t *mp, ipif_t *ipif) +ip_wput_multicast(queue_t *q, mblk_t *mp, ipif_t *ipif, zoneid_t zoneid) { ipha_t *ipha; ire_t *ire; @@ -24117,7 +24246,7 @@ * ipsec_out_attach_if so that this will not be load spread in * ip_newroute_ipif. */ - ire = ire_ctable_lookup(dst, 0, 0, ipif, ALL_ZONES, NULL, + ire = ire_ctable_lookup(dst, 0, 0, ipif, zoneid, NULL, MATCH_IRE_ILL); if (!ire) { /* @@ -24127,7 +24256,8 @@ */ mp->b_prev = NULL; mp->b_next = NULL; - ip_newroute_ipif(q, first_mp, ipif, dst, NULL, RTF_SETSRC); + ip_newroute_ipif(q, first_mp, ipif, dst, NULL, RTF_SETSRC, + zoneid); return; } @@ -24141,7 +24271,7 @@ ipha->ipha_src = ire->ire_src_addr; } - ip_wput_ire(q, first_mp, ire, NULL, B_FALSE); + ip_wput_ire(q, first_mp, ire, NULL, B_FALSE, zoneid); } /* @@ -24675,7 +24805,8 @@ * * Also handle RTF_MULTIRT routes. */ - ip_newroute_ipif(q, ipsec_mp, ipif, dst, NULL, RTF_MULTIRT); + ip_newroute_ipif(q, ipsec_mp, ipif, dst, NULL, RTF_MULTIRT, + zoneid); } else { if (attach_if) { ire = ire_ctable_lookup(dst, 0, 0, ill->ill_ipif, @@ -24729,7 +24860,7 @@ */ ipha->ipha_ident = IP_HDR_INCLUDED; ip_newroute(q, ipsec_mp, dst, NULL, - (CONN_Q(q) ? Q_TO_CONN(q) : NULL)); + (CONN_Q(q) ? Q_TO_CONN(q) : NULL), zoneid); } goto done; send: @@ -24808,7 +24939,7 @@ "fragmented accelerated packet!\n")); freemsg(ipsec_mp); } else { - ip_wput_ire_fragmentit(ipsec_mp, ire); + ip_wput_ire_fragmentit(ipsec_mp, ire, zoneid); } if (ire_need_rele) ire_refrele(ire); @@ -26729,7 +26860,7 @@ freemsg(ipsec_mp); return (-1); } - icmp_param_problem(q, ipsec_mp, (uint8_t)code); + icmp_param_problem(q, ipsec_mp, (uint8_t)code, zoneid); return (-1); bad_src_route: @@ -26742,7 +26873,7 @@ freemsg(ipsec_mp); return (-1); } - icmp_unreachable(q, ipsec_mp, ICMP_SOURCE_ROUTE_FAILED); + icmp_unreachable(q, ipsec_mp, ICMP_SOURCE_ROUTE_FAILED, zoneid); return (-1); } @@ -27050,6 +27181,8 @@ connp->conn_draining = 1; noenable(q); while ((mp = getq(q)) != NULL) { + ASSERT(CONN_Q(q)); + ip_output(Q_TO_CONN(q), mp, q, IP_WSRV); if (connp->conn_did_putbq) { /* ip_wput did a putbq */
--- a/usr/src/uts/common/inet/ip/ip6.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/ip6.c Thu Sep 14 18:05:27 2006 -0700 @@ -248,7 +248,7 @@ static void icmp_inbound_too_big_v6(queue_t *, mblk_t *, ill_t *ill, boolean_t, zoneid_t); static void icmp_pkt_v6(queue_t *, mblk_t *, void *, size_t, - const in6_addr_t *, boolean_t); + const in6_addr_t *, boolean_t, zoneid_t); static void icmp_redirect_v6(queue_t *, mblk_t *, ill_t *ill); static boolean_t icmp_redirect_ok_v6(ill_t *ill, mblk_t *mp); static int ip_bind_connected_v6(conn_t *, mblk_t *, in6_addr_t *, @@ -270,7 +270,7 @@ ip6_frag_t *, uint_t, uint_t *, uint32_t *, uint16_t *); static boolean_t ip_source_routed_v6(ip6_t *, mblk_t *); static void ip_wput_ire_v6(queue_t *, mblk_t *, ire_t *, int, int, - conn_t *, int, int, int); + conn_t *, int, int, int, zoneid_t); static boolean_t ip_ulp_cando_pkt2big(int); static void ip_rput_v6(queue_t *, mblk_t *); @@ -1540,20 +1540,17 @@ */ static in6_addr_t * icmp_pick_source_v6(queue_t *wq, in6_addr_t *origsrc, in6_addr_t *origdst, - in6_addr_t *src) + in6_addr_t *src, zoneid_t zoneid) { ill_t *ill; ire_t *ire; ipif_t *ipif; - zoneid_t zoneid; ASSERT(!(wq->q_flag & QREADR)); if (wq->q_next != NULL) { ill = (ill_t *)wq->q_ptr; - zoneid = GLOBAL_ZONEID; } else { ill = NULL; - zoneid = Q_TO_CONN(wq)->conn_zoneid; } ire = ire_route_lookup_v6(origdst, 0, 0, (IRE_LOCAL|IRE_LOOPBACK), @@ -1625,7 +1622,7 @@ */ static void icmp_pkt_v6(queue_t *q, mblk_t *mp, void *stuff, size_t len, - const in6_addr_t *v6src_ptr, boolean_t mctl_present) + const in6_addr_t *v6src_ptr, boolean_t mctl_present, zoneid_t zoneid) { ip6_t *ip6h; in6_addr_t v6dst; @@ -1703,6 +1700,14 @@ /* This is not a secure packet */ ii->ipsec_in_secure = B_FALSE; + /* + * For trusted extensions using a shared IP address we can + * send using any zoneid. + */ + if (zoneid == ALL_ZONES) + ii->ipsec_in_zoneid = GLOBAL_ZONEID; + else + ii->ipsec_in_zoneid = zoneid; ipsec_mp->b_cont = mp; ip6h = (ip6_t *)mp->b_rptr; /* @@ -1720,7 +1725,7 @@ v6src = *v6src_ptr; } else { if (icmp_pick_source_v6(q, &ip6h->ip6_src, &ip6h->ip6_dst, - &v6src) == NULL) { + &v6src, zoneid) == NULL) { freemsg(ipsec_mp); ill_refrele(ill); return; @@ -2041,7 +2046,8 @@ srcp = &ill->ill_ipif->ipif_v6src_addr; } rw_exit(&ill_g_lock); - icmp_pkt_v6(q, mp, buf, len, srcp, B_FALSE); + /* Redirects sent by router, and router is global zone */ + icmp_pkt_v6(q, mp, buf, len, srcp, B_FALSE, GLOBAL_ZONEID); kmem_free(buf, len); } @@ -2049,7 +2055,7 @@ /* Generate an ICMP time exceeded message. (May be called as writer.) */ void icmp_time_exceeded_v6(queue_t *q, mblk_t *mp, uint8_t code, - boolean_t llbcast, boolean_t mcast_ok) + boolean_t llbcast, boolean_t mcast_ok, zoneid_t zoneid) { icmp6_t icmp6; boolean_t mctl_present; @@ -2066,7 +2072,8 @@ bzero(&icmp6, sizeof (icmp6_t)); icmp6.icmp6_type = ICMP6_TIME_EXCEEDED; icmp6.icmp6_code = code; - icmp_pkt_v6(q, first_mp, &icmp6, sizeof (icmp6_t), NULL, mctl_present); + icmp_pkt_v6(q, first_mp, &icmp6, sizeof (icmp6_t), NULL, mctl_present, + zoneid); } /* @@ -2074,7 +2081,7 @@ */ void icmp_unreachable_v6(queue_t *q, mblk_t *mp, uint8_t code, - boolean_t llbcast, boolean_t mcast_ok) + boolean_t llbcast, boolean_t mcast_ok, zoneid_t zoneid) { icmp6_t icmp6; boolean_t mctl_present; @@ -2091,7 +2098,8 @@ bzero(&icmp6, sizeof (icmp6_t)); icmp6.icmp6_type = ICMP6_DST_UNREACH; icmp6.icmp6_code = code; - icmp_pkt_v6(q, first_mp, &icmp6, sizeof (icmp6_t), NULL, mctl_present); + icmp_pkt_v6(q, first_mp, &icmp6, sizeof (icmp6_t), NULL, mctl_present, + zoneid); } /* @@ -2099,7 +2107,7 @@ */ static void icmp_pkt2big_v6(queue_t *q, mblk_t *mp, uint32_t mtu, - boolean_t llbcast, boolean_t mcast_ok) + boolean_t llbcast, boolean_t mcast_ok, zoneid_t zoneid) { icmp6_t icmp6; mblk_t *first_mp; @@ -2118,7 +2126,8 @@ icmp6.icmp6_code = 0; icmp6.icmp6_mtu = htonl(mtu); - icmp_pkt_v6(q, first_mp, &icmp6, sizeof (icmp6_t), NULL, mctl_present); + icmp_pkt_v6(q, first_mp, &icmp6, sizeof (icmp6_t), NULL, mctl_present, + zoneid); } /* @@ -2127,7 +2136,7 @@ */ static void icmp_param_problem_v6(queue_t *q, mblk_t *mp, uint8_t code, - uint32_t offset, boolean_t llbcast, boolean_t mcast_ok) + uint32_t offset, boolean_t llbcast, boolean_t mcast_ok, zoneid_t zoneid) { icmp6_t icmp6; boolean_t mctl_present; @@ -2145,7 +2154,8 @@ icmp6.icmp6_type = ICMP6_PARAM_PROB; icmp6.icmp6_code = code; icmp6.icmp6_pptr = htonl(offset); - icmp_pkt_v6(q, first_mp, &icmp6, sizeof (icmp6_t), NULL, mctl_present); + icmp_pkt_v6(q, first_mp, &icmp6, sizeof (icmp6_t), NULL, mctl_present, + zoneid); } /* @@ -3487,11 +3497,11 @@ switch (icmp_type) { case ICMP6_DST_UNREACH: icmp_unreachable_v6(WR(q), first_mp, icmp_code, - B_FALSE, B_FALSE); + B_FALSE, B_FALSE, zoneid); break; case ICMP6_PARAM_PROB: icmp_param_problem_v6(WR(q), first_mp, icmp_code, - nexthdr_offset, B_FALSE, B_FALSE); + nexthdr_offset, B_FALSE, B_FALSE, zoneid); break; default: #ifdef DEBUG @@ -3557,7 +3567,7 @@ } } BUMP_MIB(ill->ill_ip6_mib, ipv6InDelivers); - tcp_xmit_listeners_reset(first_mp, hdr_len); + tcp_xmit_listeners_reset(first_mp, hdr_len, zoneid); if (connp != NULL) CONN_DEC_REF(connp); return; @@ -3603,7 +3613,7 @@ return; } if (flags & TH_ACK) { - tcp_xmit_listeners_reset(first_mp, hdr_len); + tcp_xmit_listeners_reset(first_mp, hdr_len, zoneid); CONN_DEC_REF(connp); return; } @@ -5710,7 +5720,7 @@ AF_INET6, v6dstp); } icmp_unreachable_v6(WR(q), first_mp, ICMP6_DST_UNREACH_NOROUTE, - B_FALSE, B_FALSE); + B_FALSE, B_FALSE, zoneid); } /* @@ -6394,6 +6404,8 @@ int ret = 0; mblk_t *first_mp; const char *errtype; + zoneid_t zoneid; + ill_t *ill = q->q_ptr; first_mp = mp; if (mp->b_datap->db_type == M_CTL) { @@ -6531,6 +6543,9 @@ errtype = "unknown"; /* FALLTHROUGH */ opt_error: + /* Determine which zone should send error */ + zoneid = ipif_lookup_addr_zoneid_v6( + &ip6h->ip6_dst, ill); switch (IP6OPT_TYPE(opt_type)) { case IP6OPT_TYPE_SKIP: optused = 2 + optptr[1]; @@ -6547,18 +6562,26 @@ freemsg(first_mp); return (-1); case IP6OPT_TYPE_ICMP: + if (zoneid == ALL_ZONES) { + freemsg(first_mp); + return (-1); + } icmp_param_problem_v6(WR(q), first_mp, ICMP6_PARAMPROB_OPTION, (uint32_t)(optptr - (uint8_t *)ip6h), - B_FALSE, B_FALSE); + B_FALSE, B_FALSE, zoneid); return (-1); case IP6OPT_TYPE_FORCEICMP: + if (zoneid == ALL_ZONES) { + freemsg(first_mp); + return (-1); + } icmp_param_problem_v6(WR(q), first_mp, ICMP6_PARAMPROB_OPTION, (uint32_t)(optptr - (uint8_t *)ip6h), - B_FALSE, B_TRUE); + B_FALSE, B_TRUE, zoneid); return (-1); default: ASSERT(0); @@ -6571,9 +6594,15 @@ return (ret); bad_opt: - icmp_param_problem_v6(WR(q), first_mp, ICMP6_PARAMPROB_OPTION, - (uint32_t)(optptr - (uint8_t *)ip6h), - B_FALSE, B_FALSE); + /* Determine which zone should send error */ + zoneid = ipif_lookup_addr_zoneid_v6(&ip6h->ip6_dst, ill); + if (zoneid == ALL_ZONES) { + freemsg(first_mp); + } else { + icmp_param_problem_v6(WR(q), first_mp, ICMP6_PARAMPROB_OPTION, + (uint32_t)(optptr - (uint8_t *)ip6h), + B_FALSE, B_FALSE, zoneid); + } return (-1); } @@ -6605,10 +6634,11 @@ if (rth->ip6r_type != 0) { if (hada_mp != NULL) goto hada_drop; + /* Sent by forwarding path, and router is global zone */ icmp_param_problem_v6(WR(q), mp, ICMP6_PARAMPROB_HEADER, (uint32_t)((uchar_t *)&rth->ip6r_type - (uchar_t *)ip6h), - B_FALSE, B_FALSE); + B_FALSE, B_FALSE, GLOBAL_ZONEID); return; } rthdr = (ip6_rthdr0_t *)rth; @@ -6620,10 +6650,11 @@ /* An odd length is impossible */ if (hada_mp != NULL) goto hada_drop; + /* Sent by forwarding path, and router is global zone */ icmp_param_problem_v6(WR(q), mp, ICMP6_PARAMPROB_HEADER, (uint32_t)((uchar_t *)&rthdr->ip6r0_len - (uchar_t *)ip6h), - B_FALSE, B_FALSE); + B_FALSE, B_FALSE, GLOBAL_ZONEID); return; } numaddr = rthdr->ip6r0_len / 2; @@ -6631,11 +6662,12 @@ /* segleft exceeds number of addresses in routing header */ if (hada_mp != NULL) goto hada_drop; + /* Sent by forwarding path, and router is global zone */ icmp_param_problem_v6(WR(q), mp, ICMP6_PARAMPROB_HEADER, (uint32_t)((uchar_t *)&rthdr->ip6r0_segleft - (uchar_t *)ip6h), - B_FALSE, B_FALSE); + B_FALSE, B_FALSE, GLOBAL_ZONEID); return; } addrptr += (numaddr - rthdr->ip6r0_segleft); @@ -6655,8 +6687,9 @@ if (IN6_IS_ADDR_V4MAPPED(&ip6h->ip6_dst)) { if (hada_mp != NULL) goto hada_drop; + /* Sent by forwarding path, and router is global zone */ icmp_unreachable_v6(WR(q), mp, ICMP6_DST_UNREACH_NOROUTE, - B_FALSE, B_FALSE); + B_FALSE, B_FALSE, GLOBAL_ZONEID); return; } ip_rput_data_v6(q, ill, mp, ip6h, flags, hada_mp, dl_mp); @@ -7385,8 +7418,10 @@ if (ip6h->ip6_hops <= 1) { if (hada_mp != NULL) goto hada_drop; + /* Sent by forwarding path, and router is global zone */ icmp_time_exceeded_v6(WR(q), first_mp, - ICMP6_TIME_EXCEED_TRANSIT, ll_multicast, B_FALSE); + ICMP6_TIME_EXCEED_TRANSIT, ll_multicast, B_FALSE, + GLOBAL_ZONEID); return; } /* @@ -7442,8 +7477,10 @@ } if (ip6h->ip6_hops <= 1) { ip1dbg(("ip_rput_data_v6: hop limit expired.\n")); + /* Sent by forwarding path, and router is global zone */ icmp_time_exceeded_v6(WR(q), mp, - ICMP6_TIME_EXCEED_TRANSIT, ll_multicast, B_FALSE); + ICMP6_TIME_EXCEED_TRANSIT, ll_multicast, B_FALSE, + GLOBAL_ZONEID); ire_refrele(ire); return; } @@ -7475,8 +7512,9 @@ if (pkt_len > ire->ire_max_frag) { BUMP_MIB(ill->ill_ip6_mib, ipv6InTooBigErrors); + /* Sent by forwarding path, and router is global zone */ icmp_pkt2big_v6(WR(q), mp, ire->ire_max_frag, - ll_multicast, B_TRUE); + ll_multicast, B_TRUE, GLOBAL_ZONEID); ire_refrele(ire); return; } @@ -8176,7 +8214,7 @@ icmp_param_problem_v6(WR(q), first_mp, ICMP6_PARAMPROB_NEXTHEADER, prev_nexthdr_offset, - B_FALSE, B_FALSE); + B_FALSE, B_FALSE, zoneid); return; case IPPROTO_ROUTING: { @@ -8503,10 +8541,17 @@ * of eight? */ if (more_frags && (ntohs(ip6h->ip6_plen) & 7)) { + zoneid_t zoneid; + BUMP_MIB(ill->ill_ip6_mib, ipv6InHdrErrors); + zoneid = ipif_lookup_addr_zoneid_v6(&ip6h->ip6_dst, ill); + if (zoneid == ALL_ZONES) { + freemsg(mp); + return (NULL); + } icmp_param_problem_v6(WR(q), mp, ICMP6_PARAMPROB_HEADER, (uint32_t)((char *)&ip6h->ip6_plen - - (char *)ip6h), B_FALSE, B_FALSE); + (char *)ip6h), B_FALSE, B_FALSE, zoneid); return (NULL); } @@ -8522,10 +8567,17 @@ * greater than IP_MAXPACKET - the max payload size? */ if (end > IP_MAXPACKET) { + zoneid_t zoneid; + BUMP_MIB(ill->ill_ip6_mib, ipv6InHdrErrors); + zoneid = ipif_lookup_addr_zoneid_v6(&ip6h->ip6_dst, ill); + if (zoneid == ALL_ZONES) { + freemsg(mp); + return (NULL); + } icmp_param_problem_v6(WR(q), mp, ICMP6_PARAMPROB_HEADER, (uint32_t)((char *)&fraghdr->ip6f_offlg - - (char *)ip6h), B_FALSE, B_FALSE); + (char *)ip6h), B_FALSE, B_FALSE, zoneid); return (NULL); } @@ -9131,6 +9183,11 @@ * look for the best IRE match for the unspecified group to determine * the ill. * 7. For unicast: Just do an IRE lookup for the best match. + * + * arg2 is always a queue_t *. + * When that queue is an ill_t (i.e. q_next != NULL), then arg must be + * the zoneid. + * When that queue is not an ill_t, then arg must be a conn_t pointer. */ void ip_output_v6(void *arg, mblk_t *mp, void *arg2, int caller) @@ -9239,7 +9296,7 @@ if ((mlen == sizeof (ipsec_ctl_t)) && (mctltype == IPSEC_CTL)) { - ip_output(Q_TO_CONN(q), first_mp, q, caller); + ip_output(arg, first_mp, arg2, caller); return; } @@ -9313,9 +9370,11 @@ unspec_src = 0; BUMP_MIB(mibptr, ipv6OutRequests); do_outrequests = B_FALSE; + zoneid = (zoneid_t)(uintptr_t)arg; } else { connp = (conn_t *)arg; ASSERT(connp != NULL); + zoneid = connp->conn_zoneid; /* is queue flow controlled? */ if ((q->q_first || connp->conn_draining) && @@ -9394,10 +9453,13 @@ * prepended ipsec_out_t. */ if (io != NULL) { + /* + * When coming from icmp_input_v6, the zoneid might not match + * for the loopback case, because inside icmp_input_v6 the + * queue_t is a conn queue from the sending side. + */ zoneid = io->ipsec_out_zoneid; ASSERT(zoneid != ALL_ZONES); - } else { - zoneid = (connp != NULL ? connp->conn_zoneid : ALL_ZONES); } if (ip6h->ip6_nxt == IPPROTO_RAW) { @@ -9832,7 +9894,7 @@ } } ip_wput_ire_v6(q, first_mp, ire, unspec_src, cksum_request, - connp, caller, 0, ip6i_flags); + connp, caller, 0, ip6i_flags, zoneid); if (need_decref) { CONN_DEC_REF(connp); connp = NULL; @@ -10253,7 +10315,7 @@ ip_wput_ire_v6(q, first_mp, ire, unspec_src, cksum_request, connp, caller, (attach_if ? ill->ill_phyint->phyint_ifindex : 0), - ip6i_flags); + ip6i_flags, zoneid); ire_refrele(ire); if (need_decref) { CONN_DEC_REF(connp); @@ -10390,15 +10452,25 @@ } } BUMP_MIB(mibptr, ipv6OutIPv4); - (void) ip_output(connp, first_mp, q, caller); + (void) ip_output(arg, first_mp, arg2, caller); if (ill != NULL) ill_refrele(ill); } +/* + * If this is a conn_t queue, then we pass in the conn. This includes the + * zoneid. + * Otherwise, this is a message for an ill_t queue, + * in which case we use the global zoneid since those are all part of + * the global zone. + */ static void ip_wput_v6(queue_t *q, mblk_t *mp) { - ip_output_v6(Q_TO_CONN(q), mp, q, IP_WPUT); + if (CONN_Q(q)) + ip_output_v6(Q_TO_CONN(q), mp, q, IP_WPUT); + else + ip_output_v6(GLOBAL_ZONEID, mp, q, IP_WPUT); } static void @@ -10647,7 +10719,8 @@ */ static void ip_wput_ire_v6(queue_t *q, mblk_t *mp, ire_t *ire, int unspec_src, - int cksum_request, conn_t *connp, int caller, int attach_index, int flags) + int cksum_request, conn_t *connp, int caller, int attach_index, int flags, + zoneid_t zoneid) { ip6_t *ip6h; uint8_t nexthdr; @@ -10662,9 +10735,7 @@ boolean_t conn_multicast_loop; /* conn value for multicast */ boolean_t multicast_forward; /* Should we forward ? */ int max_frag; - zoneid_t zoneid; - - zoneid = (connp != NULL ? connp->conn_zoneid : ALL_ZONES); + ill = ire_to_ill(ire); first_mp = mp; multicast_forward = B_FALSE; @@ -10678,7 +10749,7 @@ * Grab the zone id now because the M_CTL can be discarded by * ip_wput_ire_parse_ipsec_out() below. */ - zoneid = io->ipsec_out_zoneid; + ASSERT(zoneid == io->ipsec_out_zoneid); ASSERT(zoneid != ALL_ZONES); ip6h = (ip6_t *)first_mp->b_cont->b_rptr; /* @@ -10723,12 +10794,24 @@ * matching route in the forwarding table. * RTF_REJECT and RTF_BLACKHOLE are handled just like * ip_newroute_v6() does. - */ - ire_t *src_ire = ire_ftable_lookup_v6(&ip6h->ip6_dst, 0, 0, 0, + * Note that IRE_LOCAL are special, since they are used + * when the zoneid doesn't match in some cases. This means that + * we need to handle ipha_src differently since ire_src_addr + * belongs to the receiving zone instead of the sending zone. + * When ip_restrict_interzone_loopback is set, then + * ire_cache_lookup_v6() ensures that IRE_LOCAL are only used + * for loopback between zones when the logical "Ethernet" would + * have looped them back. + */ + ire_t *src_ire; + + src_ire = ire_ftable_lookup_v6(&ip6h->ip6_dst, 0, 0, 0, NULL, NULL, zoneid, 0, NULL, (MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT | MATCH_IRE_RJ_BHOLE)); if (src_ire != NULL && - !(src_ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE))) { + !(src_ire->ire_flags & (RTF_REJECT | RTF_BLACKHOLE)) && + (!ip_restrict_interzone_loopback || + ire_local_same_ill_group(ire, src_ire))) { if (IN6_IS_ADDR_UNSPECIFIED(&ip6h->ip6_src) && !unspec_src) { ip6h->ip6_src = src_ire->ire_src_addr_v6; @@ -10750,14 +10833,15 @@ return; } icmp_unreachable_v6(q, first_mp, - ICMP6_DST_UNREACH_NOROUTE, B_FALSE, B_FALSE); + ICMP6_DST_UNREACH_NOROUTE, B_FALSE, B_FALSE, + zoneid); return; } } if (mp->b_datap->db_type == M_CTL || ipsec_outbound_v6_policy_present) { mp = ip_wput_ire_parse_ipsec_out(first_mp, NULL, ip6h, ire, - connp, unspec_src); + connp, unspec_src, zoneid); if (mp == NULL) { return; } @@ -11174,7 +11258,7 @@ (ire->ire_frag_flag & IPH_FRAG_HDR)) { if (connp != NULL && (flags & IP6I_DONTFRAG)) { icmp_pkt2big_v6(ire->ire_stq, first_mp, - max_frag, B_FALSE, B_TRUE); + max_frag, B_FALSE, B_TRUE, zoneid); return; } @@ -11225,7 +11309,7 @@ * generate. */ icmp_pkt2big_v6(ire->ire_stq, first_mp, - max_frag, B_FALSE, B_TRUE); + max_frag, B_FALSE, B_TRUE, zoneid); return; } if (attach_index != 0)
--- a/usr/src/uts/common/inet/ip/ip6_if.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/ip6_if.c Thu Sep 14 18:05:27 2006 -0700 @@ -144,7 +144,8 @@ for (; ill != NULL; ill = ill_next(&ctx, ill)) { GRAB_CONN_LOCK(q); mutex_enter(&ill->ill_lock); - for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { + for (ipif = ill->ill_ipif; ipif != NULL; + ipif = ipif->ipif_next) { /* Allow the ipif to be down */ if ((ipif->ipif_flags & IPIF_POINTOPOINT) && (IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6lcl_addr, @@ -216,7 +217,8 @@ } GRAB_CONN_LOCK(q); mutex_enter(&ill->ill_lock); - for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { + for (ipif = ill->ill_ipif; ipif != NULL; + ipif = ipif->ipif_next) { if (zoneid != ALL_ZONES && ipif->ipif_zoneid != zoneid && ipif->ipif_zoneid != ALL_ZONES) @@ -252,7 +254,7 @@ RELEASE_CONN_LOCK(q); } - /* Repeat once more if needed */ + /* If we already did the ptp case, then we are done */ if (ptp) { rw_exit(&ill_g_lock); if (error != NULL) @@ -264,6 +266,70 @@ } /* + * Look for an ipif with the specified address. For point-point links + * we look for matches on either the destination address and the local + * address, but we ignore the check on the local address if IPIF_UNNUMBERED + * is set. + * Matches on a specific ill if match_ill is set. + * Return the zoneid for the ipif. ALL_ZONES if none found. + */ +zoneid_t +ipif_lookup_addr_zoneid_v6(const in6_addr_t *addr, ill_t *match_ill) +{ + ipif_t *ipif; + ill_t *ill; + boolean_t ptp = B_FALSE; + ill_walk_context_t ctx; + zoneid_t zoneid; + + rw_enter(&ill_g_lock, RW_READER); + /* + * Repeat twice, first based on local addresses and + * next time for pointopoint. + */ +repeat: + ill = ILL_START_WALK_V6(&ctx); + for (; ill != NULL; ill = ill_next(&ctx, ill)) { + if (match_ill != NULL && ill != match_ill) { + continue; + } + mutex_enter(&ill->ill_lock); + for (ipif = ill->ill_ipif; ipif != NULL; + ipif = ipif->ipif_next) { + /* Allow the ipif to be down */ + if ((!ptp && (IN6_ARE_ADDR_EQUAL( + &ipif->ipif_v6lcl_addr, addr) && + (ipif->ipif_flags & IPIF_UNNUMBERED) == 0)) || + (ptp && (ipif->ipif_flags & IPIF_POINTOPOINT) && + IN6_ARE_ADDR_EQUAL(&ipif->ipif_v6pp_dst_addr, + addr)) && + !(ipif->ipif_state_flags & IPIF_CONDEMNED)) { + zoneid = ipif->ipif_zoneid; + mutex_exit(&ill->ill_lock); + rw_exit(&ill_g_lock); + /* + * If ipif_zoneid was ALL_ZONES then we have + * a trusted extensions shared IP address. + * In that case GLOBAL_ZONEID works to send. + */ + if (zoneid == ALL_ZONES) + zoneid = GLOBAL_ZONEID; + return (zoneid); + } + } + mutex_exit(&ill->ill_lock); + } + + /* If we already did the ptp case, then we are done */ + if (ptp) { + rw_exit(&ill_g_lock); + return (ALL_ZONES); + } + ptp = B_TRUE; + goto repeat; +} + +/* * Perform various checks to verify that an address would make sense as a local * interface address. This is currently only called when an attempt is made * to set a local address.
--- a/usr/src/uts/common/inet/ip/ip6_ire.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/ip6_ire.c Thu Sep 14 18:05:27 2006 -0700 @@ -1882,8 +1882,10 @@ * ire_route_lookup_v6() is avoided when * we have only one default route. */ + match_flags |= MATCH_IRE_TYPE; rire = ire_route_lookup_v6(&gw_addr_v6, - NULL, NULL, 0, ire->ire_ipif, NULL, + NULL, NULL, IRE_INTERFACE, + ire->ire_ipif, NULL, zoneid, tsl, match_flags); if (rire != NULL) { ire_refrele(rire); @@ -2152,6 +2154,19 @@ * Lookup cache. Don't return IRE_MARK_HIDDEN entries. Callers * should use ire_ctable_lookup with MATCH_IRE_MARK_HIDDEN to get * to the hidden ones. + * + * In general the zoneid has to match (where ALL_ZONES match all of them). + * But for IRE_LOCAL we also need to handle the case where L2 should + * conceptually loop back the packet. This is necessary since neither + * Ethernet drivers nor Ethernet hardware loops back packets sent to their + * own MAC address. This loopback is needed when the normal + * routes (ignoring IREs with different zoneids) would send out the packet on + * the same ill (or ill group) as the ill with which this IRE_LOCAL is + * associated. + * + * Earlier versions of this code always matched an IRE_LOCAL independently of + * the zoneid. We preserve that earlier behavior when + * ip_restrict_interzone_loopback is turned off. */ ire_t * ire_cache_lookup_v6(const in6_addr_t *addr, zoneid_t zoneid, @@ -2179,8 +2194,18 @@ } if (zoneid == ALL_ZONES || ire->ire_zoneid == zoneid || - ire->ire_zoneid == ALL_ZONES || - ire->ire_type == IRE_LOCAL) { + ire->ire_zoneid == ALL_ZONES) { + IRE_REFHOLD(ire); + rw_exit(&irb_ptr->irb_lock); + return (ire); + } + + if (ire->ire_type == IRE_LOCAL) { + if (ip_restrict_interzone_loopback && + !ire_local_ok_across_zones(ire, zoneid, + (void *)addr, tsl)) + continue; + IRE_REFHOLD(ire); rw_exit(&irb_ptr->irb_lock); return (ire);
--- a/usr/src/uts/common/inet/ip/ip_if.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/ip_if.c Thu Sep 14 18:05:27 2006 -0700 @@ -3514,6 +3514,7 @@ uint32_t hdr_length; mblk_t *send_icmp_head; mblk_t *send_icmp_head_v6; + zoneid_t zoneid; ipfb = ill->ill_frag_hash_tbl; if (ipfb == NULL) @@ -3594,18 +3595,44 @@ * above. */ while (send_icmp_head_v6 != NULL) { + ip6_t *ip6h; + mp = send_icmp_head_v6; send_icmp_head_v6 = send_icmp_head_v6->b_next; mp->b_next = NULL; - icmp_time_exceeded_v6(ill->ill_wq, mp, - ICMP_REASSEMBLY_TIME_EXCEEDED, B_FALSE, B_FALSE); + if (mp->b_datap->db_type == M_CTL) + ip6h = (ip6_t *)mp->b_cont->b_rptr; + else + ip6h = (ip6_t *)mp->b_rptr; + zoneid = ipif_lookup_addr_zoneid_v6(&ip6h->ip6_dst, + ill); + if (zoneid == ALL_ZONES) { + freemsg(mp); + } else { + icmp_time_exceeded_v6(ill->ill_wq, mp, + ICMP_REASSEMBLY_TIME_EXCEEDED, B_FALSE, + B_FALSE, zoneid); + } } while (send_icmp_head != NULL) { + ipaddr_t dst; + mp = send_icmp_head; send_icmp_head = send_icmp_head->b_next; mp->b_next = NULL; - icmp_time_exceeded(ill->ill_wq, mp, - ICMP_REASSEMBLY_TIME_EXCEEDED); + + if (mp->b_datap->db_type == M_CTL) + dst = ((ipha_t *)mp->b_cont->b_rptr)->ipha_dst; + else + dst = ((ipha_t *)mp->b_rptr)->ipha_dst; + + zoneid = ipif_lookup_addr_zoneid(dst, ill); + if (zoneid == ALL_ZONES) { + freemsg(mp); + } else { + icmp_time_exceeded(ill->ill_wq, mp, + ICMP_REASSEMBLY_TIME_EXCEEDED, zoneid); + } } } /* @@ -5136,7 +5163,8 @@ rw_enter(&ill_g_lock, RW_READER); ill = ILL_START_WALK_ALL(&ctx); for (; ill != NULL; ill = ill_next(&ctx, ill)) { - for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { + for (ipif = ill->ill_ipif; ipif != NULL; + ipif = ipif->ipif_next) { if (zoneid != GLOBAL_ZONEID && zoneid != ipif->ipif_zoneid && ipif->ipif_zoneid != ALL_ZONES) @@ -5564,7 +5592,7 @@ RELEASE_CONN_LOCK(q); } - /* Now try the ptp case */ + /* If we already did the ptp case, then we are done */ if (ptp) { rw_exit(&ill_g_lock); if (error != NULL) @@ -5576,6 +5604,68 @@ } /* + * Look for an ipif with the specified address. For point-point links + * we look for matches on either the destination address and the local + * address, but we ignore the check on the local address if IPIF_UNNUMBERED + * is set. + * Matches on a specific ill if match_ill is set. + * Return the zoneid for the ipif which matches. ALL_ZONES if no match. + */ +zoneid_t +ipif_lookup_addr_zoneid(ipaddr_t addr, ill_t *match_ill) +{ + zoneid_t zoneid; + ipif_t *ipif; + ill_t *ill; + boolean_t ptp = B_FALSE; + ill_walk_context_t ctx; + + rw_enter(&ill_g_lock, RW_READER); + /* + * Repeat twice, first based on local addresses and + * next time for pointopoint. + */ +repeat: + ill = ILL_START_WALK_V4(&ctx); + for (; ill != NULL; ill = ill_next(&ctx, ill)) { + if (match_ill != NULL && ill != match_ill) { + continue; + } + mutex_enter(&ill->ill_lock); + for (ipif = ill->ill_ipif; ipif != NULL; + ipif = ipif->ipif_next) { + /* Allow the ipif to be down */ + if ((!ptp && (ipif->ipif_lcl_addr == addr) && + ((ipif->ipif_flags & IPIF_UNNUMBERED) == 0)) || + (ptp && (ipif->ipif_flags & IPIF_POINTOPOINT) && + (ipif->ipif_pp_dst_addr == addr)) && + !(ipif->ipif_state_flags & IPIF_CONDEMNED)) { + zoneid = ipif->ipif_zoneid; + mutex_exit(&ill->ill_lock); + rw_exit(&ill_g_lock); + /* + * If ipif_zoneid was ALL_ZONES then we have + * a trusted extensions shared IP address. + * In that case GLOBAL_ZONEID works to send. + */ + if (zoneid == ALL_ZONES) + zoneid = GLOBAL_ZONEID; + return (zoneid); + } + } + mutex_exit(&ill->ill_lock); + } + + /* If we already did the ptp case, then we are done */ + if (ptp) { + rw_exit(&ill_g_lock); + return (ALL_ZONES); + } + ptp = B_TRUE; + goto repeat; +} + +/* * Look for an ipif that matches the specified remote address i.e. the * ipif that would receive the specified packet. * First look for directly connected interfaces and then do a recursive @@ -8201,7 +8291,7 @@ rw_enter(&ill_g_lock, RW_READER); ill = ILL_START_WALK_V4(&ctx); for (; ill != NULL; ill = ill_next(&ctx, ill)) { - for (ipif = ill->ill_ipif; ipif; + for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) { if (zoneid != ipif->ipif_zoneid && ipif->ipif_zoneid != ALL_ZONES) @@ -10364,7 +10454,8 @@ if (found_sep && orig_ifindex == 0) { /* Now see if there is an IPIF with this unit number. */ - for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { + for (ipif = ill->ill_ipif; ipif != NULL; + ipif = ipif->ipif_next) { if (ipif->ipif_id == id) { err = EEXIST; goto done; @@ -18560,7 +18651,7 @@ GRAB_CONN_LOCK(q); mutex_enter(&ill->ill_lock); /* Now see if there is an IPIF with this unit number. */ - for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { + for (ipif = ill->ill_ipif; ipif != NULL; ipif = ipif->ipif_next) { if (ipif->ipif_id == id) { if (zoneid != ALL_ZONES && zoneid != ipif->ipif_zoneid &&
--- a/usr/src/uts/common/inet/ip/ip_ire.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/ip_ire.c Thu Sep 14 18:05:27 2006 -0700 @@ -1055,12 +1055,20 @@ boolean_t is_secure; uint_t ifindex; ill_t *ill; + zoneid_t zoneid = ire->ire_zoneid; ASSERT(ire->ire_ipversion == IPV4_VERSION); + ASSERT(!(ire->ire_type & IRE_LOCAL)); /* Has different ire_zoneid */ ipsec_mp = pkt; is_secure = (pkt->b_datap->db_type == M_CTL); - if (is_secure) + if (is_secure) { + ipsec_out_t *io; + pkt = pkt->b_cont; + io = (ipsec_out_t *)ipsec_mp->b_rptr; + if (io->ipsec_out_type == IPSEC_OUT) + zoneid = io->ipsec_out_zoneid; + } /* If the packet originated externally then */ if (pkt->b_prev) { @@ -1132,7 +1140,13 @@ if (ipha->ipha_dst != ire->ire_addr && !(ire->ire_marks & IRE_MARK_NOADD)) { ire_refrele(ire); /* Held in ire_add */ - (void) ip_output(Q_TO_CONN(q), ipsec_mp, q, IRE_SEND); + if (CONN_Q(q)) { + (void) ip_output(Q_TO_CONN(q), ipsec_mp, q, + IRE_SEND); + } else { + (void) ip_output((void *)(uintptr_t)zoneid, + ipsec_mp, q, IRE_SEND); + } } else { if (is_secure) { ipsec_out_t *oi; @@ -1158,14 +1172,14 @@ * ip_wput_ire. */ ip_wput_ire(q, ipsec_mp, ire, NULL, - IRE_SEND); + IRE_SEND, zoneid); } } else { /* * IRE_REFRELE will be done in ip_wput_ire. */ ip_wput_ire(q, ipsec_mp, ire, NULL, - IRE_SEND); + IRE_SEND, zoneid); } } /* @@ -1213,12 +1227,19 @@ mblk_t *ipsec_mp; boolean_t secure; uint_t ifindex; + zoneid_t zoneid = ire->ire_zoneid; ASSERT(ire->ire_ipversion == IPV6_VERSION); + ASSERT(!(ire->ire_type & IRE_LOCAL)); /* Has different ire_zoneid */ if (pkt->b_datap->db_type == M_CTL) { + ipsec_out_t *io; + ipsec_mp = pkt; pkt = pkt->b_cont; secure = B_TRUE; + io = (ipsec_out_t *)ipsec_mp->b_rptr; + if (io->ipsec_out_type == IPSEC_OUT) + zoneid = io->ipsec_out_zoneid; } else { ipsec_mp = pkt; secure = B_FALSE; @@ -1284,16 +1305,27 @@ ip_wput_ipsec_out_v6(q, ipsec_mp, ip6h, NULL, NULL); } else { - (void) ip_output_v6(Q_TO_CONN(q), ipsec_mp, - q, IRE_SEND); + if (CONN_Q(q)) { + (void) ip_output_v6(Q_TO_CONN(q), + ipsec_mp, q, IRE_SEND); + } else { + (void) ip_output_v6( + (void *)(uintptr_t)zoneid, + ipsec_mp, q, IRE_SEND); + } } } else { /* * Send packets through ip_output_v6 so that any * ip6_info header can be processed again. */ - (void) ip_output_v6(Q_TO_CONN(q), ipsec_mp, q, - IRE_SEND); + if (CONN_Q(q)) { + (void) ip_output_v6(Q_TO_CONN(q), ipsec_mp, q, + IRE_SEND); + } else { + (void) ip_output_v6((void *)(uintptr_t)zoneid, + ipsec_mp, q, IRE_SEND); + } } /* * Special code to support sending a single packet with @@ -1566,7 +1598,8 @@ * ire->ire_zoneid. */ ip_newroute(q, mp, ipha->ipha_dst, 0, - (CONN_Q(q) ? Q_TO_CONN(q) : NULL)); + (CONN_Q(q) ? Q_TO_CONN(q) : NULL), + ire->ire_zoneid); } else { ASSERT(ire->ire_ipversion == IPV6_VERSION); ip_newroute_v6(q, mp, &ip6h->ip6_dst, NULL, @@ -2656,28 +2689,30 @@ /* * Match all default routes from the global zone, irrespective - * of reachability. + * of reachability. For a non-global zone only match those + * where ire_gateway_addr has a IRE_INTERFACE for the zoneid. */ if (ire->ire_type == IRE_DEFAULT && zoneid != GLOBAL_ZONEID) { int ire_match_flags = 0; in6_addr_t gw_addr_v6; ire_t *rire; + ire_match_flags |= MATCH_IRE_TYPE; if (ire->ire_ipif != NULL) { ire_match_flags |= MATCH_IRE_ILL_GROUP; } if (ire->ire_ipversion == IPV4_VERSION) { rire = ire_route_lookup(ire->ire_gateway_addr, - 0, 0, 0, ire->ire_ipif, NULL, zoneid, NULL, - ire_match_flags); + 0, 0, IRE_INTERFACE, ire->ire_ipif, NULL, + zoneid, NULL, ire_match_flags); } else { ASSERT(ire->ire_ipversion == IPV6_VERSION); mutex_enter(&ire->ire_lock); gw_addr_v6 = ire->ire_gateway_addr_v6; mutex_exit(&ire->ire_lock); rire = ire_route_lookup_v6(&gw_addr_v6, - NULL, NULL, 0, ire->ire_ipif, NULL, zoneid, - NULL, ire_match_flags); + NULL, NULL, IRE_INTERFACE, ire->ire_ipif, + NULL, zoneid, NULL, ire_match_flags); } if (rire == NULL) { return (B_FALSE); @@ -4777,9 +4812,85 @@ } /* + * Check whether the IRE_LOCAL and the IRE potentially used to transmit + * (could be an IRE_CACHE, IRE_BROADCAST, or IRE_INTERFACE) are part of + * the same ill group. + */ +boolean_t +ire_local_same_ill_group(ire_t *ire_local, ire_t *xmit_ire) +{ + ill_t *recv_ill, *xmit_ill; + ill_group_t *recv_group, *xmit_group; + + ASSERT(ire_local->ire_type == IRE_LOCAL); + ASSERT(ire_local->ire_rfq != NULL); + ASSERT(xmit_ire->ire_type & (IRE_CACHE|IRE_BROADCAST|IRE_INTERFACE)); + ASSERT(xmit_ire->ire_stq != NULL); + ASSERT(xmit_ire->ire_ipif != NULL); + + recv_ill = ire_local->ire_rfq->q_ptr; + xmit_ill = xmit_ire->ire_stq->q_ptr; + + if (recv_ill == xmit_ill) + return (B_TRUE); + + recv_group = recv_ill->ill_group; + xmit_group = xmit_ill->ill_group; + + if (recv_group != NULL && recv_group == xmit_group) + return (B_TRUE); + + return (B_FALSE); +} + +/* + * Check if the IRE_LOCAL uses the same ill (group) as another route would use. + */ +boolean_t +ire_local_ok_across_zones(ire_t *ire_local, zoneid_t zoneid, void *addr, + const ts_label_t *tsl) +{ + ire_t *alt_ire; + boolean_t rval; + + if (ire_local->ire_ipversion == IPV4_VERSION) { + alt_ire = ire_ftable_lookup(*((ipaddr_t *)addr), 0, 0, 0, NULL, + NULL, zoneid, 0, tsl, + MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT | + MATCH_IRE_RJ_BHOLE); + } else { + alt_ire = ire_ftable_lookup_v6((in6_addr_t *)addr, NULL, NULL, + 0, NULL, NULL, zoneid, 0, tsl, + MATCH_IRE_RECURSIVE | MATCH_IRE_DEFAULT | + MATCH_IRE_RJ_BHOLE); + } + + if (alt_ire == NULL) + return (B_FALSE); + + rval = ire_local_same_ill_group(ire_local, alt_ire); + + ire_refrele(alt_ire); + return (rval); +} + +/* * Lookup cache. Don't return IRE_MARK_HIDDEN entries. Callers * should use ire_ctable_lookup with MATCH_IRE_MARK_HIDDEN to get * to the hidden ones. + * + * In general the zoneid has to match (where ALL_ZONES match all of them). + * But for IRE_LOCAL we also need to handle the case where L2 should + * conceptually loop back the packet. This is necessary since neither + * Ethernet drivers nor Ethernet hardware loops back packets sent to their + * own MAC address. This loopback is needed when the normal + * routes (ignoring IREs with different zoneids) would send out the packet on + * the same ill (or ill group) as the ill with which this IRE_LOCAL is + * associated. + * + * Earlier versions of this code always matched an IRE_LOCAL independently of + * the zoneid. We preserve that earlier behavior when + * ip_restrict_interzone_loopback is turned off. */ ire_t * ire_cache_lookup(ipaddr_t addr, zoneid_t zoneid, const ts_label_t *tsl) @@ -4807,8 +4918,18 @@ } if (zoneid == ALL_ZONES || ire->ire_zoneid == zoneid || - ire->ire_zoneid == ALL_ZONES || - ire->ire_type == IRE_LOCAL) { + ire->ire_zoneid == ALL_ZONES) { + IRE_REFHOLD(ire); + rw_exit(&irb_ptr->irb_lock); + return (ire); + } + + if (ire->ire_type == IRE_LOCAL) { + if (ip_restrict_interzone_loopback && + !ire_local_ok_across_zones(ire, zoneid, + &addr, tsl)) + continue; + IRE_REFHOLD(ire); rw_exit(&irb_ptr->irb_lock); return (ire);
--- a/usr/src/uts/common/inet/ip/ip_ndp.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/ip_ndp.c Thu Sep 14 18:05:27 2006 -0700 @@ -56,6 +56,7 @@ #include <inet/mib2.h> #include <inet/nd.h> #include <inet/ip.h> +#include <inet/ip_impl.h> #include <inet/ip_if.h> #include <inet/ip_ire.h> #include <inet/ip_rts.h> @@ -1023,37 +1024,6 @@ } /* - * Prepend the zoneid using an ipsec_out_t for later use by functions like - * ip_rput_v6() after neighbor discovery has taken place. If the message - * block already has a M_CTL at the front of it, then simply set the zoneid - * appropriately. - */ -static mblk_t * -ndp_prepend_zone(mblk_t *mp, zoneid_t zoneid) -{ - mblk_t *first_mp; - ipsec_out_t *io; - - ASSERT(zoneid != ALL_ZONES); - if (mp->b_datap->db_type == M_CTL) { - io = (ipsec_out_t *)mp->b_rptr; - ASSERT(io->ipsec_out_type == IPSEC_OUT); - io->ipsec_out_zoneid = zoneid; - return (mp); - } - - first_mp = ipsec_alloc_ipsec_out(); - if (first_mp == NULL) - return (NULL); - io = (ipsec_out_t *)first_mp->b_rptr; - /* This is not a secure packet */ - io->ipsec_out_secure = B_FALSE; - io->ipsec_out_zoneid = zoneid; - first_mp->b_cont = mp; - return (first_mp); -} - -/* * Process resolve requests. Handles both mapped entries * as well as cases that needs to be send out on the wire. * Lookup a NCE for a given IRE. Regardless of whether one exists @@ -1111,7 +1081,7 @@ NCE_REFRELE(nce); return (0); } - mp_nce = ndp_prepend_zone(mp, zoneid); + mp_nce = ip_prepend_zoneid(mp, zoneid); if (mp_nce == NULL) { /* The caller will free mp */ mutex_exit(&nce->nce_lock); @@ -1139,7 +1109,7 @@ /* Resolution in progress just queue the packet */ mutex_enter(&nce->nce_lock); if (nce->nce_state == ND_INCOMPLETE) { - mp_nce = ndp_prepend_zone(mp, zoneid); + mp_nce = ip_prepend_zoneid(mp, zoneid); if (mp_nce == NULL) { err = ENOMEM; } else { @@ -3092,7 +3062,7 @@ */ (void) ip_hdr_complete_v6((ip6_t *)mp->b_rptr, zoneid); icmp_unreachable_v6(nce->nce_ill->ill_wq, first_mp, - ICMP6_DST_UNREACH_ADDR, B_FALSE, B_FALSE); + ICMP6_DST_UNREACH_ADDR, B_FALSE, B_FALSE, zoneid); mp = nxt_mp; } } @@ -3674,7 +3644,7 @@ (void) ip_hdr_complete((ipha_t *)mp->b_rptr, zoneid); ip3dbg(("arp_resolv_failed: Calling icmp_unreachable\n")); icmp_unreachable(nce->nce_ill->ill_wq, first_mp, - ICMP_HOST_UNREACHABLE); + ICMP_HOST_UNREACHABLE, zoneid); mp = nxt_mp; } }
--- a/usr/src/uts/common/inet/ip/ip_rts.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/ip_rts.c Thu Sep 14 18:05:27 2006 -0700 @@ -280,11 +280,13 @@ tsol_gcgrp_t *gcgrp = NULL; tsol_gc_t *gc = NULL; ts_label_t *tsl = NULL; + zoneid_t zoneid; ip1dbg(("ip_rts_request: mp is %x\n", DB_TYPE(mp))); ASSERT(CONN_Q(q)); connp = Q_TO_CONN(q); + zoneid = connp->conn_zoneid; ASSERT(mp->b_cont != NULL); /* ioc_mp holds mp */ @@ -771,12 +773,25 @@ case AF_INET: if (net_mask == IP_HOST_MASK) { ire = ire_ctable_lookup(dst_addr, gw_addr, - IRE_LOCAL | IRE_LOOPBACK, NULL, ALL_ZONES, + IRE_LOCAL | IRE_LOOPBACK, NULL, zoneid, tsl, match_flags_local); + /* + * If we found an IRE_LOCAL, make sure + * it is one that would be used by this + * zone to send packets. + */ + if (ire != NULL && + ire->ire_type == IRE_LOCAL && + ip_restrict_interzone_loopback && + !ire_local_ok_across_zones(ire, + zoneid, &dst_addr, tsl)) { + ire_refrele(ire); + ire = NULL; + } } if (ire == NULL) { ire = ire_ftable_lookup(dst_addr, net_mask, - gw_addr, 0, ipif, &sire, ALL_ZONES, 0, + gw_addr, 0, ipif, &sire, zoneid, 0, tsl, match_flags); } break; @@ -784,12 +799,25 @@ if (IN6_ARE_ADDR_EQUAL(&net_mask_v6, &ipv6_all_ones)) { ire = ire_ctable_lookup_v6(&dst_addr_v6, &gw_addr_v6, IRE_LOCAL | IRE_LOOPBACK, NULL, - ALL_ZONES, tsl, match_flags_local); + zoneid, tsl, match_flags_local); + /* + * If we found an IRE_LOCAL, make sure + * it is one that would be used by this + * zone to send packets. + */ + if (ire != NULL && + ire->ire_type == IRE_LOCAL && + ip_restrict_interzone_loopback && + !ire_local_ok_across_zones(ire, + zoneid, (void *)&dst_addr_v6, tsl)) { + ire_refrele(ire); + ire = NULL; + } } if (ire == NULL) { ire = ire_ftable_lookup_v6(&dst_addr_v6, &net_mask_v6, &gw_addr_v6, 0, ipif, &sire, - ALL_ZONES, 0, tsl, match_flags); + zoneid, 0, tsl, match_flags); } break; }
--- a/usr/src/uts/common/inet/ip/spd.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip/spd.c Thu Sep 14 18:05:27 2006 -0700 @@ -3973,7 +3973,7 @@ */ mblk_t * ip_wput_attach_policy(mblk_t *ipsec_mp, ipha_t *ipha, ip6_t *ip6h, ire_t *ire, - conn_t *connp, boolean_t unspec_src) + conn_t *connp, boolean_t unspec_src, zoneid_t zoneid) { mblk_t *mp; ipsec_out_t *io = NULL; @@ -4150,17 +4150,10 @@ io->ipsec_out_ill_index = ill_index; io->ipsec_out_dontroute = conn_dontroutex; io->ipsec_out_multicast_loop = conn_multicast_loopx; - /* - * When conn is non-NULL, the zoneid is set by ipsec_init_ipsec_out(). - * Otherwise set the zoneid based on the ire. - */ - if (connp == NULL) { - zoneid_t zoneid = ire->ire_zoneid; - - if (zoneid == ALL_ZONES) - zoneid = GLOBAL_ZONEID; - io->ipsec_out_zoneid = zoneid; - } + + if (zoneid == ALL_ZONES) + zoneid = GLOBAL_ZONEID; + io->ipsec_out_zoneid = zoneid; return (ipsec_mp); }
--- a/usr/src/uts/common/inet/ip6.h Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip6.h Thu Sep 14 18:05:27 2006 -0700 @@ -347,9 +347,9 @@ extern char *inet_ntop(int, const void *, char *, int); extern int inet_pton(int, char *, void *); extern void icmp_time_exceeded_v6(queue_t *, mblk_t *, uint8_t, - boolean_t, boolean_t); + boolean_t, boolean_t, zoneid_t); extern void icmp_unreachable_v6(queue_t *, mblk_t *, uint8_t, - boolean_t, boolean_t); + boolean_t, boolean_t, zoneid_t); extern void icmp_inbound_error_fanout_v6(queue_t *, mblk_t *, ip6_t *, icmp6_t *, ill_t *, boolean_t, zoneid_t); extern boolean_t conn_wantpacket_v6(conn_t *, ill_t *, ip6_t *, int, zoneid_t);
--- a/usr/src/uts/common/inet/ip_if.h Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip_if.h Thu Sep 14 18:05:27 2006 -0700 @@ -210,6 +210,8 @@ mblk_t *, ipsq_func_t, int *); extern ipif_t *ipif_lookup_addr_v6(const in6_addr_t *, ill_t *, zoneid_t, queue_t *, mblk_t *, ipsq_func_t, int *); +extern zoneid_t ipif_lookup_addr_zoneid(ipaddr_t, ill_t *); +extern zoneid_t ipif_lookup_addr_zoneid_v6(const in6_addr_t *, ill_t *); extern ipif_t *ipif_lookup_group(ipaddr_t, zoneid_t); extern ipif_t *ipif_lookup_group_v6(const in6_addr_t *, zoneid_t); extern ipif_t *ipif_lookup_interface(ipaddr_t, ipaddr_t,
--- a/usr/src/uts/common/inet/ip_impl.h Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip_impl.h Thu Sep 14 18:05:27 2006 -0700 @@ -491,6 +491,7 @@ extern int ip_wput_frag_mdt_min; extern boolean_t ip_can_frag_mdt(mblk_t *, ssize_t, ssize_t); +extern mblk_t *ip_prepend_zoneid(mblk_t *, zoneid_t); #endif /* _KERNEL */
--- a/usr/src/uts/common/inet/ip_ire.h Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ip_ire.h Thu Sep 14 18:05:27 2006 -0700 @@ -315,6 +315,10 @@ extern ire_t *ire_ihandle_lookup_offlink(ire_t *, ire_t *); extern ire_t *ire_ihandle_lookup_offlink_v6(ire_t *, ire_t *); +extern boolean_t ire_local_same_ill_group(ire_t *, ire_t *); +extern boolean_t ire_local_ok_across_zones(ire_t *, zoneid_t, void *, + const struct ts_label_s *tsl); + extern ire_t *ire_lookup_local(zoneid_t); extern ire_t *ire_lookup_local_v6(zoneid_t);
--- a/usr/src/uts/common/inet/ipsec_impl.h Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/ipsec_impl.h Thu Sep 14 18:05:27 2006 -0700 @@ -588,9 +588,9 @@ extern void ipsec_actvec_free(ipsec_act_t *, uint_t); extern mblk_t *ipsec_construct_inverse_acquire(sadb_msg_t *, sadb_ext_t **); extern mblk_t *ip_wput_attach_policy(mblk_t *, ipha_t *, ip6_t *, ire_t *, - conn_t *, boolean_t); + conn_t *, boolean_t, zoneid_t); extern mblk_t *ip_wput_ire_parse_ipsec_out(mblk_t *, ipha_t *, ip6_t *, - ire_t *, conn_t *, boolean_t); + ire_t *, conn_t *, boolean_t, zoneid_t); extern ipsec_policy_t *ipsec_find_policy(int, conn_t *, struct ipsec_out_s *, ipsec_selector_t *); extern ipsid_t *ipsid_lookup(int, char *);
--- a/usr/src/uts/common/inet/tcp.h Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/tcp.h Thu Sep 14 18:05:27 2006 -0700 @@ -558,7 +558,8 @@ extern void tcp_free(tcp_t *tcp); extern void tcp_ddi_init(void); extern void tcp_ddi_destroy(void); -extern void tcp_xmit_listeners_reset(mblk_t *mp, uint_t ip_hdr_len); +extern void tcp_xmit_listeners_reset(mblk_t *mp, uint_t ip_hdr_len, + zoneid_t zoneid); extern void tcp_conn_request(void *arg, mblk_t *mp, void *arg2); extern void tcp_conn_request_unbound(void *arg, mblk_t *mp, void *arg2); extern void tcp_input(void *arg, mblk_t *mp, void *arg2);
--- a/usr/src/uts/common/inet/tcp/tcp.c Thu Sep 14 15:51:02 2006 -0700 +++ b/usr/src/uts/common/inet/tcp/tcp.c Thu Sep 14 18:05:27 2006 -0700 @@ -924,7 +924,8 @@ static void tcp_ack_timer(void *arg); static mblk_t *tcp_ack_mp(tcp_t *tcp); static void tcp_xmit_early_reset(char *str, mblk_t *mp, - uint32_t seq, uint32_t ack, int ctl, uint_t ip_hdr_len); + uint32_t seq, uint32_t ack, int ctl, uint_t ip_hdr_len, + zoneid_t zoneid); static void tcp_xmit_ctl(char *str, tcp_t *tcp, uint32_t seq, uint32_t ack, int ctl); static tcp_hsp_t *tcp_hsp_lookup(ipaddr_t addr); @@ -21432,7 +21433,7 @@ */ static void tcp_xmit_early_reset(char *str, mblk_t *mp, uint32_t seq, - uint32_t ack, int ctl, uint_t ip_hdr_len) + uint32_t ack, int ctl, uint_t ip_hdr_len, zoneid_t zoneid) { ipha_t *ipha = NULL; ip6_t *ip6h = NULL; @@ -21449,6 +21450,7 @@ queue_t *q = tcp_g_q; tcp_t *tcp = Q_TO_TCP(q); cred_t *cr; + mblk_t *nmp; if (!tcp_send_rst_chk()) { tcp_rst_unsent++; @@ -21610,6 +21612,16 @@ return; } } + if (zoneid == ALL_ZONES) + zoneid = GLOBAL_ZONEID; + + /* Add the zoneid so ip_output routes it properly */ + if ((nmp = ip_prepend_zoneid(ipsec_mp, zoneid)) == NULL) { + freemsg(ipsec_mp); + return; + } + ipsec_mp = nmp; + /* * NOTE: one might consider tracing a TCP packet here, but * this function has no active TCP state and no tcp structure @@ -21750,7 +21762,7 @@ * RST. */ void -tcp_xmit_listeners_reset(mblk_t *mp, uint_t ip_hdr_len) +tcp_xmit_listeners_reset(mblk_t *mp, uint_t ip_hdr_len, zoneid_t zoneid) { uchar_t *rptr; uint32_t seg_len; @@ -21829,7 +21841,7 @@ freemsg(ipsec_mp); } else if (flags & TH_ACK) { tcp_xmit_early_reset("no tcp, reset", - ipsec_mp, seg_ack, 0, TH_RST, ip_hdr_len); + ipsec_mp, seg_ack, 0, TH_RST, ip_hdr_len, zoneid); } else { if (flags & TH_SYN) { seg_len++; @@ -21848,7 +21860,7 @@ tcp_xmit_early_reset("no tcp, reset/ack", ipsec_mp, 0, seg_seq + seg_len, - TH_RST | TH_ACK, ip_hdr_len); + TH_RST | TH_ACK, ip_hdr_len, zoneid); } }