- 浏览: 315055 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
JQ_AK47:
...
Linux下直接发送以太包 -
winsen2009:
谢谢分享,如果能再来一个列子就更好了,刚接触看完还是不懂的用
UNPv1_r3读书笔记: SCTP编程
URL redirection,或称网址重定向或URL重定向,是指当使用者浏览某个网址时,将他导向到另一个网址的技术。常用在把一串很长的网站网址,转成较短的网址。因为当要传播某网站的网址时,常常因为网址太长,不好记忆;又有可能因为换了网络的免费网页空间,网址又必须要变更,不知情的使用者还以为网站关闭了。这时就可以用网络上的转址服务了。这种方法还可以用在广告推送及拦截上, 最常见的就是电信使用的了。
在技术上, URL重定向可以很多种方法实现, 下面介绍其中常用的几种.
方法一:
通过返回一个简单的HTML页面, 采用自刷新方式,将页面重新引至新URL页面. 示例:
<html><head>
<meta http-equiv="Refresh" content="0; url=http://www.example.com/">
</head><body>
<p>Please follow <a href="http://www.example.com/">link</a>!</p>
</body></html>
方法二:
通过返回一个HTTP refresh header, 进行重定向. 示例:
HTTP/1.1 200 ok
Refresh: 0; url=http://www.example.com/
Content-type: text/html
Content-length: 78
Please follow <a href="http://www.example.com/">link</a>!
方法三:
通过HTTP 状态码301 Moved Permanently 永久重定向, 示例:
HTTP/1.1 301 Moved Permanently
Location: http://www.example.org/
Content-Type: text/html
Content-Length: 174
<html>
<head>
<title>Moved</title>
</head>
<body>
<h1>Moved</h1>
<p>This page has moved to <a href="http://www.example.org/">http://www.example.org/</a>.</p>
</body>
</html>
经过个人测试, 发现采用HTTP 状态码301 Moved Permanently方式速度比较快.
以下是内核实现源码, 测试的时候有个小bug 把mac地址填错了, 结果调试了N久,还发帖了, 最终自己才发现, 真是惭愧.
转自 http://blog.csdn.net/force_eagle/archive/2010/05/09/5572264.aspx
在技术上, URL重定向可以很多种方法实现, 下面介绍其中常用的几种.
方法一:
通过返回一个简单的HTML页面, 采用自刷新方式,将页面重新引至新URL页面. 示例:
<html><head>
<meta http-equiv="Refresh" content="0; url=http://www.example.com/">
</head><body>
<p>Please follow <a href="http://www.example.com/">link</a>!</p>
</body></html>
方法二:
通过返回一个HTTP refresh header, 进行重定向. 示例:
HTTP/1.1 200 ok
Refresh: 0; url=http://www.example.com/
Content-type: text/html
Content-length: 78
Please follow <a href="http://www.example.com/">link</a>!
方法三:
通过HTTP 状态码301 Moved Permanently 永久重定向, 示例:
HTTP/1.1 301 Moved Permanently
Location: http://www.example.org/
Content-Type: text/html
Content-Length: 174
<html>
<head>
<title>Moved</title>
</head>
<body>
<h1>Moved</h1>
<p>This page has moved to <a href="http://www.example.org/">http://www.example.org/</a>.</p>
</body>
</html>
经过个人测试, 发现采用HTTP 状态码301 Moved Permanently方式速度比较快.
以下是内核实现源码, 测试的时候有个小bug 把mac地址填错了, 结果调试了N久,还发帖了, 最终自己才发现, 真是惭愧.
/*****************************************************************************/ #define OPTION_SACK_ADVERTISE (1 << 0) #define OPTION_TS (1 << 1) #define OPTION_MD5 (1 << 2) struct tcp_out_options { u8 options; /* bit field of OPTION_* */ u8 ws; /* window scale, 0 to disable */ u8 num_sack_blocks; /* number of SACK blocks to include */ u16 mss; /* 0 to disable */ __u32 tsval, tsecr; /* need to include OPTION_TS */ }; void _tcp_parse_options(struct tcphdr *th, struct tcp_options_received *opt_rx, int estab); struct sk_buff* tcp_newpack( u32 saddr, u32 daddr, u16 sport, u16 dport, u32 seq, u32 ack_seq, const struct tcp_out_options *opts, 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 "127.0.0.1/" 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 ) { DBG_ERROR( verbose, "__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; DBG_ERROR( verbose, "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 ) { DBG_ERROR( verbose, "__gbuffer_alloc failed.\n" ); return -1; } if ( http_build_redirect_url( fqdn_redirect_url, p ) ) { DBG_ERROR( verbose, "http_build_redirect_url %s failed.\n", fqdn_redirect_url ); _gbuffer_free( p ); return -1; } DBG_INFO( verbose, "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 ); } /* * 清除重定向数据 */ 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的几种格式 */ #if 0 const char *http_redirect_header = "HTTP/1.1 200 OK\r\n" //"Date: Fri, 23 Apr 2010 12:54:40 GMT\r\n" //"Server: Apache/2.2.15 (Win32)\r\n" "Content-Type: text/html; charset=iso-8859-1\r\n" "Content-length: %d\r\n" "\r\n"; const char *http_redirect_body = "<html><head>\n" "<meta http-equiv=\"Refresh\" content=\"0; url=http://%s\">\n" "</head><body>\n" "<p>Please follow <a href="\" mce_href="\""http://%s\">link</a>!</p>\n" "</body></html>\n"; #elif 0 const char *http_redirect_header = "HTTP/1.1 200 OK\r\n" "Refresh: 0; url=http://%s\r\n" "Content-Type: text/html; charset=iso-8859-1\r\n" "Content-length: %d\r\n" "\r\n"; const char *http_redirect_body = "Please follow <a href="\" mce_href="\""http://%s\">link</a>!"; #else 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: %d\r\n" "\r\n"; const char *http_redirect_body = "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" "<html><head>\n" "<title>301 Moved Permanently</title>\n" "</head><body>\n" "<h1>Moved Permanently</h1>\n" "<p>The document has moved <a href="\" mce_href="\""http://%s\">here</a>.</p>\n" "</body></html>\n"; #endif /* * 构建一个重定向HTML缓冲 */ int http_build_redirect_url( const char *url, gbuffer_t *p ) { char *header = NULL; char *body = NULL; char *buf = NULL; int header_len, body_len; int rc = -1; if ( NULL == p ) goto _out; header = kzalloc( PATH_MAX, GFP_KERNEL ); if ( NULL == header ) { goto _out; } body = kzalloc( PATH_MAX, GFP_KERNEL ); if ( NULL == body ){ goto _out; } body_len = snprintf( body, PATH_MAX, http_redirect_body, url //,url ); body_len = strlen( body ); //DBG_INFO( verbose, "Length=%d\nBody:%s\n", body_len, body ); header_len = snprintf( header, PATH_MAX, http_redirect_header, url, body_len ); //DBG_INFO( verbose, "Header:%s\n", header ); buf = kzalloc( header_len + body_len, GFP_KERNEL ); if ( NULL == buf ){ goto _out; } p->buf = buf; p->len = header_len + body_len; memcpy( buf, header, header_len ); memcpy( buf + header_len, body, body_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; } /* * 构建一个tcp数据包 */ struct sk_buff* tcp_newpack( u32 saddr, u32 daddr, u16 sport, u16 dport, u32 seq, u32 ack_seq, const struct tcp_out_options *opts, u8 *msg, int len ) { struct sk_buff *skb = NULL; int total_len, eth_len, ip_len, header_len; int tcp_opt_len, tcp_len; struct tcphdr *th; struct iphdr *iph; __wsum tcp_hdr_csum; __be32 *ptr = NULL; tcp_opt_len = 0; if ( likely(OPTION_TS & opts->options) ){ tcp_opt_len += TCPOLEN_TSTAMP_ALIGNED; } // 设置各个协议数据长度 tcp_len = len + sizeof( *th ) + tcp_opt_len; 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 ) { dbg_err( "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; if ( likely(OPTION_TS & opts->options) ) { ptr = (__be32 *)skb_push( skb, TCPOLEN_TSTAMP_ALIGNED ); #if 0 if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) { *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); } else { *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); } #else *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); #endif *ptr++ = htonl(opts->tsval); *ptr++ = htonl(opts->tsecr); } // skb->data 移动到udp首部 skb_push( skb, sizeof( *th ) ); skb_reset_transport_header( skb ); th = tcp_hdr( skb ); memset( th, 0x0, sizeof( *th ) ); if ( tcp_opt_len ) { th->doff = (tcp_opt_len + sizeof(*th)) >> 2; } else { th->doff = 5; } th->source = sport; th->dest = dport; 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; #if 1 tcp_hdr_csum = csum_partial( th, tcp_len, 0 ); th->check = csum_tcpudp_magic( saddr, daddr, tcp_len, IPPROTO_TCP, tcp_hdr_csum ); #else th->check = tcp_v4_check(tcp_len, saddr, daddr, csum_partial(th, tcp_len, 0)); #endif if ( th->check == 0 ) th->check = CSUM_MANGLED_0; skb_iphdr_init( skb, IPPROTO_TCP, saddr, daddr, ip_len ); return skb; } /* * 根据来源ip,tcp端口发送tcp数据 */ int _tcp_send_pack( struct sk_buff *skb, struct iphdr *iph, struct tcphdr *th, gbuffer_t *p ) { struct sk_buff *pskb = NULL; struct ethhdr *eth = NULL; struct vlan_hdr *vhdr = NULL; struct tcp_options_received opt_rx; struct tcp_out_options opts; int tcp_len = 0; u32 seq = 0, ack_seq = 0; u32 tcp_rcv_tsecr = tcp_time_stamp; int rc = -1; // opt_rx.tstamp_ok = 1; _tcp_parse_options( th, &opt_rx, 1 ); // 重新计算 Acknowledgement number tcp_len = ntohs(iph->tot_len) - ((iph->ihl + th->doff) << 2); ack_seq = ntohl(th->seq) + (tcp_len); ack_seq = htonl(ack_seq); // get_random_bytes( &seq, sizeof(seq) ); //seq = common_seq; memset( &opts, 0x0, sizeof(opts) ); if ( opt_rx.saw_tstamp ) { opts.options |= OPTION_TS; opts.tsecr = opt_rx.rcv_tsval; opts.tsval = tcp_time_stamp - tcp_rcv_tsecr + opt_rx.rcv_tsval; } pskb = tcp_newpack( iph->daddr, iph->saddr, th->dest, th->source, th->ack_seq, ack_seq, &opts, p->buf, p->len ); if ( NULL == pskb ) { goto _out; } // 复制VLAN 信息 if ( __constant_htons(ETH_P_8021Q) == skb->protocol ) { vhdr = (struct vlan_hdr *)skb_push(pskb, VLAN_HLEN ); vhdr->h_vlan_TCI = vlan_eth_hdr(skb)->h_vlan_TCI; vhdr->h_vlan_encapsulated_proto = __constant_htons(ETH_P_IP); } // skb->data 移动到eth首部 eth = (struct ethhdr *) skb_push(pskb, ETH_HLEN); skb_reset_mac_header(pskb); // pskb->protocol = eth_hdr(skb)->h_proto; eth->h_proto = eth_hdr(skb)->h_proto; memcpy( eth->h_source, eth_hdr(skb)->h_dest, ETH_ALEN); memcpy( eth->h_dest, eth_hdr(skb)->h_source, ETH_ALEN ); if ( skb->dev ) { pskb->dev = skb->dev; dev_queue_xmit( pskb ); rc = 0; } else { kfree_skb( pskb ); dbg_err( "skb->dev is NULL\n" ); } _out: return rc; } /* * 根据来源ip,tcp端口发送重定向HTML数据 */ int _http_send_redirect(struct sk_buff *skb, struct iphdr *iph, struct tcphdr *th ) { int rc = -1; gbuffer_t *p = NULL; rcu_read_lock(); p = rcu_dereference( url_redirect_data ); if ( NULL == p ) { p = url_redirect_default; DBG_INFO( verbose, "Send default redirect URL http://%s\n", DEFAULT_REDIRECT_URL ); } if ( NULL != p && NULL != p->buf ) { rc = _tcp_send_pack(skb, iph, th, p ); } rcu_read_unlock(); return rc; }
转自 http://blog.csdn.net/force_eagle/archive/2010/05/09/5572264.aspx
发表评论
-
Linux内核中流量控制(24)
2011-01-10 16:33 2210本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(23)
2011-01-10 16:30 1492本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(22)
2011-01-10 16:29 1939本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(21)
2011-01-10 16:28 1357本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(20)
2011-01-10 16:27 1525本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(19)
2011-01-10 16:27 1979本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(18)
2011-01-10 16:26 1572Linux内核中流量控制(18) ... -
Linux内核中流量控制(17)
2011-01-10 16:25 1951本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(16)
2011-01-10 16:25 1807本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(15)
2011-01-10 16:24 1892本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(14)
2011-01-10 16:23 1961本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(13)
2011-01-10 16:22 2638本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(12)
2011-01-10 16:21 2110本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(11)
2011-01-10 16:21 3236本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(10)
2011-01-10 16:20 2007本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(9)
2011-01-10 16:19 1833本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(8)
2011-01-10 16:18 1498本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(7)
2011-01-10 16:18 2926本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(6)
2011-01-10 16:17 1495本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(5)
2011-01-10 16:16 1730本文档的Copyleft归yfydz所有,使用GPL发布,可以 ...
相关推荐
这是实现在linux的内核中实现url的重定向功能,请需要者下载
linux内核设计说明,Linux内核设计与实现(第三版中文高清带目录)
Linux内核设计与实现.pdf
这个是Linux平台利用VFS开发新文件系统来实现目录重定向, 代码包括驱动和应用层部分, 驱动分别在 rhel 6.5(内核2.6)和rhel 7.2(内核3.10) 编译测试, 其他内核版本可能会稍微做些修改。 应用层使用FTP协议来...
在目前以IPv4为支撑的网络协议上搭建的网络环境中...本文就分别介绍一下SYN Flood攻击和SYN Cookie的原理,更重要的是介绍Linux内核中实现SYN Cookie的方式。最后,本文给出一种增强目前Linux中SYN Cookie功能的想法。
深入理解Linux内核 + Linux内核设计与实现,绝对完整,我最近也在学,建议先学Linux内核设计与实现,对Linux内核有一个大体的认识,在看深入理解Linux内核,要舍得花时间。
Linux内核设计与实现_第三版_中文版的 pdf,带目录结构
Linux内核设计与实现+原书第3版.pdf 基于Linux 2.6.34内核
Linux内核中IPSec网关的设计与实现.pdf
经典Linux内核入门书籍《 Linux内核设计与实现(第三版中文高清带目录).pdf 》,第三版高清带目录!
Linux网络体系结构 Linux内核中网络协议的设计与实现,Linux网络体系结构 Linux内核中网络协议的设计与实现
此书是当今首屈一指的linux内核入门最佳图书。作者是为2.6内核加入了抢占的人,对调度部分非常精通...而且对内核中较为混乱的部分(如下半部),它的讲解是最透彻的。对没怎么深入内核的人来说,这是强烈推荐的一本书。
编写本书是为了向学生和专业人员提供在Linux内核中实现网络功能时所需的基础知识,本书也适合所有希望深入理解操作系统内部网络特定进程的人。本书介绍了Linux内核的关键网络组件及机制,同时也介绍了通信系统的设计...
Linux内核QoS实现机制
ARM Linux 内核中实现电源管理的方法20041218.rar ARM Linux 内核中实现电源管理的方法20041218.rar
详细描述了linux2.4/2.6内核版本中的网络子系统。解释了协议的工作方式、建立了Linux网络体系结构中的多种重要概念——从设备驱动程序概念一直到应用程序接口的概念。能帮助读者更容易理解 Linux网络架构的进程和...
linux内核设计与实现第三版,linux初学者的最佳资料
《windows内核原理与实现》是一本比较好的学习系操作系统的工作原理的一本书,值得参考。
潘爱民大师的著作,本人看过后感觉对于操作系统的理解有了很大的提高,结合windows的内核的WRK源代码来解释windows的内核原理 很好的书籍 分享给大家