/* This is a module which is used for setting the IP source address * and port in an skb. */ #include #include #include #include #include #include #include MODULE_LICENSE("GPL"); MODULE_AUTHOR("Don Mahurin "); MODULE_DESCRIPTION("iptables SOURCE target module"); static u_int16_t cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck) { u_int32_t diffs[] = { oldvalinv, newval }; return csum_fold(csum_partial((char *)diffs, sizeof(diffs), oldcheck^0xFFFF)); } static unsigned int target(struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, unsigned int hooknum, const struct xt_target *target, const void *targinfo, void *userinfo) { struct sockaddr_in * sin = (struct sockaddr_in *)targinfo; struct iphdr *iph = (*pskb)->nh.iph; void *ipdata = (void *)iph + iph->ihl * 4; if(sin->sin_port != 65535) { if(iph->protocol == IPPROTO_TCP) { struct tcphdr *tcph = (struct tcphdr *)ipdata; tcph->check = cheat_check(~iph->saddr, sin->sin_addr.s_addr, cheat_check(tcph->source ^ 0xFFFF, sin->sin_port, tcph->check)); tcph->source = sin->sin_port; } else if(iph->protocol == IPPROTO_UDP) { struct udphdr *udph = (struct udphdr *)ipdata; if (udph->check) /* special case for checksum */ udph->check = cheat_check(~iph->saddr, sin->sin_addr.s_addr, cheat_check(udph->source ^ 0xFFFF, sin->sin_port, udph->check)); udph->source = sin->sin_port; } } if(sin->sin_addr.s_addr != 0L) { iph->check = cheat_check(~iph->saddr, sin->sin_addr.s_addr, iph->check); iph->saddr = sin->sin_addr.s_addr; } // (*pskb)->nfcache |= NFC_ALTERED; return IPT_CONTINUE; } static int checkentry(const char *tablename, const void *e, const struct xt_target *target, void *targinfo, unsigned int targinfosize, unsigned int hook_mask) { if (targinfosize != IPT_ALIGN(sizeof(struct sockaddr_in))) { printk(KERN_WARNING "SOURCE: targinfosize %u != %Zu\n", targinfosize, IPT_ALIGN(sizeof(struct sockaddr_in))); return 0; } /* if (strcmp(tablename, "mangle") != 0) { printk(KERN_WARNING "SOURCE: can only be called from \"mangle\" table, not \"%s\"\n", tablename); return 0; } */ return 1; } static struct ipt_target ipt_source_reg = { .name = "SOURCE", .target = target, .targetsize = sizeof(struct sockaddr_in), .table = "nat", .checkentry = checkentry, .me = THIS_MODULE }; static int __init init(void) { if (ipt_register_target(&ipt_source_reg)) return -EINVAL; return 0; } static void __exit fini(void) { ipt_unregister_target(&ipt_source_reg); } module_init(init); module_exit(fini);