func (h *Handle) xfrmStateAddOrUpdate(state *XfrmState, nlProto int) error { // A state with spi 0 can't be deleted so don't allow it to be set if state.Spi == 0 { return fmt.Errorf("Spi must be set when adding xfrm state.") } req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := &nl.XfrmUsersaInfo{} msg.Family = uint16(nl.GetIPFamily(state.Dst)) msg.Id.Daddr.FromIP(state.Dst) msg.Saddr.FromIP(state.Src) msg.Id.Proto = uint8(state.Proto) msg.Mode = uint8(state.Mode) msg.Id.Spi = nl.Swap32(uint32(state.Spi)) msg.Reqid = uint32(state.Reqid) msg.ReplayWindow = uint8(state.ReplayWindow) limitsToLft(state.Limits, &msg.Lft) req.AddData(msg) if state.Auth != nil { out := nl.NewRtAttr(nl.XFRMA_ALG_AUTH_TRUNC, writeStateAlgoAuth(state.Auth)) req.AddData(out) } if state.Crypt != nil { out := nl.NewRtAttr(nl.XFRMA_ALG_CRYPT, writeStateAlgo(state.Crypt)) req.AddData(out) } if state.Aead != nil { out := nl.NewRtAttr(nl.XFRMA_ALG_AEAD, writeStateAlgoAead(state.Aead)) req.AddData(out) } if state.Encap != nil { encapData := make([]byte, nl.SizeofXfrmEncapTmpl) encap := nl.DeserializeXfrmEncapTmpl(encapData) encap.EncapType = uint16(state.Encap.Type) encap.EncapSport = nl.Swap16(uint16(state.Encap.SrcPort)) encap.EncapDport = nl.Swap16(uint16(state.Encap.DstPort)) encap.EncapOa.FromIP(state.Encap.OriginalAddress) out := nl.NewRtAttr(nl.XFRMA_ENCAP, encapData) req.AddData(out) } if state.Mark != nil { out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark)) req.AddData(out) } _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err }
func parseXfrmPolicy(m []byte, family int) (*XfrmPolicy, error) { msg := nl.DeserializeXfrmUserpolicyInfo(m) // This is mainly for the policy dump if family != FAMILY_ALL && family != int(msg.Sel.Family) { return nil, familyError } var policy XfrmPolicy policy.Dst = msg.Sel.Daddr.ToIPNet(msg.Sel.PrefixlenD) policy.Src = msg.Sel.Saddr.ToIPNet(msg.Sel.PrefixlenS) policy.Proto = Proto(msg.Sel.Proto) policy.DstPort = int(nl.Swap16(msg.Sel.Dport)) policy.SrcPort = int(nl.Swap16(msg.Sel.Sport)) policy.Priority = int(msg.Priority) policy.Index = int(msg.Index) policy.Dir = Dir(msg.Dir) attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } for _, attr := range attrs { switch attr.Attr.Type { case nl.XFRMA_TMPL: max := len(attr.Value) for i := 0; i < max; i += nl.SizeofXfrmUserTmpl { var resTmpl XfrmPolicyTmpl tmpl := nl.DeserializeXfrmUserTmpl(attr.Value[i : i+nl.SizeofXfrmUserTmpl]) resTmpl.Dst = tmpl.XfrmId.Daddr.ToIP() resTmpl.Src = tmpl.Saddr.ToIP() resTmpl.Proto = Proto(tmpl.XfrmId.Proto) resTmpl.Mode = Mode(tmpl.Mode) resTmpl.Spi = int(nl.Swap32(tmpl.XfrmId.Spi)) resTmpl.Reqid = int(tmpl.Reqid) policy.Tmpls = append(policy.Tmpls, resTmpl) } case nl.XFRMA_MARK: mark := nl.DeserializeXfrmMark(attr.Value[:]) policy.Mark = new(XfrmMark) policy.Mark.Value = mark.Value policy.Mark.Mask = mark.Mask } } return &policy, nil }
// XfrmStateDel will delete an xfrm state from the system. Note that // the Algos are ignored when matching the state to delete. // Equivalent to: `ip xfrm state del $state` func XfrmStateDel(state *XfrmState) error { req := nl.NewNetlinkRequest(nl.XFRM_MSG_DELSA, syscall.NLM_F_ACK) msg := &nl.XfrmUsersaId{} msg.Daddr.FromIP(state.Dst) msg.Family = uint16(nl.GetIPFamily(state.Dst)) msg.Proto = uint8(state.Proto) msg.Spi = nl.Swap32(uint32(state.Spi)) req.AddData(msg) saddr := nl.XfrmAddress{} saddr.FromIP(state.Src) srcdata := nl.NewRtAttr(nl.XFRMA_SRCADDR, saddr.Serialize()) req.AddData(srcdata) _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err }
func (h *Handle) xfrmStateGetOrDelete(state *XfrmState, nlProto int) (*XfrmState, error) { req := h.newNetlinkRequest(nlProto, syscall.NLM_F_ACK) msg := &nl.XfrmUsersaId{} msg.Family = uint16(nl.GetIPFamily(state.Dst)) msg.Daddr.FromIP(state.Dst) msg.Proto = uint8(state.Proto) msg.Spi = nl.Swap32(uint32(state.Spi)) req.AddData(msg) if state.Mark != nil { out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(state.Mark)) req.AddData(out) } if state.Src != nil { out := nl.NewRtAttr(nl.XFRMA_SRCADDR, state.Src.To16()) req.AddData(out) } resType := nl.XFRM_MSG_NEWSA if nlProto == nl.XFRM_MSG_DELSA { resType = 0 } msgs, err := req.Execute(syscall.NETLINK_XFRM, uint16(resType)) if err != nil { return nil, err } if nlProto == nl.XFRM_MSG_DELSA { return nil, nil } s, err := parseXfrmState(msgs[0], FAMILY_ALL) if err != nil { return nil, err } return s, nil }
func (h *Handle) xfrmPolicyAddOrUpdate(policy *XfrmPolicy, nlProto int) error { req := h.newNetlinkRequest(nlProto, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK) msg := &nl.XfrmUserpolicyInfo{} selFromPolicy(&msg.Sel, policy) msg.Priority = uint32(policy.Priority) msg.Index = uint32(policy.Index) msg.Dir = uint8(policy.Dir) msg.Lft.SoftByteLimit = nl.XFRM_INF msg.Lft.HardByteLimit = nl.XFRM_INF msg.Lft.SoftPacketLimit = nl.XFRM_INF msg.Lft.HardPacketLimit = nl.XFRM_INF req.AddData(msg) tmplData := make([]byte, nl.SizeofXfrmUserTmpl*len(policy.Tmpls)) for i, tmpl := range policy.Tmpls { start := i * nl.SizeofXfrmUserTmpl userTmpl := nl.DeserializeXfrmUserTmpl(tmplData[start : start+nl.SizeofXfrmUserTmpl]) userTmpl.XfrmId.Daddr.FromIP(tmpl.Dst) userTmpl.Saddr.FromIP(tmpl.Src) userTmpl.XfrmId.Proto = uint8(tmpl.Proto) userTmpl.XfrmId.Spi = nl.Swap32(uint32(tmpl.Spi)) 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 := nl.NewRtAttr(nl.XFRMA_TMPL, tmplData) req.AddData(tmpls) } if policy.Mark != nil { out := nl.NewRtAttr(nl.XFRMA_MARK, writeMark(policy.Mark)) req.AddData(out) } _, err := req.Execute(syscall.NETLINK_XFRM, 0) return err }
// XfrmStateList gets a list of xfrm states in the system. // Equivalent to: `ip xfrm state show`. // The list can be filtered by ip family. func XfrmStateList(family int) ([]XfrmState, error) { req := nl.NewNetlinkRequest(nl.XFRM_MSG_GETSA, syscall.NLM_F_DUMP) msg := nl.NewIfInfomsg(family) req.AddData(msg) msgs, err := req.Execute(syscall.NETLINK_XFRM, nl.XFRM_MSG_NEWSA) if err != nil { return nil, err } var res []XfrmState for _, m := range msgs { msg := nl.DeserializeXfrmUsersaInfo(m) if family != FAMILY_ALL && family != int(msg.Family) { continue } var state XfrmState state.Dst = msg.Id.Daddr.ToIP() state.Src = msg.Saddr.ToIP() state.Proto = Proto(msg.Id.Proto) state.Mode = Mode(msg.Mode) state.Spi = int(nl.Swap32(msg.Id.Spi)) state.Reqid = int(msg.Reqid) state.ReplayWindow = int(msg.ReplayWindow) attrs, err := nl.ParseRouteAttr(m[msg.Len():]) if err != nil { return nil, err } for _, attr := range attrs { switch attr.Attr.Type { case nl.XFRMA_ALG_AUTH, nl.XFRMA_ALG_CRYPT: var resAlgo *XfrmStateAlgo if attr.Attr.Type == nl.XFRMA_ALG_AUTH { if state.Auth == nil { state.Auth = new(XfrmStateAlgo) } resAlgo = state.Auth } else { state.Crypt = new(XfrmStateAlgo) resAlgo = state.Crypt } algo := nl.DeserializeXfrmAlgo(attr.Value[:]) (*resAlgo).Name = nl.BytesToString(algo.AlgName[:]) (*resAlgo).Key = algo.AlgKey case nl.XFRMA_ALG_AUTH_TRUNC: if state.Auth == nil { state.Auth = new(XfrmStateAlgo) } algo := nl.DeserializeXfrmAlgoAuth(attr.Value[:]) state.Auth.Name = nl.BytesToString(algo.AlgName[:]) state.Auth.Key = algo.AlgKey state.Auth.TruncateLen = int(algo.AlgTruncLen) case nl.XFRMA_ENCAP: encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:]) state.Encap = new(XfrmStateEncap) state.Encap.Type = EncapType(encap.EncapType) state.Encap.SrcPort = int(nl.Swap16(encap.EncapSport)) state.Encap.DstPort = int(nl.Swap16(encap.EncapDport)) state.Encap.OriginalAddress = encap.EncapOa.ToIP() } } res = append(res, state) } return res, nil }
func parseXfrmState(m []byte, family int) (*XfrmState, error) { msg := nl.DeserializeXfrmUsersaInfo(m) // This is mainly for the state dump if family != FAMILY_ALL && family != int(msg.Family) { return nil, familyError } var state XfrmState state.Dst = msg.Id.Daddr.ToIP() state.Src = msg.Saddr.ToIP() state.Proto = Proto(msg.Id.Proto) state.Mode = Mode(msg.Mode) state.Spi = int(nl.Swap32(msg.Id.Spi)) state.Reqid = int(msg.Reqid) state.ReplayWindow = int(msg.ReplayWindow) lftToLimits(&msg.Lft, &state.Limits) attrs, err := nl.ParseRouteAttr(m[nl.SizeofXfrmUsersaInfo:]) if err != nil { return nil, err } for _, attr := range attrs { switch attr.Attr.Type { case nl.XFRMA_ALG_AUTH, nl.XFRMA_ALG_CRYPT: var resAlgo *XfrmStateAlgo if attr.Attr.Type == nl.XFRMA_ALG_AUTH { if state.Auth == nil { state.Auth = new(XfrmStateAlgo) } resAlgo = state.Auth } else { state.Crypt = new(XfrmStateAlgo) resAlgo = state.Crypt } algo := nl.DeserializeXfrmAlgo(attr.Value[:]) (*resAlgo).Name = nl.BytesToString(algo.AlgName[:]) (*resAlgo).Key = algo.AlgKey case nl.XFRMA_ALG_AUTH_TRUNC: if state.Auth == nil { state.Auth = new(XfrmStateAlgo) } algo := nl.DeserializeXfrmAlgoAuth(attr.Value[:]) state.Auth.Name = nl.BytesToString(algo.AlgName[:]) state.Auth.Key = algo.AlgKey state.Auth.TruncateLen = int(algo.AlgTruncLen) case nl.XFRMA_ALG_AEAD: state.Aead = new(XfrmStateAlgo) algo := nl.DeserializeXfrmAlgoAEAD(attr.Value[:]) state.Aead.Name = nl.BytesToString(algo.AlgName[:]) state.Aead.Key = algo.AlgKey state.Aead.ICVLen = int(algo.AlgICVLen) case nl.XFRMA_ENCAP: encap := nl.DeserializeXfrmEncapTmpl(attr.Value[:]) state.Encap = new(XfrmStateEncap) state.Encap.Type = EncapType(encap.EncapType) state.Encap.SrcPort = int(nl.Swap16(encap.EncapSport)) state.Encap.DstPort = int(nl.Swap16(encap.EncapDport)) state.Encap.OriginalAddress = encap.EncapOa.ToIP() case nl.XFRMA_MARK: mark := nl.DeserializeXfrmMark(attr.Value[:]) state.Mark = new(XfrmMark) state.Mark.Value = mark.Value state.Mark.Mask = mark.Mask } } return &state, nil }