📄 ip_input.c
字号:
/* * Adjust ip_len to not reflect header, * set ipqe_mff if more fragments are expected, * convert offset of this to bytes. */ ip->ip_len -= hlen; mff = (ip->ip_off & IP_MF) != 0; if (mff) { /* * Make sure that fragments have a data length * that's a non-zero multiple of 8 bytes. */ if (ip->ip_len == 0 || (ip->ip_len & 0x7) != 0) { ipstat.ips_badfrags++; ipq_unlock(); goto bad; } } 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 (mff || ip->ip_off) { ipstat.ips_fragments++; if (ip_frags + 1 > ip_maxqueue) { ip_flush(); ipstat.ips_rcvmemdrop++; ipq_unlock(); goto bad; } MALLOC(ipqe, struct ipqent *, sizeof (struct ipqent), M_IPQ, M_NOWAIT); if (ipqe == NULL) { ipstat.ips_rcvmemdrop++; ipq_unlock(); goto bad; } ip_frags++; ipqe->ipqe_mff = mff; ipqe->ipqe_ip = ip; ip = ip_reass(ipqe, fp); if (ip == 0) { ipq_unlock(); return; } ipstat.ips_reassembled++; m = dtom(ip); hlen = ip->ip_hl << 2; } else if (fp) ip_freef(fp); ipq_unlock(); } else ip->ip_len -= hlen; /* * Switch out to protocol's input routine. */ ipstat.ips_delivered++; (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen, NULL, 0); return;bad: m_freem(m);}struct in_ifaddr *in_iawithaddr(ina, m) struct in_addr ina; register struct mbuf *m;{ register struct in_ifaddr *ia; for (ia = in_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) { if ((ina.s_addr == ia->ia_addr.sin_addr.s_addr) || (ia->ia_addr.sin_addr.s_addr == INADDR_ANY) || ((ia->ia_ifp->if_flags & (IFF_LOOPBACK|IFF_LINK1)) == (IFF_LOOPBACK|IFF_LINK1) && ia->ia_subnet == (ina.s_addr & ia->ia_subnetmask))) return ia; if (m && ((ip_directedbcast == 0) || (ip_directedbcast && ia->ia_ifp == m->m_pkthdr.rcvif)) && (ia->ia_ifp->if_flags & IFF_BROADCAST)) { if (ina.s_addr == ia->ia_broadaddr.sin_addr.s_addr || ina.s_addr == ia->ia_netbroadcast.s_addr || /* * Look for all-0's host part (old broadcast addr), * either for subnet or net. */ ina.s_addr == ia->ia_subnet || ina.s_addr == ia->ia_net) return ia; } } return NULL;}/* * Take incoming datagram fragment and try to * reassemble it into whole datagram. If a chain for * reassembly of this datagram already exists, then it * is given as fp; otherwise have to make a chain. */struct ip *ip_reass(ipqe, fp) register struct ipqent *ipqe; register struct ipq *fp;{ register struct mbuf *m = dtom(ipqe->ipqe_ip); register struct ipqent *nq, *p, *q; struct ip *ip; struct mbuf *t; int hlen = ipqe->ipqe_ip->ip_hl << 2; int i, next; /* * Presence of header sizes in mbufs * would confuse code below. */ m->m_data += hlen; m->m_len -= hlen; /* * If first fragment to arrive, create a reassembly queue. */ if (fp == 0) { if ((t = m_get(M_DONTWAIT, MT_FTABLE)) == NULL) goto dropfrag; fp = mtod(t, struct ipq *); LIST_INSERT_HEAD(&ipq, fp, ipq_q); fp->ipq_ttl = IPFRAGTTL; fp->ipq_p = ipqe->ipqe_ip->ip_p; fp->ipq_id = ipqe->ipqe_ip->ip_id; LIST_INIT(&fp->ipq_fragq); fp->ipq_src = ipqe->ipqe_ip->ip_src; fp->ipq_dst = ipqe->ipqe_ip->ip_dst; p = NULL; goto insert; } /* * Find a segment which begins after this one does. */ for (p = NULL, q = fp->ipq_fragq.lh_first; q != NULL; p = q, q = q->ipqe_q.le_next) if (q->ipqe_ip->ip_off > ipqe->ipqe_ip->ip_off) break; /* * If there is a preceding segment, it may provide some of * our data already. If so, drop the data from the incoming * segment. If it provides all of our data, drop us. */ if (p != NULL) { i = p->ipqe_ip->ip_off + p->ipqe_ip->ip_len - ipqe->ipqe_ip->ip_off; if (i > 0) { if (i >= ipqe->ipqe_ip->ip_len) goto dropfrag; m_adj(dtom(ipqe->ipqe_ip), i); ipqe->ipqe_ip->ip_off += i; ipqe->ipqe_ip->ip_len -= i; } } /* * While we overlap succeeding segments trim them or, * if they are completely covered, dequeue them. */ for (; q != NULL && ipqe->ipqe_ip->ip_off + ipqe->ipqe_ip->ip_len > q->ipqe_ip->ip_off; q = nq) { i = (ipqe->ipqe_ip->ip_off + ipqe->ipqe_ip->ip_len) - q->ipqe_ip->ip_off; if (i < q->ipqe_ip->ip_len) { q->ipqe_ip->ip_len -= i; q->ipqe_ip->ip_off += i; m_adj(dtom(q->ipqe_ip), i); break; } nq = q->ipqe_q.le_next; m_freem(dtom(q->ipqe_ip)); LIST_REMOVE(q, ipqe_q); FREE(q, M_IPQ); ip_frags--; }insert: /* * Stick new segment in its place; * check for complete reassembly. */ if (p == NULL) { LIST_INSERT_HEAD(&fp->ipq_fragq, ipqe, ipqe_q); } else { LIST_INSERT_AFTER(p, ipqe, ipqe_q); } next = 0; for (p = NULL, q = fp->ipq_fragq.lh_first; q != NULL; p = q, q = q->ipqe_q.le_next) { if (q->ipqe_ip->ip_off != next) return (0); next += q->ipqe_ip->ip_len; } if (p->ipqe_mff) return (0); /* * Reassembly is complete. Check for a bogus message size and * concatenate fragments. */ q = fp->ipq_fragq.lh_first; ip = q->ipqe_ip; if ((next + (ip->ip_hl << 2)) > IP_MAXPACKET) { ipstat.ips_toolong++; ip_freef(fp); return (0); } m = dtom(q->ipqe_ip); t = m->m_next; m->m_next = 0; m_cat(m, t); nq = q->ipqe_q.le_next; FREE(q, M_IPQ); ip_frags--; for (q = nq; q != NULL; q = nq) { t = dtom(q->ipqe_ip); nq = q->ipqe_q.le_next; FREE(q, M_IPQ); ip_frags--; m_cat(m, t); } /* * Create header for new ip packet by * modifying header of first packet; * dequeue and discard fragment reassembly header. * Make header visible. */ ip->ip_len = next; ip->ip_src = fp->ipq_src; ip->ip_dst = fp->ipq_dst; LIST_REMOVE(fp, ipq_q); (void) m_free(dtom(fp)); m->m_len += (ip->ip_hl << 2); m->m_data -= (ip->ip_hl << 2); /* some debugging cruft by sklower, below, will go away soon */ if (m->m_flags & M_PKTHDR) { /* XXX this should be done elsewhere */ register int plen = 0; for (t = m; m; m = m->m_next) plen += m->m_len; t->m_pkthdr.len = plen; } return (ip);dropfrag: ipstat.ips_fragdropped++; m_freem(m); FREE(ipqe, M_IPQ); ip_frags--; return (0);}/* * Free a fragment reassembly header and all * associated datagrams. */voidip_freef(fp) struct ipq *fp;{ register struct ipqent *q, *p; for (q = fp->ipq_fragq.lh_first; q != NULL; q = p) { p = q->ipqe_q.le_next; m_freem(dtom(q->ipqe_ip)); LIST_REMOVE(q, ipqe_q); FREE(q, M_IPQ); ip_frags--; } LIST_REMOVE(fp, ipq_q); (void) m_free(dtom(fp));}/* * IP timer processing; * if a timer expires on a reassembly * queue, discard it. */voidip_slowtimo(){ register struct ipq *fp, *nfp; int s = splsoftnet(); ipq_lock(); for (fp = ipq.lh_first; fp != NULL; fp = nfp) { nfp = fp->ipq_q.le_next; if (--fp->ipq_ttl == 0) { ipstat.ips_fragtimeout++; ip_freef(fp); } } ipq_unlock(); splx(s);}/* * Drain off all datagram fragments. */voidip_drain(){ if (ipq_lock_try() == 0) return; while (ipq.lh_first != NULL) { ipstat.ips_fragdropped++; ip_freef(ipq.lh_first); } ipq_unlock();}/* * Flush a bunch of datagram fragments, till we are down to 75%. */voidip_flush(){ int max = 50; /* ipq already locked */ while (ipq.lh_first != NULL && ip_frags > ip_maxqueue * 3 / 4 && --max) { ipstat.ips_fragdropped++; ip_freef(ipq.lh_first); }}/* * Do option processing on a datagram, * possibly discarding it if bad options are encountered, * or forwarding it if source-routed. * Returns 1 if packet has been forwarded/freed, * 0 if the packet should be processed further. */intip_dooptions(m) struct mbuf *m;{ register struct ip *ip = mtod(m, struct ip *); register u_char *cp; register struct ip_timestamp *ipt; register struct in_ifaddr *ia; int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; struct in_addr *sin, dst; n_time ntime; dst = ip->ip_dst; cp = (u_char *)(ip + 1); cnt = (ip->ip_hl << 2) - sizeof (struct ip); for (; cnt > 0; cnt -= optlen, cp += optlen) { opt = cp[IPOPT_OPTVAL]; if (opt == IPOPT_EOL) break; if (opt == IPOPT_NOP) optlen = 1; else { optlen = cp[IPOPT_OLEN]; if (optlen <= 0 || optlen > cnt) { code = &cp[IPOPT_OLEN] - (u_char *)ip; goto bad; } } switch (opt) { default: break; /* * Source routing with record. * Find interface with current destination address. * If none on this machine then drop if strictly routed, * or do nothing if loosely routed. * Record interface address and bring up next address * component. If strictly routed make sure next * address is on directly accessible net. */ case IPOPT_LSRR: case IPOPT_SSRR: if (!ip_dosourceroute) { char buf[4*sizeof "123"]; strcpy(buf, inet_ntoa(ip->ip_dst)); log(LOG_WARNING, "attempted source route from %s to %s\n", inet_ntoa(ip->ip_src), buf); type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } ipaddr.sin_addr = ip->ip_dst; ia = ifatoia(ifa_ifwithaddr(sintosa(&ipaddr))); if (ia == 0) { if (opt == IPOPT_SSRR) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } /* * Loose routing, and not at next destination * yet; nothing to do except forward. */ break; } off--; /* 0 origin */ if (off > optlen - sizeof(struct in_addr)) { /* * End of source route. Should be for us. */ save_rte(cp, ip->ip_src); break; } /* * locate outgoing interface */ bcopy((caddr_t)(cp + off), (caddr_t)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); if (opt == IPOPT_SSRR) {#define INA struct in_ifaddr *#define SA struct sockaddr * if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) ia = (INA)ifa_ifwithnet((SA)&ipaddr); } else ia = ip_rtaddr(ipaddr.sin_addr); if (ia == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_SRCFAIL; goto bad; } ip->ip_dst = ipaddr.sin_addr; bcopy((caddr_t)&ia->ia_addr.sin_addr, (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); /* * Let ip_intr's mcast routing check handle mcast pkts */ forward = !IN_MULTICAST(ip->ip_dst.s_addr); break; case IPOPT_RR: if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { code = &cp[IPOPT_OFFSET] - (u_char *)ip; goto bad; } /* * If no space remains, ignore. */ off--; /* 0 origin */ if (off > optlen - sizeof(struct in_addr)) break; bcopy((caddr_t)(&ip->ip_dst), (caddr_t)&ipaddr.sin_addr, sizeof(ipaddr.sin_addr)); /* * locate outgoing interface; if we're the destination, * use the incoming interface (should be same). */ if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { type = ICMP_UNREACH; code = ICMP_UNREACH_HOST; goto bad; } bcopy((caddr_t)&ia->ia_addr.sin_addr, (caddr_t)(cp + off), sizeof(struct in_addr)); cp[IPOPT_OFFSET] += sizeof(struct in_addr); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -