文档章节

linux内核netfilter实现url重定向 (嵌入android系统中)

郑泮勇
 郑泮勇
发布于 2014/10/17 11:38
字数 1811
阅读 2172
收藏 3
该文件拷贝到 <AndroidSource>/kernel/net/ipv4/netfilter 目录下,
在  <AndroidSource>/kernel/net/ipv4/netfilter/Makefile 
最后一行添加:obj-y += url_redirect.o 
(Mtk系统 编译bootimage烧写 编译命令:./makeMtk [工程名] n(r) kernel && ./mk bootimage)

(在android系统中测试)该文件还需修改只能修改url,跳转还有问题, 还需添加内核文件驱动才能达到控制跳转的功能。

该文件转自:http://blog.chinaunix.net/uid-23390992-id-3485745.html
url_redirect.c:

#include <linux/init.h>
 
#include <linux/types.h>
 
#include <linux/netdevice.h>
 
#include <linux/skbuff.h>
 
#include <linux/ip.h>
 
#include <linux/udp.h>
 
#include <linux/tcp.h>
 
#include <net/tcp.h>
 
#include <linux/netfilter_ipv4.h>
 
#include <linux/netfilter_bridge.h>
 
#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    
 
    put_unaligned( 0x45, ( unsigned char * )iph );
 
    iph->tos      = 0;
 
    put_unaligned( htons( ip_len ), &( iph->tot_len ) );
 
    iph->id       = 0;
 
    iph->frag_off = htons(IP_DF);
 
    iph->ttl      = 64;
 
    iph->protocol = IPPROTO_UDP;
 
    iph->check    = 0;
 
    put_unaligned( saddr, &( iph->saddr ) );
 
    put_unaligned( daddr, &( iph->daddr ) );
 
    iph->check    = ip_fast_csum( ( unsigned char * )iph, iph->ihl );
 
#else
 
    iph->version  = 4;
 
    iph->ihl      = 5;
 
    iph->tos      = 0;
 
    iph->tot_len  = htons( ip_len );
 
    iph->id       = 0;
 
    iph->frag_off = htons(IP_DF);
 
    iph->ttl      = 64;
 
    iph->protocol = protocol;
 
    iph->check    = 0;
 
    iph->saddr    = saddr;
 
    iph->daddr    = daddr;
 
    iph->check    = 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 );
 
  
 
    memset( th, 0x0, sizeof( *th ) );
 
    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;
 
    
 
    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;
 
}
 
