X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/b2a3d55917a26470f77b73231e70f736b9ba615f..7985f2abad4958a0f6ef93ad1df40487ba6ff5a8:/usr/src/sys/netinet/ip_input.c diff --git a/usr/src/sys/netinet/ip_input.c b/usr/src/sys/netinet/ip_input.c index e971ccc9e4..c0488df76c 100644 --- a/usr/src/sys/netinet/ip_input.c +++ b/usr/src/sys/netinet/ip_input.c @@ -1,9 +1,20 @@ /* - * Copyright (c) 1982 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. + * Copyright (c) 1982, 1986 Regents of the University of California. + * All rights reserved. * - * @(#)ip_input.c 6.17 (Berkeley) %G% + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * @(#)ip_input.c 7.10 (Berkeley) %G% */ #include "param.h" @@ -224,43 +235,53 @@ next: ours: /* - * Look for queue of fragments - * of this datagram. + * If offset or IP_MF are set, must reassemble. + * Otherwise, nothing need be done. + * (We could look in the reassembly queue to see + * if the packet was previously fragmented, + * but it's not worth the time; just let them time out.) */ - for (fp = ipq.next; fp != &ipq; fp = fp->next) - if (ip->ip_id == fp->ipq_id && - ip->ip_src.s_addr == fp->ipq_src.s_addr && - ip->ip_dst.s_addr == fp->ipq_dst.s_addr && - ip->ip_p == fp->ipq_p) - goto found; - fp = 0; + if (ip->ip_off &~ IP_DF) { + /* + * Look for queue of fragments + * of this datagram. + */ + for (fp = ipq.next; fp != &ipq; fp = fp->next) + if (ip->ip_id == fp->ipq_id && + ip->ip_src.s_addr == fp->ipq_src.s_addr && + ip->ip_dst.s_addr == fp->ipq_dst.s_addr && + ip->ip_p == fp->ipq_p) + goto found; + fp = 0; found: - /* - * Adjust ip_len to not reflect header, - * set ip_mff if more fragments are expected, - * convert offset of this to bytes. - */ - ip->ip_len -= hlen; - ((struct ipasfrag *)ip)->ipf_mff = 0; - if (ip->ip_off & IP_MF) - ((struct ipasfrag *)ip)->ipf_mff = 1; - ip->ip_off <<= 3; + /* + * Adjust ip_len to not reflect header, + * set ip_mff if more fragments are expected, + * convert offset of this to bytes. + */ + ip->ip_len -= hlen; + ((struct ipasfrag *)ip)->ipf_mff = 0; + if (ip->ip_off & IP_MF) + ((struct ipasfrag *)ip)->ipf_mff = 1; + ip->ip_off <<= 3; - /* - * If datagram marked as having more fragments - * or if this is not the first fragment, - * attempt reassembly; if it succeeds, proceed. - */ - if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { - ipstat.ips_fragments++; - ip = ip_reass((struct ipasfrag *)ip, fp); - if (ip == 0) - goto next; - m = dtom(ip); + /* + * If datagram marked as having more fragments + * or if this is not the first fragment, + * attempt reassembly; if it succeeds, proceed. + */ + if (((struct ipasfrag *)ip)->ipf_mff || ip->ip_off) { + ipstat.ips_fragments++; + ip = ip_reass((struct ipasfrag *)ip, fp); + if (ip == 0) + goto next; + m = dtom(ip); + } else + if (fp) + ip_freef(fp); } else - if (fp) - ip_freef(fp); + ip->ip_len -= hlen; /* * Switch out to protocol's input routine. @@ -300,7 +321,7 @@ ip_reass(ip, fp) * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { - if ((t = m_get(M_WAIT, MT_FTABLE)) == NULL) + if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); insque(fp, &ipq); @@ -488,6 +509,7 @@ ip_drain() } } +extern struct in_ifaddr *ifptoia(); struct in_ifaddr *ip_rtaddr(); /* @@ -567,7 +589,7 @@ ip_dooptions(ip, ifp) /* * locate outgoing interface */ - bcopy(cp + off, (caddr_t)&ipaddr.sin_addr, + bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); if ((opt == IPOPT_SSRR && in_iaonnetof(in_netof(ipaddr.sin_addr)) == 0) || @@ -577,8 +599,8 @@ ip_dooptions(ip, ifp) goto bad; } ip->ip_dst = ipaddr.sin_addr; - bcopy(&(IA_SIN(ia)->sin_addr), cp + off, - sizeof(struct in_addr)); + bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), + (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); break; @@ -593,18 +615,18 @@ ip_dooptions(ip, ifp) off--; /* 0 origin */ if (off > optlen - sizeof(struct in_addr)) break; - bcopy(cp + off, (caddr_t)ipaddr.sin_addr, + bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); /* * locate outgoing interface */ if ((ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { type = ICMP_UNREACH; - code = ICMP_UNREACH_SRCFAIL; + code = ICMP_UNREACH_HOST; goto bad; } - bcopy(&(IA_SIN(ia)->sin_addr), cp + off, - sizeof(struct in_addr)); + bcopy((caddr_t)&(IA_SIN(ia)->sin_addr), + (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); break; @@ -618,7 +640,7 @@ ip_dooptions(ip, ifp) goto bad; break; } - sin = (struct in_addr *)(cp+cp[IPOPT_OFFSET]-1); + sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); switch (ipt->ipt_flg) { case IPOPT_TS_TSONLY: @@ -628,21 +650,20 @@ ip_dooptions(ip, ifp) if (ipt->ipt_ptr + sizeof(n_time) + sizeof(struct in_addr) > ipt->ipt_len) goto bad; - if (in_ifaddr == 0) - goto bad; /* ??? */ - bcopy((caddr_t)&IA_SIN(in_ifaddr)->sin_addr, + ia = ifptoia(ifp); + bcopy((caddr_t)&IA_SIN(ia)->sin_addr, (caddr_t)sin, sizeof(struct in_addr)); - sin++; + 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; - if (ipt->ipt_ptr + sizeof(n_time) + - sizeof(struct in_addr) > ipt->ipt_len) - goto bad; ipt->ipt_ptr += sizeof(struct in_addr); break; @@ -650,7 +671,8 @@ ip_dooptions(ip, ifp) goto bad; } ntime = iptime(); - bcopy((caddr_t)&ntime, (caddr_t)sin, sizeof(n_time)); + bcopy((caddr_t)&ntime, (caddr_t)cp + ipt->ipt_ptr - 1, + sizeof(n_time)); ipt->ipt_ptr += sizeof(n_time); } } @@ -699,10 +721,10 @@ ip_rtaddr(dst) * to be picked up later by ip_srcroute if the receiver is interested. */ save_rte(option, dst) - caddr_t option; + u_char *option; struct in_addr dst; { - int olen; + unsigned olen; extern ipprintfs; olen = option[IPOPT_OLEN]; @@ -711,7 +733,7 @@ save_rte(option, dst) printf("save_rte: olen %d\n", olen); return; } - bcopy(option, (caddr_t)ip_srcrt.srcopt, olen); + 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; } @@ -729,7 +751,9 @@ ip_srcroute() if (ip_nhops == 0) return ((struct mbuf *)0); - m = m_get(M_WAIT, MT_SOOPTS); + 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; /* @@ -809,6 +833,11 @@ int ipsendredirects = IPSENDREDIRECTS; * 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. */ ip_forward(ip, ifp) register struct ip *ip; @@ -819,19 +848,22 @@ ip_forward(ip, ifp) struct mbuf *mcopy; struct in_addr dest; -#ifdef lint dest.s_addr = 0; -#endif 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) { - /* can't tell difference between net and host */ + ipstat.ips_cantforward++; +#ifdef GATEWAY type = ICMP_UNREACH, code = ICMP_UNREACH_NET; goto sendicmp; +#else + m_freem(dtom(ip)); + return; +#endif } - if (ip->ip_ttl < IPTTLDEC) { + if (ip->ip_ttl <= IPTTLDEC) { type = ICMP_TIMXCEED, code = ICMP_TIMXCEED_INTRANS; goto sendicmp; } @@ -841,7 +873,7 @@ ip_forward(ip, ifp) * 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(ip->ip_len, 64)); + mcopy = m_copy(dtom(ip), 0, imin((int)ip->ip_len, 64)); sin = (struct sockaddr_in *)&ipforward_rt.ro_dst; if (ipforward_rt.ro_rt == 0 || @@ -860,11 +892,15 @@ ip_forward(ip, ifp) * 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) == 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; - extern struct in_ifaddr *ifptoia(); u_long src = ntohl(ip->ip_src.s_addr); u_long dst = ntohl(ip->ip_dst.s_addr); @@ -876,9 +912,8 @@ ip_forward(ip, ifp) dest = ip->ip_dst; /* * If the destination is reached by a route to host, - * is directly on the attached net (!), - * or if the destination is on a subnet of a local net - * not known to the source net, use host redirect. + * 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; @@ -888,8 +923,8 @@ ip_forward(ip, ifp) code = ICMP_REDIRECT_HOST; else for (ia = in_ifaddr; ia = ia->ia_next; ) if ((dst & ia->ia_netmask) == ia->ia_net) { - if ((src & ia->ia_netmask) != ia->ia_net) - code = ICMP_REDIRECT_HOST; + if (ia->ia_subnetmask != ia->ia_netmask) + code = ICMP_REDIRECT_HOST; break; } if (ipprintfs) @@ -922,7 +957,10 @@ ip_forward(ip, ifp) case ENETUNREACH: case ENETDOWN: - code = ICMP_UNREACH_NET; + if (in_localaddr(ip->ip_dst)) + code = ICMP_UNREACH_HOST; + else + code = ICMP_UNREACH_NET; break; case EMSGSIZE: