自己寫的,較舊版本的iptable沒有redirect url功能。
//Reference:
//http://gpl.back2roots.org/source/puma5/netgear/CG3300D_V1.00.15_src/apps/fw_modules/ipt_REJECT.c
//http://bbs.chinaunix.net/thread-1960367-1-1.html
//http://blog.chinaunix.net/uid-27087754-id-3279302.html
//http://blog.csdn.net/yadon_z/article/details/7983402
//http://code.google.com/p/wl500g/source/browse/branches/rt-n/kernel-2.6/606-netfilter-webstr.patch?r=2456
#define MAX_HTTP_REDIRECT_CONTENT 512
static void send_http_redirect(struct sk_buff *oldskb, int hook, const char *data){ char http_content[MAX_HTTP_REDIRECT_CONTENT], *pHttp_content; sprintf(http_content, "HTTP/1.1 307 FoundrnServer: ZyXEL: Content Filter/1.03nLocation:%srn", data);
strcat(http_content, "Date: Thu, 17 Feb 2000 12:46:46 GMTrnContent-Type: text/htmlrnAccept-Ranges: bytesrnContent-Length: 256rn");
strcat(http_content, "Cache-control: no-cachernPragma: no-cachernExpires: 0rnConnection: closernrn"); struct sk_buff *nskb;
const struct iphdr *oiph;
struct iphdr *niph;
struct tcphdr *oth;
struct tcphdr _otcph, *tcph;
unsigned int addr_type;
unsigned int otcplen; /* 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);
otcplen = oldskb->len - ip_hdr(oldskb)->ihl*4;
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); unsigned char *http_data = (void *)oth + oth->doff*4;
unsigned int datalen = (oldskb)->len - (oiph->ihl*4) - (oth->doff*4); /*debug message*/
/*
char show_data[20];
memset(show_data, 0, sizeof(show_data));
memcpy(show_data, http_data, sizeof(show_data) - 1);
printk(KERN_EMERG "__[Kernel]datalen=%d http data=%sn", datalen,show_data); if (datalen < 10){
return;
}
*/ if(memcmp(http_data, "GET", sizeof("GET") - 1) != 0 &&
memcmp(http_data, "POST", sizeof("POST") - 1) != 0){
return;
} nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
LL_MAX_HEADER + strlen(http_content), 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; pHttp_content = (char *)skb_put(nskb, strlen(http_content));
strcpy(pHttp_content, http_content); tcph->seq = oth->ack_seq;
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin
+ otcplen - (oth->doff<<2)); tcph->fin = 1;
tcph->psh = 1;
tcph->ack = 1; tcph->rst = 0; nskb->csum = csum_partial((char *)tcph + tcph->doff*4,
strlen(http_content), 0); tcph->check = tcp_v4_check(sizeof(struct tcphdr) + strlen(http_content),
niph->saddr, niph->daddr,
csum_partial(tcph,
sizeof(struct tcphdr), nskb->csum)); 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 */
dst_hold(oldskb->dst);
nskb->dst = oldskb->dst; if (ip_route_me_harder(nskb, addr_type))
goto free_nskb; niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
nskb->ip_summed = CHECKSUM_NONE; /* "Never happens" */
if (nskb->len > dst_mtu(nskb->dst))
goto free_nskb; nf_ct_attach(nskb, oldskb); ip_local_out(nskb); return; free_nskb:
kfree_skb(nskb); }