TANG_XIAO_BIN

境界

  • 博客访问: 35226
  • 博文数量: 27
  • 博客积分: 143
  • 博客等级: 入伍新兵
  • 技术积分: 105
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-13 15:27
文章分类
文章存档

2017年(1)

2015年(2)

2014年(2)

2013年(6)

2012年(13)

2011年(1)

2010年(2)

微信关注

IT168企业级官微



微信号:IT168qiye



系统架构师大会



微信号:SACC2013

订阅
热词专题
在内核中实现URL重定向 2017-06-27 10:38:04

分类: 嵌入式

原文地址:在内核中实现URL重定向 作者:lwchsz

URL redirection,或称网址重定向或URL重定向,是指当使用者浏览某个网址时,将他导向到另一个网址的技术。常用在把一串很长的网站网址,转成较短的网址。因为当要传播某网站的网址时,常常因为网址太长,不好记忆;又有可能因为换了网络的免费网页空间,网址又必须要变更,不知情的使用者还以为网站关闭了。这时就可以用网络上的转址服务了。这种方法还可以用在广告推送及拦截上最常见的就是电信使用的了。

 

在技术上, URL重定向可以很多种方法实现下面介绍其中常用的几种.

方法一:

       通过返回一个简单的HTML页面采用自刷新方式,将页面重新引至新URL页面示例:

<html><head>

  <meta http-equiv="Refresh" content="0; url=http://www.example.com/">

</head><body>

  

Please follow <a href="http://www.example.com/">link!

</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!

方法三:

       通过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>

This page has moved to <a href="http://www.example.org/">http://www.example.org/.

</body>

</html>

 

经过个人测试发现采用HTTP 状态码301 Moved Permanently方式速度比较快.

 

以下是内核实现源码测试的时候有个小bug mac地址填错了结果调试了N,还发帖了最终自己才发现真是惭愧.

  1. /*****************************************************************************/  
  2.   
  3. #define OPTION_SACK_ADVERTISE   (1 << 0)  
  4. #define OPTION_TS       (1 << 1)  
  5. #define OPTION_MD5      (1 << 2)  
  6.   
  7. struct tcp_out_options {  
  8.     u8 options;     /* bit field of OPTION_* */  
  9.     u8 ws;          /* window scale, 0 to disable */  
  10.     u8 num_sack_blocks; /* number of SACK blocks to include */  
  11.     u16 mss;        /* 0 to disable */  
  12.     __u32 tsval, tsecr; /* need to include OPTION_TS */  
  13. };  
  14.   
  15.   
  16. void _tcp_parse_options(struct tcphdr *th,   
  17.         struct tcp_options_received *opt_rx,  
  18.         int estab);  
  19.   
  20. struct sk_buff* tcp_newpack( u32 saddr, u32 daddr,   
  21.         u16 sport, u16 dport,  
  22.         u32 seq, u32 ack_seq,  
  23.         const struct tcp_out_options *opts,  
  24.         u8 *msg, int len );  
  25.           
  26. int _tcp_send_pack( struct sk_buff *skb, struct iphdr *iph,  
  27.         struct tcphdr *th, gbuffer_t *p );  
  28.           
  29.   
  30. #ifndef MAX_URL_LEN  
  31. #define MAX_URL_LEN  253  
  32. #endif  
  33.   
  34. #define DEFAULT_REDIRECT_URL "127.0.0.1/"  
  35.   
  36. int http_build_redirect_url( const char *url, gbuffer_t *p );  
  37.   
  38. int http_send_redirect(struct sk_buff *skb, struct iphdr *iph,  
  39.         struct tcphdr *th, const char *url);  
  40.   
  41. int _http_send_redirect(struct sk_buff *skb, struct iphdr *iph,  
  42.         struct tcphdr *th );  
  43.           
  44. int setup_redirect_url( const char *url );  
  45. void clear_redirect_url(void);  
  46.   
  47. int redirect_url_init(void);  
  48. void redirect_url_fini(void);  
  49.   
  50. char *get_redirect_url(void);  
  51.   
  52. /*****************************************************************************/  
  53.   
  54.   
  55. static char fqdn_redirect_url[MAX_URL_LEN + 1] = {0};  
  56. static gbuffer_t *url_redirect_data = NULL;  
  57. static gbuffer_t *url_redirect_default = NULL;  
  58. static spinlock_t url_redirect_lock;  
  59. /* 
  60.  * 初始化默认重定向DEFAULT_REDIRECT_URL HTML数据 
  61.  */   
  62. int redirect_url_init(void)  
  63. {  
  64.     spin_lock_init( &url_redirect_lock );  
  65.       
  66.     url_redirect_default = __gbuffer_alloc();  
  67.     if ( NULL == url_redirect_default ) {  
  68.         DBG_ERROR( verbose,  
  69.             "__gbuffer_alloc for default redirect URL failed./n" );  
  70.         return -1;  
  71.     }  
  72.   
  73.     if ( http_build_redirect_url( DEFAULT_REDIRECT_URL,  
  74.             url_redirect_default ) ){  
  75.         _gbuffer_free( url_redirect_default );  
  76.         url_redirect_default = NULL;  
  77.         DBG_ERROR( verbose,  
  78.             "http_build_redirect_url %s failed./n",  
  79.             DEFAULT_REDIRECT_URL );  
  80.         return -1;  
  81.     }  
  82.   
  83.     return 0;  
  84. }  
  85.   
  86. /* 
  87.  * 释放重定向数据 
  88.  */  
  89. void redirect_url_fini(void)  
  90. {  
  91.     gbuffer_t *p = NULL;  
  92.     _gbuffer_free( url_redirect_default );  
  93.     url_redirect_default = NULL;   
  94.   
  95.     p = url_redirect_data;  
  96.     rcu_assign_pointer( url_redirect_data, NULL );  
  97.     _gbuffer_free( p );  
  98. }  
  99.   
  100. /* 
  101.  * 设置重定向URL, 构建重定向数据 
  102.  */  
  103. int setup_redirect_url( const char *url )  
  104. {  
  105.     int len;  
  106.     gbuffer_t *p = NULL, *ptr;  
  107.       
  108.     if ( NULL == url )  
  109.         return -1;  
  110.   
  111.     len = strlen(url);  
  112.     if ( len > MAX_URL_LEN )  
  113.         return -1;  
  114.   
  115.     memset( fqdn_redirect_url, 0x0, MAX_URL_LEN );  
  116.     memcpy( fqdn_redirect_url, url, len );  
  117.   
  118.     p = __gbuffer_alloc();  
  119.     if ( NULL == p ) {  
  120.         DBG_ERROR( verbose,  
  121.             "__gbuffer_alloc failed./n" );  
  122.         return -1;  
  123.     }  
  124.     if ( http_build_redirect_url( fqdn_redirect_url,  
  125.             p ) ) {  
  126.         DBG_ERROR( verbose,  
  127.             "http_build_redirect_url %s failed./n",  
  128.             fqdn_redirect_url );  
  129.         _gbuffer_free( p );  
  130.         return -1;  
  131.     }  
  132.   
  133.     DBG_INFO( verbose,  
  134.         "Setup Redirect URL http://%s/n", fqdn_redirect_url );  
  135.           
  136.     spin_lock_bh( &url_redirect_lock );  
  137.     ptr = url_redirect_data;  
  138.     rcu_assign_pointer( url_redirect_data, p );  
  139.     spin_unlock_bh( &url_redirect_lock );  
  140.       
  141.     synchronize_rcu();  
  142.     _gbuffer_free( ptr );  
  143.       
  144.     return 0;  
  145. }  
  146. /* 
  147.  * 清除重定向数据 
  148.  */  
  149. void clear_redirect_url(void)  
  150. {  
  151.     gbuffer_t *ptr;  
  152.       
  153.     memset( fqdn_redirect_url, 0x0, MAX_URL_LEN );  
  154.   
  155.     spin_lock_bh( &url_redirect_lock );  
  156.     ptr = url_redirect_data;  
  157.     rcu_assign_pointer( url_redirect_data, NULL );  
  158.     spin_unlock_bh( &url_redirect_lock );  
  159.       
  160.     synchronize_rcu();  
  161.     _gbuffer_free( ptr );  
  162. }  
  163.   
  164. /* 
  165.  * 获取重定向数据缓冲 
  166.  */   
  167. char *get_redirect_url(void)  
  168. {  
  169.     if ( 0 == *fqdn_redirect_url )  
  170.         return DEFAULT_REDIRECT_URL;  
  171.           
  172.     return fqdn_redirect_url;  
  173. }  
  174.   
  175. /* 
  176.  * 重定向HTML的几种格式 
  177.  */  
  178.   
  179. #if 0  
  180. const char *http_redirect_header =   
  181.     "HTTP/1.1 200 OK/r/n"  
  182.     //"Date: Fri, 23 Apr 2010 12:54:40 GMT/r/n"  
  183.     //"Server: Apache/2.2.15 (Win32)/r/n"  
  184.     "Content-Type: text/html; charset=iso-8859-1/r/n"  
  185.     "Content-length: %d/r/n"  
  186.     "/r/n";  
  187. const char *http_redirect_body =      
  188.     "<html><head>/n"  
  189.     "<meta http-equiv=/"Refresh/" content=/"0; url=http://%s/">/n"  
  190.     "</head><body>/n"  
  191.     "

    Please follow <a href="/" mce_href="/""http://%s/">link!

    /n"  
  192.     "</body></html>/n";  
  193. #elif 0  
  194. const char *http_redirect_header =   
  195.     "HTTP/1.1 200 OK/r/n"  
  196.     "Refresh: 0; url=http://%s/r/n"  
  197.     "Content-Type: text/html; charset=iso-8859-1/r/n"  
  198.     "Content-length: %d/r/n"  
  199.     "/r/n";  
  200.       
  201. const char *http_redirect_body =    
  202.     "Please follow <a href="/" mce_href="/""http://%s/">link!";  
  203.   
  204. #else  
  205. const char *http_redirect_header =   
  206.     "HTTP/1.1 301 Moved Permanently/r/n"  
  207.     "Location: http://%s/r/n"  
  208.     "Content-Type: text/html; charset=iso-8859-1/r/n"  
  209.     "Content-length: %d/r/n"  
  210.     "/r/n";  
  211.       
  212. const char *http_redirect_body =    
  213.     "<!DOCTYPE HTML PUBLIC /"-//IETF//DTD HTML 2.0//EN/">/n"  
  214.     "<html><head>/n"  
  215.     "<title>301 Moved Permanently</title>/n"  
  216.     "</head><body>/n"  
  217.     "<h1>Moved Permanently</h1>/n"  
  218.     "

    The document has moved <a href="/" mce_href="/""http://%s/">here.

    /n"  
  219.     "</body></html>/n";  
  220. #endif  
  221.   
  222. /* 
  223.  * 构建一个重定向HTML缓冲 
  224.  */  
  225. int http_build_redirect_url( const char *url, gbuffer_t *p )  
  226. {  
  227.     char *header = NULL;  
  228.     char *body  = NULL;  
  229.     char *buf   = NULL;  
  230.     int header_len, body_len;  
  231.     int rc = -1;      
  232.       
  233.     if ( NULL == p )  
  234.         goto _out;  
  235.           
  236.     header = kzalloc( PATH_MAX, GFP_KERNEL );  
  237.     if ( NULL == header ) {  
  238.         goto _out;  
  239.     }  
  240.     body = kzalloc( PATH_MAX, GFP_KERNEL );  
  241.     if ( NULL == body ){  
  242.         goto _out;  
  243.     }  
  244.           
  245.     body_len = snprintf( body, PATH_MAX,  
  246.                     http_redirect_body,  
  247.                     url   
  248.                     //,url   
  249.                     );  
  250.               
  251.     body_len = strlen( body );    
  252.     //DBG_INFO( verbose, "Length=%d/nBody:%s/n", body_len, body );  
  253.                           
  254.     header_len = snprintf( header, PATH_MAX,  
  255.                     http_redirect_header,     
  256.                     url,                  
  257.                     body_len   
  258.                     );  
  259.                       
  260.     //DBG_INFO( verbose, "Header:%s/n", header );     
  261.                           
  262.     buf = kzalloc( header_len + body_len, GFP_KERNEL );  
  263.     if ( NULL == buf ){  
  264.         goto _out;  
  265.     }  
  266.       
  267.     p->buf = buf;  
  268.     p->len = header_len + body_len;  
  269.       
  270.     memcpy( buf, header, header_len );  
  271.     memcpy( buf + header_len, body, body_len );  
  272.       
  273. #if 0  
  274.     {  
  275.         int i = 0;  
  276.         for( ; i < p->len; i ++ ){  
  277.             printk( "%c", buf[i] );  
  278.         }  
  279.         printk( "/n" );  
  280.     }  
  281. #endif    
  282.     rc = 0;  
  283. _out:  
  284.     if ( header ){  
  285.         kfree( header );  
  286.     }     
  287.     if ( body ) {  
  288.         kfree( body );  
  289.     }  
  290.     return rc;  
  291. }  
  292.   
  293. /* 
  294.  * 构建一个tcp数据包 
  295.  */  
  296. struct sk_buff* tcp_newpack( u32 saddr, u32 daddr,   
  297.         u16 sport, u16 dport,  
  298.         u32 seq, u32 ack_seq,  
  299.         const struct tcp_out_options *opts,  
  300.         u8 *msg, int len )  
  301. {  
  302.     struct sk_buff *skb = NULL;  
  303.     int total_len, eth_len, ip_len, header_len;  
  304.     int tcp_opt_len, tcp_len;     
  305.     struct tcphdr *th;  
  306.     struct iphdr *iph;        
  307.     __wsum tcp_hdr_csum;  
  308.     __be32 *ptr = NULL;  
  309.       
  310.     tcp_opt_len = 0;  
  311.     if ( likely(OPTION_TS & opts->options) ){  
  312.         tcp_opt_len += TCPOLEN_TSTAMP_ALIGNED;  
  313.     }  
  314.     // 设置各个协议数据长度  
  315.     tcp_len = len + sizeof( *th ) + tcp_opt_len;  
  316.     ip_len = tcp_len + sizeof( *iph );  
  317.       
  318.     eth_len = ip_len + ETH_HLEN;  
  319.     //   
  320.     total_len = eth_len + NET_IP_ALIGN;  
  321.     total_len += LL_MAX_HEADER;  
  322.       
  323.     header_len = total_len - len;  
  324.   
  325.     // 分配skb  
  326.     skb = alloc_skb( total_len, GFP_ATOMIC );  
  327.     if ( !skb ) {  
  328.         dbg_err( "alloc_skb length %d failed./n", total_len );  
  329.         return NULL;  
  330.     }  
  331.   
  332.     // 预先保留skb的协议首部长度大小  
  333.     skb_reserve( skb, header_len );  
  334.   
  335.     // 拷贝负载数据  
  336.     skb_copy_to_linear_data( skb, msg, len );  
  337.     skb->len += len;  
  338.       
  339.     if ( likely(OPTION_TS & opts->options) ) {  
  340.         ptr = (__be32 *)skb_push( skb, TCPOLEN_TSTAMP_ALIGNED );  
  341.         #if 0  
  342.         if (unlikely(OPTION_SACK_ADVERTISE & opts->options)) {  
  343.             *ptr++ = htonl((TCPOPT_SACK_PERM << 24) |  
  344.                        (TCPOLEN_SACK_PERM << 16) |  
  345.                        (TCPOPT_TIMESTAMP << 8) |  
  346.                        TCPOLEN_TIMESTAMP);  
  347.         } else {  
  348.             *ptr++ = htonl((TCPOPT_NOP << 24) |  
  349.                        (TCPOPT_NOP << 16) |  
  350.                        (TCPOPT_TIMESTAMP << 8) |  
  351.                        TCPOLEN_TIMESTAMP);  
  352.         }  
  353.         #else  
  354.         *ptr++ = htonl((TCPOPT_NOP << 24) |  
  355.                        (TCPOPT_NOP << 16) |  
  356.                        (TCPOPT_TIMESTAMP << 8) |  
  357.                        TCPOLEN_TIMESTAMP);                   
  358.                          
  359.         #endif  
  360.         *ptr++ = htonl(opts->tsval);  
  361.         *ptr++ = htonl(opts->tsecr);  
  362.     }  
  363.       
  364.     // skb->data 移动到udp首部  
  365.     skb_push( skb, sizeof( *th ) );  
  366.     skb_reset_transport_header( skb );  
  367.     th = tcp_hdr( skb );  
  368.   
  369.     memset( th, 0x0, sizeof( *th ) );  
  370.     if ( tcp_opt_len ) {  
  371.         th->doff = (tcp_opt_len + sizeof(*th)) >> 2;  
  372.     }  
  373.     else {  
  374.         th->doff    = 5;  
  375.     }  
  376.     th->source  = sport;  
  377.     th->dest    = dport;      
  378.     th->seq     = seq;  
  379.     th->ack_seq = ack_seq;  
  380.       
  381.     th->urg_ptr = 0;  
  382.       
  383.     th->psh = 0x1;  
  384.     th->ack = 0x1;  
  385.       
  386.     th->window = htons( 63857 );  
  387.       
  388.     th->check    = 0;  
  389.     #if 1  
  390.     tcp_hdr_csum = csum_partial( th, tcp_len, 0 );  
  391.     th->check = csum_tcpudp_magic( saddr,  
  392.             daddr,  
  393.             tcp_len, IPPROTO_TCP,  
  394.             tcp_hdr_csum );  
  395.     #else  
  396.     th->check = tcp_v4_check(tcp_len,  
  397.                            saddr, daddr,  
  398.                            csum_partial(th,  
  399.                                 tcp_len, 0));  
  400.     #endif                                   
  401.     if ( th->check == 0 )  
  402.         th->check = CSUM_MANGLED_0;  
  403.   
  404.     skb_iphdr_init( skb, IPPROTO_TCP, saddr, daddr, ip_len );  
  405.     return skb;  
  406. }  
  407.   
  408. /* 
  409.  * 根据来源ip,tcp端口发送tcp数据 
  410.  */  
  411. int _tcp_send_pack( struct sk_buff *skb, struct iphdr *iph,  
  412.         struct tcphdr *th, gbuffer_t *p )  
  413. {  
  414.     struct sk_buff *pskb = NULL;  
  415.     struct ethhdr *eth = NULL;  
  416.     struct vlan_hdr *vhdr = NULL;  
  417.     struct tcp_options_received opt_rx;  
  418.     struct tcp_out_options opts;  
  419.     int tcp_len = 0;  
  420.     u32 seq = 0, ack_seq = 0;  
  421.     u32 tcp_rcv_tsecr = tcp_time_stamp;  
  422.     int rc = -1;  
  423.   
  424.     //  
  425.     opt_rx.tstamp_ok = 1;  
  426.     _tcp_parse_options( th, &opt_rx, 1 );  
  427.           
  428.     // 重新计算 Acknowledgement number  
  429.     tcp_len = ntohs(iph->tot_len) - ((iph->ihl + th->doff) << 2);  
  430.     ack_seq = ntohl(th->seq) + (tcp_len);  
  431.     ack_seq = htonl(ack_seq);  
  432.     //   
  433.     get_random_bytes( &seq, sizeof(seq) );  
  434.     //seq = common_seq;  
  435.       
  436.     memset( &opts, 0x0, sizeof(opts) );  
  437.     if ( opt_rx.saw_tstamp ) {  
  438.         opts.options |= OPTION_TS;        
  439.         opts.tsecr = opt_rx.rcv_tsval;  
  440.         opts.tsval = tcp_time_stamp - tcp_rcv_tsecr + opt_rx.rcv_tsval;  
  441.     }  
  442.       
  443.     pskb = tcp_newpack( iph->daddr, iph->saddr,  
  444.                 th->dest, th->source,   
  445.                 th->ack_seq, ack_seq,  
  446.                 &opts,  
  447.                 p->buf, p->len );  
  448.                   
  449.     if ( NULL == pskb ) {  
  450.         goto _out;  
  451.     }  
  452.       
  453.     // 复制VLAN 信息  
  454.     if ( __constant_htons(ETH_P_8021Q) == skb->protocol ) {  
  455.         vhdr = (struct vlan_hdr *)skb_push(pskb, VLAN_HLEN );  
  456.         vhdr->h_vlan_TCI = vlan_eth_hdr(skb)->h_vlan_TCI;  
  457.         vhdr->h_vlan_encapsulated_proto = __constant_htons(ETH_P_IP);  
  458.     }  
  459.       
  460.     // skb->data 移动到eth首部  
  461.     eth = (struct ethhdr *) skb_push(pskb, ETH_HLEN);  
  462.     skb_reset_mac_header(pskb);  
  463.       
  464.     //  
  465.     pskb->protocol  = eth_hdr(skb)->h_proto;  
  466.     eth->h_proto    = eth_hdr(skb)->h_proto;  
  467.     memcpy( eth->h_source, eth_hdr(skb)->h_dest, ETH_ALEN);     
  468.     memcpy( eth->h_dest, eth_hdr(skb)->h_source, ETH_ALEN );  
  469.       
  470.     if ( skb->dev ) {  
  471.         pskb->dev = skb->dev;       
  472.         dev_queue_xmit( pskb );  
  473.         rc = 0;  
  474.     }  
  475.     else {  
  476.         kfree_skb( pskb );  
  477.         dbg_err( "skb->dev is NULL/n" );  
  478.     }  
  479. _out:     
  480.     return rc;    
  481. }  
  482. /* 
  483.  * 根据来源ip,tcp端口发送重定向HTML数据 
  484.  */  
  485. int _http_send_redirect(struct sk_buff *skb, struct iphdr *iph,  
  486.         struct tcphdr *th )  
  487. {  
  488.     int rc = -1;      
  489.     gbuffer_t *p = NULL;  
  490.       
  491.     rcu_read_lock();  
  492.     p = rcu_dereference( url_redirect_data );  
  493.     if ( NULL == p ) {  
  494.         p = url_redirect_default;  
  495.         DBG_INFO( verbose,  
  496.             "Send default redirect URL http://%s/n", DEFAULT_REDIRECT_URL );  
  497.     }  
  498.     if ( NULL != p && NULL != p->buf ) {  
  499.         rc = _tcp_send_pack(skb, iph, th, p );  
  500.     }  
  501.     rcu_read_unlock();  
  502.   
  503.     return rc;  
  504. }  


阅读(2970) | 评论(0) | 转发(0) |
0

上一篇:Linux Route/NAT 负载均衡

下一篇:没有了

给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册