static unsigned int tarpit_tg4(struct sk_buff *skb, const struct xt_action_param *par) { const struct iphdr *iph = ip_hdr(skb); const struct rtable *rt = skb_rtable(skb); const struct xt_tarpit_tginfo *info = par->targinfo; /* Do we have an input route cache entry? (Not in PREROUTING.) */ if (rt == NULL) return NF_DROP; /* No replies to physical multicast/broadcast */ /* skb != PACKET_OTHERHOST handled by ip_rcv() */ if (skb->pkt_type != PACKET_HOST) return NF_DROP; /* Now check at the protocol level */ if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) return NF_DROP; /* * Our naive response construction does not deal with IP * options, and probably should not try. */ if (ip_hdrlen(skb) != sizeof(struct iphdr)) return NF_DROP; /* We are not interested in fragments */ if (iph->frag_off & htons(IP_OFFSET)) return NF_DROP; tarpit_tcp4(par_net(par), skb, par->state->hook, info->variant); return NF_DROP; }
static unsigned int tarpit_tg6(struct sk_buff *skb, const struct xt_action_param *par) { const struct ipv6hdr *iph = ipv6_hdr(skb); const struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); const struct xt_tarpit_tginfo *info = par->targinfo; uint8_t proto; __be16 frag_off; /* Do we have an input route cache entry? (Not in PREROUTING.) */ if (rt == NULL) { pr_debug("Dropping no input route cache entry\n"); return NF_DROP; } /* No replies to physical multicast/broadcast */ /* skb != PACKET_OTHERHOST handled by ip_rcv() */ if (skb->pkt_type != PACKET_HOST) { pr_debug("type != PACKET_HOST"); return NF_DROP; } /* * Our naive response construction does not deal with IP * options, and probably should not try. */ proto = iph->nexthdr; if (ipv6_skip_exthdr(skb, skb_network_header_len(skb), &proto, &frag_off) != sizeof(struct ipv6hdr)) return NF_DROP; if ((!(ipv6_addr_type(&iph->saddr) & IPV6_ADDR_UNICAST)) || (!(ipv6_addr_type(&iph->daddr) & IPV6_ADDR_UNICAST))) { pr_debug("addr is not unicast.\n"); return NF_DROP; } tarpit_tcp6(par_net(par), skb, par->state->hook, info->variant); return NF_DROP; }
static unsigned int echo_tg6(struct sk_buff *oldskb, const struct xt_action_param *par) { const struct udphdr *oldudp; const struct ipv6hdr *oldip; struct udphdr *newudp, oldudp_buf; struct ipv6hdr *newip; struct sk_buff *newskb; unsigned int data_len; void *payload; struct flowi6 fl; struct dst_entry *dst = NULL; struct net *net = dev_net((par->in != NULL) ? par->in : par->out); /* This allows us to do the copy operation in fewer lines of code. */ if (skb_linearize(oldskb) < 0) return NF_DROP; oldip = ipv6_hdr(oldskb); oldudp = skb_header_pointer(oldskb, par->thoff, sizeof(*oldudp), &oldudp_buf); if (oldudp == NULL) return NF_DROP; if (ntohs(oldudp->len) <= sizeof(*oldudp)) return NF_DROP; newskb = alloc_skb(LL_MAX_HEADER + sizeof(*newip) + ntohs(oldudp->len), GFP_ATOMIC); if (newskb == NULL) return NF_DROP; skb_reserve(newskb, LL_MAX_HEADER); newskb->protocol = oldskb->protocol; skb_reset_network_header(newskb); newip = (void *)skb_put(newskb, sizeof(*newip)); newip->version = oldip->version; newip->priority = oldip->priority; memcpy(newip->flow_lbl, oldip->flow_lbl, sizeof(newip->flow_lbl)); newip->nexthdr = par->target->proto; newip->saddr = oldip->daddr; newip->daddr = oldip->saddr; skb_reset_transport_header(newskb); newudp = (void *)skb_put(newskb, sizeof(*newudp)); newudp->source = oldudp->dest; newudp->dest = oldudp->source; newudp->len = oldudp->len; data_len = htons(oldudp->len) - sizeof(*oldudp); payload = skb_header_pointer(oldskb, par->thoff + sizeof(*oldudp), data_len, NULL); memcpy(skb_put(newskb, data_len), payload, data_len); newip->payload_len = htons(newskb->len); #if 0 /* * Since no fields are modified (we just swapped things around), * this works too in our specific echo case. */ newudp->check = oldudp->check; #else newudp->check = 0; newudp->check = csum_ipv6_magic(&newip->saddr, &newip->daddr, ntohs(newudp->len), IPPROTO_UDP, csum_partial(newudp, ntohs(newudp->len), 0)); #endif memset(&fl, 0, sizeof(fl)); fl.flowi6_proto = newip->nexthdr; memcpy(&fl.saddr, &newip->saddr, sizeof(fl.saddr)); memcpy(&fl.daddr, &newip->daddr, sizeof(fl.daddr)); fl.fl6_sport = newudp->source; fl.fl6_dport = newudp->dest; security_skb_classify_flow((struct sk_buff *)oldskb, flowi6_to_flowi(&fl)); dst = ip6_route_output(net, NULL, &fl); if (dst == NULL || dst->error != 0) { dst_release(dst); goto free_nskb; } skb_dst_set(newskb, dst); newip->hop_limit = ip6_dst_hoplimit(skb_dst(newskb)); newskb->ip_summed = CHECKSUM_NONE; /* "Never happens" (?) */ if (newskb->len > dst_mtu(skb_dst(newskb))) goto free_nskb; nf_ct_attach(newskb, oldskb); ip6_local_out(par_net(par), newskb->sk, newskb); return NF_DROP; free_nskb: kfree_skb(newskb); return NF_DROP; }
static unsigned int echo_tg4(struct sk_buff *oldskb, const struct xt_action_param *par) { const struct udphdr *oldudp; const struct iphdr *oldip; struct udphdr *newudp, oldudp_buf; struct iphdr *newip; struct sk_buff *newskb; unsigned int data_len; void *payload; /* This allows us to do the copy operation in fewer lines of code. */ if (skb_linearize(oldskb) < 0) return NF_DROP; oldip = ip_hdr(oldskb); oldudp = skb_header_pointer(oldskb, par->thoff, sizeof(*oldudp), &oldudp_buf); if (oldudp == NULL) return NF_DROP; if (ntohs(oldudp->len) <= sizeof(*oldudp)) return NF_DROP; newskb = alloc_skb(LL_MAX_HEADER + sizeof(*newip) + ntohs(oldudp->len), GFP_ATOMIC); if (newskb == NULL) return NF_DROP; skb_reserve(newskb, LL_MAX_HEADER); newskb->protocol = oldskb->protocol; skb_reset_network_header(newskb); newip = (void *)skb_put(newskb, sizeof(*newip)); newip->version = oldip->version; newip->ihl = sizeof(*newip) / 4; newip->tos = oldip->tos; newip->id = oldip->id; newip->frag_off = 0; newip->protocol = oldip->protocol; newip->check = 0; newip->saddr = oldip->daddr; newip->daddr = oldip->saddr; skb_reset_transport_header(newskb); newudp = (void *)skb_put(newskb, sizeof(*newudp)); newudp->source = oldudp->dest; newudp->dest = oldudp->source; newudp->len = oldudp->len; data_len = htons(oldudp->len) - sizeof(*oldudp); payload = skb_header_pointer(oldskb, par->thoff + sizeof(*oldudp), data_len, NULL); memcpy(skb_put(newskb, data_len), payload, data_len); newip->tot_len = htons(newskb->len); #if 0 /* * Since no fields are modified (we just swapped things around), * this works too in our specific echo case. */ newudp->check = oldudp->check; #else newudp->check = 0; newudp->check = csum_tcpudp_magic(newip->saddr, newip->daddr, ntohs(newudp->len), IPPROTO_UDP, csum_partial(newudp, ntohs(newudp->len), 0)); #endif /* ip_route_me_harder expects the skb's dst to be set */ skb_dst_set(newskb, dst_clone(skb_dst(oldskb))); if (ip_route_me_harder(par_net(par), newskb, RTN_UNSPEC) != 0) goto free_nskb; newip->ttl = ip4_dst_hoplimit(skb_dst(newskb)); newskb->ip_summed = CHECKSUM_NONE; /* "Never happens" (?) */ if (newskb->len > dst_mtu(skb_dst(newskb))) goto free_nskb; nf_ct_attach(newskb, oldskb); ip_local_out(par_net(par), newskb->sk, newskb); return NF_DROP; free_nskb: kfree_skb(newskb); return NF_DROP; }