-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathxfrm_policy_linux.go
225 lines (193 loc) · 5.54 KB
/
xfrm_policy_linux.go
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
package netlink
import (
"syscall"
"unsafe"
)
const (
SizeofXfrmUserpolicyId = 0x40
SizeofXfrmUserpolicyInfo = 0xa8
SizeofXfrmUserTmpl = 0x40
)
// struct xfrm_userpolicy_id {
// struct xfrm_selector sel;
// __u32 index;
// __u8 dir;
// };
//
type XfrmUserpolicyId struct {
Sel XfrmSelector
Index uint32
Dir uint8
Pad [3]byte
}
func (msg *XfrmUserpolicyId) Len() int {
return SizeofXfrmUserpolicyId
}
func DeserializeXfrmUserpolicyId(b []byte) *XfrmUserpolicyId {
return (*XfrmUserpolicyId)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyId][0]))
}
func (msg *XfrmUserpolicyId) Serialize() []byte {
return (*(*[SizeofXfrmUserpolicyId]byte)(unsafe.Pointer(msg)))[:]
}
// struct xfrm_userpolicy_info {
// struct xfrm_selector sel;
// struct xfrm_lifetime_cfg lft;
// struct xfrm_lifetime_cur curlft;
// __u32 priority;
// __u32 index;
// __u8 dir;
// __u8 action;
// #define XFRM_POLICY_ALLOW 0
// #define XFRM_POLICY_BLOCK 1
// __u8 flags;
// #define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */
// /* Automatically expand selector to include matching ICMP payloads. */
// #define XFRM_POLICY_ICMP 2
// __u8 share;
// };
type XfrmUserpolicyInfo struct {
Sel XfrmSelector
Lft XfrmLifetimeCfg
Curlft XfrmLifetimeCur
Priority uint32
Index uint32
Dir uint8
Action uint8
Flags uint8
Share uint8
Pad [4]byte
}
func (msg *XfrmUserpolicyInfo) Len() int {
return SizeofXfrmUserpolicyInfo
}
func DeserializeXfrmUserpolicyInfo(b []byte) *XfrmUserpolicyInfo {
return (*XfrmUserpolicyInfo)(unsafe.Pointer(&b[0:SizeofXfrmUserpolicyInfo][0]))
}
func (msg *XfrmUserpolicyInfo) Serialize() []byte {
return (*(*[SizeofXfrmUserpolicyInfo]byte)(unsafe.Pointer(msg)))[:]
}
// struct xfrm_user_tmpl {
// struct xfrm_id id;
// __u16 family;
// xfrm_address_t saddr;
// __u32 reqid;
// __u8 mode;
// __u8 share;
// __u8 optional;
// __u32 aalgos;
// __u32 ealgos;
// __u32 calgos;
// }
type XfrmUserTmpl struct {
XfrmId XfrmId
Family uint16
Pad1 [2]byte
Saddr XfrmAddress
Reqid uint32
Mode uint8
Share uint8
Optional uint8
Pad2 byte
Aalgos uint32
Ealgos uint32
Calgos uint32
}
func (msg *XfrmUserTmpl) Len() int {
return SizeofXfrmUserTmpl
}
func DeserializeXfrmUserTmpl(b []byte) *XfrmUserTmpl {
return (*XfrmUserTmpl)(unsafe.Pointer(&b[0:SizeofXfrmUserTmpl][0]))
}
func (msg *XfrmUserTmpl) Serialize() []byte {
return (*(*[SizeofXfrmUserTmpl]byte)(unsafe.Pointer(msg)))[:]
}
// XfrmPolicyAdd will add an xfrm policy to the system.
// Equivalent to: `ip xfrm policy add $policy`
func XfrmPolicyAdd(s *NetlinkSocket, policy *XfrmPolicy) error {
req := NewNetlinkRequest(XFRM_MSG_NEWPOLICY, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
msg := &XfrmUserpolicyInfo{}
msg.Sel = *policy.Sel
msg.Priority = uint32(policy.Priority)
msg.Index = uint32(policy.Index)
msg.Dir = uint8(policy.Dir)
msg.Lft.SoftByteLimit = XFRM_INF
msg.Lft.HardByteLimit = XFRM_INF
msg.Lft.SoftPacketLimit = XFRM_INF
msg.Lft.HardPacketLimit = XFRM_INF
req.AddData(msg)
tmplData := make([]byte, SizeofXfrmUserTmpl*len(policy.Tmpls))
for i, tmpl := range policy.Tmpls {
start := i * SizeofXfrmUserTmpl
userTmpl := DeserializeXfrmUserTmpl(tmplData[start : start+SizeofXfrmUserTmpl])
userTmpl.XfrmId.Daddr.FromIP(tmpl.Dst)
userTmpl.Saddr.FromIP(tmpl.Src)
userTmpl.XfrmId.Proto = uint8(tmpl.Proto)
userTmpl.Mode = uint8(tmpl.Mode)
userTmpl.Reqid = uint32(tmpl.Reqid)
userTmpl.Aalgos = ^uint32(0)
userTmpl.Ealgos = ^uint32(0)
userTmpl.Calgos = ^uint32(0)
}
if len(tmplData) > 0 {
tmpls := NewRtAttr(XFRMA_TMPL, tmplData)
req.AddData(tmpls)
}
_, err := req.Execute(s, 0)
return err
}
// XfrmPolicyDel will delete an xfrm policy from the system. Note that
// the Tmpls are ignored when matching the policy to delete.
// Equivalent to: `ip xfrm policy del $policy`
func XfrmPolicyDel(s *NetlinkSocket, policy *XfrmPolicy) error {
req := NewNetlinkRequest(XFRM_MSG_DELPOLICY, syscall.NLM_F_ACK)
msg := &XfrmUserpolicyId{}
msg.Sel = *policy.Sel
msg.Index = uint32(policy.Index)
msg.Dir = uint8(policy.Dir)
req.AddData(msg)
_, err := req.Execute(s, 0)
return err
}
// XfrmPolicyList gets a list of xfrm policies in the system.
// Equivalent to: `ip xfrm policy show`.
// The list can be filtered by ip family.
func XfrmPolicyList(s *NetlinkSocket, family int) ([]XfrmPolicy, error) {
req := NewNetlinkRequest(XFRM_MSG_GETPOLICY, syscall.NLM_F_DUMP)
msg := NewIfInfomsg(family)
req.AddData(msg)
msgs, err := req.Execute(s, XFRM_MSG_NEWPOLICY)
if err != nil {
return nil, err
}
res := make([]XfrmPolicy, 0)
for _, m := range msgs {
msg := DeserializeXfrmUserpolicyInfo(m)
if family != FAMILY_ALL && family != int(msg.Sel.Family) {
continue
}
var policy XfrmPolicy
policy.Sel = &msg.Sel
attrs, err := ParseRouteAttr(m[msg.Len():])
if err != nil {
return nil, err
}
for _, attr := range attrs {
switch attr.Attr.Type {
case XFRMA_TMPL:
max := len(attr.Value)
for i := 0; i < max; i += SizeofXfrmUserTmpl {
var resTmpl XfrmPolicyTmpl
tmpl := DeserializeXfrmUserTmpl(attr.Value[i : i+SizeofXfrmUserTmpl])
resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP()
resTmpl.Src = tmpl.Saddr.ToIP()
resTmpl.Proto = Proto(tmpl.XfrmId.Proto)
resTmpl.Mode = Mode(tmpl.Mode)
resTmpl.Reqid = tmpl.Reqid
policy.Tmpls = append(policy.Tmpls, resTmpl)
}
}
}
res = append(res, policy)
}
return res, nil
}