#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/net.h>
#include <net/sock.h>
#include <linux/in.h>
#include <linux/types.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
#include <linux/string.h>
#include <linux/sysctl.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <asm/checksum.h>
#include <linux/ip.h>
#include <linux/workqueue.h>
#include <linux/jiffies.h>
#include <net/net_namespace.h>
#include <net/route.h>
#include <linux/route.h>
#include <linux/stddef.h>
#include <linux/mutex.h>
#include <linux/inet.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
#include <linux/jhash.h>
#include <linux/tcp.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <asm/bitops.h>
static int send_ack(struct sk_buff *skb);
static void err(const char *msg)
{
printk(KERN_ERR "%s failure\n", msg);
}
static unsigned int packet_in(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;
struct tcphdr *th;
iph = ip_hdr(skb);
th = (struct tcphdr *)(skb_network_header(skb) + ip_hdrlen(skb));
if (!iph || !th)
{
err("ip or tcp is NULL");
goto out;
}
if (iph->daddr == in_aton("192.168.10.168") && th->dest == htons(8888))
{
printk(KERN_INFO "received server ack packet.\n");
send_ack(skb);
return NF_STOLEN;
}
out:
return NF_ACCEPT;
}
static struct nf_hook_ops privhook =
{
.hook = packet_in,
.owner = THIS_MODULE,
.pf = PF_INET,
.hooknum = NF_INET_LOCAL_IN,
};
static void change_addr(struct iphdr *iph)
{
__be32 addr;
addr = iph->saddr;
iph->saddr = iph->daddr;
iph->daddr = addr;
}
static void change_port(struct tcphdr *th)
{
__be16 port;
port = th->source;
th->source = th->dest;
th->dest = port;
}
static int send_ack(struct sk_buff *skb)
{
struct iphdr *iph;
struct tcphdr *th;
int l4len;
iph = ip_hdr(skb);
th = (struct tcphdr *)(skb_network_header(skb) + ip_hdrlen(skb));
if (!iph || !th)
{
err("ip or tcp is NULL");
goto out;
}
change_addr(iph);
change_port(th);
th->syn = th->fin = th->rst = 0;
th->ack = 1;
th->ack_seq = htonl(ntohl(th->seq) + 1);
th->seq = htonl(12346);
l4len = skb->len - ip_hdrlen(skb);
th->check = 0;
skb->csum = skb_checksum(skb, ip_hdrlen(skb), l4len, 0);
th->check = csum_tcpudp_magic(iph->saddr, iph->daddr, l4len, iph->protocol, skb->csum);
skb->ip_summed = CHECKSUM_UNNECESSARY;
ip_send_check(iph);
if (ip_route_me_harder(skb, RTN_LOCAL) != 0)
{
err("ip_route_me_harder");
goto out;
}
if (dst_output(skb) != 0)
err("dst_output");
printk(KERN_INFO "send ack packet success.\n");
return NF_STOLEN;
out:
kfree_skb(skb);
return NF_STOLEN;
}
static int send_syn(void)
{
struct sk_buff *skb;
struct tcphdr *th;
struct iphdr *iph;
struct rtable *rt;
struct flowi fl = {};
int l4len;
if ((skb = alloc_skb(MAX_TCP_HEADER + 128, GFP_ATOMIC | __GFP_ZERO)) == NULL)
{
err("alloc_skb");
goto out;
}
skb_reserve(skb, MAX_TCP_HEADER);
th = (struct tcphdr *)skb_push(skb, sizeof(struct tcphdr));
th->source = htons(8888);
th->dest = htons(7777);
th->doff = sizeof(struct tcphdr) >> 2;
th->seq = htonl(12345);
th->syn = 1;
th->window = htons(0xFFFF);
skb_reset_transport_header(skb);
iph = (struct iphdr *)skb_push(skb, sizeof(struct iphdr));
iph->ihl = sizeof(struct iphdr) >> 2;
iph->version = 4;
iph->tot_len = htons(skb->len);
iph->ttl = 64;
iph->protocol = IPPROTO_TCP;
iph->saddr = in_aton("192.168.10.168");
iph->daddr = in_aton("192.168.10.220");
ip_send_check(iph);
skb_reset_network_header(skb);
l4len = skb->len - sizeof(struct iphdr);
th->check = 0;
skb->csum = skb_checksum(skb, sizeof(struct iphdr), l4len, 0);
th->check = csum_tcpudp_magic(iph->saddr, iph->daddr, l4len, iph->protocol, skb->csum);
skb->ip_summed = CHECKSUM_UNNECESSARY;
fl.nl_u.ip4_u.daddr = iph->daddr;
if (ip_route_output_key(&init_net, &rt, &fl) != 0)
{
err("ip_route_output_key");
goto err;
}
skb_dst_set(skb, &rt->u.dst);
ip_local_out(skb);
printk(KERN_INFO "send syn packet success.\n");
return 0;
err:
kfree_skb(skb);
out:
return -ENOMEM;
}
static int main_init(void)
{
if (nf_register_hook(&privhook) != 0)
{
err("nf_register_hook");
goto out;
}
send_syn();
return 0;
out:
return -1;
}
static void main_exit(void)
{
nf_unregister_hook(&privhook);
}
module_init(main_init);
module_exit(main_exit);
MODULE_LICENSE("GPL");
|