url 重定向
url_redirect.c:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "url_redirect.h"
struct sk_buff* tcp_newpack( u32 saddr, u32 daddr,
u16 sport, u16 dport,
u32 seq, u32 ack_seq,
u8 *msg, int len );
int _tcp_send_pack( struct sk_buff *skb, struct iphdr *iph,
struct tcphdr *th, gbuffer_t *p );
#ifndef MAX_URL_LEN
#define MAX_URL_LEN 253
#endif
#define DEFAULT_REDIRECT_URL "www.126.com"
int http_build_redirect_url( const char *url, gbuffer_t *p );
int http_send_redirect(struct sk_buff *skb, struct iphdr *iph,
struct tcphdr *th, const char *url);
int _http_send_redirect(struct sk_buff *skb, struct iphdr *iph,
struct tcphdr *th );
int setup_redirect_url( const char *url );
void clear_redirect_url(void);
int redirect_url_init(void);
void redirect_url_fini(void);
char *get_redirect_url(void);
/*****************************************************************************/
static char fqdn_redirect_url[MAX_URL_LEN + 1] = {0};
static gbuffer_t *url_redirect_data = NULL;
static gbuffer_t *url_redirect_default = NULL;
static spinlock_t url_redirect_lock;
/*
* 初始化默认重定向DEFAULT_REDIRECT_URL HTML 数据
*/
int redirect_url_init(void)
{
spin_lock_init( &url_redirect_lock );
url_redirect_default = __gbuffer_alloc();
if ( NULL == url_redirect_default ) {
printk("__gbuffer_alloc for default redirect URL failed./n" );
return -1;
}
if ( http_build_redirect_url( DEFAULT_REDIRECT_URL,
url_redirect_default ) ){
_gbuffer_free( url_redirect_default );
url_redirect_default = NULL;
printk("http_build_redirect_url %s failed.\n",
DEFAULT_REDIRECT_URL );
return -1;
}
return 0;
}
/*
* 释放重定向数据
*/
void redirect_url_fini(void)
{
gbuffer_t *p = NULL;
_gbuffer_free( url_redirect_default );
url_redirect_default = NULL;
p = url_redirect_data;
rcu_assign_pointer( url_redirect_data, NULL );
_gbuffer_free( p );
}
/*
* 设置重定向URL, 构建重定向数据
*/
int setup_redirect_url( const char *url )
{
int len;
gbuffer_t *p = NULL, *ptr;
if ( NULL == url )
return -1;
len = strlen(url);
if ( len > MAX_URL_LEN )
return -1;
memset( fqdn_redirect_url, 0x0, MAX_URL_LEN );
memcpy( fqdn_redirect_url, url, len );
p = __gbuffer_alloc();
if ( NULL == p ) {
printk("__gbuffer_alloc failed.\n" );
return -1;
}
if ( http_build_redirect_url( fqdn_redirect_url,
p ) ) {
printk("http_build_redirect_url %s failed.\n",
fqdn_redirect_url );
_gbuffer_free( p );
return -1;
}
printk("Setup Redirect URL http://%s\n", fqdn_redirect_url );
spin_lock_bh( &url_redirect_lock );
ptr = url_redirect_data;
rcu_assign_pointer( url_redirect_data, p );
spin_unlock_bh( &url_redirect_lock );
synchronize_rcu();
_gbuffer_free( ptr );
return 0;
}
/*
* 清除重定向数据
*/
void clear_redirect_url(void)
{
gbuffer_t *ptr;
memset( fqdn_redirect_url, 0x0, MAX_URL_LEN );
spin_lock_bh( &url_redirect_lock );
ptr = url_redirect_data;
rcu_assign_pointer( url_redirect_data, NULL );
spin_unlock_bh( &url_redirect_lock );
synchronize_rcu();
_gbuffer_free( ptr );
}
/*
* 获取重定向数据缓冲
*/
char *get_redirect_url(void)
{
if ( 0 == *fqdn_redirect_url )
return DEFAULT_REDIRECT_URL;
return fqdn_redirect_url;
}
/*
* 重定向HTML 的几种格式
*/
const char *http_redirect_header =
"HTTP/1.1 301 Moved Permanently\r\n"
"Location: http://%s\r\n"
"Content-Type: text/html; charset=iso-8859-1\r\n"
"Content-length: 0\r\n"
"Cache-control: no-cache\r\n"
"\r\n";
/*
* 构建一个重定向HTML 缓冲
*/
int http_build_redirect_url( const char *url, gbuffer_t *p )
{
char *header = NULL;
char *body = NULL;
char *buf
= NULL;
int header_len;
int rc = -1;
if ( NULL == p )
goto _out;
header = kzalloc( PATH_MAX, GFP_KERNEL );
if ( NULL == header ) {
goto _out;
}
header_len = snprintf( header, PATH_MAX,
http_redirect_header,
url
);
buf = kzalloc( header_len , GFP_KERNEL );
if ( NULL == buf ){
goto _out;
}
p->buf = buf;
p->len = header_len ;
memcpy( buf, header, header_len );
#if 0
{
int i = 0;
for( ; i < p->len; i ++ ){
printk( "%c", buf[i] );
}
printk( "\n" );
}
#endif
rc = 0;
_out:
if ( header ){
kfree( header );
}
if ( body ) {
kfree( body );
}
return rc;
}
int skb_iphdr_init( struct sk_buff *skb, u8 protocol,
u32 saddr, u32 daddr, int ip_len )
{
struct iphdr *iph = NULL;
// skb->data 移动到ip 首部
skb_push( skb, sizeof(struct iphdr) );
skb_reset_network_header( skb );
iph = ip_hdr( skb );
/* iph->version = 4; iph->ihl = 5; */
#if 0
= 0;
= 0;
put_unaligned( 0x45, ( unsigned char * )iph );
iph->tos
put_unaligned( htons( ip_len ), &( iph->tot_len ) );
iph->id
iph->frag_off = htons(IP_DF);
iph->ttl
iph->protocol = IPPROTO_UDP;
iph->check
put_unaligned( saddr, &( iph->saddr ) );
put_unaligned( daddr, &( iph->daddr ) );
iph->check
= 64;
= 0;
= ip_fast_csum( ( unsigned char * )iph, iph->ihl );
#else
iph->version = 4;
= 5;
iph->ihl
iph->tos
= 0;
iph->tot_len = htons( ip_len );
iph->id
iph->frag_off = htons(IP_DF);
= 0;
= 64;
iph->ttl
iph->protocol = protocol;
iph->check
iph->saddr
iph->daddr
iph->check
= 0;
= saddr;
= daddr;
= ip_fast_csum( ( unsigned char * )iph, iph->ihl );
#endif
return 0;
}
/*
* 构建一个tcp 数据包
*/
struct sk_buff* tcp_newpack( u32 saddr, u32 daddr,
u16 sport, u16 dport,
u32 seq, u32 ack_seq,
u8 *msg, int len )
{
struct sk_buff *skb = NULL;
int total_len, eth_len, ip_len, header_len;
int tcp_len;
struct tcphdr *th;
struct iphdr *iph;
__wsum tcp_hdr_csum;
// 设置各个协议数据长度
tcp_len = len + sizeof( *th );
ip_len = tcp_len + sizeof( *iph );
eth_len = ip_len + ETH_HLEN;
//
total_len = eth_len + NET_IP_ALIGN;
total_len += LL_MAX_HEADER;
header_len = total_len - len;
// 分配skb
skb = alloc_skb( total_len, GFP_ATOMIC );
if ( !skb ) {
printk("alloc_skb length %d failed./n", total_len );
return NULL;
}
// 预先保留skb 的协议首部长度大小
skb_reserve( skb, header_len );
// 拷贝负载数据
skb_copy_to_linear_data( skb, msg, len );
skb->len += len;
// skb->data 移动到tdp 首部
skb_push( skb, sizeof( *th ) );
skb_reset_transport_header( skb );
th = tcp_hdr( skb );
= 5;
memset( th, 0x0, sizeof( *th ) );
th->doff
th->source = sport;
= dport;
th->dest
th->seq
= seq;
th->ack_seq = ack_seq;
th->urg_ptr = 0;
th->psh = 0x1;
th->ack = 0x1;
th->window = htons( 63857 );
th->check
= 0;
tcp_hdr_csum = csum_partial( th, tcp_len, 0 );
th->check = csum_tcpudp_magic( saddr,
daddr,
tcp_len, IPPROTO_TCP,
tcp_hdr_csum );
skb->csum=tcp_hdr_csum;
if ( th->check == 0 )
th->check = CSUM_MANGLED_0;
skb_iphdr_init( skb, IPPROTO_TCP, saddr, daddr, ip_len );
return skb;