8 "github.com/vishvananda/netlink/nl"
11 func writeStateAlgo(a *XfrmStateAlgo) []byte {
13 AlgKeyLen: uint32(len(a.Key) * 8),
20 copy(algo.AlgName[:end], a.Name)
21 return algo.Serialize()
24 func writeStateAlgoAuth(a *XfrmStateAlgo) []byte {
25 algo := nl.XfrmAlgoAuth{
26 AlgKeyLen: uint32(len(a.Key) * 8),
27 AlgTruncLen: uint32(a.TruncateLen),
34 copy(algo.AlgName[:end], a.Name)
35 return algo.Serialize()
38 func writeStateAlgoAead(a *XfrmStateAlgo) []byte {
39 algo := nl.XfrmAlgoAEAD{
40 AlgKeyLen: uint32(len(a.Key) * 8),
41 AlgICVLen: uint32(a.ICVLen),
48 copy(algo.AlgName[:end], a.Name)
49 return algo.Serialize()
52 func writeMark(m *XfrmMark) []byte {
58 mark.Mask = ^uint32(0)
60 return mark.Serialize()
63 func writeReplayEsn(replayWindow int) []byte {
64 replayEsn := &nl.XfrmReplayStateEsn{
69 ReplayWindow: uint32(replayWindow),
72 // taken from iproute2/ip/xfrm_state.c:
73 replayEsn.BmpLen = uint32((replayWindow + (4 * 8) - 1) / (4 * 8))
75 return replayEsn.Serialize()
78 // XfrmStateAdd will add an xfrm state to the system.
79 // Equivalent to: `ip xfrm state add $state`
80 func XfrmStateAdd(state *XfrmState) error {
81 return pkgHandle.XfrmStateAdd(state)
84 // XfrmStateAdd will add an xfrm state to the system.
85 // Equivalent to: `ip xfrm state add $state`
86 func (h *Handle) XfrmStateAdd(state *XfrmState) error {
87 return h.xfrmStateAddOrUpdate(state, nl.XFRM_MSG_NEWSA)
90 // XfrmStateAllocSpi will allocate an xfrm state in the system.
91 // Equivalent to: `ip xfrm state allocspi`
92 func XfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
93 return pkgHandle.xfrmStateAllocSpi(state)
96 // XfrmStateUpdate will update an xfrm state to the system.
97 // Equivalent to: `ip xfrm state update $state`
98 func XfrmStateUpdate(state *XfrmState) error {
99 return pkgHandle.XfrmStateUpdate(state)
102 // XfrmStateUpdate will update an xfrm state to the system.
103 // Equivalent to: `ip xfrm state update $state`
104 func (h *Handle) XfrmStateUpdate(state *XfrmState) error {
105 return h.xfrmStateAddOrUpdate(state, nl.XFRM_MSG_UPDSA)
108 func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
110 // A state with spi 0 can't be deleted so don't allow it to be set
112 return fmt.Errorf("Spi must be set when adding xfrm state.")
114 req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
116 msg := xfrmUsersaInfoFromXfrmState(state)
119 if state.ReplayWindow == 0 {
120 return fmt.Errorf("ESN flag set without ReplayWindow")
122 msg.Flags |= nl.XFRM_STATE_ESN
126 limitsToLft(state.Limits, &msg.Lft)
129 if state.Auth != nil {
130 out := nl.NewRtAttr(nl.XFRMA_ALG_AUTH_TRUNC, writeStateAlgoAuth(state.Auth))
133 if state.Crypt != nil {
134 out := nl.NewRtAttr(nl.XFRMA_ALG_CRYPT, writeStateAlgo(state.Crypt))
137 if state.Aead != nil {
138 out := nl.NewRtAttr(nl.XFRMA_ALG_AEAD, writeStateAlgoAead(state.Aead))
141 if state.Encap != nil {
142 encapData := make([]byte, nl.SizeofXfrmEncapTmpl)
143 encap := nl.DeserializeXfrmEncapTmpl(encapData)
144 encap.EncapType = uint16(state.Encap.Type)
145 encap.EncapSport = nl.Swap16(uint16(state.Encap.SrcPort))
146 encap.EncapDport = nl.Swap16(uint16(state.Encap.DstPort))
147 encap.EncapOa.FromIP(state.Encap.OriginalAddress)
148 out := nl.NewRtAttr(nl.XFRMA_ENCAP, encapData)
151 if state.Mark != nil {
152 out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
156 out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow))
160 _, err := req.Execute(syscall.NETLINK_XFRM, 0)
164 func (h *Handle) xfrmStateAllocSpi(state *XfrmState) (*XfrmState, error) {
165 req := h.newNetlinkRequest(nl.XFRM_MSG_ALLOCSPI,
166 syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
168 msg := &nl.XfrmUserSpiInfo{}
169 msg.XfrmUsersaInfo = *(xfrmUsersaInfoFromXfrmState(state))
170 // 1-255 is reserved by IANA for future use
175 if state.Mark != nil {
176 out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
180 msgs, err := req.Execute(syscall.NETLINK_XFRM, 0)
185 s, err := parseXfrmState(msgs[0], FAMILY_ALL)
193 // XfrmStateDel will delete an xfrm state from the system. Note that
194 // the Algos are ignored when matching the state to delete.
195 // Equivalent to: `ip xfrm state del $state`
196 func XfrmStateDel(state *XfrmState) error {
197 return pkgHandle.XfrmStateDel(state)
200 // XfrmStateDel will delete an xfrm state from the system. Note that
201 // the Algos are ignored when matching the state to delete.
202 // Equivalent to: `ip xfrm state del $state`
203 func (h *Handle) XfrmStateDel(state *XfrmState) error {
204 _, err := h.xfrmStateGetOrDelete(state, nl.XFRM_MSG_DELSA)
208 // XfrmStateList gets a list of xfrm states in the system.
209 // Equivalent to: `ip [-4|-6] xfrm state show`.
210 // The list can be filtered by ip family.
211 func XfrmStateList(family int) ([]XfrmState, error) {
212 return pkgHandle.XfrmStateList(family)
215 // XfrmStateList gets a list of xfrm states in the system.
216 // Equivalent to: `ip xfrm state show`.
217 // The list can be filtered by ip family.
218 func (h *Handle) XfrmStateList(family int) ([]XfrmState, error) {
219 req := h.newNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP)
221 msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
227 for _, m := range msgs {
228 if state, err := parseXfrmState(m, family); err == nil {
229 res = append(res, *state)
230 } else if err == familyError {
239 // XfrmStateGet gets the xfrm state described by the ID, if found.
240 // Equivalent to: `ip xfrm state get ID [ mark MARK [ mask MASK ] ]`.
241 // Only the fields which constitue the SA ID must be filled in:
242 // ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]
244 func XfrmStateGet(state *XfrmState) (*XfrmState, error) {
245 return pkgHandle.XfrmStateGet(state)
248 // XfrmStateGet gets the xfrm state described by the ID, if found.
249 // Equivalent to: `ip xfrm state get ID [ mark MARK [ mask MASK ] ]`.
250 // Only the fields which constitue the SA ID must be filled in:
251 // ID := [ src ADDR ] [ dst ADDR ] [ proto XFRM-PROTO ] [ spi SPI ]
253 func (h *Handle) XfrmStateGet(state *XfrmState) (*XfrmState, error) {
254 return h.xfrmStateGetOrDelete(state, nl.XFRM_MSG_GETSA)
257 func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState, error) {
258 req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK)
260 msg := &nl.XfrmUsersaId{}
261 msg.Family = uint16(nl.GetIPFamily(state.Dst))
262 msg.Daddr.FromIP(state.Dst)
263 msg.Proto = uint8(state.Proto)
264 msg.Spi = nl.Swap32(uint32(state.Spi))
267 if state.Mark != nil {
268 out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
271 if state.Src != nil {
272 out := nl.NewRtAttr(nl.XFRMA_SRCADDR, state.Src.To16())
276 resType := nl.XFRM_MSG_NEWSA
277 if nlProto == nl.XFRM_MSG_DELSA {
281 msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType))
286 if nlProto == nl.XFRM_MSG_DELSA {
290 s, err := parseXfrmState(msgs[0], FAMILY_ALL)
298 var familyError = fmt.Errorf("family error")
300 func xfrmStateFromXfrmUsersaInfo(msg *nl.XfrmUsersaInfo) *XfrmState {
303 state.Dst = msg.Id.Daddr.ToIP()
304 state.Src = msg.Saddr.ToIP()
305 state.Proto = Proto(msg.Id.Proto)
306 state.Mode = Mode(msg.Mode)
307 state.Spi = int(nl.Swap32(msg.Id.Spi))
308 state.Reqid = int(msg.Reqid)
309 state.ReplayWindow = int(msg.ReplayWindow)
310 lftToLimits(&msg.Lft, &state.Limits)
315 func parseXfrmState(m []byte, family int) (*XfrmState, error) {
316 msg := nl.DeserializeXfrmUsersaInfo(m)
318 // This is mainly for the state dump
319 if family != FAMILY_ALL && family != int(msg.Family) {
320 return nil, familyError
323 state := xfrmStateFromXfrmUsersaInfo(msg)
325 attrs, err := nl.ParseRouteAttr(m[nl.SizeofXfrmUsersaInfo:])
330 for _, attr := range attrs {
331 switch attr.Attr.Type {
332 case nl.XFRMA_ALG_AUTH, nl.XFRMA_ALG_CRYPT:
333 var resAlgo *XfrmStateAlgo
334 if attr.Attr.Type == nl.XFRMA_ALG_AUTH {
335 if state.Auth == nil {
336 state.Auth = new(XfrmStateAlgo)
340 state.Crypt = new(XfrmStateAlgo)
341 resAlgo = state.Crypt
343 algo := nl.DeserializeXfrmAlgo(attr.Value[:])
344 (*resAlgo).Name = nl.BytesToString(algo.AlgName[:])
345 (*resAlgo).Key = algo.AlgKey
346 case nl.XFRMA_ALG_AUTH_TRUNC:
347 if state.Auth == nil {
348 state.Auth = new(XfrmStateAlgo)
350 algo := nl.DeserializeXfrmAlgoAuth(attr.Value[:])
351 state.Auth.Name = nl.BytesToString(algo.AlgName[:])
352 state.Auth.Key = algo.AlgKey
353 state.Auth.TruncateLen = int(algo.AlgTruncLen)
354 case nl.XFRMA_ALG_AEAD:
355 state.Aead = new(XfrmStateAlgo)
356 algo := nl.DeserializeXfrmAlgoAEAD(attr.Value[:])
357 state.Aead.Name = nl.BytesToString(algo.AlgName[:])
358 state.Aead.Key = algo.AlgKey
359 state.Aead.ICVLen = int(algo.AlgICVLen)
361 encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:])
362 state.Encap = new(XfrmStateEncap)
363 state.Encap.Type = EncapType(encap.EncapType)
364 state.Encap.SrcPort = int(nl.Swap16(encap.EncapSport))
365 state.Encap.DstPort = int(nl.Swap16(encap.EncapDport))
366 state.Encap.OriginalAddress = encap.EncapOa.ToIP()
368 mark := nl.DeserializeXfrmMark(attr.Value[:])
369 state.Mark = new(XfrmMark)
370 state.Mark.Value = mark.Value
371 state.Mark.Mask = mark.Mask
378 // XfrmStateFlush will flush the xfrm state on the system.
379 // proto = 0 means any transformation protocols
380 // Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]`
381 func XfrmStateFlush(proto Proto) error {
382 return pkgHandle.XfrmStateFlush(proto)
385 // XfrmStateFlush will flush the xfrm state on the system.
386 // proto = 0 means any transformation protocols
387 // Equivalent to: `ip xfrm state flush [ proto XFRM-PROTO ]`
388 func (h *Handle) XfrmStateFlush(proto Proto) error {
389 req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHSA, syscall.NLM_F_ACK)
391 req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)})
393 _, err := req.Execute(syscall.NETLINK_XFRM, 0)
401 func limitsToLft(lmts XfrmStateLimits, lft *nl.XfrmLifetimeCfg) {
402 if lmts.ByteSoft != 0 {
403 lft.SoftByteLimit = lmts.ByteSoft
405 lft.SoftByteLimit = nl.XFRM_INF
407 if lmts.ByteHard != 0 {
408 lft.HardByteLimit = lmts.ByteHard
410 lft.HardByteLimit = nl.XFRM_INF
412 if lmts.PacketSoft != 0 {
413 lft.SoftPacketLimit = lmts.PacketSoft
415 lft.SoftPacketLimit = nl.XFRM_INF
417 if lmts.PacketHard != 0 {
418 lft.HardPacketLimit = lmts.PacketHard
420 lft.HardPacketLimit = nl.XFRM_INF
422 lft.SoftAddExpiresSeconds = lmts.TimeSoft
423 lft.HardAddExpiresSeconds = lmts.TimeHard
424 lft.SoftUseExpiresSeconds = lmts.TimeUseSoft
425 lft.HardUseExpiresSeconds = lmts.TimeUseHard
428 func lftToLimits(lft *nl.XfrmLifetimeCfg, lmts *XfrmStateLimits) {
429 *lmts = *(*XfrmStateLimits)(unsafe.Pointer(lft))
432 func xfrmUsersaInfoFromXfrmState(state *XfrmState) *nl.XfrmUsersaInfo {
433 msg := &nl.XfrmUsersaInfo{}
434 msg.Family = uint16(nl.GetIPFamily(state.Dst))
435 msg.Id.Daddr.FromIP(state.Dst)
436 msg.Saddr.FromIP(state.Src)
437 msg.Id.Proto = uint8(state.Proto)
438 msg.Mode = uint8(state.Mode)
439 msg.Id.Spi = nl.Swap32(uint32(state.Spi))
440 msg.Reqid = uint32(state.Reqid)
441 msg.ReplayWindow = uint8(state.ReplayWindow)