📄 ip_input.c
字号:
case IPOPT_TS_TSONLY: break; case IPOPT_TS_TSANDADDR: if (ipt->ipt_ptr + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; ia = ifptoia(ifp); bcopy((caddr_t)&IA_SIN(ia)->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 + 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((struct sockaddr *)&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); } } return (0);bad: ip->ip_len -= sizeof(struct ip); /* deduct header added by ipintr() */ icmp_error(ip, type, code, ifp, NULL); /* fallthrough */bad2: IPSTAT(ips_badoptions++); /* track number of bad options */ 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; register struct in_ifaddr *ia; RTLOCK(); sin = (struct sockaddr_in *) &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_addr = dst; rtalloc(&ipforward_rt); } if (ipforward_rt.ro_rt == 0){ RTUNLOCK(); return ((struct in_ifaddr *)0); } /* * Find address associated with outgoing interface. */ for (ia = in_ifaddr; ia; ia = ia->ia_next) if (ia->ia_ifp == ipforward_rt.ro_rt->rt_ifp) break; RTUNLOCK(); return (ia);}/* * Save incoming source route for use in replies, * to be picked up later by ip_srcroute if the receiver is interested. */save_rte(option, dst) u_char *option; struct in_addr dst;{ unsigned olen; extern ipprintfs; olen = option[IPOPT_OLEN]; if (olen > sizeof(ip_srcrt) - 1) { if (ipprintfs) printf("save_rte: olen %d\n", olen); return; } bcopy((caddr_t)option, (caddr_t)ip_srcrt.srcopt, olen); ip_nhops = (olen - IPOPT_OFFSET - 1) / sizeof(struct in_addr); ip_srcrt.route[ip_nhops++] = dst;}/* * 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); m->m_len = ip_nhops * sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1; /* * First save first hop for return route */ p = &ip_srcrt.route[ip_nhops - 1]; *(mtod(m, struct in_addr *)) = *p--; /* * Copy option fields and padding (nop) to mbuf. */ ip_srcrt.nop = IPOPT_NOP; bcopy((caddr_t)&ip_srcrt, mtod(m, caddr_t) + sizeof(struct in_addr), IPOPT_OFFSET + 1 + 1); q = (struct in_addr *)(mtod(m, caddr_t) + sizeof(struct in_addr) + IPOPT_OFFSET + 1 + 1); /* * Record return path as an IP source route, * reversing the path (pointers are now aligned). */ while (p >= ip_srcrt.route) *q++ = *p--; 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. */ip_stripoptions(ip, mopt) struct ip *ip; struct mbuf *mopt;{ register int i; register struct mbuf *m; register caddr_t opts; int olen, optsoff = 0; olen = (ip->ip_hl<<2) - sizeof (struct ip); m = dtom(ip); opts = (caddr_t)(ip + 1); if (mopt) { /* * If m_len is 0, we're dealing with an option set which * ip_srcroute found no source routing in. So, we've got an * empty mbuf, into the * beginning of which we have to coerce * a "first hop" address. In a packet with no source routing, * this would be the destination * address. Otherwise, m_len * is real, and we're just appending to the mbuf coming out * of ip_srcroute. */ if (!mopt->m_len) { mopt->m_len = sizeof(struct in_addr); bcopy(&ip->ip_dst, mtod(mopt, caddr_t), mopt->m_len); } /* * Push the rest of the options in. We don't have to worry * about the other IP level options like we do the source * routing, so just search for them and insert them into the * mbuf. Notice that anything dealing with source routing is * ignored, since you would want to do that in ip_srcroute * instead. */ while (optsoff + 1 <= olen) { switch(opts[optsoff]) { case IPOPT_LSRR: case IPOPT_SSRR: optsoff += opts[optsoff + IPOPT_OLEN]; break; case IPOPT_EOL: case IPOPT_NOP: mopt->m_dat[mopt->m_len++] = opts[optsoff++]; break; default: bcopy(&opts[optsoff],&mopt->m_dat[mopt->m_len], opts[optsoff + IPOPT_OLEN]); mopt->m_len += opts[optsoff + IPOPT_OLEN]; optsoff += opts[optsoff + IPOPT_OLEN]; break; } } mopt->m_off = MMINOFF; } i = m->m_len - (sizeof (struct ip) + olen); bcopy(opts + olen, opts, (unsigned)i); m->m_len -= olen; ip->ip_hl = sizeof(struct ip) >> 2;}u_char inetctlerrmap[PRC_NCMDS] = { 0, 0, 0, 0, 0, 0, EHOSTDOWN, EHOSTUNREACH, ENETUNREACH, EHOSTUNREACH, ECONNREFUSED, ECONNREFUSED, EMSGSIZE, EHOSTUNREACH, 0, 0, 0, 0, 0, 0, ENOPROTOOPT};#ifndef IPFORWARDING#define IPFORWARDING 1#endif#ifndef IPSENDREDIRECTS#define IPSENDREDIRECTS 1#endifint ipprintfs = 0;int ipforwarding = IPFORWARDING;extern int in_interfaces;int ipsendredirects = IPSENDREDIRECTS;int ipgateway = 0;/* * 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 (possibly because we have only a single external * network), 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. *//* * SMP: No smp locks held coming in. * No lock held for call to ip_output. 5.27.87.us */ip_forward(ip, ifp) register struct ip *ip; struct ifnet *ifp;{ register int error, type = 0, code; register struct sockaddr_in *sin; struct mbuf *mcopy; struct in_addr dest; dest.s_addr = 0; if (ipprintfs) printf("forward: src %x dst %x ttl %x\n", ip->ip_src, ip->ip_dst, ip->ip_ttl); ip->ip_id = htons(ip->ip_id); if (ipforwarding == 0 || in_interfaces <= 1) { IPSTAT(ips_cantforward++); if (ipgateway) { /* can't tell difference between net and host */ type = ICMP_UNREACH, code = ICMP_UNREACH_NET; goto sendicmp; } else { m_freem(dtom(ip)); return; } } if (in_canforward(ip->ip_dst) == 0) { m_freem(dtom(ip)); return; } if (ip->ip_ttl <= IPTTLDEC) { type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS; goto sendicmp; } ip->ip_ttl -= IPTTLDEC; /* * Save at most 64 bytes of the packet in case * we need to generate an ICMP message to the src. */ mcopy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64)); RTLOCK(); sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; if (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_addr = ip->ip_dst; rtalloc(&ipforward_rt); } /* * 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 modfied by a redirect. */#define satosin(sa) ((struct sockaddr_in *)(sa)) if (ipforward_rt.ro_rt && ipforward_rt.ro_rt->rt_ifp == ifp && (ipforward_rt.ro_rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && satosin(&ipforward_rt.ro_rt->rt_dst)->sin_addr.s_addr != 0 && ipsendredirects && ip->ip_hl == (sizeof(struct ip) >> 2)) { struct in_ifaddr *ia; u_long src = ntohl(ip->ip_src.s_addr); u_long dst = ntohl(ip->ip_dst.s_addr); if ((ia = ifptoia(ifp)) && (src & ia->ia_subnetmask) == ia->ia_subnet) { if (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) dest = satosin(&ipforward_rt.ro_rt->rt_gateway)->sin_addr; else dest = ip->ip_dst; /* * If the destination is reached by a route to host, * is on a subnet of a local net, or is directly * on the attached net (!), use host redirect. * (We may be the correct first hop for other subnets.) */ type = ICMP_REDIRECT; code = ICMP_REDIRECT_NET; if ((ipforward_rt.ro_rt->rt_flags & RTF_HOST) || (ipforward_rt.ro_rt->rt_flags & RTF_GATEWAY) == 0) code = ICMP_REDIRECT_HOST; else{ for (ia = in_ifaddr; ia = ia->ia_next; ) if ((dst & ia->ia_netmask) == ia->ia_net) { if (ia->ia_subnetmask != ia->ia_netmask) code = ICMP_REDIRECT_HOST; break; } } if (ipprintfs) printf("redirect (%d) to %x\n", code, dest); } } RTUNLOCK(); /* SMP: call ip_output with no smp lock. 4.21.87.us */ error = ip_output(dtom(ip), (struct mbuf *)0, &ipforward_rt, IP_FORWARDING, NULL); if (error) { IPSTAT(ips_cantforward++); } else if (type) { IPSTAT(ips_redirectsent++); } else { if (mcopy) m_freem(mcopy); IPSTAT(ips_forward++); return; } if (mcopy == NULL) return; ip = mtod(mcopy, struct ip *); type = ICMP_UNREACH; switch (error) { case 0: /* forwarded, but need redirect */ type = ICMP_REDIRECT; /* code set above */ break; case ENETUNREACH: case ENETDOWN: if (in_localaddr(ip->ip_dst)) code = ICMP_UNREACH_HOST; else code = ICMP_UNREACH_NET; break; case EMSGSIZE: code = ICMP_UNREACH_NEEDFRAG; break; case EPERM: code = ICMP_UNREACH_PORT; break; case ENOBUFS: type = ICMP_SOURCEQUENCH; break; case EHOSTDOWN: case EHOSTUNREACH: code = ICMP_UNREACH_HOST; break; }sendicmp: icmp_error(ip, type, code, ifp, dest);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -