- 论坛徽章:
- 0
|
在前面有一篇笔记中写了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 |
|