📄 ip_input.c
字号:
case IPOPT_TS: code = cp - (u_char *)ip; ipt = (struct ip_timestamp *)cp; if (ipt->ipt_ptr < 5 || ipt->ipt_len < 5) goto bad; if (ipt->ipt_ptr - 1 + sizeof(n_time) > ipt->ipt_len) { if (++ipt->ipt_oflw == 0) goto bad; break; } sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); switch (ipt->ipt_flg) { case IPOPT_TS_TSONLY: break; case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr - 1 + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; ipaddr.sin_addr = dst; ia = (INA)ifaof_ifpforaddr((SA)&ipaddr, m->m_pkthdr.rcvif); if (ia == 0) continue; bcopy((caddr_t)&ia->ia_addr.sin_addr, (caddr_t)sin, sizeof(struct in_addr)); ipt->ipt_ptr += sizeof(struct in_addr); break; case IPOPT_TS_PRESPEC: if (ipt->ipt_ptr - 1 + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; bcopy((caddr_t)sin, (caddr_t)&ipaddr.sin_addr, sizeof(struct in_addr)); if (ifa_ifwithaddr((SA)&ipaddr) == 0) continue; ipt->ipt_ptr += sizeof(struct in_addr); break; default: goto bad; } ntime = iptime(); bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, sizeof(n_time)); ipt->ipt_ptr += sizeof(n_time); } }#ifndef PMON if (forward && ipforwarding) { ip_forward(m, 1); return (1); }#endif return (0);bad: ip->ip_len -= ip->ip_hl << 2; /* XXX icmp_error adds in hdr length */ HTONS(ip->ip_len); /* XXX because ip_input changed these three */ HTONS(ip->ip_id); HTONS(ip->ip_off); icmp_error(m, type, code, 0, 0); ipstat.ips_badoptions++; return (1);}/* * Given address of next destination (final or next hop), * return internet address info of interface to be used to get there. */struct in_ifaddr *ip_rtaddr(dst) struct in_addr dst;{ register struct sockaddr_in *sin; sin = satosin(&ipforward_rt.ro_dst); if (ipforward_rt.ro_rt == 0 || dst.s_addr != sin->sin_addr.s_addr) { if (ipforward_rt.ro_rt) { RTFREE(ipforward_rt.ro_rt); ipforward_rt.ro_rt = 0; } sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_addr = dst; rtalloc(&ipforward_rt); } if (ipforward_rt.ro_rt == 0) return ((struct in_ifaddr *)0); return (ifatoia(ipforward_rt.ro_rt->rt_ifa));}/* * Save incoming source route for use in replies, * to be picked up later by ip_srcroute if the receiver is interested. */voidsave_rte(option, dst) u_char *option; struct in_addr dst;{ unsigned olen; olen = option[IPOPT_OLEN];#ifdef DIAGNOSTIC if (ipprintfs) printf("save_rte: olen %d\n", olen);#endif if (olen > sizeof(ip_srcrt) - (1 + sizeof(dst))) return; bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen); ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); ip_srcrt.dst = dst;}#ifndef PMON/* * Check whether we do proxy ARP for this address and we point to ourselves. * Code shamelessly copied from arplookup(). */static intip_weadvertise(addr) u_int32_t addr;{ register struct rtentry *rt; register struct ifnet *ifp; register struct ifaddr *ifa; struct sockaddr_inarp sin; sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr.s_addr = addr; sin.sin_other = SIN_PROXY; rt = rtalloc1(sintosa(&sin), 0); if (rt == 0) return 0; RTFREE(rt); if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 || rt->rt_gateway->sa_family != AF_LINK) return 0; for (ifp = ifnet.tqh_first; ifp != 0; ifp = ifp->if_list.tqe_next) for (ifa = ifp->if_addrlist.tqh_first; ifa != 0; ifa = ifa->ifa_list.tqe_next) { if (ifa->ifa_addr->sa_family != rt->rt_gateway->sa_family) continue; if (!bcmp(LLADDR((struct sockaddr_dl *)ifa->ifa_addr), LLADDR((struct sockaddr_dl *)rt->rt_gateway), ETHER_ADDR_LEN)) return 1; } return 0;}#endif/* * Retrieve incoming source route for use in replies, * in the same form used by setsockopt. * The first hop is placed before the options, will be removed later. */struct mbuf *ip_srcroute(){ register struct in_addr *p, *q; register struct mbuf *m; if (ip_nhops == 0) return ((struct mbuf *)0); m = m_get(M_DONTWAIT, MT_SOOPTS); if (m == 0) return ((struct mbuf *)0);#define OPTSIZ (sizeof(ip_srcrt.nop) + sizeof(ip_srcrt.srcopt)) /* length is (nhops+1)*sizeof(addr) + sizeof(nop + srcrt header) */ m->m_len = ip_nhops * sizeof(struct in_addr) + sizeof(struct in_addr) + OPTSIZ;#ifdef DIAGNOSTIC if (ipprintfs) printf("ip_srcroute: nhops %d mlen %d", ip_nhops, m->m_len);#endif /* * First save first hop for return route */ p = &ip_srcrt.route[ip_nhops - 1]; *(mtod(m, struct in_addr *)) = *p--;#ifdef DIAGNOSTIC if (ipprintfs) printf(" hops %x", ntohl(mtod(m, struct in_addr *)->s_addr));#endif /* * Copy option fields and padding (nop) to mbuf. */ ip_srcrt.nop = IPOPT_NOP; ip_srcrt.srcopt[IPOPT_OFFSET] = IPOPT_MINOFF; bcopy((caddr_t)&ip_srcrt.nop, mtod(m, caddr_t) + sizeof(struct in_addr), OPTSIZ); q = (struct in_addr *)(mtod(m, caddr_t) + sizeof(struct in_addr) + OPTSIZ);#undef OPTSIZ /* * Record return path as an IP source route, * reversing the path (pointers are now aligned). */ while (p >= ip_srcrt.route) {#ifdef DIAGNOSTIC if (ipprintfs) printf(" %x", ntohl(q->s_addr));#endif *q++ = *p--; } /* * Last hop goes to final destination. */ *q = ip_srcrt.dst;#ifdef DIAGNOSTIC if (ipprintfs) printf(" %x\n", ntohl(q->s_addr));#endif return (m);}/* * Strip out IP options, at higher * level protocol in the kernel. * Second argument is buffer to which options * will be moved, and return value is their length. * XXX should be deleted; last arg currently ignored. */voidip_stripoptions(m, mopt) register struct mbuf *m; struct mbuf *mopt;{ register int i; struct ip *ip = mtod(m, struct ip *); register caddr_t opts; int olen; olen = (ip->ip_hl<<2) - sizeof (struct ip); opts = (caddr_t)(ip + 1); i = m->m_len - (sizeof (struct ip) + olen); bcopy(opts + olen, opts, (unsigned)i); m->m_len -= olen; if (m->m_flags & M_PKTHDR) m->m_pkthdr.len -= olen; ip->ip_hl = sizeof(struct ip) >> 2;}int inetctlerrmap[PRC_NCMDS] = { 0, 0, 0, 0, 0, EMSGSIZE, EHOSTDOWN, EHOSTUNREACH, EHOSTUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, EMSGSIZE, EHOSTUNREACH, 0, 0, 0, 0, 0, 0, ENOPROTOOPT};#ifndef PMON/* * Forward a packet. If some error occurs return the sender * an icmp packet. Note we can't always generate a meaningful * icmp message because icmp doesn't have a large enough repertoire * of codes and types. * * If not forwarding, just drop the packet. This could be confusing * if ipforwarding was zero but some routing protocol was advancing * us as a gateway to somewhere. However, we must let the routing * protocol deal with that. * * The srcrt parameter indicates whether the packet is being forwarded * via a source route. */voidip_forward(m, srcrt) struct mbuf *m; int srcrt;{ register struct ip *ip = mtod(m, struct ip *); register struct sockaddr_in *sin; register struct rtentry *rt; int error, type = 0, code = 0; struct mbuf *mcopy; n_long dest; struct ifnet *destifp; dest = 0;#ifdef DIAGNOSTIC if (ipprintfs) printf("forward: src %x dst %x ttl %x\n", ip->ip_src.s_addr, ip->ip_dst.s_addr, ip->ip_ttl);#endif if (m->m_flags & M_BCAST || in_canforward(ip->ip_dst) == 0) { ipstat.ips_cantforward++; m_freem(m); return; } HTONS(ip->ip_id); if (ip->ip_ttl <= IPTTLDEC) { icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0); return; } ip->ip_ttl -= IPTTLDEC; sin = satosin(&ipforward_rt.ro_dst); if ((rt = ipforward_rt.ro_rt) == 0 || ip->ip_dst.s_addr != sin->sin_addr.s_addr) { if (ipforward_rt.ro_rt) { RTFREE(ipforward_rt.ro_rt); ipforward_rt.ro_rt = 0; } sin->sin_family = AF_INET; sin->sin_len = sizeof(*sin); sin->sin_addr = ip->ip_dst; rtalloc(&ipforward_rt); if (ipforward_rt.ro_rt == 0) { icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0); return; } rt = ipforward_rt.ro_rt; } /* * Save at most 68 bytes of the packet in case * we need to generate an ICMP message to the src. */ mcopy = m_copy(m, 0, imin((int)ip->ip_len, 68)); /* * If forwarding packet using same interface that it came in on, * perhaps should send a redirect to sender to shortcut a hop. * Only send redirect if source is sending directly to us, * and if packet was not source routed (or has any options). * Also, don't send redirect if forwarding using a default route * or a route modified by a redirect. * Don't send redirect if we advertise destination's arp address * as ours (proxy arp). */ if (rt->rt_ifp == m->m_pkthdr.rcvif && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && satosin(rt_key(rt))->sin_addr.s_addr != 0 && ipsendredirects && !srcrt && !ip_weadvertise(satosin(rt_key(rt))->sin_addr.s_addr)) { if (rt->rt_ifa && (ip->ip_src.s_addr & ifatoia(rt->rt_ifa)->ia_subnetmask) == ifatoia(rt->rt_ifa)->ia_subnet) { if (rt->rt_flags & RTF_GATEWAY) dest = satosin(rt->rt_gateway)->sin_addr.s_addr; else dest = ip->ip_dst.s_addr; /* Router requirements says to only send host redirects */ type = ICMP_REDIRECT; code = ICMP_REDIRECT_HOST;#ifdef DIAGNOSTIC if (ipprintfs) printf("redirect (%d) to %x\n", code, (u_int32_t)dest);#endif } } error = ip_output(m, (struct mbuf *)0, &ipforward_rt, (IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)), 0, NULL, NULL); if (error) ipstat.ips_cantforward++; else { ipstat.ips_forward++; if (type) ipstat.ips_redirectsent++; else { if (mcopy) m_freem(mcopy); return; } } if (mcopy == NULL) return; destifp = NULL; switch (error) { case 0: /* forwarded, but need redirect */ /* type, code set above */ break; case ENETUNREACH: /* shouldn't happen, checked above */ case EHOSTUNREACH: case ENETDOWN: case EHOSTDOWN: default: type = ICMP_UNREACH; code = ICMP_UNREACH_HOST; break; case EMSGSIZE: type = ICMP_UNREACH; code = ICMP_UNREACH_NEEDFRAG; if (ipforward_rt.ro_rt) destifp = ipforward_rt.ro_rt->rt_ifp; ipstat.ips_cantfrag++; break; case ENOBUFS: type = ICMP_SOURCEQUENCH; code = 0; break; } icmp_error(mcopy, type, code, dest, destifp);}#endif /* PMON */intip_sysctl(name, namelen, oldp, oldlenp, newp, newlen) int *name; u_int namelen; void *oldp; size_t *oldlenp; void *newp; size_t newlen;{ /* All sysctl names at this level are terminal. */ if (namelen != 1) return (ENOTDIR); switch (name[0]) {#ifndef PMON case IPCTL_FORWARDING: return (sysctl_int(oldp, oldlenp, newp, newlen, &ipforwarding)); case IPCTL_SENDREDIRECTS: return (sysctl_int(oldp, oldlenp, newp, newlen, &ipsendredirects)); case IPCTL_DEFTTL: return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_defttl));#ifdef notyet case IPCTL_DEFMTU: return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_mtu));#endif case IPCTL_SOURCEROUTE: /* * Don't allow this to change in a secure environment. */ if (newp && securelevel > 0) return (EPERM); return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_dosourceroute)); case IPCTL_DIRECTEDBCAST: return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_directedbcast)); case IPCTL_IPPORT_FIRSTAUTO: return (sysctl_int(oldp, oldlenp, newp, newlen, &ipport_firstauto)); case IPCTL_IPPORT_LASTAUTO: return (sysctl_int(oldp, oldlenp, newp, newlen, &ipport_lastauto)); case IPCTL_IPPORT_HIFIRSTAUTO: return (sysctl_int(oldp, oldlenp, newp, newlen, &ipport_hifirstauto)); case IPCTL_IPPORT_HILASTAUTO: return (sysctl_int(oldp, oldlenp, newp, newlen, &ipport_hilastauto)); case IPCTL_IPPORT_MAXQUEUE: return (sysctl_int(oldp, oldlenp, newp, newlen, &ip_maxqueue)); case IPCTL_ENCDEBUG: return (sysctl_int(oldp, oldlenp, newp, newlen, &encdebug));#endif default: return (EOPNOTSUPP); } /* NOTREACHED */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -