• IP隧道基础研究


    static char banner[] __initdata = KERN_INFO "IPv4 over IPv4 tunneling driver
    ";
    static struct xfrm_tunnel ipip_handler = {
        .handler        =       ipip_rcv, //看下面接收处理函数实现
        .err_handler    =       ipip_err,
        .priority       =       1,
    };
    static int __init ipip_init(void) // net/ipv4/ipip.c
    {
        int err;
        printk(banner); //打印信息
    
        //注册ipip接收处理函数
        if (xfrm4_tunnel_register(&ipip_handler)) {
            printk(KERN_INFO "ipip init: can't register tunnel
    ");
            return -EAGAIN;
        }
        //分配一个网络设备,设备名tunl0
        ipip_fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "tunl0", ipip_tunnel_setup);
        if (!ipip_fb_tunnel_dev) {
            err = -ENOMEM;
            goto err1;
        }
        ipip_fb_tunnel_dev->init = ipip_fb_tunnel_init; //初始化函数
    
        //注册这个网络设备,会调用上面的初始化函数
        if ((err = register_netdev(ipip_fb_tunnel_dev)))
            goto err2;
    out:
        return err;
    err2:
        free_netdev(ipip_fb_tunnel_dev);
    err1:
        xfrm4_tunnel_deregister(&ipip_handler);
        goto out;
    }
    //注册处理函数
    static struct xfrm_tunnel *tunnel4_handlers;
    int xfrm4_tunnel_register(struct xfrm_tunnel *handler)
    {
        struct xfrm_tunnel **pprev;
        int ret = -EEXIST;
        int priority = handler->priority; //权限
    
        mutex_lock(&tunnel4_mutex);
        for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) {
            if ((*pprev)->priority > priority) //找到位置,从小到大排列
                break;
    
            if ((*pprev)->priority == priority) //重复,出错
                goto err;
        }
        handler->next = *pprev;
        *pprev = handler;
        ret = 0;
    err:
        mutex_unlock(&tunnel4_mutex);
        return ret;
    }
    
    ipip协议
    static struct net_protocol tunnel4_protocol = { //IPIP协议处理
        .handler        =       tunnel4_rcv,
        .err_handler    =       tunnel4_err,
        .no_policy      =       1,
    };
        ipip协议注册
    static int __init tunnel4_init(void)
    {
        //向核心注册ipip协议
        if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) {
            printk(KERN_ERR "tunnel4 init: can't add protocol
    ");
            return -EAGAIN;
        }
        return 0;
    }
    static int tunnel4_rcv(struct sk_buff *skb)
    {
        struct xfrm_tunnel *handler;
    
        if (!pskb_may_pull(skb, sizeof(struct iphdr)))
            goto drop;
    
        //调用连表中的所有处理函数,已经安大小排过序了
        for (handler = tunnel4_handlers; handler; handler = handler->next)
            if (!handler->handler(skb)) //处理函数返回0,正确结束
                return 0;
        //有一个不对就发送icmp目的和端口不可达包
        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
    drop:
        kfree_skb(skb);
        return 0;
    }
    现在我们看出只要是调用了xfrm4_tunnel_register函数向ipip协议注册了处理函数那么就会被ipip协议接收函数调用,权限字段值越小越先被调用.
    在ip_local_deliver_finish函数中(可以参考linux协议占函数流程一文)会根据ip协议中的协议字段调用相应的协议处理函数。
    
    ......
    int protocol = skb->nh.iph->protocol;
    ......
    if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) {
        ......
        ret = ipprot->handler(skb); //调用ipip协议的处理函数tunnel4_rcv
        ......
    }
    [接收处理函数实现]
    每一个IP数据包均交由ip_rcv函数处理,在进行一些必要的判断后,ip_rcv对于发送给本机的数据包将交给上层处理程序。
    对于IPIP包来说,其处理函数是ipip_rcv(就如TCP包的处理函数是tcp_rcv一样,IP层不加区分)。
    也就是说,当一个目的地址为本机的封包到达后,ip_rcv函数进行一些基本检查并除去IP头,然后交由ipip_rcv解封。
        ipip_rcv所做的工作就是去掉封包头,还原数据包,然后把还原后的数据包放入相应的接收队列netif_rx().
    static int ipip_rcv(struct sk_buff *skb)
    {
        struct iphdr *iph;
        struct ip_tunnel *tunnel;
        iph = skb->nh.iph;
    
        read_lock(&ipip_lock);
        //在hash表中查询
        if ((tunnel = ipip_tunnel_lookup(iph->saddr, iph->daddr)) != NULL) {
            if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { //检测IPSEC包策略
                read_unlock(&ipip_lock);
                kfree_skb(skb);
                return 0;
            }
    
            secpath_reset(skb); //释放sec_path
    
            skb->mac.raw = skb->nh.raw;
            skb->nh.raw = skb->data; //指向这个封装的ip头
            skb->protocol = htons(ETH_P_IP);//协议变为IP
            skb->pkt_type = PACKET_HOST;
    
            tunnel->stat.rx_packets++;
            tunnel->stat.rx_bytes += skb->len;
            skb->dev = tunnel->dev;//指向这个虚拟设备
            dst_release(skb->dst); //释放路由缓存,需要从新查找
            skb->dst = NULL;
            nf_reset(skb); //释放ip_conntrack结构
            ipip_ecn_decapsulate(iph, skb); //ECN解封,IPSEC相关
            netif_rx(skb);//重新递交
            read_unlock(&ipip_lock);
            return 0;
        }
        read_unlock(&ipip_lock);
        return -1; //查询不到出错
    }
    
    static struct ip_tunnel *tunnels_r_l[HASH_SIZE]; //(remote,local)
    static struct ip_tunnel *tunnels_r[HASH_SIZE];   //(remote,*)
    static struct ip_tunnel *tunnels_l[HASH_SIZE];   //(*,local)
    static struct ip_tunnel *tunnels_wc[1];           //(*,*)
    static struct ip_tunnel **tunnels[4] = { tunnels_wc, tunnels_l, tunnels_r, tunnels_r_l };
    static struct ip_tunnel * ipip_tunnel_lookup(u32 remote, u32 local)
    {
        //计算出hash值
        unsigned h0 = HASH(remote);
        unsigned h1 = HASH(local);
        struct ip_tunnel *t;
        //在源和目的地址都在的hash表中寻找
        for (t = tunnels_r_l[h0^h1]; t; t = t->next) {
            if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
                return t;
        }
        //在只有目的地址hash表中寻找
        for (t = tunnels_r[h0]; t; t = t->next) {
            if (remote == t->parms.iph.daddr && (t->dev->flags&IFF_UP))
                return t;
        }
        //在只有源地址hash表中寻找
        for (t = tunnels_l[h1]; t; t = t->next) {
            if (local == t->parms.iph.saddr && (t->dev->flags&IFF_UP))
                return t;
        }
        if ((t = tunnels_wc[0]) != NULL && (t->dev->flags&IFF_UP))
            return t;
        return NULL;
    }
    [接收处理函数实现]
  • 相关阅读:
    (unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated UXXXXXXXX escape 错误
    Pandas_key_point
    鲁棒性、稳定性、非脆弱性
    防止过拟合的处理方法
    Python中的random模块
    Python reload(sys)找不到,name 'reload' is not defined
    sigmoid 和 soft-max总结
    2.7 Structured Regression Models
    2.x ESL第二章习题2.4
    2.6. Statistical Models, Supervised Learning and Function Approximation
  • 原文地址:https://www.cnblogs.com/super-king/p/3286747.html
Copyright © 2020-2023  润新知