1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
| static struct xfrm_type ah_type = // net/ipv4/ah4.c
{
.description = "AH4",
.owner = THIS_MODULE,
.proto = IPPROTO_AH,
.flags = XFRM_TYPE_REPLAY_PROT,
.init_state = ah_init_state, //状态初始化
.destructor = ah_destroy,//协议释放
.input = ah_input, //协议输入
.output = ah_output //协议输出
};
状态初始化
ah_data数据结构
struct ah_data //include/net/ah.h
{
u8 *work_icv; //工作初始化向量
int icv_full_len; //初始化向量完整长度
int icv_trunc_len; //初始化向量截断长度
struct crypto_hash *tfm; //HASH算法
};
该函数被xfrm状态(SA)初始化函数xfrm_init_state调用,用来生成SA中所有的AH数据处理结构相关信息
static int ah_init_state(struct xfrm_state *x)
{
struct ah_data *ahp = NULL;
struct xfrm_algo_desc *aalg_desc;
struct crypto_hash *tfm;
if (!x->aalg) //对AH协议的SA, 认证算法是必须的, 否则就没法进行AH认证了
goto error;
if (x->encap)//如果要进行UDP封装(进行NAT穿越), 错误, 因为AH是不支持NAT的
goto error;
ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);//分配ah_data数据结构空间
if (ahp == NULL)
return -ENOMEM;
//分配认证算法HASH结构指针并赋值给AH数据结构
//算法是固定相同的, 但在每个应用使用算法时的上下文是不同的, 该结构就是描述具体应用时的相关处理的上下文数据的
tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm))
goto error;
ahp->tfm = tfm;
//设置认证算法密钥
if (crypto_hash_setkey(tfm, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8))
goto error;
/*
* Lookup the algorithm description maintained by xfrm_algo,
* verify crypto transform properties, and store information
* we need for AH processing. This lookup cannot fail here
* after a successful crypto_alloc_hash().
*/
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);//查找算法描述结构
BUG_ON(!aalg_desc);
if (aalg_desc->uinfo.auth.icv_fullbits / 8 != crypto_hash_digestsize(tfm)) {
printk(KERN_INFO "AH: %s digestsize %u != %hu\n", x->aalg->alg_name, crypto_hash_digestsize(tfm),
aalg_desc->uinfo.auth.icv_fullbits/8);
goto error;
}
//AH数据结构的初始化向量的总长和截断长度的赋值
ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
//分配初始化向量空间, 没对其赋值, 其初始值就是随机值, 这也是初始化向量所需要的
ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL);
if (!ahp->work_icv)
goto error;
//AH类型SA中AH头长度: ip_auth_hdr结构和初始化向量长度, 按8字节对齐
//反映在AH封装操作时要将数据包增加的长度
x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len);
if (x->props.mode == XFRM_MODE_TUNNEL)//如果是通道模式, 增加IP头长度
x->props.header_len += sizeof(struct iphdr);
x->data = ahp;//SA数据指向AH数据结构
return 0;
error:
if (ahp) {
kfree(ahp->work_icv);
crypto_free_hash(ahp->tfm);
kfree(ahp);
}
return -EINVAL;
}
接收数据处理, 在xfrm4_rcv_encap()函数中调用,进行AH认证, 剥离AH头
static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
{
int ah_hlen;
int ihl;
int nexthdr;
int err = -EINVAL;
struct iphdr *iph;
struct ip_auth_hdr *ah;
struct ah_data *ahp;
char work_buf[60]; //IP头备份空间
if (!pskb_may_pull(skb, sizeof(*ah)))//skb数据包要准备留出AH头空间
goto out;
ah = (struct ip_auth_hdr *)skb->data; //IP上层数据为AH数据
//SA相关的AH处理数据
ahp = x->data;
nexthdr = ah->nexthdr;
ah_hlen = (ah->hdrlen + 2) << 2;
//AH头部长度合法性检查
if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) && ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len))
goto out;
//skb数据包要准备留出实际AH头空间
if (!pskb_may_pull(skb, ah_hlen))
goto out;
/* We are going to _remove_ AH header to keep sockets happy, so... Later this can change. */
if (skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC))//对于clone的包要复制成独立包
goto out;
skb->ip_summed = CHECKSUM_NONE;
ah = (struct ip_auth_hdr *)skb->data;//可能包已经进行了复制, 所以对ah重新赋值
iph = ip_hdr(skb);
ihl = skb->data - skb_network_header(skb); //IP头长度
memcpy(work_buf, iph, ihl); //备份外部IP头数据
//将IP头中的一些参数清零, 这些参数不进行认证
iph->ttl = 0;
iph->tos = 0;
iph->frag_off = 0;
iph->check = 0;
if (ihl > sizeof(*iph)) {//IP头长度超过20字节时,处理IP选项参数
__be32 dummy;
if (ip_clear_mutable_options(iph, &dummy))
goto out;
}
{
u8 auth_data[MAX_AH_AUTH_LEN];//认证数据缓冲区
memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);//拷贝数据包中的认证数据到缓冲区
skb_push(skb, ihl);//包括IP头部分数据
err = ah_mac_digest(ahp, skb, ah->auth_data);//计算认证值是否匹配, 非0表示出错
if (err)
goto out;
err = -EINVAL;
if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len)) {//复制一定长度的认证数据作为初始化向量
x->stats.integrity_failed++;
goto out;
}
}
skb->network_header += ah_hlen; //更新网络头字段
memcpy(skb_network_header(skb), work_buf, ihl);//将原来IP头数据拷贝到原来AH头后面作为新IP头
skb->transport_header = skb->network_header;
__skb_pull(skb, ah_hlen + ihl);//skb包缩减原来的IP头和AH头, 以新IP头作为数据开始
return nexthdr; //返回AH内部包裹的协议
out:
return err;
}
发送数据处理, 在xfrm4_output_one()中调用,计算AH认证值, 添加AH头
static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
struct iphdr *iph, *top_iph;
struct ip_auth_hdr *ah;
struct ah_data *ahp;
union {//临时IP头缓冲区, 最大IP头60字节
struct iphdr iph;
char buf[60];
} tmp_iph;
skb_push(skb, -skb_network_offset(skb)); //data指针移动到网络头位置
top_iph = ip_hdr(skb);//当前的IP头将作为最外部IP头
iph = &tmp_iph.iph; //临时IP头,用于临时保存IP头内部分字段数据
//将当前IP头中不进行认证的字段数据复制到临时IP头
iph->tos = top_iph->tos;
iph->ttl = top_iph->ttl;
iph->frag_off = top_iph->frag_off;
if (top_iph->ihl != 5) {//如果有IP选项, 处理IP选项
iph->daddr = top_iph->daddr;
memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
err = ip_clear_mutable_options(top_iph, &top_iph->daddr);
if (err)
goto error;
}
//AH头定位在外部IP头后面, skb缓冲中已经预留出AH头的数据部分了,
//这是通过mode->output函数预留的, 通常调用type->output前要调用mode->oputput,参考上面函数xfrm_output
ah = ip_auth_hdr(skb);
ah->nexthdr = *skb_mac_header(skb);//AH中的下一个头用mac中指定的协议
*skb_mac_header(skb) = IPPROTO_AH; //mac中协议字段改为AH
//将外部IP头的不进行认证计算的部分字段清零
top_iph->tos = 0;
top_iph->tot_len = htons(skb->len);
top_iph->frag_off = 0;
top_iph->ttl = 0;
top_iph->check = 0;
ahp = x->data;//AH数据处理结构
ah->hdrlen = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;//AH头长度对齐
//AH头参数赋值
ah->reserved = 0;
ah->spi = x->id.spi;//SPI值
ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq);//序列号
spin_lock_bh(&x->lock);
err = ah_mac_digest(ahp, skb, ah->auth_data);//对skb进行AH认证值的计算
memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);//赋值初始化向量值到认证数据部分
spin_unlock_bh(&x->lock);
if (err)
goto error;
// 恢复原来IP头的的不认证部分的值
top_iph->tos = iph->tos;
top_iph->ttl = iph->ttl;
top_iph->frag_off = iph->frag_off;
if (top_iph->ihl != 5) { //处理ip选项
top_iph->daddr = iph->daddr;
memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
}
err = 0;
error:
return err;
}
static struct xfrm_type esp_type = //net/ipv4/esp4.c
{
.description = "ESP4",
.owner = THIS_MODULE,
.proto = IPPROTO_ESP,
.flags = XFRM_TYPE_REPLAY_PROT,
.init_state = esp_init_state,
.destructor = esp_destroy,
.get_mtu = esp4_get_mtu, //获取mtu
.input = esp_input,
.output = esp_output
};
esp_data数据结构
struct esp_data
{
struct scatterlist sgbuf[ESP_NUM_FAST_SG];
/* Confidentiality */
struct {//加密使用的相关数据
int padlen; //填充长度 /* 0..255 */
/* ivlen is offset from enc_data, where encrypted data start.
* It is logically different of crypto_tfm_alg_ivsize(tfm).
* We assume that it is either zero (no ivec), or
* >= crypto_tfm_alg_ivsize(tfm). */
int ivlen; //初始化向量长度
int ivinitted; //初始化向量是否初始化标志
u8 *ivec; //初始化向量 /* ivec buffer */
struct crypto_blkcipher *tfm; //加密算法 /* crypto handle */
} conf;
/* Integrity. It is active when icv_full_len != 0 */
struct {//认证使用的相关数据
u8 *work_icv;//初始化向量
int icv_full_len;//初始化向量全长
int icv_trunc_len;//初始化向量截断长度
struct crypto_hash *tfm;//HASH算法
} auth;
};
ESP的esp_data数据结构初始化
static int esp_init_state(struct xfrm_state *x)
{
struct esp_data *esp = NULL;
struct crypto_blkcipher *tfm;
u32 align;
if (x->ealg == NULL)//ESP加密算法是必须的
goto error;
esp = kzalloc(sizeof(*esp), GFP_KERNEL);//分配esp_data数据结构空间
if (esp == NULL)
return -ENOMEM;
//如果定义了认证算法, 初始化认证算法参数, 和AH类似
if (x->aalg) {
struct xfrm_algo_desc *aalg_desc;
struct crypto_hash *hash;
//分配HASH算法的实现
hash = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(hash))
goto error;
esp->auth.tfm = hash;
//设置HASH算法密钥
if (crypto_hash_setkey(hash, x->aalg->alg_key, (x->aalg->alg_key_len + 7) / 8))
goto error;
//找到算法描述
aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
BUG_ON(!aalg_desc);
//检查算法初始化向量长度合法性
if (aalg_desc->uinfo.auth.icv_fullbits/8 != crypto_hash_digestsize(hash)) {
NETDEBUG(KERN_INFO "ESP: %s digestsize %u != %hu\n", x->aalg->alg_name,
crypto_hash_digestsize(hash), aalg_desc->uinfo.auth.icv_fullbits/8);
goto error;
}
//初始化向量的全长和截断长度
esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8;
esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL);//分配全长度的初始化向量空间
if (!esp->auth.work_icv)
goto error;
}
//查找加密算法的具体实现结构
tfm = crypto_alloc_blkcipher(x->ealg->alg_name, 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(tfm))
goto error;
esp->conf.tfm = tfm;
esp->conf.ivlen = crypto_blkcipher_ivsize(tfm);//初始化向量大小
esp->conf.padlen = 0;//填充数据长度初始化为0
if (esp->conf.ivlen) {//初始化向量长度非0, 分配具体的初始化向量空间
esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
if (unlikely(esp->conf.ivec == NULL))
goto error;
esp->conf.ivinitted = 0;
}
//设置加密算法密钥
if (crypto_blkcipher_setkey(tfm, x->ealg->alg_key, (x->ealg->alg_key_len + 7) / 8))
goto error;
//定义SA中ESP头部长度: ESP头加初始化向量长度
//反映在ESP封装操作时要将数据包增加的长度
x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen;
if (x->props.mode == XFRM_MODE_TUNNEL)//如果是通道模式, 还需要增加IP头长度
x->props.header_len += sizeof(struct iphdr);
else if (x->props.mode == XFRM_MODE_BEET)//如果是BEET模式, 还需要增加IP头长度
x->props.header_len += IPV4_BEET_PHMAXLEN;
if (x->encap) {//如果要进行UDP封装
struct xfrm_encap_tmpl *encap = x->encap;
switch (encap->encap_type) {
default:
goto error;
case UDP_ENCAP_ESPINUDP://该类型封装增加UDP头长度
x->props.header_len += sizeof(struct udphdr);
break;
case UDP_ENCAP_ESPINUDP_NON_IKE://该类型封装增加UDP头长度外加加8字节
x->props.header_len += sizeof(struct udphdr) + 2 * sizeof(u32);
break;
}
}
x->data = esp;//将esp_data作为SA的data指针
align = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4); //加密块长度, 按4字节对齐
if (esp->conf.padlen)
align = max_t(u32, align, esp->conf.padlen);
x->props.trailer_len = align + 1 + esp->auth.icv_trunc_len; //加密块长度 + 1 + 认证长度
return 0;
......
}
获取mtu
static u32 esp4_get_mtu(struct xfrm_state *x, int mtu)
{
struct esp_data *esp = x->data;
u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);//加密块长度, 按4字节对齐
u32 align = max_t(u32, blksize, esp->conf.padlen);
u32 rem;
mtu -= x->props.header_len + esp->auth.icv_trunc_len;
rem = mtu & (align - 1);
mtu &= ~(align - 1); ///mtu对齐
switch (x->props.mode) {
case XFRM_MODE_TUNNEL:
break;
default:
case XFRM_MODE_TRANSPORT://传输模式下
/* The worst case */
mtu -= blksize - 4;
mtu += min_t(u32, blksize - 4, rem);
break;
case XFRM_MODE_BEET:
/* The worst case. */
mtu += min_t(u32, IPV4_BEET_PHMAXLEN, rem);
break;
}
return mtu - 2;
}
接收数据处理, 在xfrm4_rcv_encap()函数中调用
进行ESP认证解密, 剥离ESP头, 解密成普通数据包, 数据包长度减少
static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
{
struct iphdr *iph;
struct ip_esp_hdr *esph;
struct esp_data *esp = x->data;
struct crypto_blkcipher *tfm = esp->conf.tfm;
struct blkcipher_desc desc = { .tfm = tfm };
struct sk_buff *trailer;
int blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
int alen = esp->auth.icv_trunc_len;//认证初始化向量截断长度
//需要加密的数据长度: 总长减ESP头, 加密初始化向量长度, 认证初始化向量长度
int elen = skb->len - sizeof(*esph) - esp->conf.ivlen - alen;
int nfrags;
int ihl;
u8 nexthdr[2];
struct scatterlist *sg;
int padlen;
int err;
if (!pskb_may_pull(skb, sizeof(*esph)))//在skb头要有足够的ESP头空间
goto out;
if (elen <= 0 || (elen & (blksize-1)))//检查需要加密的数据长度, 必须大于0而且按块大小对齐的
goto out;
/* If integrity check is required, do this. */
if (esp->auth.icv_full_len) {//认证计算处理
u8 sum[alen];
//计算认证值, 认证值保存在esp_data结构中
err = esp_mac_digest(esp, skb, 0, skb->len - alen);
if (err)
goto out;
//将skb中的认证初始化向量部分数据拷贝到缓冲区sum中
if (skb_copy_bits(skb, skb->len - alen, sum, alen))
BUG();
//比较sum中的向量值和认证算法结构中的向量值是否匹配, 数据包正常情况下应该是相同的
if (unlikely(memcmp(esp->auth.work_icv, sum, alen))) {
x->stats.integrity_failed++;
goto out;
}
}
//使数据包可写,返回使用了多少个内存页
if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0)
goto out;
skb->ip_summed = CHECKSUM_NONE;
//定位在数据包中的ESP头位置, 为当前的data位置
esph = (struct ip_esp_hdr *)skb->data;
/* Get ivec. This can be wrong, check against another impls. */
if (esp->conf.ivlen)//设置加密算法的初始化向量
crypto_blkcipher_set_iv(tfm, esph->enc_data, esp->conf.ivlen);//拷贝esph头后的数据到加密算法结构中
sg = &esp->sgbuf[0];
if (unlikely(nfrags > ESP_NUM_FAST_SG)) {//内存页超过 4
sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
if (!sg)
goto out;
}
sg_init_table(sg, nfrags);
skb_to_sgvec(skb, sg, sizeof(*esph) + esp->conf.ivlen, elen);
//解密操作, 返回非0表示失败
err = crypto_blkcipher_decrypt(&desc, sg, sg, elen);
if (unlikely(sg != &esp->sgbuf[0]))
kfree(sg);
if (unlikely(err))//解密失败返回
return err;
if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2))//拷贝两字节数据
BUG();
padlen = nexthdr[0]; //填充数据长度
if (padlen+2 >= elen)
goto out;
/* RFC4303: Drop dummy packets without any error */
if (nexthdr[1] == IPPROTO_NONE)
goto out;
iph = ip_hdr(skb);//IP头
ihl = iph->ihl * 4;
if (x->encap) {//如果是NAT穿越情况, 进行一些处理
struct xfrm_encap_tmpl *encap = x->encap;//xfrm封装模板
struct udphdr *uh = (void *)(skb_network_header(skb) + ihl);//定位UDP数据头位置, 在IP头之后
//如果IP头源地址和SA提议中的源地址不同或源端口不同
if (iph->saddr != x->props.saddr.a4 || uh->source != encap->encap_sport) {
xfrm_address_t ipaddr;
ipaddr.a4 = iph->saddr;//保存当前IP头源地址
km_new_mapping(x, &ipaddr, uh->source);//进行NAT通知回调处理
}
if (x->props.mode == XFRM_MODE_TRANSPORT)//如果是传输模式, 设置不需要计算校验和
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
//缩减skb数据包长度,调整len和tail字段
pskb_trim(skb, skb->len - alen - padlen - 2);
//调整data到esph头和数据后面
__skb_pull(skb, sizeof(*esph) + esp->conf.ivlen);
skb_set_transport_header(skb, -ihl); //定位传输层头,data前面20字节处
return nexthdr[1]; //返回记录的IP头中协议
out:
return -EINVAL;
}
发送数据处理, 在xfrm4_output_one()中调用
添加ESP头, 对数据包进行加密和认证处理, 数据包长度扩大
在NAT穿越情况下会封装为UDP数据
static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
{
int err;
struct ip_esp_hdr *esph;
struct crypto_blkcipher *tfm;
struct blkcipher_desc desc;
struct esp_data *esp;
struct sk_buff *trailer;
u8 *tail;
int blksize;
int clen;
int alen;
int nfrags;
/* skb is pure payload to encrypt */
err = -ENOMEM;
/* Round to block size */
clen = skb->len;//加密块的初始值
esp = x->data;//获取SA的esp_data数据结构
alen = esp->auth.icv_trunc_len;//认证初始化向量截断长度
tfm = esp->conf.tfm;//加密算法
//给块加密算法描述结构赋值
desc.tfm = tfm;
desc.flags = 0;
//每个加密块大小
blksize = ALIGN(crypto_blkcipher_blocksize(tfm), 4);
clen = ALIGN(clen + 2, blksize);//对齐要加密的数据总长
if (esp->conf.padlen)//如果要考虑填充, 继续对齐
clen = ALIGN(clen, esp->conf.padlen);
//使数据包可写
if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0)
goto error;
/* Fill padding... */
tail = skb_tail_pointer(trailer);//长度对齐后填充多余长度部分内容
do {
int i;
for (i = 0; i < clen - skb->len - 2; i++)
tail[i] = i + 1;
} while (0);
//最后两字节表示填充数据的长度和ip中原来的协议
tail[clen - skb->len - 2] = (clen - skb->len) - 2; //数据长度
pskb_put(skb, trailer, clen - skb->len);//调整skb->tail位置
//将IP头部分扩展回来,data调整到网络头位置
skb_push(skb, -skb_network_offset(skb));
esph = ip_esp_hdr(skb);//esp头跟在IP头后
*(skb_tail_pointer(trailer) - 1) = *skb_mac_header(skb); //记录ip中原来的协议
*skb_mac_header(skb) = IPPROTO_ESP; //修改ip头中协议
spin_lock_bh(&x->lock);
/* this is non-NULL only with UDP Encapsulation */
if (x->encap) {//NAT穿越情况下要将数据封装为UDP包
struct xfrm_encap_tmpl *encap = x->encap;
struct udphdr *uh;
__be32 *udpdata32;
uh = (struct udphdr *)esph;//IP头后改为UDP头
//填充UDP头参数, 源端口, 目的端口, UDP数据长度
uh->source = encap->encap_sport;
uh->dest = encap->encap_dport;
uh->len = htons(skb->len + alen - skb_transport_offset(skb));
uh->check = 0;//校验和为0, 表示不需要计算校验和, ESP本身就进行认证了
switch (encap->encap_type) {
default:
case UDP_ENCAP_ESPINUDP://在该模式下ESP头跟在UDP头后面
esph = (struct ip_esp_hdr *)(uh + 1);
break;
case UDP_ENCAP_ESPINUDP_NON_IKE://在该模式下ESP头跟在UDP头后面2字节处
udpdata32 = (__be32 *)(uh + 1);
udpdata32[0] = udpdata32[1] = 0;
esph = (struct ip_esp_hdr *)(udpdata32 + 2);
break;
}
*skb_mac_header(skb) = IPPROTO_UDP;//外部IP头协议是UDP
}
//填充ESP头中的SPI和序列号
esph->spi = x->id.spi;
esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq);
//如果加密初始化向量长度非零, 设置加密算法中的初始化向量
if (esp->conf.ivlen) {
if (unlikely(!esp->conf.ivinitted)) {
get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
esp->conf.ivinitted = 1;
}
crypto_blkcipher_set_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
}
//加密操作
do {
struct scatterlist *sg = &esp->sgbuf[0];
if (unlikely(nfrags > ESP_NUM_FAST_SG)) {
sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
if (!sg)
goto unlock;
}
sg_init_table(sg, nfrags);
skb_to_sgvec(skb, sg, esph->enc_data + esp->conf.ivlen - skb->data, clen);//对数据加密
err = crypto_blkcipher_encrypt(&desc, sg, sg, clen);
if (unlikely(sg != &esp->sgbuf[0]))
kfree(sg);
} while (0);
if (esp->conf.ivlen) {//将加密算法初始化向量拷贝到数据包
memcpy(esph->enc_data, esp->conf.ivec, esp->conf.ivlen);
crypto_blkcipher_get_iv(tfm, esp->conf.ivec, esp->conf.ivlen);
}
if (esp->auth.icv_full_len) {//认证计算, 计算出HASH值并拷贝到数据包中
err = esp_mac_digest(esp, skb, (u8 *)esph - skb->data, sizeof(*esph) + esp->conf.ivlen + clen);
memcpy(pskb_put(skb, trailer, alen), esp->auth.work_icv, alen);
}
unlock:
spin_unlock_bh(&x->lock);
error:
return err;
}
static struct xfrm_type ipcomp_type = { //net/ipv4/ipcomp.c ip压缩协议
.description = "IPCOMP4",
.owner = THIS_MODULE,
.proto = IPPROTO_COMP,
.init_state = ipcomp_init_state,
.destructor = ipcomp_destroy,
.input = ipcomp_input,
.output = ipcomp_output
};
static struct xfrm_type ipip_type = { ///net/ipv4/xfrm4_tunnel.c ipip协议
.description = "IPIP",
.owner = THIS_MODULE,
.proto = IPPROTO_IPIP,
.init_state = ipip_init_state,
.destructor = ipip_destroy,
.input = ipip_xfrm_rcv,
.output = ipip_output
};
static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
{
skb_push(skb, -skb_network_offset(skb));
return 0;
}
static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb)
{
return ip_hdr(skb)->protocol;
}
|