/*
 
 * 根据来源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;
 
    int tcp_len = 0;
 
    u32 ack_seq = 0;
 
    int rc = -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);
 
     
 
    pskb = tcp_newpack( iph->daddr, iph->saddr,
 
                th->dest, th->source, 
 
                th->ack_seq, ack_seq,
 
                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 );
 
        printk( "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;
 
    }
 
    if ( NULL != p && NULL != p->buf ) {
 
        rc = _tcp_send_pack(skb, iph, th, p );
 
    }
 
    rcu_read_unlock();
 
  
 
    return rc;
 
}
 
  
 
static unsigned int direct_fun(unsigned int hook,
 
                           struct sk_buff *skb,
 
                           const struct net_device *in,
 
                           const struct net_device *out,
 
                           int (*okfn)(struct sk_buff *)
 
                          )
 
{
 
    struct iphdr *iph = ip_hdr(skb);
 
    struct ethhdr *eth = eth_hdr(skb);
 
    struct tcphdr *tcph = NULL;
 
    struct udphdr *udph=NULL;
 
  
 
    unsigned int sip, dip;
 
    unsigned short source, dest;
 
    unsigned char *payload;
 
    int plen;
 
    if(!skb)
 
        return NF_ACCEPT;
 
    if(!eth){
 
        return NF_ACCEPT;
 
    }
 
    if(!iph){
 
        return NF_ACCEPT;
 
    }
 
  
 
    if(skb->pkt_type == PACKET_BROADCAST)
 
        return NF_ACCEPT;
 
     
 
    if((skb->protocol==htons(ETH_P_8021Q)||skb->protocol==htons(ETH_P_IP))&&skb->len>=sizeof(struct ethhdr)){
 
         
 
        if(skb->protocol==htons(ETH_P_8021Q))
 
        {
 
            iph=(struct iphdr *)((u8*)iph+4);
 
        }
 
  
 
        if(iph->version!=4)
 
            return NF_ACCEPT;
 
         
 
        if (skb->len < 20)
 
            return NF_ACCEPT;
 
         
 
        if ((iph->ihl * 4) > skb->len || skb->len < ntohs(iph->tot_len) || (iph->frag_off & htons(0x1FFF)) != 0)
 
            return NF_ACCEPT;
 
         
 
        sip = iph->saddr;
 
        dip = iph->daddr;
 
        if(iph->protocol == 6){
 
            tcph = (struct tcphdr *)((unsigned char *)iph+iph->ihl*4);
 
  
 
            source = ntohs(tcph->source);
 
            dest = ntohs(tcph->dest);
 
             
 
            if(dest == 53 || source == 53){  // dns
 
                return NF_ACCEPT;
 
            }
 
            plen = ntohs(iph->tot_len) - iph->ihl*4 - tcph->doff*4;
 
  
 
            //http
 
            if(source == 80 || dest == 80){
 
                payload = (unsigned char *)tcph + tcph->doff*4;
 
                if(plen > 10 && payload[0] == 'G' && payload[1] == 'E' && payload[2] == 'T' && payload[3] == ' '){
 
                    _http_send_redirect(skb,iph,tcph);
 
                }
 
            }
 
        }
 
        else if( iph->protocol == 17){
 
            udph = (struct udphdr *)((char *) iph + iph->ihl * 4);
 
             
 
            source = ntohs(udph->source);
 
            dest = ntohs(udph->dest);
 
         
 
            if(dest == 68 || source == 67 || dest == 53 || source == 53){  //dhcp dns
 
                return NF_ACCEPT;
 
            }
 
            if(255 == plen || 0 == dip){ //广播
 
                return NF_ACCEPT;
 
            }
 
        }
 
    }
 
     
 
    return NF_ACCEPT;
 
}
 
  
 
static struct nf_hook_ops auth_ops =
 
{
 
    .hook = direct_fun,
 
    .pf = PF_INET,
 
    .hooknum = NF_INET_PRE_ROUTING,
 
    .priority = NF_IP_PRI_FIRST,
 
}; 
 
  
 
static int __init auth_init(void)
 
{
 
    redirect_url_init();
 
    nf_register_hook(&auth_ops);
 
     
 
    return 0;
 
}
 
  
 
static void __exit auth_eixt(void)
 
{
 
    nf_unregister_hook(&auth_ops);
 
    redirect_url_fini();
 
}
  
 
MODULE_LICENSE("GPL");
 
  
module_init(auth_init);
 
module_exit(auth_eixt);


 url_redirect.h:

struct gbuffer{  
 
    u8  *buf;  
 
    u32 len;  
 
};  
 
   
 
typedef struct gbuffer gbuffer;  
 
typedef struct gbuffer gbuffer_t;  
 
   
 
static inline void gbuffer_init(gbuffer *p)  
 
{  
 
    p->len = 0;  
 
    p->buf = NULL;  
 
}  
 
   
 
static inline void __gbuffer_init(gbuffer *p, u8 *buf, u32 len)  
 
{  
 
    p->len = len;  
 
    p->buf = buf;  
 
}  
 
   
 
static inline int gbuffer_empty(gbuffer *p)  
 
{  
 
    return ( p->buf == NULL );  
 
}  
 
   
 
static inline void gbuffer_free(gbuffer *p)  
 
{  
 
    if ( NULL == p )  
 
        return;  
 
   
 
#ifdef __KERNEL__  
 
    if ( likely( p->buf != NULL ) ){  
 
        kfree( p->buf );  
 
        p->buf = NULL;  
 
    }  
 
#else   
 
    if ( NULL != p->buf ) {  
 
        free( p->buf );  
 
    }  
 
#endif  
 
    p->len = 0;  
 
}  
 
   
 
static inline void _gbuffer_free(gbuffer *p)  
 
{  
 
    if ( NULL == p )  
 
        return;  
 
   
 
#ifdef __KERNEL__  
 
    if ( likely( p->buf != NULL ) ){  
 
        kfree( p->buf );  
 
        p->buf = NULL;  
 
    }  
 
    kfree( p );  
 
#else   
 
    if ( NULL != p->buf ) {  
 
        free( p->buf );  
 
    }  
 
    free( p );  
 
#endif  
 
}  
 
   
 
static inline gbuffer_t* __gbuffer_alloc(void)  
 
{  
 
    gbuffer_t *p = NULL;  
 
#ifdef __KERNEL__  
 
    p = kzalloc( sizeof(*p), GFP_KERNEL );  
 
    if ( unlikely( NULL == p ) ){  
 
        return NULL;  
 
    }  
 
#else  
 
    p = malloc( sizeof(*p) );  
 
    if ( NULL == p )  
 
        return NULL;  
 
#endif  
 
    p->buf = NULL;  
 
    p->len = 0;  
 
   
 
    return p;  
 
}  
 
   
 
static inline gbuffer_t* _gbuffer_alloc(u32 len)  
 
{  
 
    gbuffer_t *p = NULL;  
 
   
 
#ifdef __KERNEL__  
 
    p = kzalloc( sizeof(*p), GFP_KERNEL );  
 
    if ( unlikely( NULL == p ) ){  
 
        return NULL;  
 
    }  
 
       
 
    p->buf = kzalloc( len, GFP_KERNEL );  
 
    if ( unlikely( NULL == p->buf ) ){  
 
        kfree( p );  
 
        return NULL;  
 
    }  
 
#else  
 
    p = malloc( sizeof(*p) );  
 
    if ( NULL == p )  
 
        return NULL;  
 
           
 
    p->buf = malloc( len );  
 
    if ( NULL == p->buf ){  
 
        free( p );  
 
        return -1;  
 
    }  
 
#endif  
 
    p->len = len;  
 
    return p;  
 
}  
 
   
 
static inline int gbuffer_alloc( gbuffer *p, u32 len )  
 
{  
 
    if ( NULL == p )  
 
        return -1;  
 
   
 
#ifdef __KERNEL__  
 
    p->buf = kzalloc( len, GFP_KERNEL );  
 
    if ( unlikely( NULL == p->buf ) ){  
 
        return -1;  
 
    }  
 
#else  
 
    p->buf = malloc( len );  
 
    if ( NULL == p->buf ){  
 
        return -1;  
 
    }  
 
#endif  
 
    p->len = len;  
 
    return 0;  
 
} 

Makefile:
 
TARGET = url_redirect 
 
CURRENT = $(shell uname -r) 
 
KDIR = /lib/modules/$(CURRENT)/build
 
PWD = $(shell pwd) 
 
obj-m := $(TARGET).o 
 
default: 
 
    make -C $(KDIR) M=$(PWD) modules 
 
clean: 
 
    -rm -f *.o *.ko .*.cmd .*.flags *.mod.c *.order *.markers *.symvers




© 著作权归作者所有

郑泮勇
粉丝 2
博文 42
码字总数 5348
作品 0
温州
程序员
私信 提问
加载中

评论(2)

kslr
kslr
佐须之男
佐须之男
苏州康倍思网络成立于2009年,致力于企业及个人网络设备解决方案及技术咨询。核心业务是有线/无线/软路由器(Linux,OpenWRT,DD-WRT,Tomato)系统的定制,修改以及开发。拥有国内相关领域顶尖的技术和经验,有成熟且稳定的Ralink,Broadcom,Atheros,MTK,X86等系统解决方案,和国内外多家知名软件和硬件厂商及公司有密切的业务合作关系(武汉海蜘蛛,上海镜尚传媒,杭州通策,杭州树熊,斑马传媒,无线城市,茂名群英网络,广州网恒信息,深圳腾达,深圳同德,台湾Catch-tec,西安电信,北京网格,成都纽扣科技)。

拥有领先业界的核心技术:
1.传统模式的网页认证和互联网模式的第三方认证,迎合目前流行的广告路由和认证路由需求。(典型案例:武汉海蜘蛛-海魔方营销路由 北京-太阳系营销路由)
2.页面劫持和任意JavaScript代码注入技术,可实现上网行为的统计,广告的投放,定时推送等功能。(典型案例:武汉-湖北电力导航,Wayos)
3.企业级行为管理,拥有一套自主研发的匹配特征库,能识别300多种主流应用。(典型案例:广州网恒信息-行为管理设备)。
4.内核级智能流控Qos,基于内核调度的算法。(典型案例:台湾侠诺-CA2/4系列系统)
5.运营级别防火墙,DDOS防火墙,SPI防火墙。(典型案例:茂名群英网络-IDC机房环境)
6.URL和DNS劫持技术,可实现类似电信/联通等运营商的URL劫持和域名纠错广告,实现推送广告效果。(典型案例:惠州-彩虹无线)
7.3G路由,支持国内常用的3G卡,拨号稳定且不掉线。(典型案例:北极星3G路由器)
8.X86软路由解决方案,有成熟的软路由方案,适合大带机量环境。(典型案例:万达广场)
10.GBK/UTF8 双编码SSID,解决了Windows系统乱码的问题。
11.WEB缓存系统,可以有效减少第三方登陆页面和网页的载入时间,提高网络的有效利用率.(典型案例:杭州通策集团-医院项目)
12.远程管理功能

软件业务合作联系:一八零一三五八二一二五 (陆工) http://www.router.tw
深入解读Linux与Android的相互关系& Android消息处理系统的原理

深入解读Linux与Android的相互关系 大家都知道Android是基于Linux内核的操作系统,也曾经和Linux基金会因为内核问题产生过分歧,本文将开始对Android的内核进行剖析,主要介绍Android和Linux...

AlphaJay
2011/07/29
0
0
Android基础之Android系统架构

Android采用层次化系统架构,官方公布的标准架构如下图所示。Android由底层往上分为4个主要功能层,分别是linux内核层(Linux Kernel),系统运行时库层(Libraries和Android Runtime),应用...

柳哥
2014/11/28
0
2
浅入浅出 Android 安全:第一章 Android

第一章 Android 来源:Yury Zhauniarovich | Publications 译者:飞龙 协议:CC BY-NC-SA 4.0 Android 安全架构的理解不仅帮助我了解 Android 的工作原理,而且为我开启了如何构建移动操作系...

apachecn_飞龙
2016/11/27
0
0
Android基础之Android系统启动

Android系统的启动操作流程由Linux系统启动与Android应用系统启动两个阶段组成。 Linux系统启动 Android操作系统启动次序分别为系统上电,Bootloader引导,Linux内核启动,init初始化系统服务...

柳哥
2014/11/28
0
0
Linux与Android的关系

大家都知道Android是基于Linux内核的操作系统,也曾经和Linux基金会因为内核问题产生过分歧,本文将开始对Android的内核进行剖析,主要介绍Android和Linux之间的关系,后续还会讲到Android系...

开心303
2011/08/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何使用 rsync 备份 Linux 系统的一些介绍

备份一直是 Linux 世界的热门话题。回到 2017,David Both 为 Opensource.com 的读者在使用 rsync 备份 Linux 系统方面提了一些建议,在这年的更早时候,他发起了一项问卷调查询问大家,在 ...

xiangyunyan
42分钟前
1
0
二进制位操作

单片机,或者一些模块的设置操作,都是由一个字节数据来完成,每位各有定义。就需进行位操作来组合需要的数字结果。 以JavaScript为例,编写位操作。 我们期望得到这样一个二进制数:0101101...

format
56分钟前
4
0
聊聊中国的通信行业:从“七国八制”到“中华”脊梁

本期文章和大家一起来聊一聊我曾经从事过的通信行业吧。最近各方面信息的泛滥,包括和华为的同学聊天,自己确实也感慨颇多。想想我自己本科主修通信工程,研究生再修信息与通信工程,从本科开...

CodeSheep
今天
7
0
MDK:ARM M451M:exceed the range of code meory, continue to erase or not?

问题: 代码空间超限 几天前就遇到:exceed the range of code meory, continue to erase or not? 如下所示: 解决过程 开始以为中MDK软件的128KB限制,如是就不能生成HEX文件,应该链接时有提...

SamXIAO
今天
3
1
OSChina 周六乱弹 —— 因违反《中华人民共和国治安管理处罚法》第四十四条之规定

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @xiaoshiyue :#今日歌曲推荐# 惊艳分享谷微的单曲《安守本份》(@网易云音乐) 《安守本份》- 谷微 手机党少年们想听歌,请使劲儿戳(这里) ...

小小编辑
今天
710
15

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部