赞
踩
原标题:Linux网络子系统安全性模块代码详细分析之文件esp4.c中内部函数和核心代码注释
2.4.6.5内部函数1. esp_init_state( )
函数原型:static int esp_init_state(struct xfrm_state *x)
函数参数:参数x为安全关联。
函数功能:初始化SA中用于ESP处理的相关字段,主要初始化认证加密算法和协议头的长度,在初始化认证加密算法中。
返回值:返回算法初始化函数的返回值。
2. esp_init_aead( )
函数原型:static int esp_init_aead(struct xfrm_state *x)
函数参数:参数x为安全关联。
函数功能:分配认证加密算法结构,并设置算法密钥和认证向量的长度。
返回值:正确则返回0,否则返回错误码。
3. esp_input( )
函数原型:static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
函数参数:参数x为SA结构,skb为套接字缓冲区。
函数功能:ESP协议封装的数据包的进入链处理,首先进行身份认证,认证通过后则调用解密算法进行数据包的解密,如果经过了UDP封装还要修改端口等字段。
返回值:返回下一头标号。
4. esp_input_done2( )
函数原型:static int esp_input_done2(struct sk_buff *skb, int err)
函数参数:参数skb为套接字缓冲区,err为加密的结果。
函数功能:进入数据包的第二阶段处理,主要是判断是否需要进行UDP封装和重新设置传输层头。
返回值:查找到的SA。
5. esp_output( )
函数原型:static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
函数参数:参数x为SA结构,skb为套接字缓冲区。
函数功能:进行输出链ESP协议处理,主要完成了认证向量的初始化,数据包的加密,以及UDP封装等操作。
返回值:解密的结果。
2.4.6.6 核心代码注释
esp_input( )和esp_output( )函数是本文件的核心函数,分别是数据包进入链和发送链的ESP处理,其执行逻辑参见2.3.2节,由于进入和发送处理正好是相反的操作,此处主要分析esp_output( )函数的代码。
static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
struct ip_esp_hdr *esph;
struct crypto_aead *aead;
struct aead_givcrypt_request *req;
struct scatterlist *sg;
struct scatterlist *asg;
struct esp_data *esp;
struct sk_buff *trailer;
void *tmp;
u8 *iv;
u8 *tail;
int blksize;
int clen;
int alen;
int plen;
int tfclen;
int nfrags;
int assoclen;
int sglists;
int seqhilen;
__be32 *seqhi;
err = -ENOMEM;
//从SA中获取进行esp处理的数据、认证加密算法,并计算认证长度
esp = x->data;
aead = esp->aead;
alen = crypto_aead_authsize(aead);
//填充数据处理
tfclen = 0;
if (x->tfcpad) {
struct xfrm_dst *dst = (struct xfrm_dst *)skb_dst(skb);
u32 padto;
padto = min(x->tfcpad, esp4_get_mtu(x, dst->child_mtu_cached));
if (skb->len < padto)
tfclen = padto - skb->len;
}
//加密块的大小、加密长度的获取
blksize = ALIGN(crypto_aead_blocksize(aead), 4);
clen = ALIGN(skb->len + 2 + tfclen, blksize);
if (esp->padlen)
clen = ALIGN(clen, esp->padlen);
plen = clen - skb->len - tfclen;
//让套接字缓冲区可写,并获取分片数存放在nfrags变量中
err = skb_cow_data(skb, tfclen + plen + alen, &trailer);
if (err < 0)
goto error;
nfrags = err;
assoclen = sizeof(*esph);
sglists = 1;
seqhilen = 0;
if (x->props.flags & XFRM_STATE_ESN) {
sglists += 2;
seqhilen += sizeof(__be32);
assoclen += seqhilen;
}
//分配一个用于认证加密的临时结构,该结构中主要存储了认证向量IV和分片链表SG
tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
if (!tmp)
goto error;
//从临时结构中获取相应的结构
seqhi = esp_tmp_seqhi(tmp);
iv = esp_tmp_iv(aead, tmp, seqhilen);
req = esp_tmp_givreq(aead, iv);
asg = esp_givreq_sg(aead, req);
sg = asg + sglists;
//填充套接字缓冲区尾部
tail = skb_tail_pointer(trailer);
if (tfclen) {
memset(tail, 0, tfclen);
tail += tfclen;
}
do {
int i;
for (i = 0; i < plen - 2; i++)
tail[i] = i + 1;
} while (0);
tail[plen - 2] = plen - 2;
tail[plen - 1] = *skb_mac_header(skb);
//增加缓冲区的头部和尾部
pskb_put(skb, trailer, clen - skb->len + alen);
skb_push(skb, -skb_network_offset(skb));
esph = ip_esp_hdr(skb);
*skb_mac_header(skb) = IPPROTO_ESP;
//如果经过了NAT,则要进行UDP封装,并修改传输层头中的源端口和目的端口
if (x->encap) {
struct xfrm_encap_tmpl *encap = x->encap;
struct udphdr *uh;
__be32 *udpdata32;
__be16 sport, dport;
int encap_type;
spin_lock_bh(&x->lock);
sport = encap->encap_sport;
dport = encap->encap_dport;
encap_type = encap->encap_type;
spin_unlock_bh(&x->lock);
uh = (struct udphdr *)esph;
uh->source = sport;
uh->dest = dport;
uh->len = htons(skb->len - skb_transport_offset(skb));
uh->check = 0;
switch (encap_type) {
default:
case UDP_ENCAP_ESPINUDP:
esph = (struct ip_esp_hdr *)(uh + 1);
break;
case UDP_ENCAP_ESPINUDP_NON_IKE:
udpdata32 = (__be32 *)(uh + 1);
udpdata32[0] = udpdata32[1] = 0;
esph = (struct ip_esp_hdr *)(udpdata32 + 2);
break;
}
*skb_mac_header(skb) = IPPROTO_UDP;
}
//修改esp头中的spi和序列号
esph->spi = x->id.spi;
esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
//设置分片列表SG
sg_init_table(sg, nfrags);
skb_to_sgvec(skb, sg,
esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
clen + alen);
…
//设置加密回调函数,设置加密请求结构req,以及IV等信息
aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
aead_givcrypt_set_assoc(req, asg, assoclen);
aead_givcrypt_set_giv(req, esph->enc_data,XFRM_SKB_CB(skb)->seq.output.low);
//加密数据包
err = crypto_aead_givencrypt(req);
kfree(tmp);
error:
return err;
责任编辑:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。