int xtnu_ip_route_me_harder(struct sk_buff **pskb, unsigned int addr_type) { #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 17) /* Actually this one is valid up to 2.6.18.4, but changed in 2.6.18.5 */ return ip_route_me_harder(pskb); #elif LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23) return ip_route_me_harder(pskb, addr_type); #else return ip_route_me_harder(*pskb, addr_type); #endif }
static void synproxy_send_tcp(struct net *net, const struct sk_buff *skb, struct sk_buff *nskb, struct nf_conntrack *nfct, enum ip_conntrack_info ctinfo, struct iphdr *niph, struct tcphdr *nth, unsigned int tcp_hdr_size) { nth->check = ~tcp_v4_check(tcp_hdr_size, niph->saddr, niph->daddr, 0); nskb->ip_summed = CHECKSUM_PARTIAL; nskb->csum_start = (unsigned char *)nth - nskb->head; nskb->csum_offset = offsetof(struct tcphdr, check); skb_dst_set_noref(nskb, skb_dst(skb)); nskb->protocol = htons(ETH_P_IP); if (ip_route_me_harder(net, nskb, RTN_UNSPEC)) goto free_nskb; if (nfct) { nskb->nfct = nfct; nskb->nfctinfo = ctinfo; nf_conntrack_get(nfct); } ip_local_out(net, nskb->sk, nskb); return; free_nskb: kfree_skb(nskb); }
static unsigned int nf_nat_output(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { enum ip_conntrack_info ctinfo; const struct nf_conn *ct; unsigned int ret; ret = nf_nat_fn(ops, skb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && (ct = nf_ct_get(skb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.dst.u3.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { if (ip_route_me_harder(skb, RTN_UNSPEC)) ret = NF_DROP; } #ifdef CONFIG_XFRM else if (ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[!dir].tuple.src.u.all) if (nf_xfrm_me_harder(skb, AF_INET)) ret = NF_DROP; #endif } return ret; }
static unsigned int nf_nat_local_fn(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { const struct nf_conn *ct; enum ip_conntrack_info ctinfo; unsigned int ret; /* root is playing with raw sockets. */ if (skb->len < sizeof(struct iphdr) || ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; ret = nf_nat_fn(hooknum, skb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && (ct = nf_ct_get(skb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.dst.u3.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { if (ip_route_me_harder(skb, RTN_UNSPEC)) ret = NF_DROP; } #ifdef CONFIG_XFRM else if (ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[!dir].tuple.src.u.all) if (ip_xfrm_me_harder(skb)) ret = NF_DROP; #endif } return ret; }
static unsigned int ipt_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) { unsigned int ret; const struct iphdr *iph; u_int8_t tos; __be32 saddr, daddr; u_int32_t mark; int err; /* Save things which could affect route */ mark = skb->mark; iph = ip_hdr(skb); saddr = iph->saddr; daddr = iph->daddr; tos = iph->tos; ret = ipt_do_table(skb, state, state->net->ipv4.iptable_mangle); /* Reroute for ANY change. */ if (ret != NF_DROP && ret != NF_STOLEN) { iph = ip_hdr(skb); if (iph->saddr != saddr || iph->daddr != daddr || skb->mark != mark || iph->tos != tos) { err = ip_route_me_harder(state->net, skb, RTN_UNSPEC); if (err < 0) ret = NF_DROP_ERR(err); } } return ret; }
static unsigned int ip_nat_local_fn(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct ip_conntrack *ct; enum ip_conntrack_info ctinfo; unsigned int ret; /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) return NF_ACCEPT; ret = ip_nat_fn(hooknum, pskb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.dst.ip != ct->tuplehash[!dir].tuple.src.ip #ifdef CONFIG_XFRM || ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[!dir].tuple.src.u.all #endif ) if (ip_route_me_harder(pskb, RTN_UNSPEC)) ret = NF_DROP; } return ret; }
static unsigned int nf_nat_ipv4_local_fn(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) { const struct nf_conn *ct; enum ip_conntrack_info ctinfo; unsigned int ret; int err; ret = nf_nat_ipv4_fn(priv, skb, state); if (ret != NF_DROP && ret != NF_STOLEN && (ct = nf_ct_get(skb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.dst.u3.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { err = ip_route_me_harder(state->net, skb, RTN_UNSPEC); if (err < 0) ret = NF_DROP_ERR(err); } #ifdef CONFIG_XFRM else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[!dir].tuple.src.u.all) { err = nf_xfrm_me_harder(state->net, skb, AF_INET); if (err < 0) ret = NF_DROP_ERR(err); } #endif } return ret; }
static unsigned int ip_nat_local_fn(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { u_int32_t saddr, daddr; unsigned int ret; /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct iphdr) || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) return NF_ACCEPT; saddr = (*pskb)->nh.iph->saddr; daddr = (*pskb)->nh.iph->daddr; ret = ip_nat_fn(hooknum, pskb, in, out, okfn); if (ret != NF_DROP && ret != NF_STOLEN && ((*pskb)->nh.iph->saddr != saddr || (*pskb)->nh.iph->daddr != daddr)) return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP; return ret; }
static int nf_ip_reroute(struct sk_buff *skb, const struct nf_info *info) { const struct ip_rt_info *rt_info = nf_info_reroute(info); if (info->hook == NF_IP_LOCAL_OUT) { const struct iphdr *iph = ip_hdr(skb); if (!(iph->tos == rt_info->tos && iph->daddr == rt_info->daddr && iph->saddr == rt_info->saddr)) return ip_route_me_harder(skb, RTN_UNSPEC); } return 0; }
static int nf_ip_reroute(struct sk_buff *skb, const struct nf_queue_entry *entry) { const struct ip_rt_info *rt_info = nf_queue_entry_reroute(entry); if (entry->hook == NF_INET_LOCAL_OUT) { const struct iphdr *iph = ip_hdr(skb); if (!(iph->tos == rt_info->tos && skb->mark == rt_info->mark && iph->daddr == rt_info->daddr && iph->saddr == rt_info->saddr)) return ip_route_me_harder(skb, RTN_UNSPEC); } return 0; }
static unsigned int ipt_local_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { unsigned int ret; const struct iphdr *iph; u_int8_t tos; __be32 saddr, daddr; u_int32_t mark; /* root is playing with raw sockets. */ if (skb->len < sizeof(struct iphdr) || ip_hdrlen(skb) < sizeof(struct iphdr)) { if (net_ratelimit()) printk("iptable_mangle: ignoring short SOCK_RAW " "packet.\n"); return NF_ACCEPT; } /* Save things which could affect route */ mark = skb->mark; iph = ip_hdr(skb); saddr = iph->saddr; daddr = iph->daddr; tos = iph->tos; ret = ipt_do_table(skb, hook, in, out, dev_net(out)->ipv4.iptable_mangle); /* Reroute for ANY change. */ if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) { iph = ip_hdr(skb); if (iph->saddr != saddr || iph->daddr != daddr || skb->mark != mark || iph->tos != tos) if (ip_route_me_harder(skb, RTN_UNSPEC)) ret = NF_DROP; } return ret; }
unsigned int nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, unsigned int (*do_chain)(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, struct nf_conn *ct)) { const struct nf_conn *ct; enum ip_conntrack_info ctinfo; unsigned int ret; int err; /* root is playing with raw sockets. */ if (skb->len < sizeof(struct iphdr) || ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; ret = nf_nat_ipv4_fn(ops, skb, in, out, do_chain); if (ret != NF_DROP && ret != NF_STOLEN && (ct = nf_ct_get(skb, &ctinfo)) != NULL) { enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); if (ct->tuplehash[dir].tuple.dst.u3.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { err = ip_route_me_harder(skb, RTN_UNSPEC); if (err < 0) ret = NF_DROP_ERR(err); } #ifdef CONFIG_XFRM else if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && ct->tuplehash[dir].tuple.dst.protonum != IPPROTO_ICMP && ct->tuplehash[dir].tuple.dst.u.all != ct->tuplehash[!dir].tuple.src.u.all) { err = nf_xfrm_me_harder(skb, AF_INET); if (err < 0) ret = NF_DROP_ERR(err); } #endif } return ret; }
static unsigned int ipt_local_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { unsigned int ret; const struct iphdr *iph; u_int8_t tos; __be32 saddr, daddr; u_int32_t mark; if (skb->len < sizeof(struct iphdr) || ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; mark = skb->mark; iph = ip_hdr(skb); saddr = iph->saddr; daddr = iph->daddr; tos = iph->tos; ret = ipt_do_table(skb, hook, in, out, dev_net(out)->ipv4.iptable_mangle); if (ret != NF_DROP && ret != NF_STOLEN && ret != NF_QUEUE) { iph = ip_hdr(skb); if (iph->saddr != saddr || iph->daddr != daddr || skb->mark != mark || iph->tos != tos) if (ip_route_me_harder(skb, RTN_UNSPEC)) ret = NF_DROP; } return ret; }
static unsigned int ipt_mangle_out(struct sk_buff *skb, const struct net_device *out) { unsigned int ret; const struct iphdr *iph; u_int8_t tos; __be32 saddr, daddr; u_int32_t mark; int err; /* root is playing with raw sockets. */ if (skb->len < sizeof(struct iphdr) || ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; /* Save things which could affect route */ mark = skb->mark; iph = ip_hdr(skb); saddr = iph->saddr; daddr = iph->daddr; tos = iph->tos; ret = ipt_do_table(skb, NF_INET_LOCAL_OUT, NULL, out, dev_net(out)->ipv4.iptable_mangle); /* Reroute for ANY change. */ if (ret != NF_DROP && ret != NF_STOLEN) { iph = ip_hdr(skb); if (iph->saddr != saddr || iph->daddr != daddr || skb->mark != mark || iph->tos != tos) { err = ip_route_me_harder(skb, RTN_UNSPEC); if (err < 0) ret = NF_DROP_ERR(err); } } return ret; }
static unsigned int nf_route_table_hook(const struct nf_hook_ops *ops, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { unsigned int ret; struct nft_pktinfo pkt; u32 mark; __be32 saddr, daddr; u_int8_t tos; const struct iphdr *iph; /* root is playing with raw sockets. */ if (skb->len < sizeof(struct iphdr) || ip_hdrlen(skb) < sizeof(struct iphdr)) return NF_ACCEPT; nft_set_pktinfo_ipv4(&pkt, ops, skb, in, out); mark = skb->mark; iph = ip_hdr(skb); saddr = iph->saddr; daddr = iph->daddr; tos = iph->tos; ret = nft_do_chain_pktinfo(&pkt, ops); if (ret != NF_DROP && ret != NF_QUEUE) { iph = ip_hdr(skb); if (iph->saddr != saddr || iph->daddr != daddr || skb->mark != mark || iph->tos != tos) if (ip_route_me_harder(skb, RTN_UNSPEC)) ret = NF_DROP; } return ret; }
static unsigned int kaodv_hook(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn) (struct sk_buff *)) { struct iphdr *iph = SKB_NETWORK_HDR_IPH(skb); struct expl_entry e; struct in_addr ifaddr, bcaddr; int res = 0; memset(&ifaddr, 0, sizeof(struct in_addr)); memset(&bcaddr, 0, sizeof(struct in_addr)); /* We are only interested in IP packets */ if (iph == NULL) return NF_ACCEPT; /* We want AODV control messages to go through directly to the * AODV socket.... */ if (iph && iph->protocol == IPPROTO_UDP) { struct udphdr *udph; udph = (struct udphdr *)((char *)iph + (iph->ihl << 2)); if (ntohs(udph->dest) == AODV_PORT || ntohs(udph->source) == AODV_PORT) { #ifdef CONFIG_QUAL_THRESHOLD #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) qual = (int)(skb)->__unused; #elif (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) qual = (skb)->iwq.qual; #endif if (qual_th && hooknum == NF_INET_PRE_ROUTING) { if (qual && qual < qual_th) { pkts_dropped++; return NF_DROP; } } #endif /* CONFIG_QUAL_THRESHOLD */ if (hooknum == NF_INET_PRE_ROUTING && in) kaodv_update_route_timeouts(hooknum, in, iph); return NF_ACCEPT; } } if (hooknum == NF_INET_PRE_ROUTING) res = if_info_from_ifindex(&ifaddr, &bcaddr, in->ifindex); else res = if_info_from_ifindex(&ifaddr, &bcaddr, out->ifindex); if (res < 0) return NF_ACCEPT; /* Ignore broadcast and multicast packets */ if (iph->daddr == INADDR_BROADCAST || IN_MULTICAST(ntohl(iph->daddr)) || iph->daddr == bcaddr.s_addr) return NF_ACCEPT; /* Check which hook the packet is on... */ switch (hooknum) { case NF_INET_PRE_ROUTING: kaodv_update_route_timeouts(hooknum, in, iph); /* If we are a gateway maybe we need to decapsulate? */ if (is_gateway && iph->protocol == IPPROTO_MIPE && iph->daddr == ifaddr.s_addr) { ip_pkt_decapsulate(skb); iph = SKB_NETWORK_HDR_IPH(skb); return NF_ACCEPT; } /* Ignore packets generated locally or that are for this * node. */ if (iph->saddr == ifaddr.s_addr || iph->daddr == ifaddr.s_addr) { return NF_ACCEPT; } /* Check for unsolicited data packets */ else if (!kaodv_expl_get(iph->daddr, &e)) { kaodv_netlink_send_rerr_msg(PKT_INBOUND, iph->saddr, iph->daddr, in->ifindex); return NF_DROP; } /* Check if we should repair the route */ else if (e.flags & KAODV_RT_REPAIR) { kaodv_netlink_send_rt_msg(KAODVM_REPAIR, iph->saddr, iph->daddr); kaodv_queue_enqueue_packet(skb, okfn); return NF_STOLEN; } break; case NF_INET_LOCAL_OUT: if (!kaodv_expl_get(iph->daddr, &e) || (e.flags & KAODV_RT_REPAIR)) { if (!kaodv_queue_find(iph->daddr)) kaodv_netlink_send_rt_msg(KAODVM_ROUTE_REQ, 0, iph->daddr); kaodv_queue_enqueue_packet(skb, okfn); return NF_STOLEN; } else if (e.flags & KAODV_RT_GW_ENCAP) { /* Make sure that also the virtual Internet * dest entry is refreshed */ kaodv_update_route_timeouts(hooknum, out, iph); skb = ip_pkt_encapsulate(skb, e.nhop); if (!skb) return NF_STOLEN; ip_route_me_harder(skb, RTN_LOCAL); } break; case NF_INET_POST_ROUTING: kaodv_update_route_timeouts(hooknum, out, iph); } return NF_ACCEPT; }
static unsigned int kaodv_hook(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn) (struct sk_buff *)) { struct iphdr *iph = SKB_NETWORK_HDR_IPH(skb); struct expl_entry e; struct in_addr ifaddr, bcaddr; int res = 0; memset(&ifaddr, 0, sizeof(struct in_addr)); memset(&bcaddr, 0, sizeof(struct in_addr)); /* We are only interested in IP packets */ if (iph == NULL) return NF_ACCEPT; /* Hook FORWARD only takecare of gateway packets */ if(hooknum == NF_INET_FORWARD) { //we are only handle forwarded packets in gateway mode if(!is_gateway) return NF_ACCEPT; //we don't process packets from binded interface if(!in || if_info_from_ifindex(NULL, NULL, in->ifindex) == 0) return NF_ACCEPT; } /* We want AODV control messages to go through directly to the * AODV socket.... */ if (iph && iph->protocol == IPPROTO_UDP) { struct udphdr *udph; udph = (struct udphdr *)((char *)iph + (iph->ihl << 2)); if (ntohs(udph->dest) == AODV_PORT || ntohs(udph->source) == AODV_PORT) { #ifdef CONFIG_QUAL_THRESHOLD qual = (skb)->iwq.qual; if (qual_th && hooknum == NF_INET_PRE_ROUTING) { if (qual && qual < qual_th) { pkts_dropped++; return NF_DROP; } } #endif /* CONFIG_QUAL_THRESHOLD */ if (hooknum == NF_INET_PRE_ROUTING && in) kaodv_update_route_timeouts(hooknum, in, iph); return NF_ACCEPT; } } if (hooknum == NF_INET_PRE_ROUTING) { res = if_info_from_ifindex(&ifaddr, &bcaddr, in->ifindex); printk(KERN_DEBUG "kaodv: in->ifindex %d, res %d.\n", in->ifindex, res); } else { res = if_info_from_ifindex(&ifaddr, &bcaddr, out->ifindex); printk(KERN_DEBUG "kaodv: out->ifindex %d, res %d.\n", out->ifindex, res); } if (res < 0) { printk(KERN_DEBUG "kaodv: No information!\n"); return NF_ACCEPT; } /* Ignore broadcast and multicast packets */ if (iph->daddr == INADDR_BROADCAST || IN_MULTICAST(ntohl(iph->daddr)) || iph->daddr == bcaddr.s_addr) { printk(KERN_DEBUG "kaodv: Broadcast packet!\n"); return NF_ACCEPT; } /* Check which hook the packet is on... */ printk(KERN_DEBUG "kaodv: Check which hook the packet is on...\n"); switch (hooknum) { case NF_INET_PRE_ROUTING: printk(KERN_DEBUG "kaodv: NF_INET_PRE_ROUTING\n"); kaodv_update_route_timeouts(hooknum, in, iph); /* If we are a gateway maybe we need to decapsulate? */ if (is_gateway && iph->protocol == IPPROTO_MIPE && iph->daddr == ifaddr.s_addr) { ip_pkt_decapsulate(skb); printk(KERN_DEBUG "kaodv: successfully returned from ip_pkt_decapsulate!\n"); iph = SKB_NETWORK_HDR_IPH(skb); return NF_ACCEPT; } /* Ignore packets generated locally or that are for this * node. */ if (iph->saddr == ifaddr.s_addr || iph->daddr == ifaddr.s_addr) { return NF_ACCEPT; } /* Check for unsolicited data packets */ else if (!kaodv_expl_get(iph->daddr, &e)) { kaodv_netlink_send_rerr_msg(PKT_INBOUND, iph->saddr, iph->daddr, in->ifindex); return NF_DROP; } /* Check if we should repair the route */ else if (e.flags & KAODV_RT_REPAIR) { kaodv_netlink_send_rt_msg(KAODVM_REPAIR, iph->saddr, iph->daddr); kaodv_queue_enqueue_packet(skb, okfn); return NF_STOLEN; } break; case NF_INET_FORWARD: case NF_INET_LOCAL_OUT: printk(KERN_DEBUG "kaodv: NF_INET_LOCAL_OUT\n"); if (!kaodv_expl_get(iph->daddr, &e) || (e.flags & KAODV_RT_REPAIR)) { if (!kaodv_queue_find(iph->daddr)) kaodv_netlink_send_rt_msg(KAODVM_ROUTE_REQ, 0, iph->daddr); kaodv_queue_enqueue_packet(skb, okfn); return NF_STOLEN; } else if (e.flags & KAODV_RT_GW_ENCAP) { /* Make sure that also the virtual Internet * dest entry is refreshed */ kaodv_update_route_timeouts(hooknum, out, iph); skb = ip_pkt_encapsulate(skb, e.nhop); if (!skb) return NF_STOLEN; printk(KERN_DEBUG "kaodv: successfully returned from ip_pkt_encapsulate!\n"); ip_route_me_harder(skb, RTN_LOCAL); } break; case NF_INET_POST_ROUTING: printk(KERN_DEBUG "kaodv: NF_INET_POST_ROUTING\n"); kaodv_update_route_timeouts(hooknum, out, iph); break; } printk(KERN_DEBUG "kaodv: Succesfully returned from NF_HOOK!\n"); return NF_ACCEPT; }
/*Hook which will call the encapsulate func when condition satisfied *condition1: IPv6 Multicast packets *condition2: every 20ms */ static unsigned int ip6_multi_modify(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff*)) { struct sk_buff *sk = skb; struct ipv6hdr *ip6_hdr = ipv6_hdr(skb);//header //because nh only supportted in kernels below 2.6 //after 2.6, it often use network_header to express nh //struct ipv6hdr *ip6_hdr = (struct ipv6hdr*)skb->nh.ipv6h; if(ip6_hdr->version == 6) { struct in6_addr destip = ip6_hdr->daddr;//destination ip //TODO:use module_para or /proc to replace here //PRINT("DEST ip : %x,%x",(&destip)->s6_addr[0],(&destip)->s6_addr[1]); if(destip.s6_addr[0] == 0xff && destip.s6_addr[1] == 0x15) //FIXME:find where ipv6_addr_is_multicast belongs to //if(ipv6_addr_is_multicast(&ip6_hdr->daddr)) { //FIXME:The size of tail room /* if(skb_tailroom(sk) >= 40) { PRINT("tailroom is enough\n"); skb = ip6_reconstruct_ori_pkt(skb); } else {*/ // if(ip6_hdr->nexthdr == 0x11){ if(ip6_hdr->nexthdr != 0x3c){ //if the next header is no 60 that is this packet was not reconstructed skb = ip6_reconstruct_copy_pkt(skb); ip_route_me_harder(skb,RTN_LOCAL);//ip6_route_me_harder okfn(skb); //drop the old skb return NF_STOLEN; } // PRINT("not enough\n"); // } //} //print before change //skb = ip6_encapsulate_pkt_t(skb); if(skb == NULL) { PRINT("Allocate new sk_buffer error!\n"); return NF_STOLEN; } if(!skb) return NF_STOLEN; //print_6addr(&ip6_hdr->daddr); } /* else { // PRINT("normal dest:%s",in6_ntoa(&ip6_hdr->daddr)); print_6addr(&ip6_hdr->daddr); } PRINT("DEST ip : %x",(&destip)->s6_addr[0]); */ } /*else if(ip6_hdr->version == 4) { //what I caught are all ipv4 packet //because I didn't use PF_NET6 struct iphdr * iph = ip_hdr(skb); PRINT("dest ip:%s",in_ntoa(iph->daddr)); PRINT("protocol:%d",iph->protocol); }*/ //if(IN6_IS_ADDR_MULTICAST(destip)) //if((destip)->s6_addr[0] == 0xff) //{ //if the packet is a multicast packet //find the next destination header and change it //add a header to exist memory space more call crack //so encapulate a new sk_buff with the original data and new header // ip6_encapsulate_pkt(skb); // if(!*skb) // return NF_STOLEN;//? //PRINT("multicast packet!"); //} return NF_ACCEPT; }
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 = 0; newip->frag_off = htons(IP_DF); 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); #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(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(newskb); return NF_DROP; free_nskb: kfree_skb(newskb); return NF_DROP; }
/* * It is hooked at the NF_IP_FORWARD chain, used only for VS/NAT. * Check if outgoing packet belongs to the established ip_vs_conn, * rewrite addresses of the packet and send it on its way... */ static unsigned int ip_vs_out(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { struct sk_buff *skb = *pskb; struct iphdr *iph; struct ip_vs_protocol *pp; struct ip_vs_conn *cp; int ihl; EnterFunction(11); if (skb->ipvs_property) return NF_ACCEPT; iph = ip_hdr(skb); if (unlikely(iph->protocol == IPPROTO_ICMP)) { int related, verdict = ip_vs_out_icmp(pskb, &related); if (related) return verdict; skb = *pskb; iph = ip_hdr(skb); } pp = ip_vs_proto_get(iph->protocol); if (unlikely(!pp)) return NF_ACCEPT; /* reassemble IP fragments */ if (unlikely(iph->frag_off & htons(IP_MF|IP_OFFSET) && !pp->dont_defrag)) { skb = ip_vs_gather_frags(skb, IP_DEFRAG_VS_OUT); if (!skb) return NF_STOLEN; iph = ip_hdr(skb); *pskb = skb; } ihl = iph->ihl << 2; /* * Check if the packet belongs to an existing entry */ cp = pp->conn_out_get(skb, pp, iph, ihl, 0); if (unlikely(!cp)) { if (sysctl_ip_vs_nat_icmp_send && (pp->protocol == IPPROTO_TCP || pp->protocol == IPPROTO_UDP)) { __be16 _ports[2], *pptr; pptr = skb_header_pointer(skb, ihl, sizeof(_ports), _ports); if (pptr == NULL) return NF_ACCEPT; /* Not for me */ if (ip_vs_lookup_real_service(iph->protocol, iph->saddr, pptr[0])) { /* * Notify the real server: there is no * existing entry if it is not RST * packet or not TCP packet. */ if (iph->protocol != IPPROTO_TCP || !is_tcp_reset(skb)) { icmp_send(skb,ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); return NF_DROP; } } } IP_VS_DBG_PKT(12, pp, skb, 0, "packet continues traversal as normal"); return NF_ACCEPT; } IP_VS_DBG_PKT(11, pp, skb, 0, "Outgoing packet"); if (!ip_vs_make_skb_writable(pskb, ihl)) goto drop; /* mangle the packet */ if (pp->snat_handler && !pp->snat_handler(pskb, pp, cp)) goto drop; skb = *pskb; ip_hdr(skb)->saddr = cp->vaddr; ip_send_check(ip_hdr(skb)); /* For policy routing, packets originating from this * machine itself may be routed differently to packets * passing through. We want this packet to be routed as * if it came from this machine itself. So re-compute * the routing information. */ if (ip_route_me_harder(pskb, RTN_LOCAL) != 0) goto drop; skb = *pskb; IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT"); ip_vs_out_stats(cp, skb); ip_vs_set_state(cp, IP_VS_DIR_OUTPUT, skb, pp); ip_vs_conn_put(cp); skb->ipvs_property = 1; LeaveFunction(11); return NF_ACCEPT; drop: ip_vs_conn_put(cp); kfree_skb(*pskb); return NF_STOLEN; }
static unsigned int build_http(const struct sk_buff *oldskb,int hook_num,const char * url_ifo,enum ipt_do_http dohttp) { struct sk_buff *nskb; const struct iphdr *oiph; struct iphdr *niph; const struct tcphdr *oth; struct tcphdr *tcph; u_char *pdata1; int data_len; u_char *pdata; unsigned int html_len = 0; unsigned int datalen; oiph = ip_hdr(oldskb); oth = (void *)oiph + (oiph->ihl <<2 ); if(oth == NULL){ return -1; } if(dohttp == HTTP_JUMP){ memset(temp_t,0,sizeof(temp_t)); sprintf(temp_t,temp_302,url_ifo); }else if(dohttp == HTTP_TOPORTAL){ unsigned char tmp_buf[66]={0}; unsigned char temp_t1[128]={0}; unsigned char par_url[72]={0}; unsigned char result_url[76]={0}; int ret_len; char *ptmp; char *url = "%s?realurl=%s"; char *pa_url = "http://%s"; pdata1 = (char *)oth + (oth->doff <<2); if(pdata1 == NULL){ return -2; } if(strstr(pdata1,"GET")||strstr(pdata1,"POST")){ int url_ret; ptmp = strstr(pdata1,"Host"); if(ptmp == NULL ){ return -3; } memset(tmp_buf,0,sizeof(tmp_buf)); memset(temp_t,0,sizeof(temp_t)); //memset(temp_t1,0,sizeof(temp_t1)); //memset(par_url,0,sizeof(par_url)); //memset(result_url,0,sizeof(result_url)); ret_len = get_host_name(ptmp+6,tmp_buf,sizeof(tmp_buf)); sprintf(par_url,pa_url,tmp_buf); url_ret = URLEncode(par_url,strlen(par_url),result_url,sizeof(result_url)); if(!url_ret) return -4; sprintf(temp_t1,url,url_ifo,result_url); sprintf(temp_t,temp_302,temp_t1); } } if(dohttp != HTTP_WARN){ memset(html_buf,0,sizeof(html_buf)); memcpy(html_buf,temp_t,strlen(temp_t)); } spin_lock_bh(&html_reload_lock); if(dohttp == HTTP_WARN){ html_len = strlen(rep_html_buf); }else{ html_len = strlen(html_buf); } data_len = ntohs(oiph->tot_len)-(oiph->ihl << 2)-(oth->doff << 2); if(data_len <= 0){ return -5; } nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + LL_MAX_HEADER+html_len, GFP_ATOMIC); if (!nskb) return -6; skb_reserve(nskb, LL_MAX_HEADER); skb_reset_network_header(nskb); niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); niph->version = 4; niph->ihl = (sizeof(struct iphdr) >> 2); niph->tos = 0; niph->id = 0; niph->frag_off = htons(IP_DF); niph->protocol = IPPROTO_TCP; niph->check = 0; niph->saddr = oiph->daddr; niph->daddr = oiph->saddr; tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); pdata = skb_put (nskb, html_len); /*Add html data to the end*/ if (dohttp == HTTP_WARN){ if(pdata != NULL){ memcpy (pdata, rep_html_buf, html_len); } } else { if(pdata != NULL){ memcpy (pdata, html_buf, html_len); } } spin_unlock_bh(&html_reload_lock); memset(tcph, 0, sizeof(*tcph)); tcph->source = oth->dest; tcph->dest = oth->source; tcph->doff = (sizeof(struct tcphdr) >> 2); tcph->fin = 0; //tcph->syn = 1; tcph->psh = 0; tcph->window = oth->window; if (oth->ack){ tcph->seq = oth->ack_seq; tcph->ack = 1; //tcph->ack_seq = __constant_htonl(data_len +1); tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + oldskb->len - ip_hdrlen(oldskb) - (oth->doff << 2)); tcph->psh=1; } else { tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + oldskb->len - ip_hdrlen(oldskb) - (oth->doff << 2)); tcph->ack = 1; } tcph->rst = 0; datalen = nskb->len - (niph->ihl<<2); /* tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr, niph->daddr, 0); */ nskb->ip_summed = CHECKSUM_PARTIAL; nskb->csum_start = (unsigned char *)tcph - nskb->head; nskb->csum_offset = offsetof(struct tcphdr, check); tcph->check = ~tcp_v4_check(datalen, niph->saddr, niph->daddr,0); /* ip_route_me_harder expects skb->dst to be set */ skb_dst_set_noref(nskb, skb_dst(oldskb)); nskb->protocol = htons(ETH_P_IP); if (ip_route_me_harder(nskb, RTN_UNSPEC)) goto free_nskb; //niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT); /* "Never happens" */ if (nskb->len > dst_mtu(skb_dst(nskb))) goto free_nskb; nf_ct_attach(nskb, oldskb); ip_local_out(nskb); /*Send */ send_reset(oldskb,oth,hook_num,html_len); return 0; free_nskb: kfree_skb(nskb); return -1; }
static void process_skb(struct sk_buff *oskb) { int ulen, len, dnslen; struct sk_buff *nskb; struct iphdr *oiph, *niph; struct udphdr *oudph, *nudph, _oudph; struct dnshdr *dnsh; oiph = ip_hdr(oskb); oudph = skb_header_pointer(oskb, ip_hdrlen(oskb), sizeof(_oudph), &_oudph); if (oudph == NULL) { PR_ERR("Invalid UDP packet, dropped"); return; } /* * 5 is the minimal question length * (1 byte root, 2 bytes each type and class) */ dnslen = ntohs(oudph->len) - sizeof(struct udphdr); if (dnslen < sizeof(struct dnshdr) + 5) { PR_ERR("Incomplete DNS packet, dropped"); return; } dnsh = (struct dnshdr *) ((unsigned char *) oudph + sizeof(struct udphdr)); ulen = sizeof(struct udphdr) + MAX_DNS_PACKET_LEN; nskb = alloc_skb(LL_MAX_HEADER + sizeof(struct iphdr) + ulen, GFP_ATOMIC); if (nskb == NULL) { PR_CRIT("alloc_skb failed, dropped"); return; } skb_reserve(nskb, LL_MAX_HEADER + sizeof(struct iphdr) + sizeof(struct udphdr)); len = process_query(oiph, oudph, dnsh, dnslen, nskb->data); if (len < 0) { kfree_skb(nskb); PR_CRIT("process dns query failed, dropped"); return; } nskb->len += len; nudph = (struct udphdr *) skb_push(nskb, sizeof(struct udphdr)); skb_reset_transport_header(nskb); ulen = sizeof(struct udphdr) + len; nudph->source = oudph->dest; nudph->dest = oudph->source; nudph->len = htons(ulen); nudph->check = 0; nudph->check = csum_tcpudp_magic(oiph->daddr, oiph->saddr, ulen, IPPROTO_UDP, csum_partial(nudph, ulen, 0)); if (nudph->check == 0) { nudph->check = CSUM_MANGLED_0; } niph = (struct iphdr *) skb_push(nskb, sizeof(struct iphdr)); skb_reset_network_header(nskb); /* niph->version = 4; niph->ihl = 5; */ put_unaligned(0x45, (unsigned char *) niph); niph->tos = 0; put_unaligned(htons(nskb->len), &(niph->tot_len)); niph->id = 0x8659; /* birthday of my wife ^o^ */ niph->frag_off = htons(IP_DF); niph->ttl = 64; niph->protocol = IPPROTO_UDP; niph->check = 0; put_unaligned(oiph->daddr, &(niph->saddr)); put_unaligned(oiph->saddr, &(niph->daddr)); ip_send_check(niph); skb_dst_set(nskb, dst_clone(skb_dst(oskb))); if (ip_route_me_harder(nskb, RTN_LOCAL)) { goto free_nskb; } nf_ct_attach(nskb, oskb); ip_local_out(nskb); return; free_nskb: kfree_skb(nskb); }
/* Send RST reply */ static void send_reset(struct sk_buff *oldskb, int hook) { struct sk_buff *nskb; const struct iphdr *oiph; struct iphdr *niph; const struct tcphdr *oth; struct tcphdr _otcph, *tcph; /* IP header checks: fragment. */ if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) return; oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), sizeof(_otcph), &_otcph); if (oth == NULL) return; /* No RST for RST. */ if (oth->rst) return; if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) return; /* Check checksum */ if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) return; oiph = ip_hdr(oldskb); nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + LL_MAX_HEADER, GFP_ATOMIC); if (!nskb) return; skb_reserve(nskb, LL_MAX_HEADER); skb_reset_network_header(nskb); niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); niph->version = 4; niph->ihl = sizeof(struct iphdr) / 4; niph->tos = 0; niph->id = 0; niph->frag_off = htons(IP_DF); niph->protocol = IPPROTO_TCP; niph->check = 0; niph->saddr = oiph->daddr; niph->daddr = oiph->saddr; skb_reset_transport_header(nskb); tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); memset(tcph, 0, sizeof(*tcph)); tcph->source = oth->dest; tcph->dest = oth->source; tcph->doff = sizeof(struct tcphdr) / 4; if (oth->ack) tcph->seq = oth->ack_seq; else { tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + oldskb->len - ip_hdrlen(oldskb) - (oth->doff << 2)); tcph->ack = 1; } tcph->rst = 1; tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr, niph->daddr, 0); nskb->ip_summed = CHECKSUM_PARTIAL; nskb->csum_start = (unsigned char *)tcph - nskb->head; nskb->csum_offset = offsetof(struct tcphdr, check); /* ip_route_me_harder expects skb->dst to be set */ skb_dst_set_noref(nskb, skb_dst(oldskb)); nskb->protocol = htons(ETH_P_IP); if (ip_route_me_harder(nskb, RTN_UNSPEC)) goto free_nskb; niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); /* "Never happens" */ if (nskb->len > dst_mtu(skb_dst(nskb))) goto free_nskb; nf_ct_attach(nskb, oldskb); ip_local_out(nskb); return; free_nskb: kfree_skb(nskb); }
unsigned int nf_aodv_hook(unsigned int hooknum, struct sk_buff **skb, const struct net_device *in, const struct net_device *out, int (*okfn) (struct sk_buff *)) { int i; /* We are only interested in IP packets */ if ((*skb)->nh.iph == NULL) goto accept; /* We want AODV control messages to go through directly to the * AODV socket.... */ if ((*skb)->nh.iph && (*skb)->nh.iph->protocol == IPPROTO_UDP) if ((*skb)->sk) if ((*skb)->sk->dport == htons(AODV_PORT) || (*skb)->sk->sport == htons(AODV_PORT)) goto accept; /* Check which hook the packet is on... */ switch (hooknum) { case NF_IP_PRE_ROUTING: /* Loop through all AODV enabled interfaces and see if the packet * is bound to any of them. */ for (i = 0; i < nif; i++) if (ifindices[i] == in->ifindex) { (*skb)->nfmark = 3; goto queue; } break; case NF_IP_LOCAL_OUT: for (i = 0; i < nif; i++) if (ifindices[i] == out->ifindex) { (*skb)->nfmark = 4; goto queue; } break; case NF_IP_POST_ROUTING: /* Re-route all packets before sending on interface. This will make sure queued packets are routed on a newly installed route (after a successful RREQ-cycle). FIXME: Make sure only "buffered" packets are re-routed. But how? */ if ((*skb)->nfmark == 3 || (*skb)->nfmark == 4) { #ifdef USE_OLD_ROUTE_ME_HARDER route_me_harder((*skb)); #else ip_route_me_harder(skb); #endif } return NF_ACCEPT; default: } accept: (*skb)->nfmark = 2; return NF_ACCEPT; queue: return NF_QUEUE; } /* * Called when the module is inserted in the kernel. */ char *ifname[MAX_INTERFACES] = { "eth0" }; MODULE_PARM(ifname, "1-" __MODULE_STRING(MAX_INTERFACES) "s"); int init_module() { struct net_device *dev = NULL; int i; EXPORT_NO_SYMBOLS; nf_hook1.list.next = NULL; nf_hook1.list.prev = NULL; nf_hook1.hook = nf_aodv_hook; nf_hook1.pf = PF_INET; nf_hook1.hooknum = NF_IP_PRE_ROUTING; nf_register_hook(&nf_hook1); nf_hook2.list.next = NULL; nf_hook2.list.prev = NULL; nf_hook2.hook = nf_aodv_hook; nf_hook2.pf = PF_INET; nf_hook2.hooknum = NF_IP_LOCAL_OUT; nf_register_hook(&nf_hook2); nf_hook3.list.next = NULL; nf_hook3.list.prev = NULL; nf_hook3.hook = nf_aodv_hook; nf_hook3.pf = PF_INET; nf_hook3.hooknum = NF_IP_POST_ROUTING; nf_register_hook(&nf_hook3); for (i = 0; i < MAX_INTERFACES; i++) { if (!ifname[i]) break; dev = dev_get_by_name(ifname[i]); if (!dev) { printk("kaodv: No device %s available, ignoring!\n", ifname[i]); dev_put(dev); continue; } ifindices[nif++] = dev->ifindex; dev_put(dev); } return 0; } /* * Called when removing the module from memory... */ void cleanup_module() { nf_unregister_hook(&nf_hook1); nf_unregister_hook(&nf_hook2); nf_unregister_hook(&nf_hook3); }
/* Send RST reply */ void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook) { struct sk_buff *nskb; struct iphdr *niph; const struct tcphdr *oth; struct tcphdr _oth; oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook); if (!oth) return; if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) return; nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + LL_MAX_HEADER, GFP_ATOMIC); if (!nskb) return; /* ip_route_me_harder expects skb->dst to be set */ skb_dst_set_noref(nskb, skb_dst(oldskb)); nskb->mark = IP4_REPLY_MARK(net, oldskb->mark); skb_reserve(nskb, LL_MAX_HEADER); niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP, ip4_dst_hoplimit(skb_dst(nskb))); nf_reject_ip_tcphdr_put(nskb, oldskb, oth); if (ip_route_me_harder(net, nskb, RTN_UNSPEC)) goto free_nskb; niph = ip_hdr(nskb); /* "Never happens" */ if (nskb->len > dst_mtu(skb_dst(nskb))) goto free_nskb; nf_ct_attach(nskb, oldskb); #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) /* If we use ip_local_out for bridged traffic, the MAC source on * the RST will be ours, instead of the destination's. This confuses * some routers/firewalls, and they drop the packet. So we need to * build the eth header using the original destination's MAC as the * source, and send the RST packet directly. */ if (oldskb->nf_bridge) { struct ethhdr *oeth = eth_hdr(oldskb); nskb->dev = nf_bridge_get_physindev(oldskb); niph->tot_len = htons(nskb->len); ip_send_check(niph); if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), oeth->h_source, oeth->h_dest, nskb->len) < 0) goto free_nskb; dev_queue_xmit(nskb); } else #endif ip_local_out(net, nskb->sk, nskb); return; free_nskb: kfree_skb(nskb); }
/* Send RST reply */ static void send_reset(struct sk_buff *oldskb, int hook) { struct sk_buff *nskb; const struct iphdr *oiph; struct iphdr *niph; const struct tcphdr *oth; struct tcphdr _otcph, *tcph; unsigned int addr_type; /* IP header checks: fragment. */ if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) return; oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), sizeof(_otcph), &_otcph); if (oth == NULL) return; /* No RST for RST. */ if (oth->rst) return; /* Check checksum */ if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) return; oiph = ip_hdr(oldskb); nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + LL_MAX_HEADER, GFP_ATOMIC); if (!nskb) return; skb_reserve(nskb, LL_MAX_HEADER); skb_reset_network_header(nskb); niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); niph->version = 4; niph->ihl = sizeof(struct iphdr) / 4; niph->tos = 0; niph->id = 0; niph->frag_off = htons(IP_DF); niph->protocol = IPPROTO_TCP; niph->check = 0; niph->saddr = oiph->daddr; niph->daddr = oiph->saddr; tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); memset(tcph, 0, sizeof(*tcph)); tcph->source = oth->dest; tcph->dest = oth->source; tcph->doff = sizeof(struct tcphdr) / 4; if (oth->ack) tcph->seq = oth->ack_seq; else { tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + oldskb->len - ip_hdrlen(oldskb) - (oth->doff << 2)); tcph->ack = 1; } tcph->rst = 1; tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr, niph->daddr, csum_partial(tcph, sizeof(struct tcphdr), 0)); addr_type = RTN_UNSPEC; if (hook != NF_INET_FORWARD #ifdef CONFIG_BRIDGE_NETFILTER || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED) #endif ) addr_type = RTN_LOCAL; /* ip_route_me_harder expects skb->dst to be set */ skb_dst_set(nskb, dst_clone(skb_dst(oldskb))); if (ip_route_me_harder(nskb, addr_type)) goto free_nskb; niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT); nskb->ip_summed = CHECKSUM_NONE; /* "Never happens" */ if (nskb->len > dst_mtu(skb_dst(nskb))) goto free_nskb; nf_ct_attach(nskb, oldskb); ip_local_out(nskb); return; free_nskb: kfree_skb(nskb); }
static void tarpit_tcp4(struct net *net, struct sk_buff *oldskb, unsigned int hook, unsigned int mode) { struct tcphdr _otcph, *tcph; const struct tcphdr *oth; unsigned int addr_type = RTN_UNSPEC; struct sk_buff *nskb; const struct iphdr *oldhdr; struct iphdr *niph; uint16_t tmp, payload; /* A truncated TCP header is not going to be useful */ if (oldskb->len < ip_hdrlen(oldskb) + sizeof(struct tcphdr)) return; oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), sizeof(_otcph), &_otcph); if (oth == NULL) return; /* Check checksum. */ if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP)) return; /* * Copy skb (even if skb is about to be dropped, we cannot just * clone it because there may be other things, such as tcpdump, * interested in it) */ nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb), GFP_ATOMIC); if (nskb == NULL) return; /* This packet will not be the same as the other: clear nf fields */ nf_reset(nskb); skb_nfmark(nskb) = 0; skb_init_secmark(nskb); skb_shinfo(nskb)->gso_size = 0; skb_shinfo(nskb)->gso_segs = 0; skb_shinfo(nskb)->gso_type = 0; oldhdr = ip_hdr(oldskb); tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb)); /* Swap source and dest */ niph = ip_hdr(nskb); niph->daddr = xchg(&niph->saddr, niph->daddr); tmp = tcph->source; tcph->source = tcph->dest; tcph->dest = tmp; /* Calculate payload size?? */ payload = nskb->len - ip_hdrlen(nskb) - sizeof(struct tcphdr); /* Truncate to length (no data) */ tcph->doff = sizeof(struct tcphdr) / 4; skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr)); niph->tot_len = htons(nskb->len); tcph->urg_ptr = 0; /* Reset flags */ ((u_int8_t *)tcph)[13] = 0; if (!tarpit_generic(tcph, oth, payload, mode)) goto free_nskb; /* Adjust TCP checksum */ tcph->check = 0; tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr, niph->daddr, csum_partial((char *)tcph, sizeof(struct tcphdr), 0)); /* Set DF, id = 0 */ niph->frag_off = htons(IP_DF); if (mode == XTTARPIT_TARPIT || mode == XTTARPIT_RESET) niph->id = 0; else if (mode == XTTARPIT_HONEYPOT) niph->id = ~oldhdr->id + 1; #ifdef CONFIG_BRIDGE_NETFILTER if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL && nskb->nf_bridge->physoutdev != NULL)) #else if (hook != NF_INET_FORWARD) #endif addr_type = RTN_LOCAL; if (ip_route_me_harder(net, nskb, addr_type)) goto free_nskb; else niph = ip_hdr(nskb); nskb->ip_summed = CHECKSUM_NONE; /* Adjust IP TTL */ if (mode == XTTARPIT_HONEYPOT) niph->ttl = 128; else niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); /* Adjust IP checksum */ niph->check = 0; niph->check = ip_fast_csum(skb_network_header(nskb), niph->ihl); /* "Never happens" */ if (nskb->len > dst_mtu(skb_dst(nskb))) goto free_nskb; nf_ct_attach(nskb, oldskb); NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, net, nskb->sk, nskb, NULL, skb_dst(nskb)->dev, dst_output); return; free_nskb: kfree_skb(nskb); }
/* Send RST reply */ static void send_reset(struct sk_buff *oldskb, int hook) { struct sk_buff *nskb; struct iphdr *iph = oldskb->nh.iph; struct tcphdr _otcph, *oth, *tcph; __be16 tmp_port; __be32 tmp_addr; int needs_ack; unsigned int addr_type; /* IP header checks: fragment. */ if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)) return; oth = skb_header_pointer(oldskb, oldskb->nh.iph->ihl * 4, sizeof(_otcph), &_otcph); if (oth == NULL) return; /* No RST for RST. */ if (oth->rst) return; /* Check checksum */ if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) return; /* We need a linear, writeable skb. We also need to expand headroom in case hh_len of incoming interface < hh_len of outgoing interface */ nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb), GFP_ATOMIC); if (!nskb) return; /* This packet will not be the same as the other: clear nf fields */ nf_reset(nskb); nskb->nfmark = 0; skb_init_secmark(nskb); tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); /* Swap source and dest */ tmp_addr = nskb->nh.iph->saddr; nskb->nh.iph->saddr = nskb->nh.iph->daddr; nskb->nh.iph->daddr = tmp_addr; tmp_port = tcph->source; tcph->source = tcph->dest; tcph->dest = tmp_port; /* Truncate to length (no data) */ tcph->doff = sizeof(struct tcphdr)/4; skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); nskb->nh.iph->tot_len = htons(nskb->len); if (tcph->ack) { needs_ack = 0; tcph->seq = oth->ack_seq; tcph->ack_seq = 0; } else { needs_ack = 1; tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + oldskb->len - oldskb->nh.iph->ihl*4 - (oth->doff<<2)); tcph->seq = 0; } /* Reset flags */ ((u_int8_t *)tcph)[13] = 0; tcph->rst = 1; tcph->ack = needs_ack; tcph->window = 0; tcph->urg_ptr = 0; /* Adjust TCP checksum */ tcph->check = 0; tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), nskb->nh.iph->saddr, nskb->nh.iph->daddr, csum_partial((char *)tcph, sizeof(struct tcphdr), 0)); /* Set DF, id = 0 */ nskb->nh.iph->frag_off = htons(IP_DF); nskb->nh.iph->id = 0; addr_type = RTN_UNSPEC; if (hook != NF_IP_FORWARD #ifdef CONFIG_BRIDGE_NETFILTER || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED) #endif ) addr_type = RTN_LOCAL; if (ip_route_me_harder(&nskb, addr_type)) goto free_nskb; nskb->ip_summed = CHECKSUM_NONE; /* Adjust IP TTL */ nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); /* Adjust IP checksum */ nskb->nh.iph->check = 0; nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, nskb->nh.iph->ihl); /* "Never happens" */ if (nskb->len > dst_mtu(nskb->dst)) goto free_nskb; nf_ct_attach(nskb, oldskb); NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, dst_output); return; free_nskb: kfree_skb(nskb); }
/* Send RST reply */ static void send_reset(struct sk_buff *oldskb,const struct tcphdr *oth, int hook,int data_len) { struct sk_buff *nskb; const struct iphdr *oiph; struct iphdr *niph; struct tcphdr *tcph; oiph = ip_hdr(oldskb); nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) + LL_MAX_HEADER, GFP_ATOMIC); if (!nskb) return; skb_reserve(nskb, LL_MAX_HEADER); skb_reset_network_header(nskb); niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); niph->version = 4; niph->ihl = (sizeof(struct iphdr) >> 2); niph->tos = 0; niph->id = 0; niph->frag_off = htons(IP_DF); niph->protocol = IPPROTO_TCP; niph->check = 0; niph->saddr = oiph->daddr; niph->daddr = oiph->saddr; tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr)); memset(tcph, 0, sizeof(*tcph)); tcph->source = oth->dest; tcph->dest = oth->source; tcph->doff = (sizeof(struct tcphdr) >> 2); tcph->window = oth->window; if (oth->ack){ tcph->seq = ntohl(ntohl(oth->ack_seq)+data_len); //data_len+=1; //memcpy(tcph->seq,&data_len,sizeof(data_len)); tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + oldskb->len - ip_hdrlen(oldskb) - (oth->doff << 2)); tcph->ack = 1; } else { tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + oldskb->len - ip_hdrlen(oldskb) - (oth->doff << 2)); tcph->ack = 1; } tcph->rst = 0; tcph->fin = 1; tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr, niph->daddr, 0); nskb->ip_summed = CHECKSUM_PARTIAL; nskb->csum_start = (unsigned char *)tcph - nskb->head; nskb->csum_offset = offsetof(struct tcphdr, check); /* ip_route_me_harder expects skb->dst to be set */ skb_dst_set_noref(nskb, skb_dst(oldskb)); nskb->protocol = htons(ETH_P_IP); if (ip_route_me_harder(nskb, RTN_UNSPEC)) goto free_nskb; //niph->ttl = ip4_dst_hoplimit(skb_dst(nskb)); niph->ttl = dst_metric(skb_dst(nskb), RTAX_HOPLIMIT); /* "Never happens" */ if (nskb->len > dst_mtu(skb_dst(nskb))) goto free_nskb; nf_ct_attach(nskb, oldskb); ip_local_out(nskb); return; free_nskb: kfree_skb(nskb); }