@@ -22,8 +22,36 @@ import (
2222 "github.com/vishvananda/netlink"
2323)
2424
25+ /*
26+ Encrypted overlay networks use IPsec in transport mode to encrypt and
27+ authenticate the VXLAN UDP datagrams. This driver implements a bespoke control
28+ plane which negotiates the security parameters for each peer-to-peer tunnel.
29+
30+ IPsec Terminology
31+
32+ - ESP: IPSec Encapsulating Security Payload
33+ - SPI: Security Parameter Index
34+ - ICV: Integrity Check Value
35+ - SA: Security Association https://en.wikipedia.org/wiki/IPsec#Security_association
36+
37+
38+ Developer documentation for Linux IPsec is rather sparse online. The following
39+ slide deck provides a decent overview.
40+ https://libreswan.org/wiki/images/e/e0/Netdev-0x12-ipsec-flow.pdf
41+
42+ The Linux IPsec stack is part of XFRM, the netlink packet transformation
43+ interface.
44+ https://man7.org/linux/man-pages/man8/ip-xfrm.8.html
45+ */
46+
2547const (
26- r = 0xD0C4E3
48+ // Value used to mark outgoing packets which should have our IPsec
49+ // processing applied. It is also used as a label to identify XFRM
50+ // states (Security Associations) and policies (Security Policies)
51+ // programmed by us so we know which ones we can clean up without
52+ // disrupting other VPN connections on the system.
53+ mark = 0xD0C4E3
54+
2755 pktExpansion = 26 // SPI(4) + SeqN(4) + IV(8) + PadLength(1) + NextHeader(1) + ICV(8)
2856)
2957
@@ -33,7 +61,9 @@ const (
3361 bidir
3462)
3563
36- var spMark = netlink.XfrmMark {Value : uint32 (r ), Mask : 0xffffffff }
64+ // Mark value for matching packets which should have our IPsec security policy
65+ // applied.
66+ var spMark = netlink.XfrmMark {Value : mark , Mask : 0xffffffff }
3767
3868type key struct {
3969 value []byte
@@ -47,6 +77,9 @@ func (k *key) String() string {
4777 return ""
4878}
4979
80+ // Security Parameter Indices for the IPsec flows between local node and a
81+ // remote peer, which identify the Security Associations (XFRM states) to be
82+ // applied when encrypting and decrypting packets.
5083type spi struct {
5184 forward int
5285 reverse int
@@ -204,7 +237,7 @@ func programMangle(vni uint32, add bool) (err error) {
204237 var (
205238 p = strconv .FormatUint (uint64 (overlayutils .VXLANUDPPort ()), 10 )
206239 c = fmt .Sprintf ("0>>22&0x3C@12&0xFFFFFF00=%d" , int (vni )<< 8 )
207- m = strconv .FormatUint (uint64 ( r ) , 10 )
240+ m = strconv .FormatUint (mark , 10 )
208241 chain = "OUTPUT"
209242 rule = []string {"-p" , "udp" , "--dport" , p , "-m" , "u32" , "--u32" , c , "-j" , "MARK" , "--set-mark" , m }
210243 a = "-A"
@@ -251,10 +284,12 @@ func programInput(vni uint32, add bool) (err error) {
251284 msg = "remove"
252285 }
253286
287+ // Accept incoming VXLAN datagrams for the VNI which were subjected to IPSec processing.
254288 if err := iptable .ProgramRule (iptables .Filter , chain , action , accept ); err != nil {
255289 logrus .Errorf ("could not %s input rule: %v. Please do it manually." , msg , err )
256290 }
257291
292+ // Drop incoming VXLAN datagrams for the VNI which were received in cleartext.
258293 if err := iptable .ProgramRule (iptables .Filter , chain , action , block ); err != nil {
259294 logrus .Errorf ("could not %s input rule: %v. Please do it manually." , msg , err )
260295 }
@@ -280,7 +315,7 @@ func programSA(localIP, remoteIP net.IP, spi *spi, k *key, dir int, add bool) (f
280315 Proto : netlink .XFRM_PROTO_ESP ,
281316 Spi : spi .reverse ,
282317 Mode : netlink .XFRM_MODE_TRANSPORT ,
283- Reqid : r ,
318+ Reqid : mark ,
284319 }
285320 if add {
286321 rSA .Aead = buildAeadAlgo (k , spi .reverse )
@@ -306,7 +341,7 @@ func programSA(localIP, remoteIP net.IP, spi *spi, k *key, dir int, add bool) (f
306341 Proto : netlink .XFRM_PROTO_ESP ,
307342 Spi : spi .forward ,
308343 Mode : netlink .XFRM_MODE_TRANSPORT ,
309- Reqid : r ,
344+ Reqid : mark ,
310345 }
311346 if add {
312347 fSA .Aead = buildAeadAlgo (k , spi .forward )
@@ -355,7 +390,7 @@ func programSP(fSA *netlink.XfrmState, rSA *netlink.XfrmState, add bool) error {
355390 Proto : netlink .XFRM_PROTO_ESP ,
356391 Mode : netlink .XFRM_MODE_TRANSPORT ,
357392 Spi : fSA .Spi ,
358- Reqid : r ,
393+ Reqid : mark ,
359394 },
360395 },
361396 }
@@ -569,7 +604,7 @@ func updateNodeKey(lIP, aIP, rIP net.IP, idxs []*spi, curKeys []*key, newIdx, pr
569604 Proto : netlink .XFRM_PROTO_ESP ,
570605 Mode : netlink .XFRM_MODE_TRANSPORT ,
571606 Spi : fSA2 .Spi ,
572- Reqid : r ,
607+ Reqid : mark ,
573608 },
574609 },
575610 }
@@ -638,7 +673,7 @@ func clearEncryptionStates() {
638673 }
639674 for _ , sa := range saList {
640675 sa := sa
641- if sa .Reqid == r {
676+ if sa .Reqid == mark {
642677 if err := nlh .XfrmStateDel (& sa ); err != nil {
643678 logrus .Warnf ("Failed to delete stale SA %s: %v" , sa , err )
644679 continue
0 commit comments