void udp_input(struct mbuf *m, ...) { struct ip *ip; struct udphdr *uh; struct inpcb *inp = NULL; struct mbuf *opts = NULL; struct ip save_ip; int iphlen, len; va_list ap; u_int16_t savesum; union { struct sockaddr sa; struct sockaddr_in sin; #ifdef INET6 struct sockaddr_in6 sin6; #endif /* INET6 */ } srcsa, dstsa; #ifdef INET6 struct ip6_hdr *ip6; #endif /* INET6 */ #ifdef IPSEC struct m_tag *mtag; struct tdb_ident *tdbi; struct tdb *tdb; int error, s; #endif /* IPSEC */ va_start(ap, m); iphlen = va_arg(ap, int); va_end(ap); udpstat.udps_ipackets++; switch (mtod(m, struct ip *)->ip_v) { case 4: ip = mtod(m, struct ip *); #ifdef INET6 ip6 = NULL; #endif /* INET6 */ srcsa.sa.sa_family = AF_INET; break; #ifdef INET6 case 6: ip = NULL; ip6 = mtod(m, struct ip6_hdr *); srcsa.sa.sa_family = AF_INET6; break; #endif /* INET6 */ default: goto bad; } IP6_EXTHDR_GET(uh, struct udphdr *, m, iphlen, sizeof(struct udphdr)); if (!uh) { udpstat.udps_hdrops++; return; } /* Check for illegal destination port 0 */ if (uh->uh_dport == 0) { udpstat.udps_noport++; goto bad; } /* * Make mbuf data length reflect UDP length. * If not enough data to reflect UDP length, drop. */ len = ntohs((u_int16_t)uh->uh_ulen); if (ip) { if (m->m_pkthdr.len - iphlen != len) { if (len > (m->m_pkthdr.len - iphlen) || len < sizeof(struct udphdr)) { udpstat.udps_badlen++; goto bad; } m_adj(m, len - (m->m_pkthdr.len - iphlen)); } } #ifdef INET6 else if (ip6) { /* jumbograms */ if (len == 0 && m->m_pkthdr.len - iphlen > 0xffff) len = m->m_pkthdr.len - iphlen; if (len != m->m_pkthdr.len - iphlen) { udpstat.udps_badlen++; goto bad; } } #endif else /* shouldn't happen */ goto bad; /* * Save a copy of the IP header in case we want restore it * for sending an ICMP error message in response. */ if (ip) save_ip = *ip; /* * Checksum extended UDP header and data. * from W.R.Stevens: check incoming udp cksums even if * udpcksum is not set. */ savesum = uh->uh_sum; #ifdef INET6 if (ip6) { /* Be proactive about malicious use of IPv4 mapped address */ if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { /* XXX stat */ goto bad; } /* * In IPv6, the UDP checksum is ALWAYS used. */ if (uh->uh_sum == 0) { udpstat.udps_nosum++; goto bad; } if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) { if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) { udpstat.udps_badsum++; udpstat.udps_inhwcsum++; goto bad; } if ((uh->uh_sum = in6_cksum(m, IPPROTO_UDP, iphlen, len))) { udpstat.udps_badsum++; goto bad; } } else { m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_IN_OK; udpstat.udps_inhwcsum++; } } else #endif /* INET6 */ if (uh->uh_sum) { if ((m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_OK) == 0) { if (m->m_pkthdr.csum_flags & M_UDP_CSUM_IN_BAD) { udpstat.udps_badsum++; udpstat.udps_inhwcsum++; m_freem(m); return; } if ((uh->uh_sum = in4_cksum(m, IPPROTO_UDP, iphlen, len))) { udpstat.udps_badsum++; m_freem(m); return; } } else { m->m_pkthdr.csum_flags &= ~M_UDP_CSUM_IN_OK; udpstat.udps_inhwcsum++; } } else udpstat.udps_nosum++; #ifdef IPSEC if (udpencap_enable && udpencap_port && uh->uh_dport == htons(udpencap_port)) { u_int32_t spi; int skip = iphlen + sizeof(struct udphdr); if (m->m_pkthdr.len - skip < sizeof(u_int32_t)) { /* packet too short */ m_freem(m); return; } m_copydata(m, skip, sizeof(u_int32_t), (caddr_t) &spi); /* * decapsulate if the SPI is not zero, otherwise pass * to userland */ if (spi != 0) { if ((m = m_pullup(m, skip)) == NULL) { udpstat.udps_hdrops++; return; } /* remove the UDP header */ bcopy(mtod(m, u_char *), mtod(m, u_char *) + sizeof(struct udphdr), iphlen); m_adj(m, sizeof(struct udphdr)); skip -= sizeof(struct udphdr); espstat.esps_udpencin++; ipsec_common_input(m, skip, offsetof(struct ip, ip_p), srcsa.sa.sa_family, IPPROTO_ESP, 1); return; } }
int ipsec_filter(struct mbuf **mp, int dir, int flags) { int error, i; struct ip *ip; KASSERT(encif != NULL, ("%s: encif is null", __func__)); KASSERT(flags & (ENC_IN|ENC_OUT), ("%s: invalid flags: %04x", __func__, flags)); if ((encif->if_drv_flags & IFF_DRV_RUNNING) == 0) return (0); if (flags & ENC_IN) { if ((flags & ipsec_filter_mask_in) == 0) return (0); } else { if ((flags & ipsec_filter_mask_out) == 0) return (0); } /* Skip pfil(9) if no filters are loaded */ if (1 #ifdef INET && !PFIL_HOOKED(&V_inet_pfil_hook) #endif #ifdef INET6 && !PFIL_HOOKED(&V_inet6_pfil_hook) #endif ) { return (0); } i = min((*mp)->m_pkthdr.len, max_protohdr); if ((*mp)->m_len < i) { *mp = m_pullup(*mp, i); if (*mp == NULL) { printf("%s: m_pullup failed\n", __func__); return (-1); } } error = 0; ip = mtod(*mp, struct ip *); switch (ip->ip_v) { #ifdef INET case 4: error = pfil_run_hooks(&V_inet_pfil_hook, mp, encif, dir, NULL); break; #endif #ifdef INET6 case 6: error = pfil_run_hooks(&V_inet6_pfil_hook, mp, encif, dir, NULL); break; #endif default: printf("%s: unknown IP version\n", __func__); } /* * If the mbuf was consumed by the filter for requeueing (dummynet, etc) * then error will be zero but we still want to return an error to our * caller so the null mbuf isn't forwarded further. */ if (*mp == NULL && error == 0) return (-1); /* Consumed by the filter */ if (*mp == NULL) return (error); if (error != 0) goto bad; return (error); bad: m_freem(*mp); *mp = NULL; return (error); }
/* * Ip input routine. Checksum and byte swap header. If fragmented * try to reassamble. If complete and fragment queue exists, discard. * Process options. Pass to next level. */ ipintr() { register struct ip *ip; register struct mbuf *m; struct mbuf *m0; register int i; register struct ipq *fp; register struct in_ifaddr *ia; struct ifnet *ifp; int hlen, s; /* IOdebug( "ipintr: called" ); */ next: /* * Get next datagram off input queue and get IP header * in first mbuf. */ s = splimp(); IF_DEQUEUEIF(&ipintrq, m, ifp); splx(s); if (m == NULL) { /* IOdebug( "ipintr: no more mbufs" ); */ return; } /* * If no IP addresses have been set yet but the interfaces * are receiving, can't do anything with incoming packets yet. */ if (in_ifaddr == NULL) goto bad; ipstat.ips_total++; if ((m->m_off > MMAXOFF || m->m_len < sizeof (struct ip)) && (m = m_pullup(m, sizeof (struct ip))) == 0) { ipstat.ips_toosmall++; goto next; } ip = mtod(m, struct ip *); hlen = ip->ip_hl << 2; if (hlen < sizeof(struct ip)) { /* minimum header length */ ipstat.ips_badhlen++; goto bad; } if (hlen > m->m_len) { if ((m = m_pullup(m, hlen)) == 0) { ipstat.ips_badhlen++; goto next; } ip = mtod(m, struct ip *); } if (ipcksum) if (ip->ip_sum = in_cksum(m, hlen)) { ipstat.ips_badsum++; /* IOdebug( "ipintr: bad checksum" ); */ goto bad; } /* * Convert fields to host representation. */ ip->ip_len = ntohs((u_short)ip->ip_len); if (ip->ip_len < hlen) { ipstat.ips_badlen++; goto bad; } ip->ip_id = ntohs(ip->ip_id); ip->ip_off = ntohs((u_short)ip->ip_off); /* * Check that the amount of data in the buffers * is as at least much as the IP header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ i = -(u_short)ip->ip_len; m0 = m; for (;;) { i += m->m_len; if (m->m_next == 0) break; m = m->m_next; } if (i != 0) { if (i < 0) { ipstat.ips_tooshort++; m = m0; goto bad; } if (i <= m->m_len) m->m_len -= i; else m_adj(m0, -i); } m = m0; /* * Process options and, if not destined for us, * ship it on. ip_dooptions returns 1 when an * error was detected (causing an icmp message * to be sent and the original packet to be freed). */ ip_nhops = 0; /* for source routed packets */ if (hlen > sizeof (struct ip) && ip_dooptions(ip, ifp)) goto next; /* * Check our list of addresses, to see if the packet is for us. */ /* IOdebug( "ipintr: checking address" ); */ for (ia = in_ifaddr; ia; ia = ia->ia_next) { #define satosin(sa) ((struct sockaddr_in *)(sa)) if (IA_SIN(ia)->sin_addr.s_addr == ip->ip_dst.s_addr) goto ours; if ( #ifdef DIRECTED_BROADCAST ia->ia_ifp == ifp && #endif (ia->ia_ifp->if_flags & IFF_BROADCAST)) { u_long t; if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == ip->ip_dst.s_addr) goto ours; if (ip->ip_dst.s_addr == ia->ia_netbroadcast.s_addr) goto ours; /* * Look for all-0's host part (old broadcast addr), * either for subnet or net. */ t = ntohl(ip->ip_dst.s_addr); if (t == ia->ia_subnet) goto ours; if (t == ia->ia_net) goto ours; } } if (ip->ip_dst.s_addr == (u_long)INADDR_BROADCAST) goto ours; if (ip->ip_dst.s_addr == INADDR_ANY) goto ours; /* * Not for us; forward if possible and desirable. */ ip_forward(ip, ifp); /* IOdebug( "ipintr: not for us" ); */ goto next; ours: /* IOdebug( "ipintr: ours" ); */ /* * 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.) */ 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; /* * 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) { /* IOdebug( "ipintr: attempting reassembly" ); */ ipstat.ips_fragments++; ip = ip_reass((struct ipasfrag *)ip, fp); if (ip == NULL) { /* IOdebug( "ipintr: attempt failed" ); */ goto next; } m = dtom(ip); } else if (fp) ip_freef(fp); } else ip->ip_len -= hlen; /* * Switch out to protocol's input routine. */ /* IOdebug( "ipintr: handling packet of len %d", ip->ip_len ); */ (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, ifp); /* IOdebug( "ipintr: handled" ); */ goto next; bad: /* IOdebug( "ipintr: bad input" ); */ m_freem(m); goto next; }
/* * IPX input routine. Pass to next level. */ void ipxintr() { struct ipx *ipx; struct mbuf *m; struct ipxpcb *ipxp; struct ipx_ifaddr *ia; int len, s; next: /* * Get next datagram off input queue and get IPX header * in first mbuf. */ s = splimp(); IF_DEQUEUE(&ipxintrq, m); splx(s); if (m == NULL) { return; } ipxstat.ipxs_total++; if ((m->m_flags & M_EXT || m->m_len < sizeof(struct ipx)) && (m = m_pullup(m, sizeof(struct ipx))) == 0) { ipxstat.ipxs_toosmall++; goto next; } /* * Give any raw listeners a crack at the packet */ for (ipxp = ipxrawcbtable.ipxpt_queue.cqh_first; ipxp != (struct ipxpcb *)&ipxrawcbtable.ipxpt_queue; ipxp = ipxp->ipxp_queue.cqe_next) { struct mbuf *m1 = m_copy(m, 0, (int)M_COPYALL); if (m1) ipx_input(m1, ipxp); } ipx = mtod(m, struct ipx *); len = ntohs(ipx->ipx_len); /* * Check that the amount of data in the buffers * is as at least much as the IPX header would have us expect. * Trim mbufs if longer than we expect. * Drop packet if shorter than we expect. */ if (m->m_pkthdr.len < len) { ipxstat.ipxs_tooshort++; goto bad; } if (m->m_pkthdr.len > len) { if (m->m_len == m->m_pkthdr.len) { m->m_len = len; m->m_pkthdr.len = len; } else m_adj(m, len - m->m_pkthdr.len); } if (ipxcksum && ipx->ipx_sum != 0xffff) { if (ipx->ipx_sum != ipx_cksum(m, len)) { ipxstat.ipxs_badsum++; goto bad; } } /* * Propagated (Netbios) packets (type 20) has to be handled * different. :-( */ if (ipx->ipx_pt == IPXPROTO_NETBIOS) { if (ipxnetbios) { ipx_output_type20(m); goto next; } else goto bad; } /* * Is this a directed broadcast? */ if (ipx_hosteqnh(ipx_broadhost,ipx->ipx_dna.ipx_host)) { if ((!ipx_neteq(ipx->ipx_dna, ipx->ipx_sna)) && (!ipx_neteqnn(ipx->ipx_dna.ipx_net, ipx_broadnet)) && (!ipx_neteqnn(ipx->ipx_sna.ipx_net, ipx_zeronet)) && (!ipx_neteqnn(ipx->ipx_dna.ipx_net, ipx_zeronet)) ) { /* * If it is a broadcast to the net where it was * received from, treat it as ours. */ for (ia = ipx_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) if((ia->ia_ifa.ifa_ifp == m->m_pkthdr.rcvif) && ipx_neteq(ia->ia_addr.sipx_addr, ipx->ipx_dna)) goto ours; /* * Look to see if I need to eat this packet. * Algorithm is to forward all young packets * and prematurely age any packets which will * by physically broadcasted. * Any very old packets eaten without forwarding * would die anyway. * * Suggestion of Bill Nesheim, Cornell U. */ if (ipx->ipx_tc < IPX_MAXHOPS) { ipx_forward(m); goto next; } } /* * Is this our packet? If not, forward. */ } else { for (ia = ipx_ifaddr.tqh_first; ia; ia = ia->ia_list.tqe_next) if (ipx_hosteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) && (ipx_neteq(ipx->ipx_dna, ia->ia_addr.sipx_addr) || ipx_neteqnn(ipx->ipx_dna.ipx_net, ipx_zeronet))) break; if (ia == NULL) { ipx_forward(m); goto next; } } ours: /* * Locate pcb for datagram. */ ipxp = ipx_pcblookup(&ipx->ipx_sna, ipx->ipx_dna.ipx_port, IPX_WILDCARD); /* * Switch out to protocol's input routine. */ if (ipxp) { ipxstat.ipxs_delivered++; if ((ipxp->ipxp_flags & IPXP_ALL_PACKETS) == 0) switch (ipx->ipx_pt) { case IPXPROTO_SPX: spx_input(m, ipxp); goto next; } ipx_input(m, ipxp); } else goto bad; goto next; bad: m_freem(m); goto next; }
int gre_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, struct rtentry *rt) { int error = 0; struct gre_softc *sc = (struct gre_softc *) (ifp->if_softc); struct greip *gh = NULL; struct ip *inp = NULL; u_int8_t ip_tos = 0; u_int16_t etype = 0; struct mobile_h mob_h; struct m_tag *mtag; if ((ifp->if_flags & IFF_UP) == 0 || sc->g_src.s_addr == INADDR_ANY || sc->g_dst.s_addr == INADDR_ANY) { m_freem(m); error = ENETDOWN; goto end; } /* Try to limit infinite recursion through misconfiguration. */ for (mtag = m_tag_find(m, PACKET_TAG_GRE, NULL); mtag; mtag = m_tag_find(m, PACKET_TAG_GRE, mtag)) { if (!bcmp((caddr_t)(mtag + 1), &ifp, sizeof(struct ifnet *))) { IF_DROP(&ifp->if_snd); m_freem(m); error = EIO; goto end; } } mtag = m_tag_get(PACKET_TAG_GRE, sizeof(struct ifnet *), M_NOWAIT); if (mtag == NULL) { IF_DROP(&ifp->if_snd); m_freem(m); error = ENOBUFS; goto end; } bcopy(&ifp, (caddr_t)(mtag + 1), sizeof(struct ifnet *)); m_tag_prepend(m, mtag); m->m_flags &= ~(M_BCAST|M_MCAST); #if NBPFILTER >0 if (ifp->if_bpf) bpf_mtap_af(ifp->if_bpf, dst->sa_family, m, BPF_DIRECTION_OUT); #endif if (sc->g_proto == IPPROTO_MOBILE) { if (ip_mobile_allow == 0) { IF_DROP(&ifp->if_snd); m_freem(m); error = EACCES; goto end; } if (dst->sa_family == AF_INET) { struct mbuf *m0; int msiz; /* * Make sure the complete IP header (with options) * is in the first mbuf. */ if (m->m_len < sizeof(struct ip)) { m = m_pullup(m, sizeof(struct ip)); if (m == NULL) { IF_DROP(&ifp->if_snd); error = ENOBUFS; goto end; } else inp = mtod(m, struct ip *); if (m->m_len < inp->ip_hl << 2) { m = m_pullup(m, inp->ip_hl << 2); if (m == NULL) { IF_DROP(&ifp->if_snd); error = ENOBUFS; goto end; } } } inp = mtod(m, struct ip *); bzero(&mob_h, MOB_H_SIZ_L); mob_h.proto = (inp->ip_p) << 8; mob_h.odst = inp->ip_dst.s_addr; inp->ip_dst.s_addr = sc->g_dst.s_addr; /* * If the packet comes from our host, we only change * the destination address in the IP header. * Otherwise we need to save and change the source. */ if (inp->ip_src.s_addr == sc->g_src.s_addr) { msiz = MOB_H_SIZ_S; } else { mob_h.proto |= MOB_H_SBIT; mob_h.osrc = inp->ip_src.s_addr; inp->ip_src.s_addr = sc->g_src.s_addr; msiz = MOB_H_SIZ_L; } HTONS(mob_h.proto); mob_h.hcrc = gre_in_cksum((u_int16_t *) &mob_h, msiz); /* Squeeze in the mobility header */ if ((m->m_data - msiz) < m->m_pktdat) { /* Need new mbuf */ MGETHDR(m0, M_DONTWAIT, MT_HEADER); if (m0 == NULL) { IF_DROP(&ifp->if_snd); m_freem(m); error = ENOBUFS; goto end; } M_MOVE_HDR(m0, m); m0->m_len = msiz + (inp->ip_hl << 2); m0->m_data += max_linkhdr; m0->m_pkthdr.len = m->m_pkthdr.len + msiz; m->m_data += inp->ip_hl << 2; m->m_len -= inp->ip_hl << 2; bcopy((caddr_t) inp, mtod(m0, caddr_t), sizeof(struct ip)); m0->m_next = m; m = m0; } else { /* we have some space left in the old one */ m->m_data -= msiz; m->m_len += msiz; m->m_pkthdr.len += msiz; bcopy(inp, mtod(m, caddr_t), inp->ip_hl << 2); } /* Copy Mobility header */ inp = mtod(m, struct ip *); bcopy(&mob_h, (caddr_t)(inp + 1), (unsigned) msiz); inp->ip_len = htons(ntohs(inp->ip_len) + msiz); } else { /* AF_INET */