📄 ip_gre.c
字号:
default: return; case ICMP_PARAMETERPROB: if (skb->h.icmph->un.gateway < (iph->ihl<<2)) return; /* So... This guy found something strange INSIDE encapsulated packet. Well, he is fool, but what can we do ? */ rel_type = ICMP_PARAMETERPROB; rel_info = skb->h.icmph->un.gateway - grehlen; break; case ICMP_DEST_UNREACH: switch (code) { case ICMP_SR_FAILED: case ICMP_PORT_UNREACH: /* Impossible event. */ return; case ICMP_FRAG_NEEDED: /* And it is the only really necesary thing :-) */ rel_info = ntohs(skb->h.icmph->un.frag.mtu); if (rel_info < grehlen+68) return; rel_info -= grehlen; /* BSD 4.2 MORE DOES NOT EXIST IN NATURE. */ if (rel_info > ntohs(eiph->tot_len)) return; break; default: /* All others are translated to HOST_UNREACH. rfc2003 contains "deep thoughts" about NET_UNREACH, I believe, it is just ether pollution. --ANK */ rel_type = ICMP_DEST_UNREACH; rel_code = ICMP_HOST_UNREACH; break; } break; case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) return; break; } /* Prepare fake skb to feed it to icmp_send */ skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 == NULL) return; dst_release(skb2->dst); skb2->dst = NULL; skb_pull(skb2, skb->data - (u8*)eiph); skb2->nh.raw = skb2->data; /* Try to guess incoming interface */ if (ip_route_output(&rt, eiph->saddr, 0, RT_TOS(eiph->tos), 0)) { kfree_skb(skb2); return; } skb2->dev = rt->u.dst.dev; /* route "incoming" packet */ if (rt->rt_flags&RTCF_LOCAL) { ip_rt_put(rt); rt = NULL; if (ip_route_output(&rt, eiph->daddr, eiph->saddr, eiph->tos, 0) || rt->u.dst.dev->type != ARPHRD_IPGRE) { ip_rt_put(rt); kfree_skb(skb2); return; } } else { ip_rt_put(rt); if (ip_route_input(skb2, eiph->daddr, eiph->saddr, eiph->tos, skb2->dev) || skb2->dst->dev->type != ARPHRD_IPGRE) { kfree_skb(skb2); return; } } /* change mtu on this route */ if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { if (rel_info > skb2->dst->pmtu) { kfree_skb(skb2); return; } skb2->dst->pmtu = rel_info; rel_info = htonl(rel_info); } else if (type == ICMP_TIME_EXCEEDED) { struct ip_tunnel *t = (struct ip_tunnel*)skb2->dev->priv; if (t->parms.iph.ttl) { rel_type = ICMP_DEST_UNREACH; rel_code = ICMP_HOST_UNREACH; } } icmp_send(skb2, rel_type, rel_code, rel_info); kfree_skb(skb2);#endif}static inline void ipgre_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb){ if (INET_ECN_is_ce(iph->tos)) { if (skb->protocol == __constant_htons(ETH_P_IP)) { if (INET_ECN_is_not_ce(skb->nh.iph->tos)) IP_ECN_set_ce(skb->nh.iph); } else if (skb->protocol == __constant_htons(ETH_P_IPV6)) { if (INET_ECN_is_not_ce(ip6_get_dsfield(skb->nh.ipv6h))) IP6_ECN_set_ce(skb->nh.ipv6h); } }}static inline u8ipgre_ecn_encapsulate(u8 tos, struct iphdr *old_iph, struct sk_buff *skb){ u8 inner = 0; if (skb->protocol == __constant_htons(ETH_P_IP)) inner = old_iph->tos; else if (skb->protocol == __constant_htons(ETH_P_IPV6)) inner = ip6_get_dsfield((struct ipv6hdr*)old_iph); return INET_ECN_encapsulate(tos, inner);}int ipgre_rcv(struct sk_buff *skb){ struct iphdr *iph; u8 *h; u16 flags; u16 csum = 0; u32 key = 0; u32 seqno = 0; struct ip_tunnel *tunnel; int offset = 4; if (!pskb_may_pull(skb, 16)) goto drop_nolock; iph = skb->nh.iph; h = skb->data; flags = *(u16*)h; if (flags&(GRE_CSUM|GRE_KEY|GRE_ROUTING|GRE_SEQ|GRE_VERSION)) { /* - Version must be 0. - We do not support routing headers. */ if (flags&(GRE_VERSION|GRE_ROUTING)) goto drop_nolock; if (flags&GRE_CSUM) { if (skb->ip_summed == CHECKSUM_HW) { csum = (u16)csum_fold(skb->csum); if (csum) skb->ip_summed = CHECKSUM_NONE; } if (skb->ip_summed == CHECKSUM_NONE) { skb->csum = skb_checksum(skb, 0, skb->len, 0); skb->ip_summed = CHECKSUM_HW; csum = (u16)csum_fold(skb->csum); } offset += 4; } if (flags&GRE_KEY) { key = *(u32*)(h + offset); offset += 4; } if (flags&GRE_SEQ) { seqno = ntohl(*(u32*)(h + offset)); offset += 4; } } read_lock(&ipgre_lock); if ((tunnel = ipgre_tunnel_lookup(iph->saddr, iph->daddr, key)) != NULL) { skb->mac.raw = skb->nh.raw; skb->nh.raw = __pskb_pull(skb, offset); memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); if (skb->ip_summed == CHECKSUM_HW) skb->csum = csum_sub(skb->csum, csum_partial(skb->mac.raw, skb->nh.raw-skb->mac.raw, 0)); skb->protocol = *(u16*)(h + 2); skb->pkt_type = PACKET_HOST;#ifdef CONFIG_NET_IPGRE_BROADCAST if (MULTICAST(iph->daddr)) { /* Looped back packet, drop it! */ if (((struct rtable*)skb->dst)->key.iif == 0) goto drop; tunnel->stat.multicast++; skb->pkt_type = PACKET_BROADCAST; }#endif if (((flags&GRE_CSUM) && csum) || (!(flags&GRE_CSUM) && tunnel->parms.i_flags&GRE_CSUM)) { tunnel->stat.rx_crc_errors++; tunnel->stat.rx_errors++; goto drop; } if (tunnel->parms.i_flags&GRE_SEQ) { if (!(flags&GRE_SEQ) || (tunnel->i_seqno && (s32)(seqno - tunnel->i_seqno) < 0)) { tunnel->stat.rx_fifo_errors++; tunnel->stat.rx_errors++; goto drop; } tunnel->i_seqno = seqno + 1; } tunnel->stat.rx_packets++; tunnel->stat.rx_bytes += skb->len; skb->dev = tunnel->dev; dst_release(skb->dst); skb->dst = NULL;#ifdef CONFIG_NETFILTER nf_conntrack_put(skb->nfct); skb->nfct = NULL;#ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug = 0;#endif#endif ipgre_ecn_decapsulate(iph, skb); netif_rx(skb); read_unlock(&ipgre_lock); return(0); } icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, 0);drop: read_unlock(&ipgre_lock);drop_nolock: kfree_skb(skb); return(0);}/* Need this wrapper because NF_HOOK takes the function address */static inline int do_ip_send(struct sk_buff *skb){ return ip_send(skb);}static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev){ struct ip_tunnel *tunnel = (struct ip_tunnel*)dev->priv; struct net_device_stats *stats = &tunnel->stat; struct iphdr *old_iph = skb->nh.iph; struct iphdr *tiph; u8 tos; u16 df; struct rtable *rt; /* Route to the other host */ struct net_device *tdev; /* Device to other host */ struct iphdr *iph; /* Our new IP header */ int max_headroom; /* The extra header space needed */ int gre_hlen; u32 dst; int mtu; if (tunnel->recursion++) { tunnel->stat.collisions++; goto tx_error; } if (dev->hard_header) { gre_hlen = 0; tiph = (struct iphdr*)skb->data; } else { gre_hlen = tunnel->hlen; tiph = &tunnel->parms.iph; } if ((dst = tiph->daddr) == 0) { /* NBMA tunnel */ if (skb->dst == NULL) { tunnel->stat.tx_fifo_errors++; goto tx_error; } if (skb->protocol == __constant_htons(ETH_P_IP)) { rt = (struct rtable*)skb->dst; if ((dst = rt->rt_gateway) == 0) goto tx_error_icmp; }#ifdef CONFIG_IPV6 else if (skb->protocol == __constant_htons(ETH_P_IPV6)) { struct in6_addr *addr6; int addr_type; struct neighbour *neigh = skb->dst->neighbour; if (neigh == NULL) goto tx_error; addr6 = (struct in6_addr*)&neigh->primary_key; addr_type = ipv6_addr_type(addr6); if (addr_type == IPV6_ADDR_ANY) { addr6 = &skb->nh.ipv6h->daddr; addr_type = ipv6_addr_type(addr6); } if ((addr_type & IPV6_ADDR_COMPATv4) == 0) goto tx_error_icmp; dst = addr6->s6_addr32[3]; }#endif else goto tx_error; } tos = tiph->tos; if (tos&1) { if (skb->protocol == __constant_htons(ETH_P_IP)) tos = old_iph->tos; tos &= ~1; } if (ip_route_output(&rt, dst, tiph->saddr, RT_TOS(tos), tunnel->parms.link)) { tunnel->stat.tx_carrier_errors++; goto tx_error; } tdev = rt->u.dst.dev; if (tdev == dev) { ip_rt_put(rt); tunnel->stat.collisions++; goto tx_error; } df = tiph->frag_off; mtu = rt->u.dst.pmtu - tunnel->hlen; if (skb->protocol == __constant_htons(ETH_P_IP)) { if (skb->dst && mtu < skb->dst->pmtu && mtu >= 68) skb->dst->pmtu = mtu; df |= (old_iph->frag_off&__constant_htons(IP_DF)); if ((old_iph->frag_off&__constant_htons(IP_DF)) && mtu < ntohs(old_iph->tot_len)) { icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); ip_rt_put(rt); goto tx_error; } }#ifdef CONFIG_IPV6 else if (skb->protocol == __constant_htons(ETH_P_IPV6)) { struct rt6_info *rt6 = (struct rt6_info*)skb->dst; if (rt6 && mtu < rt6->u.dst.pmtu && mtu >= IPV6_MIN_MTU) { if ((tunnel->parms.iph.daddr && !MULTICAST(tunnel->parms.iph.daddr)) || rt6->rt6i_dst.plen == 128) { rt6->rt6i_flags |= RTF_MODIFIED; skb->dst->pmtu = mtu; } } if (mtu >= IPV6_MIN_MTU && mtu < skb->len - tunnel->hlen + gre_hlen) { icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); ip_rt_put(rt); goto tx_error; } }#endif if (tunnel->err_count > 0) { if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) { tunnel->err_count--; dst_link_failure(skb); } else tunnel->err_count = 0; } skb->h.raw = skb->nh.raw; max_headroom = ((tdev->hard_header_len+15)&~15)+ gre_hlen; if (skb_headroom(skb) < max_headroom || skb_cloned(skb) || skb_shared(skb)) { struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); if (!new_skb) { ip_rt_put(rt); stats->tx_dropped++; dev_kfree_skb(skb); tunnel->recursion--; return 0; } if (skb->sk) skb_set_owner_w(new_skb, skb->sk); dev_kfree_skb(skb); skb = new_skb; } skb->nh.raw = skb_push(skb, gre_hlen); memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); dst_release(skb->dst); skb->dst = &rt->u.dst; /* * Push down and install the IPIP header. */ iph = skb->nh.iph; iph->version = 4; iph->ihl = sizeof(struct iphdr) >> 2; iph->frag_off = df; iph->protocol = IPPROTO_GRE; iph->tos = ipgre_ecn_encapsulate(tos, old_iph, skb); iph->daddr = rt->rt_dst; iph->saddr = rt->rt_src; if ((iph->ttl = tiph->ttl) == 0) { if (skb->protocol == __constant_htons(ETH_P_IP)) iph->ttl = old_iph->ttl;#ifdef CONFIG_IPV6 else if (skb->protocol == __constant_htons(ETH_P_IPV6)) iph->ttl = ((struct ipv6hdr*)old_iph)->hop_limit;#endif else iph->ttl = sysctl_ip_default_ttl; } ((u16*)(iph+1))[0] = tunnel->parms.o_flags; ((u16*)(iph+1))[1] = skb->protocol; if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) { u32 *ptr = (u32*)(((u8*)iph) + tunnel->hlen - 4); if (tunnel->parms.o_flags&GRE_SEQ) { ++tunnel->o_seqno; *ptr = htonl(tunnel->o_seqno); ptr--; } if (tunnel->parms.o_flags&GRE_KEY) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -