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