-#endif
-
-#if IPFIREWALL_FORWARD
- /* Here we check dst to make sure it's directly reachable on the
- * interface we previously thought it was.
- * If it isn't (which may be likely in some situations) we have
- * to re-route it (ie, find a route for the next-hop and the
- * associated interface) and set them here. This is nested
- * forwarding which in most cases is undesirable, except where
- * such control is nigh impossible. So we do it here.
- * And I'm babbling.
- */
- if (off == 0 && old != dst) {
- struct in_ifaddr *ia_fw;
-
- /* It's changed... */
- /* There must be a better way to do this next line... */
- static struct route sro_fwd, *ro_fwd = &sro_fwd;
-#if IPFIREWALL_FORWARD_DEBUG
- printf("IPFIREWALL_FORWARD: New dst ip: ");
- print_ip(dst->sin_addr);
- printf("\n");
-#endif
- /*
- * We need to figure out if we have been forwarded
- * to a local socket. If so then we should somehow
- * "loop back" to ip_input, and get directed to the
- * PCB as if we had received this packet. This is
- * because it may be dificult to identify the packets
- * you want to forward until they are being output
- * and have selected an interface. (e.g. locally
- * initiated packets) If we used the loopback inteface,
- * we would not be able to control what happens
- * as the packet runs through ip_input() as
- * it is done through a ISR.
- */
- TAILQ_FOREACH(ia_fw, &in_ifaddrhead, ia_link) {
- /*
- * If the addr to forward to is one
- * of ours, we pretend to
- * be the destination for this packet.
- */
- if (IA_SIN(ia_fw)->sin_addr.s_addr ==
- dst->sin_addr.s_addr)
- break;
- }
- if (ia) {
- /* tell ip_input "dont filter" */
- struct m_tag *fwd_tag;
- struct ip_fwd_tag *ipfwd_tag;
-
- fwd_tag = m_tag_alloc(KERNEL_MODULE_TAG_ID, KERNEL_TAG_TYPE_IPFORWARD,
- sizeof(struct sockaddr_in), M_NOWAIT);
- if (fwd_tag == NULL) {
- error = ENOBUFS;
- goto bad;
- }
-
- ipfwd_tag = (struct ip_fwd_tag *)(fwd_tag+1);
- ipfwd_tag->next_hop = args.next_hop;
-
- m_tag_prepend(m, fwd_tag);
-
- if (m->m_pkthdr.rcvif == NULL)
- m->m_pkthdr.rcvif = ifunit("lo0");
- if ((~IF_HWASSIST_CSUM_FLAGS(m->m_pkthdr.rcvif->if_hwassist) &
- m->m_pkthdr.csum_flags) == 0) {
- if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
- m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
- m->m_pkthdr.csum_flags |=
- CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
- m->m_pkthdr.csum_data = 0xffff;
- }
- m->m_pkthdr.csum_flags |=
- CSUM_IP_CHECKED | CSUM_IP_VALID;
- }
- else if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) {
- in_delayed_cksum(m);
- m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA;
- ip->ip_sum = in_cksum(m, hlen);
- }
- HTONS(ip->ip_len);
- HTONS(ip->ip_off);
-
- lck_mtx_unlock(ip_mutex);
-
- /* we need to call dlil_output to run filters
- * and resync to avoid recursion loops.
- */
- if (lo_ifp) {
- dlil_output(lo_ifp, PF_INET, m, 0, (struct sockaddr *)dst, 0);
- }
- else {
- printf("ip_output: no loopback ifp for forwarding!!!\n");
- }
- goto done;
- }
- /* Some of the logic for this was
- * nicked from above.
- *
- * This rewrites the cached route in a local PCB.
- * Is this what we want to do?
- */
- bcopy(dst, &ro_fwd->ro_dst, sizeof(*dst));
-
- ro_fwd->ro_rt = 0;
- rtalloc_ign(ro_fwd, RTF_PRCLONING);
-
- if (ro_fwd->ro_rt == 0) {
- ipstat.ips_noroute++;
- error = EHOSTUNREACH;
- goto bad;
- }
-
- ia_fw = ifatoia(ro_fwd->ro_rt->rt_ifa);
- ifp = ro_fwd->ro_rt->rt_ifp;
- ro_fwd->ro_rt->rt_use++;
- if (ro_fwd->ro_rt->rt_flags & RTF_GATEWAY)
- dst = (struct sockaddr_in *)ro_fwd->ro_rt->rt_gateway;
- if (ro_fwd->ro_rt->rt_flags & RTF_HOST)
- isbroadcast =
- (ro_fwd->ro_rt->rt_flags & RTF_BROADCAST);
- else
- isbroadcast = in_broadcast(dst->sin_addr, ifp);
- rtfree(ro->ro_rt);
- ro->ro_rt = ro_fwd->ro_rt;
- dst = (struct sockaddr_in *)&ro_fwd->ro_dst;
-
- /*
- * If we added a default src ip earlier,
- * which would have been gotten from the-then
- * interface, do it again, from the new one.
- */
- if (fwd_rewrite_src)
- ip->ip_src = IA_SIN(ia_fw)->sin_addr;
- goto pass ;
- }
-#endif /* IPFIREWALL_FORWARD */
- /*
- * if we get here, none of the above matches, and
- * we have to drop the pkt
- */
- m_freem(m);
- error = EACCES; /* not sure this is the right error msg */
- lck_mtx_unlock(ip_mutex);
- goto done;