Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / vishvananda / netlink / xfrm_state_linux.go
1 package netlink
2
3 import (
4         "fmt"
5         "syscall"
6         "unsafe"
7
8         "github.com/vishvananda/netlink/nl"
9 )
10
11 func writeStateAlgo(a *XfrmStateAlgo) []byte {
12         algo := nl.XfrmAlgo{
13                 AlgKeyLen: uint32(len(a.Key) * 8),
14                 AlgKey:    a.Key,
15         }
16         end := len(a.Name)
17         if end > 64 {
18                 end = 64
19         }
20         copy(algo.AlgName[:end], a.Name)
21         return algo.Serialize()
22 }
23
24 func writeStateAlgoAuth(a *XfrmStateAlgo) []byte {
25         algo := nl.XfrmAlgoAuth{
26                 AlgKeyLen:   uint32(len(a.Key) * 8),
27                 AlgTruncLen: uint32(a.TruncateLen),
28                 AlgKey:      a.Key,
29         }
30         end := len(a.Name)
31         if end > 64 {
32                 end = 64
33         }
34         copy(algo.AlgName[:end], a.Name)
35         return algo.Serialize()
36 }
37
38 func writeStateAlgoAead(a *XfrmStateAlgo) []byte {
39         algo := nl.XfrmAlgoAEAD{
40                 AlgKeyLen: uint32(len(a.Key) * 8),
41                 AlgICVLen: uint32(a.ICVLen),
42                 AlgKey:    a.Key,
43         }
44         end := len(a.Name)
45         if end > 64 {
46                 end = 64
47         }
48         copy(algo.AlgName[:end], a.Name)
49         return algo.Serialize()
50 }
51
52 func writeMark(m *XfrmMark) []byte {
53         mark := &nl.XfrmMark{
54                 Value: m.Value,
55                 Mask:  m.Mask,
56         }
57         if mark.Mask == 0 {
58                 mark.Mask = ^uint32(0)
59         }
60         return mark.Serialize()
61 }
62
63 func writeReplayEsn(replayWindow int) []byte {
64         replayEsn := &nl.XfrmReplayStateEsn{
65                 OSeq:         0,
66                 Seq:          0,
67                 OSeqHi:       0,
68                 SeqHi:        0,
69                 ReplayWindow: uint32(replayWindow),
70         }
71
72         // taken from iproute2/ip/xfrm_state.c:
73         replayEsn.BmpLen = uint32((replayWindow + (4 * 8) - 1) / (4 * 8))
74
75         return replayEsn.Serialize()
76 }
77
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)
82 }
83
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)
88 }
89
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)
94 }
95
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)
100 }
101
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)
106 }
107
108 func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error {
109
110         // A state with spi 0 can't be deleted so don't allow it to be set
111         if state.Spi == 0 {
112                 return fmt.Errorf("Spi must be set when adding xfrm state.")
113         }
114         req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
115
116         msg := xfrmUsersaInfoFromXfrmState(state)
117
118         if state.ESN {
119                 if state.ReplayWindow == 0 {
120                         return fmt.Errorf("ESN flag set without ReplayWindow")
121                 }
122                 msg.Flags |= nl.XFRM_STATE_ESN
123                 msg.ReplayWindow = 0
124         }
125
126         limitsToLft(state.Limits, &msg.Lft)
127         req.AddData(msg)
128
129         if state.Auth != nil {
130                 out := nl.NewRtAttr(nl.XFRMA_ALG_AUTH_TRUNC, writeStateAlgoAuth(state.Auth))
131                 req.AddData(out)
132         }
133         if state.Crypt != nil {
134                 out := nl.NewRtAttr(nl.XFRMA_ALG_CRYPT, writeStateAlgo(state.Crypt))
135                 req.AddData(out)
136         }
137         if state.Aead != nil {
138                 out := nl.NewRtAttr(nl.XFRMA_ALG_AEAD, writeStateAlgoAead(state.Aead))
139                 req.AddData(out)
140         }
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)
149                 req.AddData(out)
150         }
151         if state.Mark != nil {
152                 out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
153                 req.AddData(out)
154         }
155         if state.ESN {
156                 out := nl.NewRtAttr(nl.XFRMA_REPLAY_ESN_VAL, writeReplayEsn(state.ReplayWindow))
157                 req.AddData(out)
158         }
159
160         _, err := req.Execute(syscall.NETLINK_XFRM, 0)
161         return err
162 }
163
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)
167
168         msg := &nl.XfrmUserSpiInfo{}
169         msg.XfrmUsersaInfo = *(xfrmUsersaInfoFromXfrmState(state))
170         // 1-255 is reserved by IANA for future use
171         msg.Min = 0x100
172         msg.Max = 0xffffffff
173         req.AddData(msg)
174
175         if state.Mark != nil {
176                 out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
177                 req.AddData(out)
178         }
179
180         msgs, err := req.Execute(syscall.NETLINK_XFRM, 0)
181         if err != nil {
182                 return nil, err
183         }
184
185         s, err := parseXfrmState(msgs[0], FAMILY_ALL)
186         if err != nil {
187                 return nil, err
188         }
189
190         return s, err
191 }
192
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)
198 }
199
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)
205         return err
206 }
207
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)
213 }
214
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)
220
221         msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA)
222         if err != nil {
223                 return nil, err
224         }
225
226         var res []XfrmState
227         for _, m := range msgs {
228                 if state, err := parseXfrmState(m, family); err == nil {
229                         res = append(res, *state)
230                 } else if err == familyError {
231                         continue
232                 } else {
233                         return nil, err
234                 }
235         }
236         return res, nil
237 }
238
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 ]
243 // mark is optional
244 func XfrmStateGet(state *XfrmState) (*XfrmState, error) {
245         return pkgHandle.XfrmStateGet(state)
246 }
247
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 ]
252 // mark is optional
253 func (h *Handle) XfrmStateGet(state *XfrmState) (*XfrmState, error) {
254         return h.xfrmStateGetOrDelete(state, nl.XFRM_MSG_GETSA)
255 }
256
257 func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState, error) {
258         req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK)
259
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))
265         req.AddData(msg)
266
267         if state.Mark != nil {
268                 out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark))
269                 req.AddData(out)
270         }
271         if state.Src != nil {
272                 out := nl.NewRtAttr(nl.XFRMA_SRCADDR, state.Src.To16())
273                 req.AddData(out)
274         }
275
276         resType := nl.XFRM_MSG_NEWSA
277         if nlProto == nl.XFRM_MSG_DELSA {
278                 resType = 0
279         }
280
281         msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType))
282         if err != nil {
283                 return nil, err
284         }
285
286         if nlProto == nl.XFRM_MSG_DELSA {
287                 return nil, nil
288         }
289
290         s, err := parseXfrmState(msgs[0], FAMILY_ALL)
291         if err != nil {
292                 return nil, err
293         }
294
295         return s, nil
296 }
297
298 var familyError = fmt.Errorf("family error")
299
300 func xfrmStateFromXfrmUsersaInfo(msg *nl.XfrmUsersaInfo) *XfrmState {
301         var state XfrmState
302
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)
311
312         return &state
313 }
314
315 func parseXfrmState(m []byte, family int) (*XfrmState, error) {
316         msg := nl.DeserializeXfrmUsersaInfo(m)
317
318         // This is mainly for the state dump
319         if family != FAMILY_ALL && family != int(msg.Family) {
320                 return nil, familyError
321         }
322
323         state := xfrmStateFromXfrmUsersaInfo(msg)
324
325         attrs, err := nl.ParseRouteAttr(m[nl.SizeofXfrmUsersaInfo:])
326         if err != nil {
327                 return nil, err
328         }
329
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)
337                                 }
338                                 resAlgo = state.Auth
339                         } else {
340                                 state.Crypt = new(XfrmStateAlgo)
341                                 resAlgo = state.Crypt
342                         }
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)
349                         }
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)
360                 case nl.XFRMA_ENCAP:
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()
367                 case nl.XFRMA_MARK:
368                         mark := nl.DeserializeXfrmMark(attr.Value[:])
369                         state.Mark = new(XfrmMark)
370                         state.Mark.Value = mark.Value
371                         state.Mark.Mask = mark.Mask
372                 }
373         }
374
375         return state, nil
376 }
377
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)
383 }
384
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)
390
391         req.AddData(&nl.XfrmUsersaFlush{Proto: uint8(proto)})
392
393         _, err := req.Execute(syscall.NETLINK_XFRM, 0)
394         if err != nil {
395                 return err
396         }
397
398         return nil
399 }
400
401 func limitsToLft(lmts XfrmStateLimits, lft *nl.XfrmLifetimeCfg) {
402         if lmts.ByteSoft != 0 {
403                 lft.SoftByteLimit = lmts.ByteSoft
404         } else {
405                 lft.SoftByteLimit = nl.XFRM_INF
406         }
407         if lmts.ByteHard != 0 {
408                 lft.HardByteLimit = lmts.ByteHard
409         } else {
410                 lft.HardByteLimit = nl.XFRM_INF
411         }
412         if lmts.PacketSoft != 0 {
413                 lft.SoftPacketLimit = lmts.PacketSoft
414         } else {
415                 lft.SoftPacketLimit = nl.XFRM_INF
416         }
417         if lmts.PacketHard != 0 {
418                 lft.HardPacketLimit = lmts.PacketHard
419         } else {
420                 lft.HardPacketLimit = nl.XFRM_INF
421         }
422         lft.SoftAddExpiresSeconds = lmts.TimeSoft
423         lft.HardAddExpiresSeconds = lmts.TimeHard
424         lft.SoftUseExpiresSeconds = lmts.TimeUseSoft
425         lft.HardUseExpiresSeconds = lmts.TimeUseHard
426 }
427
428 func lftToLimits(lft *nl.XfrmLifetimeCfg, lmts *XfrmStateLimits) {
429         *lmts = *(*XfrmStateLimits)(unsafe.Pointer(lft))
430 }
431
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)
442
443         return msg
444 }