免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 844 | 回复: 0
打印 上一主题 下一主题

cipe主要实现函数之cipe_xmit详解 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-12-09 10:09 |只看该作者 |倒序浏览

在前面有一篇笔记中写了cipe的原理,大概流程,实现的主要文件和主要函数,cipe_xmit为output.c中最主要的函数,为cipe的发送函数,研究了一下,把注释加了进去记录在此,由于本人菜鸟一个,难免有错误,希望看到的朋友给予及时指正,感激不尽.
/*
*函数名:cipe_xmit
*函数作用:把原来的包重新封装在一个udp报文中,然后调用ipforward发送出去
*大体流程:
*将原始数据包加密,然后封装在udp中,即需要重新构造ip头和udp头,然后调用ipforward发送出去
*注意,加密后的数据比加密前的长度要大
*/
int cipe_xmit(struct sk_buff *skb, struct NET_DEVICE *dev)
{
    struct enet_statistics *stats;    /* This device's statistics */
    struct rtable *rt;         /* Route to the other host */
    struct NET_DEVICE *tdev;        /* Device to other host */
    struct iphdr *iph;            /* Our new IP header */
    struct udphdr *udph;
    __u32 target;        /* The other host's IP address */
    int max_headroom;        /* The extra header space needed */
    int max_tailroom;
    int tos, ttl, length;
    /*调用后,c指向dev->priv,即c指向dev所对应的cipe*/
    DEVTOCIPE(dev,c,0);
    if (skb == NULL || dev == NULL) {
    dprintk(DEB_OUT, (KERN_INFO "%s: nothing to do\n", dev->name));
    return 0;
    }
    /*
     *    Make sure we are not busy (check lock variable)
     */
    stats = &(c->stat);
    if (dev->tbusy != 0)
    {
    printk(KERN_WARNING "%s: device timeout (really possible?)\n",
     dev->name);
    dev->tbusy=0;
    stats->tx_errors++;
    return(1);
    }
#ifdef DEBUG
    if (cipe_debug&DEB_PKOU)
        cipe_dump_packet("original", skb, 0);
#endif
    /*
     * First things first. Look up the destination address in the
     * routing tables
     */
    target = c->peeraddr;
    if ((!target) || (!c->peerport) || (!c->myport)) {
    /* unconfigured device */
    printk(KERN_INFO "%s: unconfigured\n", dev->name);
    goto error;
    }
    /*在本机路由表中查找到target的路由*/
    if ((rt = iproute(target, 0, skb->sk?skb->sk->bound_device:NULL)) == NULL)
    {
    /* No route to host */
    printk(KERN_INFO "%s: target unreachable\n", dev->name);
    goto error;
    }
    dprintk(DEB_OUT, (KERN_INFO
         "%s: routing to %08lX from %08lX via %08lX dev %s\n",
         dev->name, ntohl(rt->rt_dst), ntohl(rt->rt_src),
         ntohl(rt->rt_gateway), rt->rt_dev->name));
    /*tdev为发送包到目的端所使用本地的device还是目的端的device,有待进一步研究,但是不影响对此函数的理解*/
    tdev = rt->rt_dev;
    ip_rt_put(rt);
    if (tdev == dev)
    {
    /* Tunnel to ourselves? -- I don't think so. */
    printk ( KERN_INFO "%s: Packet targetted at myself!\n" , dev->name);
    goto error;
    }
    /*
     * Okay, now see if we can stuff it in the buffer as-is. We can not.
     */
    max_headroom = (((tdev->hard_header_len+15)&~15)+cipehdrlen+
         ((c->sockshost) ? sizeof(struct sockshdr) : 0));
    max_tailroom = (c->flags&CIPF_HAVE_KEY) ? cipefootlen : 0;
    {
        struct sk_buff *new_skb;
        if ( !(new_skb =
         dev_alloc_skb(skb->len+max_headroom+max_tailroom)) )
        {
            printk(KERN_INFO "%s: Out of memory, dropped packet\n",
             dev->name);
              dev->tbusy = 0;
              stats->tx_dropped++;
            dev_kfree_skb(skb, FREE_WRITE);
            return 0;
        }
        new_skb->free = 1;
        /*
         * Reserve space for our header and the lower device header
         */
        skb_reserve(new_skb, max_headroom);
        /*
         * Copy the old packet to the new buffer.
         * Note that new_skb->h.iph will be our (tunnel driver's) header
         * and new_skb->ip_hdr is the IP header of the old packet.
         */
        /*令ip_hdr指向原数据包的ip头*/
        new_skb->ip_hdr = (struct iphdr *) skb_put(new_skb, skb->len);
        new_skb->mac.raw = new_skb->data;
        new_skb->dev = skb->dev;
        /*复制原数据包到新的数据包中*/
        memcpy(new_skb->ip_hdr, skb->data, skb->len);
        memset(new_skb->proto_priv, 0, sizeof(skb->proto_priv));
        /* Free the old packet, we no longer need it */
        dev_kfree_skb(skb, FREE_WRITE);
        skb = new_skb;
    }
#ifdef VER_ETH
    if (skb->mac.ethernet->h_proto==htons(ETH_P_IP)) {
#endif
    tos = skb->ip_hdr->tos;
    ttl = skb->ip_hdr->ttl;
#ifdef VER_ETH
    } else {
    tos = 0;
    ttl = 64;
    }
#endif
        length = skb->len;
    if (c->flags&CIPF_HAVE_KEY) {
     /* Add an IV ,IV为初始化向量,加密用的*/
     /*用一个新的random key把数据加密后然后加到新的skb中,skb的长度增加了c->cipher->ivsize*/
     cipe_cryptpad(skb_push(skb, c->cipher->ivsize),
                          c->cipher->ivsize);
     length+=c->cipher->ivsize;
     /*如果不可以使用静态密钥进行加密而且又不是动态加密密钥,则报错*/
            if (!c->flags&CIPF_MAY_STKEY && !c->flags&CIPF_HAVE_SKEY)
                /* Attempt to encrypt data using invalid static key */
                goto error;
     cipe_encrypt(c, skb->data, &length, TW_DATA);
     /* This is incorrect - the tail room gets first used and then
     reserved. Doesn't matter in the current (2.0.29) implementation
     of skb_put though. Alternative solution would ruin the nice
     module separation - we don't need to know the real amount
     of padding here. */
     (void) skb_put(skb, length-skb->len);
    } else if (!c->flags&CIPF_MAY_CLEAR) {
     goto error;
    }
        if (c->sockshost) {
     /* Install a SOCKS header */
     struct sockshdr *sh = (struct sockshdr *)
        skb_push(skb, sizeof(struct sockshdr));
     memset(sh, 0, 4);
     sh->atyp=1;
     /* sockshost and socksport contain the real peer's address
     and the configured/guessed peer is really the socks relayer! */
     sh->dstaddr=c->sockshost;
     sh->dstport=c->socksport;
     length+=sizeof(struct sockshdr);
    }
        /* Install our new headers */
        /*为ip头和udp头预留空间*/
        udph = (struct udphdr *) skb_push(skb, sizeof(struct udphdr));
        skb->h.iph = (struct iphdr *) skb_push(skb, sizeof(struct iphdr));
    /*
     *    Push down and install the CIPE/UDP header.
     */
    /*填充新数据包的ip头*/
    iph             =    skb->h.iph;
    iph->version        =     4;
    iph->tos        =    tos;
    /* In new_tunnel.c, we use the original packet's TTL here.
     Setting a new TTL behaves better to the user, and RFC2003
     recommends it too. But this doesn't fully protect against
     routing loops. So make it configurable via an argument:
     "cttl" gives the TTL value; if 0 use the packet's
     value. Default should be 64, as with the other protocols
     (ip_statistics.IpDefaultTTL, but this variable is not
     available for modules). */
    iph->ttl         =    c->cttl ? c->cttl : ttl;
    iph->frag_off        =    0;
    iph->daddr        =    target;
    iph->saddr        =    c->myaddr; /* tdev->pa_addr; */
    iph->protocol        =    IPPROTO_UDP;
    iph->ihl        =    5;
    iph->tot_len        =    htons(skb->len);
    iph->id            =    htons(ip_id_count++);    /* Race condition here? */
    /*做校验和*/
    ip_send_check(iph);
        /*填充新数据包的udp头*/
        udph->source = c->myport;
        udph->dest = c->peerport;
        udph->len = htons(length+sizeof(struct udphdr));
        /* Encrypted packets are checksummed already, so we can safely
     ignore the UDP checksum. Provide a means to do it nonetheless */
    udph->check = 0;
    if (c->flags&CIPF_DO_CSUM) {
     udph->check=csum_tcpudp_magic(
        iph->saddr, iph->daddr,
        length+sizeof(struct udphdr), IPPROTO_UDP,
        csum_partial((char *)udph, length+sizeof(struct udphdr), 0));
     if (!udph->check)
        udph->check=-1;
    }
    skb->ip_hdr         = skb->h.iph;
    skb->protocol        =    htons(ETH_P_IP);
    /*
     *    Send the packet on its way!
     *    Note that dev_queue_xmit() will eventually free the skb.
     *    If ip_forward() made a copy, it will return 1 so we can free.
     */
    dprintk(DEB_OUT, (KERN_INFO "%s: send to %s via %s\n",
             dev->name, cipe_ntoa(target), tdev->name));
#ifdef DEBUG
    if (cipe_debug &DEB_PKOU)
        cipe_dump_packet("sending", skb, 0);
#endif
/* 新的数据包构造好后,调用ipforward将包发送出去*/
    switch (ipforward(skb, dev, IPFWD_NOTTLDEC, target)) {
    case -1:
     printk(KERN_INFO "%s: forwarding failed\n", dev->name);
     /* fall thru */
    case 1:
     dev_kfree_skb(skb, FREE_WRITE);
     /* Does it really need dev_ here? I think so. */
     break;
    default:
     /* nothing to do */
    }
    /*
     *    Clean up: We're done with the route and the packet
     */
    /* Record statistics and return */
    stats->tx_packets++;
    dev->tbusy=0;
    return 0;
    error:
    stats->tx_errors++;
    dev_kfree_skb(skb, FREE_WRITE);
    dev->tbusy=0;
    return 0;
}
#endif /* LINUX_21 */

ps:大部分e文的为源代码的注释,c文为自己研究时自己对代码的理解.


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/83905/showart_1687147.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP