在 Tan Sir
眼中,一切都是那么自然且和谐。
假设这篇是有读者的,我得先声明几件需要声明的事。
RFC-2408
是什么并不重要,因为假设过我们已经有所了解;
- 开源程序库到底选了哪个也不重要,因为都是些基本语法实现的东西,没有原因看不懂。
但其实说点令人伤感的话,在布置这个大作业之前,《自顶向下》 哪怕一个章节我都没有完整地读过。计网基础不说是 0,也算是 std::numeric_limits<double>::epsilon()
了。
我也不知道为什么,也不知道怎么样,我就是在 Mayaqua
这个文件夹里面找到了 Memory.h
这个头文件,并且非常笃定里面会定义一些我阅读协议分析代码区块时,非常需要的一些定义类型,比如:
1. 莫名其妙的定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct BUF { void *Buf; UINT Size; UINT SizeReserved; UINT Current; };
struct LIST { REF *ref; UINT num_item, num_reserved; void **p; LOCK *lock; COMPARE *cmp; bool sorted; UINT64 Param1; };
|
ISAKMP
使用的过程中,毕竟它是一个协议嘛,而且定义的东西也不仅仅是一个来回而已,所以每次往返都需要某种格式。那么就自然考虑到,这个协议需要定义一个协议头,也就是 ISAKMP Header
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Initiator ! ! Cookie ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Responder ! ! Cookie ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Message ID ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
现在我也不知道 initiator / responder cookie
是做什么的,本来也不知道它是不是用 MD5 / SHA
等一系列摘要算法生成的,更不知道生成 cookie
的输入是主机的一些标识信息还是其他。
总之,它现在只是两个 64 位长的数据罢了。
Next Payload
,现在我也不知道为什么有这个字段,也猜不到它是不是会构成一个 链式结构,总之这个字段放在这里就仅仅为了标识下一个 Payload
到底是什么类型(如果有的话),十分巧的是,我找到了 Cedar/Proto_IkePacket.h
这个头文件中的一些宏定义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #define IKE_PAYLOAD_NONE 0 #define IKE_PAYLOAD_SA 1 #define IKE_PAYLOAD_PROPOSAL 2 #define IKE_PAYLOAD_TRANSFORM 3 #define IKE_PAYLOAD_KEY_EXCHANGE 4 #define IKE_PAYLOAD_ID 5 #define IKE_PAYLOAD_CERT 6 #define IKE_PAYLOAD_CERT_REQUEST 7 #define IKE_PAYLOAD_HASH 8 #define IKE_PAYLOAD_SIGN 9 #define IKE_PAYLOAD_RAND 10 #define IKE_PAYLOAD_NOTICE 11 #define IKE_PAYLOAD_DELETE 12 #define IKE_PAYLOAD_VENDOR_ID 13 #define IKE_PAYLOAD_NAT_D 20 #define IKE_PAYLOAD_NAT_OA 21 #define IKE_PAYLOAD_NAT_D_DRAFT 130 #define IKE_PAYLOAD_NAT_OA_DRAFT 16 #define IKE_PAYLOAD_NAT_OA_DRAFT_2 131
|
这与 RFC-2408
上对 ISAKMP
定义的大体相仿,并且可以了解到,有些应该是 SoftEtherVPN
自己搞的。但是对此,暂时就不需要深究了。
Exchange Type
貌似是比较重要的字段,或许它有 identity protection / base / informatioinal
这些选择,但是 SoftEtherVPN
中实现的是 IKE
,应该就只有 aggressive / authentication
两种了。
Flags
也是老熟人了,不过这里看起来只定义了 29(A), 30(C), 31(E) 位的样子,RFC
上的叙述又臭又长,看到:
1 2 3 4
| #define IKE_HEADER_FLAG_ENCRYPTED 1 #define IKE_HEADER_FLAG_COMMIT 2 #define IKE_HEADER_FLAG_AUTH_ONLY 4
|
想必整个 Flags
占 8 位,里面的 E
就在最末一位,然后 A
就在倒数第三位吧?一定是这样的。
再后面是 Message ID
,看不懂。不过,总体来看,有些契合同为 Cedar/Proto_IkePacket.h
中的:
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct IKE_PACKET { UINT64 InitiatorCookie; UINT64 ResponderCookie; UCHAR ExchangeType; bool FlagEncrypted; bool FlagCommit; bool FlagAuthOnly; UINT MessageId; LIST *PayloadList; BUF *DecryptedPayload; UINT MessageSize; };
|
第一反应肯定是 Payload
就老老实实当 Payload
,为什么还有 Header
,所以啊,这就是数据报又臭又长的原因所在吗?
由于 ISAKMP Header
中 Next Header
的存在。首先,这个 Next Header
字段肯定不是为了标识下一个数据报的类型,尽管从 ISAKMP
这个协议角度来看,当前协议的确了解下一次从本机出发的协议,在正常情况下到底是什么类型,都有什么参数。但是我认为还是不能认为它知道下一个是什么。
好吧,其实这个 Next Header
是为了指示本次数据报中,位于 Payload
中的类型。这也就是为什么 Payload
还有自己的 Header
。其实就是类似嵌套嘛。(但个人以为这和外层协议包裹内层不完全相同,无论是从数据结构的逻辑上,还是从 ISAKMP
这个协议体给人感受到的语义上)
a. 通用的
较为通用的协议头—— Generic Header
:
1 2 3 4 5
| 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload ! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
我不知道为什么就一下子在 Cedar/Proto_IkePacket.h
里面找到了这段定义:
1 2 3 4 5 6
| struct IKE_COMMON_HEADER { UCHAR NextPayload; UCHAR Reserved; USHORT PayloadSize; } GCC_PACKED;
|
b. SA Payload
通过与 RFC-2408
“反复” 比较,这个 SA_HEADER
也算是和代码定义的差不多吧,就是差了点东西。
1 2 3 4 5 6 7 8 9 10 11
| 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload ! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Domain of Interpretation (DOI) ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! ~ Situation ~ ! ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
1 2 3 4 5 6
| struct IKE_SA_HEADER { UINT DoI; UINT Situation; } GCC_PACKED;
|
轻松地观察到只要在这个 IKE_SA_HEADER
前面加上 IKE_COMMON_HEADER
就可以变成 RFC-2408
中 3.4 Security Association Payload
所示图了。
从这里,我进一步了解到什么叫做 Generic Header
。
但是……
c. 通用的为什么是通用的?
不知道为什么我就定义到了 Cedar/Proto_IkePacket.c
这个源文件了:
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
| BUF *IkeBuildPayloadList(LIST *o) { BUF *b; UINT i;
b = NewBuf(); for (i = 0;i < LIST_NUM(o);i++) { IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i); IKE_PACKET_PAYLOAD *next = NULL; IKE_COMMON_HEADER h; BUF *tmp;
if (i < (LIST_NUM(o) - 1)) next = LIST_DATA(o, i + 1);
Zero(&h, sizeof(h)); if (next != NULL) h.NextPayload = next->PayloadType; else h.NextPayload = IKE_PAYLOAD_NONE;
tmp = IkeBuildPayload(p); if (tmp != NULL) { h.PayloadSize = Endian16(tmp->Size + (USHORT)sizeof(h)); WriteBuf(b, &h, sizeof(h)); WriteBuf(b, tmp->Buf, tmp->Size); FreeBuf(tmp); } }
SeekBuf(b, 0, 0); return b; }
|
这里简单做一些不负责任的说明。
首先,LIST
是 Payload
的 LIST
,通过 LIST_DATA
这个函数,可以基于给定数字,给出 Payload
。这也是为什么:
1 2 3
| IKE_PACKET_PAYLOAD *p = LIST_DATA(o, i);
next = LIST_DATA(o, i + 1);
|
的原因。
其次,我们还知道了一个用脚趾头想都能想出来的道理:
1 2
| 如果 LIST_DATA 中的 Payload 遍历完了, 就应该把指针指向一个代表 “空” 的事物,以表示链终止。
|
这在程序里面表示为:
1 2 3 4
| if (next != NULL) h.NextPayload = next->PayloadType; else h.NextPayload = IKE_PAYLOAD_NONE;
|
最后,写入是由顺序的,COMMON_HEADER
在前,XXX_HEADER
在后(注意,这之后的都是 Payload Header)。
这也就是为什么 Cedar/Proto_IkePacket.h
中的所有 Payload Header
都不像 RFC-2408
中描述的那样完整。
具体在代码中是这样体现的:
1 2 3 4
| tmp = IkeBuildPayload(p); h.PayloadSize = Endian16(tmp->Size + (USHORT)sizeof(h)); WriteBuf(b, &h, sizeof(h)); WriteBuf(b, tmp->Buf, tmp->Size);
|
通过这段程序……
- 岂不是轻松得知一堆
Payload Header
的定义?
- 岂不是立刻找到一堆
SoftEtherVPN
和 RFC-2408
的区别之处?
比如:
1 2 3 4 5 6 7 8 9
| 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload ! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Proposal # ! Protocol-Id ! SPI Size !# of Transforms! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! SPI (variable) ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
中的 “Proposal #”
,在 Cedar/Proto_IkePacket.h
中却是:
1 2 3 4 5 6 7
| struct IKE_PROPOSAL_HEADER { UCHAR Number; UCHAR ProtocolId; UCHAR SpiSize; UCHAR NumTransforms; } GCC_PACKED;
|
当然,这种不同是可以理解的。因为没有必要为了与 RFC
相同而做许多不必要的变量名限制。
可是,这种就比较不同了:
1 2 3 4 5
| struct IKE_PACKET_DATA_PAYLOAD { BUF *Data; };
|
RFC
中完全不存在这么一种通用载荷 Format
。这只是因为比如 KE / Hash / SIG / Nonce Payload
们大体格式都是一样的,只是装填的数据不同。
然而这种不同,还和其算法有关,因此不好特化。一旦泛化到了极致,Format
就差不多了:
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
| 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload ! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! ~ Key Exchange Data ~ ! ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload ! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! ~ Hash Data ~ ! ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload ! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! ~ Signature Data ~ ! ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload ! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! ~ Nonce Data ~ ! ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
之后的之后再看。
end.