github.com/vishvananda/netlink@v1.3.0/xfrm_policy_linux.go (about) 1 package netlink 2 3 import ( 4 "fmt" 5 "net" 6 7 "github.com/vishvananda/netlink/nl" 8 "golang.org/x/sys/unix" 9 ) 10 11 // Dir is an enum representing an ipsec template direction. 12 type Dir uint8 13 14 const ( 15 XFRM_DIR_IN Dir = iota 16 XFRM_DIR_OUT 17 XFRM_DIR_FWD 18 XFRM_SOCKET_IN 19 XFRM_SOCKET_OUT 20 XFRM_SOCKET_FWD 21 ) 22 23 func (d Dir) String() string { 24 switch d { 25 case XFRM_DIR_IN: 26 return "dir in" 27 case XFRM_DIR_OUT: 28 return "dir out" 29 case XFRM_DIR_FWD: 30 return "dir fwd" 31 case XFRM_SOCKET_IN: 32 return "socket in" 33 case XFRM_SOCKET_OUT: 34 return "socket out" 35 case XFRM_SOCKET_FWD: 36 return "socket fwd" 37 } 38 return fmt.Sprintf("socket %d", d-XFRM_SOCKET_IN) 39 } 40 41 // PolicyAction is an enum representing an ipsec policy action. 42 type PolicyAction uint8 43 44 const ( 45 XFRM_POLICY_ALLOW PolicyAction = 0 46 XFRM_POLICY_BLOCK PolicyAction = 1 47 ) 48 49 func (a PolicyAction) String() string { 50 switch a { 51 case XFRM_POLICY_ALLOW: 52 return "allow" 53 case XFRM_POLICY_BLOCK: 54 return "block" 55 default: 56 return fmt.Sprintf("action %d", a) 57 } 58 } 59 60 // XfrmPolicyTmpl encapsulates a rule for the base addresses of an ipsec 61 // policy. These rules are matched with XfrmState to determine encryption 62 // and authentication algorithms. 63 type XfrmPolicyTmpl struct { 64 Dst net.IP 65 Src net.IP 66 Proto Proto 67 Mode Mode 68 Spi int 69 Reqid int 70 Optional int 71 } 72 73 func (t XfrmPolicyTmpl) String() string { 74 return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, Mode: %s, Spi: 0x%x, Reqid: 0x%x}", 75 t.Dst, t.Src, t.Proto, t.Mode, t.Spi, t.Reqid) 76 } 77 78 // XfrmPolicy represents an ipsec policy. It represents the overlay network 79 // and has a list of XfrmPolicyTmpls representing the base addresses of 80 // the policy. 81 type XfrmPolicy struct { 82 Dst *net.IPNet 83 Src *net.IPNet 84 Proto Proto 85 DstPort int 86 SrcPort int 87 Dir Dir 88 Priority int 89 Index int 90 Action PolicyAction 91 Ifindex int 92 Ifid int 93 Mark *XfrmMark 94 Tmpls []XfrmPolicyTmpl 95 } 96 97 func (p XfrmPolicy) String() string { 98 return fmt.Sprintf("{Dst: %v, Src: %v, Proto: %s, DstPort: %d, SrcPort: %d, Dir: %s, Priority: %d, Index: %d, Action: %s, Ifindex: %d, Ifid: %d, Mark: %s, Tmpls: %s}", 99 p.Dst, p.Src, p.Proto, p.DstPort, p.SrcPort, p.Dir, p.Priority, p.Index, p.Action, p.Ifindex, p.Ifid, p.Mark, p.Tmpls) 100 } 101 102 func selFromPolicy(sel *nl.XfrmSelector, policy *XfrmPolicy) { 103 sel.Family = uint16(nl.FAMILY_V4) 104 if policy.Dst != nil { 105 sel.Family = uint16(nl.GetIPFamily(policy.Dst.IP)) 106 sel.Daddr.FromIP(policy.Dst.IP) 107 prefixlenD, _ := policy.Dst.Mask.Size() 108 sel.PrefixlenD = uint8(prefixlenD) 109 } 110 if policy.Src != nil { 111 sel.Saddr.FromIP(policy.Src.IP) 112 prefixlenS, _ := policy.Src.Mask.Size() 113 sel.PrefixlenS = uint8(prefixlenS) 114 } 115 sel.Proto = uint8(policy.Proto) 116 sel.Dport = nl.Swap16(uint16(policy.DstPort)) 117 sel.Sport = nl.Swap16(uint16(policy.SrcPort)) 118 if sel.Dport != 0 { 119 sel.DportMask = ^uint16(0) 120 } 121 if sel.Sport != 0 { 122 sel.SportMask = ^uint16(0) 123 } 124 sel.Ifindex = int32(policy.Ifindex) 125 } 126 127 // XfrmPolicyAdd will add an xfrm policy to the system. 128 // Equivalent to: `ip xfrm policy add $policy` 129 func XfrmPolicyAdd(policy *XfrmPolicy) error { 130 return pkgHandle.XfrmPolicyAdd(policy) 131 } 132 133 // XfrmPolicyAdd will add an xfrm policy to the system. 134 // Equivalent to: `ip xfrm policy add $policy` 135 func (h *Handle) XfrmPolicyAdd(policy *XfrmPolicy) error { 136 return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_NEWPOLICY) 137 } 138 139 // XfrmPolicyUpdate will update an xfrm policy to the system. 140 // Equivalent to: `ip xfrm policy update $policy` 141 func XfrmPolicyUpdate(policy *XfrmPolicy) error { 142 return pkgHandle.XfrmPolicyUpdate(policy) 143 } 144 145 // XfrmPolicyUpdate will update an xfrm policy to the system. 146 // Equivalent to: `ip xfrm policy update $policy` 147 func (h *Handle) XfrmPolicyUpdate(policy *XfrmPolicy) error { 148 return h.xfrmPolicyAddOrUpdate(policy, nl.XFRM_MSG_UPDPOLICY) 149 } 150 151 func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error { 152 req := h.newNetlinkRequest(nlProto, unix.NLM_F_CREATE|unix.NLM_F_EXCL|unix.NLM_F_ACK) 153 154 msg := &nl.XfrmUserpolicyInfo{} 155 selFromPolicy(&msg.Sel, policy) 156 msg.Priority = uint32(policy.Priority) 157 msg.Index = uint32(policy.Index) 158 msg.Dir = uint8(policy.Dir) 159 msg.Action = uint8(policy.Action) 160 msg.Lft.SoftByteLimit = nl.XFRM_INF 161 msg.Lft.HardByteLimit = nl.XFRM_INF 162 msg.Lft.SoftPacketLimit = nl.XFRM_INF 163 msg.Lft.HardPacketLimit = nl.XFRM_INF 164 req.AddData(msg) 165 166 tmplData := make([]byte, nl.SizeofXfrmUserTmpl*len(policy.Tmpls)) 167 for i, tmpl := range policy.Tmpls { 168 start := i * nl.SizeofXfrmUserTmpl 169 userTmpl := nl.DeserializeXfrmUserTmpl(tmplData[start : start+nl.SizeofXfrmUserTmpl]) 170 userTmpl.XfrmId.Daddr.FromIP(tmpl.Dst) 171 userTmpl.Saddr.FromIP(tmpl.Src) 172 userTmpl.Family = uint16(nl.GetIPFamily(tmpl.Dst)) 173 userTmpl.XfrmId.Proto = uint8(tmpl.Proto) 174 userTmpl.XfrmId.Spi = nl.Swap32(uint32(tmpl.Spi)) 175 userTmpl.Mode = uint8(tmpl.Mode) 176 userTmpl.Reqid = uint32(tmpl.Reqid) 177 userTmpl.Optional = uint8(tmpl.Optional) 178 userTmpl.Aalgos = ^uint32(0) 179 userTmpl.Ealgos = ^uint32(0) 180 userTmpl.Calgos = ^uint32(0) 181 } 182 if len(tmplData) > 0 { 183 tmpls := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData) 184 req.AddData(tmpls) 185 } 186 if policy.Mark != nil { 187 out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark)) 188 req.AddData(out) 189 } 190 191 if policy.Ifid != 0 { 192 ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid))) 193 req.AddData(ifId) 194 } 195 196 _, err := req.Execute(unix.NETLINK_XFRM, 0) 197 return err 198 } 199 200 // XfrmPolicyDel will delete an xfrm policy from the system. Note that 201 // the Tmpls are ignored when matching the policy to delete. 202 // Equivalent to: `ip xfrm policy del $policy` 203 func XfrmPolicyDel(policy *XfrmPolicy) error { 204 return pkgHandle.XfrmPolicyDel(policy) 205 } 206 207 // XfrmPolicyDel will delete an xfrm policy from the system. Note that 208 // the Tmpls are ignored when matching the policy to delete. 209 // Equivalent to: `ip xfrm policy del $policy` 210 func (h *Handle) XfrmPolicyDel(policy *XfrmPolicy) error { 211 _, err := h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_DELPOLICY) 212 return err 213 } 214 215 // XfrmPolicyList gets a list of xfrm policies in the system. 216 // Equivalent to: `ip xfrm policy show`. 217 // The list can be filtered by ip family. 218 func XfrmPolicyList(family int) ([]XfrmPolicy, error) { 219 return pkgHandle.XfrmPolicyList(family) 220 } 221 222 // XfrmPolicyList gets a list of xfrm policies in the system. 223 // Equivalent to: `ip xfrm policy show`. 224 // The list can be filtered by ip family. 225 func (h *Handle) XfrmPolicyList(family int) ([]XfrmPolicy, error) { 226 req := h.newNetlinkRequest(nl.XFRM_MSG_GETPOLICY, unix.NLM_F_DUMP) 227 228 msg := nl.NewIfInfomsg(family) 229 req.AddData(msg) 230 231 msgs, err := req.Execute(unix.NETLINK_XFRM, nl.XFRM_MSG_NEWPOLICY) 232 if err != nil { 233 return nil, err 234 } 235 236 var res []XfrmPolicy 237 for _, m := range msgs { 238 if policy, err := parseXfrmPolicy(m, family); err == nil { 239 res = append(res, *policy) 240 } else if err == familyError { 241 continue 242 } else { 243 return nil, err 244 } 245 } 246 return res, nil 247 } 248 249 // XfrmPolicyGet gets a the policy described by the index or selector, if found. 250 // Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`. 251 func XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) { 252 return pkgHandle.XfrmPolicyGet(policy) 253 } 254 255 // XfrmPolicyGet gets a the policy described by the index or selector, if found. 256 // Equivalent to: `ip xfrm policy get { SELECTOR | index INDEX } dir DIR [ctx CTX ] [ mark MARK [ mask MASK ] ] [ ptype PTYPE ]`. 257 func (h *Handle) XfrmPolicyGet(policy *XfrmPolicy) (*XfrmPolicy, error) { 258 return h.xfrmPolicyGetOrDelete(policy, nl.XFRM_MSG_GETPOLICY) 259 } 260 261 // XfrmPolicyFlush will flush the policies on the system. 262 // Equivalent to: `ip xfrm policy flush` 263 func XfrmPolicyFlush() error { 264 return pkgHandle.XfrmPolicyFlush() 265 } 266 267 // XfrmPolicyFlush will flush the policies on the system. 268 // Equivalent to: `ip xfrm policy flush` 269 func (h *Handle) XfrmPolicyFlush() error { 270 req := h.newNetlinkRequest(nl.XFRM_MSG_FLUSHPOLICY, unix.NLM_F_ACK) 271 _, err := req.Execute(unix.NETLINK_XFRM, 0) 272 return err 273 } 274 275 func (h *Handle) xfrmPolicyGetOrDelete(policy *XfrmPolicy, nlProto int) (*XfrmPolicy, error) { 276 req := h.newNetlinkRequest(nlProto, unix.NLM_F_ACK) 277 278 msg := &nl.XfrmUserpolicyId{} 279 selFromPolicy(&msg.Sel, policy) 280 msg.Index = uint32(policy.Index) 281 msg.Dir = uint8(policy.Dir) 282 req.AddData(msg) 283 284 if policy.Mark != nil { 285 out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark)) 286 req.AddData(out) 287 } 288 289 if policy.Ifid != 0 { 290 ifId := nl.NewRtAttr(nl.XFRMA_IF_ID, nl.Uint32Attr(uint32(policy.Ifid))) 291 req.AddData(ifId) 292 } 293 294 resType := nl.XFRM_MSG_NEWPOLICY 295 if nlProto == nl.XFRM_MSG_DELPOLICY { 296 resType = 0 297 } 298 299 msgs, err := req.Execute(unix.NETLINK_XFRM, uint16(resType)) 300 if err != nil { 301 return nil, err 302 } 303 304 if nlProto == nl.XFRM_MSG_DELPOLICY { 305 return nil, err 306 } 307 308 return parseXfrmPolicy(msgs[0], FAMILY_ALL) 309 } 310 311 func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) { 312 msg := nl.DeserializeXfrmUserpolicyInfo(m) 313 314 // This is mainly for the policy dump 315 if family != FAMILY_ALL && family != int(msg.Sel.Family) { 316 return nil, familyError 317 } 318 319 var policy XfrmPolicy 320 321 policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD, uint16(family)) 322 policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS, uint16(family)) 323 policy.Proto = Proto(msg.Sel.Proto) 324 policy.DstPort = int(nl.Swap16(msg.Sel.Dport)) 325 policy.SrcPort = int(nl.Swap16(msg.Sel.Sport)) 326 policy.Ifindex = int(msg.Sel.Ifindex) 327 policy.Priority = int(msg.Priority) 328 policy.Index = int(msg.Index) 329 policy.Dir = Dir(msg.Dir) 330 policy.Action = PolicyAction(msg.Action) 331 332 attrs, err := nl.ParseRouteAttr(m[msg.Len():]) 333 if err != nil { 334 return nil, err 335 } 336 337 for _, attr := range attrs { 338 switch attr.Attr.Type { 339 case nl.XFRMA_TMPL: 340 max := len(attr.Value) 341 for i := 0; i < max; i += nl.SizeofXfrmUserTmpl { 342 var resTmpl XfrmPolicyTmpl 343 tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl]) 344 resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP() 345 resTmpl.Src = tmpl.Saddr.ToIP() 346 resTmpl.Proto = Proto(tmpl.XfrmId.Proto) 347 resTmpl.Mode = Mode(tmpl.Mode) 348 resTmpl.Spi = int(nl.Swap32(tmpl.XfrmId.Spi)) 349 resTmpl.Reqid = int(tmpl.Reqid) 350 resTmpl.Optional = int(tmpl.Optional) 351 policy.Tmpls = append(policy.Tmpls, resTmpl) 352 } 353 case nl.XFRMA_MARK: 354 mark := nl.DeserializeXfrmMark(attr.Value[:]) 355 policy.Mark = new(XfrmMark) 356 policy.Mark.Value = mark.Value 357 policy.Mark.Mask = mark.Mask 358 case nl.XFRMA_IF_ID: 359 policy.Ifid = int(native.Uint32(attr.Value)) 360 } 361 } 362 363 return &policy, nil 364 }