From 30e049eda93fb4458f79568378ae8e43b6bdfead Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Fri, 15 Apr 2022 13:03:52 +0000 Subject: [PATCH 01/33] Support multiple PDU session per UE and create XFRMi automatically Graceful shutdown NF and delete all XFRM interfaces created Send UL UP in according to the relationship of child SA and PDU session Use NAS envelop for nas messages sent through TCP --- internal/ngap/dispatcher.go | 9 +++ internal/ngap/handler/handler.go | 2 +- internal/ngap/message/build.go | 12 ++-- internal/ngap/message/send.go | 9 +++ internal/ngap/service/service.go | 9 ++- internal/nwucp/service/service.go | 18 +++++ internal/nwuup/service/service.go | 36 ++++++++-- internal/util/initContext.go | 50 +++++++++++--- pkg/context/context.go | 10 ++- pkg/context/ue.go | 16 +++-- pkg/factory/config.go | 13 ++-- pkg/factory/factory.go | 6 +- pkg/ike/dispatcher.go | 8 +++ pkg/ike/handler/handler.go | 39 ++++++++++- pkg/ike/message/build.go | 4 +- pkg/ike/message/message.go | 4 +- pkg/ike/service/service.go | 8 +++ pkg/ike/{handler => xfrm}/xfrm.go | 81 ++++++++++++++++++---- pkg/service/init.go | 107 ++++++++++++++++++++++++++++++ 19 files changed, 382 insertions(+), 59 deletions(-) rename pkg/ike/{handler => xfrm}/xfrm.go (79%) diff --git a/internal/ngap/dispatcher.go b/internal/ngap/dispatcher.go index fd6e4f95..a3bf2a41 100644 --- a/internal/ngap/dispatcher.go +++ b/internal/ngap/dispatcher.go @@ -1,6 +1,8 @@ package ngap import ( + "runtime/debug" + "git.cs.nctu.edu.tw/calee/sctp" "github.com/sirupsen/logrus" @@ -18,6 +20,13 @@ func init() { } func Dispatch(conn *sctp.SCTPConn, msg []byte) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.NgapLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + // AMF SCTP address sctpAddr := conn.RemoteAddr().String() // AMF context diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index 59462b6c..54281075 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -1583,7 +1583,7 @@ func HandlePDUSessionResourceSetupRequest(amf *context.N3IWFAMF, message *ngapTy proposal.ExtendedSequenceNumbers.BuildTransform( ike_message.TypeExtendedSequenceNumbers, ike_message.ESN_NO, nil, nil, nil) - n3iwfUe.CreateHalfChildSA(ikeMessage.MessageID, spi) + n3iwfUe.CreateHalfChildSA(ikeMessage.MessageID, spi, pduSessionID) // Build Nonce nonceData := handler.GenerateRandomNumber().Bytes() diff --git a/internal/ngap/message/build.go b/internal/ngap/message/build.go index df2bbc00..da28f58f 100644 --- a/internal/ngap/message/build.go +++ b/internal/ngap/message/build.go @@ -558,8 +558,8 @@ func BuildUEContextReleaseComplete(ue *context.N3IWFUe, for _, pduSession := range ue.PduSessionList { pDUSessionResourceItemCxtRelCpl := ngapType.PDUSessionResourceItemCxtRelCpl{} pDUSessionResourceItemCxtRelCpl.PDUSessionID.Value = pduSession.Id - pDUSessionResourceListCxtRelCpl.List = - append(pDUSessionResourceListCxtRelCpl.List, pDUSessionResourceItemCxtRelCpl) + pDUSessionResourceListCxtRelCpl.List = append(pDUSessionResourceListCxtRelCpl.List, + pDUSessionResourceItemCxtRelCpl) } uEContextReleaseCompleteIEs.List = append(uEContextReleaseCompleteIEs.List, ie) @@ -629,8 +629,8 @@ func BuildUEContextReleaseRequest(ue *context.N3IWFUe, cause ngapType.Cause) ([] for _, pduSession := range ue.PduSessionList { pDUSessionResourceItem := ngapType.PDUSessionResourceItemCxtRelReq{} pDUSessionResourceItem.PDUSessionID.Value = pduSession.Id - pDUSessionResourceListCxtRelReq.List = - append(pDUSessionResourceListCxtRelReq.List, pDUSessionResourceItem) + pDUSessionResourceListCxtRelReq.List = append(pDUSessionResourceListCxtRelReq.List, + pDUSessionResourceItem) } uEContextReleaseRequestIEs.List = append(uEContextReleaseRequestIEs.List, ie) @@ -1749,8 +1749,8 @@ func BuildPDUSessionResourceSetupResponseTransfer(pduSession *context.PDUSession Value: int64(qfi), }, } - qosFlowPerTNLInformation.AssociatedQosFlowList.List = - append(qosFlowPerTNLInformation.AssociatedQosFlowList.List, associatedQosFlowItem) + qosFlowPerTNLInformation.AssociatedQosFlowList.List = append( + qosFlowPerTNLInformation.AssociatedQosFlowList.List, associatedQosFlowItem) } return aper.MarshalWithParams(transfer, "valueExt") diff --git a/internal/ngap/message/send.go b/internal/ngap/message/send.go index 34137e3f..b6d392b9 100644 --- a/internal/ngap/message/send.go +++ b/internal/ngap/message/send.go @@ -1,6 +1,8 @@ package message import ( + "runtime/debug" + "git.cs.nctu.edu.tw/calee/sctp" "github.com/sirupsen/logrus" @@ -28,6 +30,13 @@ func SendToAmf(amf *context.N3IWFAMF, pkt []byte) { } func SendNGSetupRequest(conn *sctp.SCTPConn) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.NgapLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + ngaplog.Infoln("[N3IWF] Send NG Setup Request") sctpAddr := conn.RemoteAddr().String() diff --git a/internal/ngap/service/service.go b/internal/ngap/service/service.go index 402f7eeb..81d85169 100644 --- a/internal/ngap/service/service.go +++ b/internal/ngap/service/service.go @@ -3,6 +3,7 @@ package service import ( "errors" "io" + "runtime/debug" "time" "git.cs.nctu.edu.tw/calee/sctp" @@ -43,9 +44,15 @@ func Run() error { } func listenAndServe(localAddr, remoteAddr *sctp.SCTPAddr, errChan chan<- error) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.NgapLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + var conn *sctp.SCTPConn var err error - // Connect the session for i := 0; i < 3; i++ { conn, err = sctp.DialSCTP("sctp", localAddr, remoteAddr) diff --git a/internal/nwucp/service/service.go b/internal/nwucp/service/service.go index 73faec17..283d6ff0 100644 --- a/internal/nwucp/service/service.go +++ b/internal/nwucp/service/service.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net" + "runtime/debug" "strings" "github.com/sirupsen/logrus" @@ -47,6 +48,11 @@ func Run() error { // received from the connection. func listenAndServe(tcpListener net.Listener) { defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.NWuCPLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + err := tcpListener.Close() if err != nil { nwucpLog.Errorf("Error closing tcpListener: %+v", err) @@ -112,6 +118,11 @@ func decapNasMsgFromEnvelope(envelop []byte) []byte { // to AMF func serveConn(ue *context.N3IWFUe, connection net.Conn) { defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.NWuCPLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + err := connection.Close() if err != nil { nwucpLog.Errorf("Error closing connection: %+v", err) @@ -142,6 +153,13 @@ func serveConn(ue *context.N3IWFUe, connection net.Conn) { // forward forwards NAS messages sent from UE to the // associated AMF func forward(ue *context.N3IWFUe, packet []byte) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.NWuCPLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + nwucpLog.Trace("Forward NWu -> N2") message.SendUplinkNASTransport(ue.AMF, ue, packet) } diff --git a/internal/nwuup/service/service.go b/internal/nwuup/service/service.go index 0972dee9..e3e07fa0 100644 --- a/internal/nwuup/service/service.go +++ b/internal/nwuup/service/service.go @@ -3,6 +3,7 @@ package service import ( "errors" "net" + "runtime/debug" "github.com/sirupsen/logrus" gtpv1 "github.com/wmnsk/go-gtp/gtpv1" @@ -52,6 +53,11 @@ func Run() error { // forward packet. func listenAndServe(ipv4PacketConn *ipv4.PacketConn) { defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.NWuUPLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + err := ipv4PacketConn.Close() if err != nil { nwuupLog.Errorf("Error closing raw socket: %+v", err) @@ -60,24 +66,36 @@ func listenAndServe(ipv4PacketConn *ipv4.PacketConn) { buffer := make([]byte, 65535) + if err := ipv4PacketConn.SetControlMessage(ipv4.FlagInterface|ipv4.FlagTTL, true); err != nil { + nwuupLog.Errorf("Set control message visibility for IPv4 packet connection fail: %+v", err) + return + } + for { - n, _, src, err := ipv4PacketConn.ReadFrom(buffer) - nwuupLog.Tracef("Read %d bytes", n) + n, cm, src, err := ipv4PacketConn.ReadFrom(buffer) + nwuupLog.Tracef("Read %d bytes, %s", n, cm) if err != nil { - nwuupLog.Errorf("Error read from IPv4 Packet connection: %+v", err) + nwuupLog.Errorf("Error read from IPv4 packet connection: %+v", err) return } forwardData := make([]byte, n) copy(forwardData, buffer) - go forward(src.String(), forwardData) + go forward(src.String(), cm.IfIndex, forwardData) } } // forward forwards user plane packets from NWu to UPF // with GTP header encapsulated -func forward(ueInnerIP string, rawData []byte) { +func forward(ueInnerIP string, ifIndex int, rawData []byte) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.NWuUPLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + // Find UE information self := context.N3IWFSelf() ue, ok := self.AllocatedUEIPAddressLoad(ueInnerIP) @@ -88,8 +106,12 @@ func forward(ueInnerIP string, rawData []byte) { var pduSession *context.PDUSession - for _, pduSession = range ue.PduSessionList { - break + for _, childSA := range ue.N3IWFChildSecurityAssociation { + // Check which child SA the packet come from with interface index, + // and find the corresponding PDU session + if childSA.XfrmIface != nil && childSA.XfrmIface.Attrs().Index == ifIndex { + pduSession = ue.PduSessionList[childSA.PDUSessionIds[0]] + } } if pduSession == nil { diff --git a/internal/util/initContext.go b/internal/util/initContext.go index e41b43e3..0ca6443b 100644 --- a/internal/util/initContext.go +++ b/internal/util/initContext.go @@ -5,6 +5,7 @@ import ( "crypto/sha1" "crypto/x509" "encoding/pem" + "fmt" "io/ioutil" "net" "strings" @@ -19,12 +20,9 @@ import ( var contextLog *logrus.Entry -func init() { - contextLog = logger.ContextLog -} - func InitN3IWFContext() bool { var ok bool + contextLog = logger.ContextLog if factory.N3iwfConfig.Configuration == nil { contextLog.Error("No N3IWF configuration found") @@ -226,11 +224,27 @@ func InitN3IWFContext() bool { n3iwfContext.Subnet = ueIPRange } - if factory.N3iwfConfig.Configuration.InterfaceMark == 0 { - contextLog.Warn("IPSec interface mark is not defined, set to default value 7") - n3iwfContext.Mark = 7 + // XFRM related + ikeBindIfaceName, err := GetInterfaceName(factory.N3iwfConfig.Configuration.IKEBindAddr) + if err != nil { + contextLog.Error(err) + return false + } else { + n3iwfContext.XfrmParentIfaceName = ikeBindIfaceName + } + + if factory.N3iwfConfig.Configuration.XfrmIfaceName == "" { + contextLog.Error("XFRM interface Name is empty, set to default \"ipsec\"") + n3iwfContext.XfrmIfaceName = "ipsec" + } else { + n3iwfContext.XfrmIfaceName = factory.N3iwfConfig.Configuration.XfrmIfaceName + } + + if factory.N3iwfConfig.Configuration.XfrmIfaceId == 0 { + contextLog.Warn("XFRM interface id is not defined, set to default value 7") + n3iwfContext.XfrmIfaceId = 7 } else { - n3iwfContext.Mark = factory.N3iwfConfig.Configuration.InterfaceMark + n3iwfContext.XfrmIfaceId = factory.N3iwfConfig.Configuration.XfrmIfaceId } return true @@ -291,3 +305,23 @@ func formatSupportedTAList(info *context.N3IWFNFInfo) bool { return true } + +func GetInterfaceName(IPAddress string) (interfaceName string, err error) { + interfaces, err := net.Interfaces() + if err != nil { + return "nil", err + } + + for _, inter := range interfaces { + addrs, err := inter.Addrs() + if err != nil { + return "nil", err + } + for _, addr := range addrs { + if IPAddress == addr.String()[0:strings.Index(addr.String(), "/")] { + return inter.Name, nil + } + } + } + return "", fmt.Errorf("Cannot find interface name") +} diff --git a/pkg/context/context.go b/pkg/context/context.go index 87349c5f..d4ae3af4 100644 --- a/pkg/context/context.go +++ b/pkg/context/context.go @@ -51,8 +51,14 @@ type N3IWFContext struct { // UEIPAddressRange Subnet *net.IPNet - // Network interface mark for xfrm - Mark uint32 + // XFRM interface + XfrmIfaceId uint32 + XfrmIfaces sync.Map // map[uint32]*netlink.Link, XfrmIfaceId as key + XfrmIfaceName string + XfrmParentIfaceName string + + // Every UE's first UP IPsec will use default XFRM interface, additoinal UP IPsec will offset its XFRM id + XfrmIfaceIdOffsetForUP uint32 // N3IWF local address IKEBindAddress string diff --git a/pkg/context/ue.go b/pkg/context/ue.go index c38ef0fe..7e1a1ae6 100644 --- a/pkg/context/ue.go +++ b/pkg/context/ue.go @@ -5,6 +5,7 @@ import ( "fmt" "net" + "github.com/vishvananda/netlink" gtpv1 "github.com/wmnsk/go-gtp/gtpv1" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" @@ -174,6 +175,9 @@ type ChildSecurityAssociation struct { InboundSPI uint32 // N3IWF Specify OutboundSPI uint32 // Non-3GPP UE Specify + // Associated XFRM interface + XfrmIface netlink.Link + // IP address PeerPublicIPAddr net.IP LocalPublicIPAddr net.IP @@ -197,6 +201,9 @@ type ChildSecurityAssociation struct { N3IWFPort int NATPort int + // PDU Session IDs associated with this child SA + PDUSessionIds []int64 + // UE context ThisUE *N3IWFUe } @@ -251,9 +258,10 @@ func (ue *N3IWFUe) CreatePDUSession(pduSessionID int64, snssai ngapType.SNSSAI) // When N3IWF send CREATE_CHILD_SA request to N3UE, the inbound SPI of childSA will be only stored first until // receive response and call CompleteChildSAWithProposal to fill the all data of childSA -func (ue *N3IWFUe) CreateHalfChildSA(msgID, inboundSPI uint32) { +func (ue *N3IWFUe) CreateHalfChildSA(msgID, inboundSPI uint32, pduSessionID int64) { childSA := new(ChildSecurityAssociation) childSA.InboundSPI = inboundSPI + childSA.PDUSessionIds = append(childSA.PDUSessionIds, pduSessionID) // Link UE context childSA.ThisUE = ue // Map Exchange Message ID and Child SA data until get paired response @@ -282,12 +290,10 @@ func (ue *N3IWFUe) CompleteChildSA(msgID uint32, outboundSPI uint32, childSA.OutboundSPI = outboundSPI if len(chosenSecurityAssociation.Proposals[0].EncryptionAlgorithm) != 0 { - childSA.EncryptionAlgorithm = - chosenSecurityAssociation.Proposals[0].EncryptionAlgorithm[0].TransformID + childSA.EncryptionAlgorithm = chosenSecurityAssociation.Proposals[0].EncryptionAlgorithm[0].TransformID } if len(chosenSecurityAssociation.Proposals[0].IntegrityAlgorithm) != 0 { - childSA.IntegrityAlgorithm = - chosenSecurityAssociation.Proposals[0].IntegrityAlgorithm[0].TransformID + childSA.IntegrityAlgorithm = chosenSecurityAssociation.Proposals[0].IntegrityAlgorithm[0].TransformID } if len(chosenSecurityAssociation.Proposals[0].ExtendedSequenceNumbers) != 0 { if chosenSecurityAssociation.Proposals[0].ExtendedSequenceNumbers[0].TransformID == 0 { diff --git a/pkg/factory/config.go b/pkg/factory/config.go index 069ef524..577a7618 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -14,7 +14,7 @@ import ( ) const ( - N3IWF_EXPECTED_CONFIG_VERSION = "1.0.1" + N3iwfExpectedConfigVersion = "1.0.3" ) type Config struct { @@ -60,13 +60,14 @@ type Configuration struct { N3IWFInfo context.N3IWFNFInfo `yaml:"N3IWFInformation" valid:"required"` AMFSCTPAddresses []context.AMFSCTPAddresses `yaml:"AMFSCTPAddresses" valid:"required"` + TCPPort uint16 `yaml:"NASTCPPort" valid:"port,required"` IKEBindAddr string `yaml:"IKEBindAddress" valid:"host,required"` - IPSecGatewayAddr string `yaml:"IPSecInterfaceAddress" valid:"host,required"` + IPSecGatewayAddr string `yaml:"IPSecTunnelAddress" valid:"host,required"` + UEIPAddressRange string `yaml:"UEIPAddressRange" valid:"cidr,required"` // e.g. 10.0.1.0/24 + XfrmIfaceName string `yaml:"XFRMInterfaceName" valid:"stringlength(1|10),optional"` // must != 0 + XfrmIfaceId uint32 `yaml:"XFRMInterfaceID" valid:"numeric,optional"` // must != 0 GTPBindAddr string `yaml:"GTPBindAddress" valid:"host,required"` - TCPPort uint16 `yaml:"NASTCPPort" valid:"port,required"` - FQDN string `yaml:"FQDN" valid:"url,required"` // e.g. n3iwf.free5gc.org - UEIPAddressRange string `yaml:"UEIPAddressRange" valid:"cidr,required"` // e.g. 10.0.1.0/24 - InterfaceMark uint32 `yaml:"IPSecInterfaceMark" valid:"numeric,optional"` // must != 0 + FQDN string `yaml:"FQDN" valid:"url,required"` // e.g. n3iwf.free5gc.org PrivateKey string `yaml:"PrivateKey" valid:"type(string),minstringlength(1),optional"` CertificateAuthority string `yaml:"CertificateAuthority" valid:"type(string),minstringlength(1),optional"` Certificate string `yaml:"Certificate" valid:"type(string),minstringlength(1),optional"` diff --git a/pkg/factory/factory.go b/pkg/factory/factory.go index 6f61e575..61f1c891 100644 --- a/pkg/factory/factory.go +++ b/pkg/factory/factory.go @@ -8,7 +8,7 @@ import ( "fmt" "io/ioutil" - "gopkg.in/yaml.v2" + yaml "gopkg.in/yaml.v2" "github.com/free5gc/n3iwf/internal/logger" ) @@ -33,9 +33,9 @@ func InitConfigFactory(f string) error { func CheckConfigVersion() error { currentVersion := N3iwfConfig.GetVersion() - if currentVersion != N3IWF_EXPECTED_CONFIG_VERSION { + if currentVersion != N3iwfExpectedConfigVersion { return fmt.Errorf("config version is [%s], but expected is [%s].", - currentVersion, N3IWF_EXPECTED_CONFIG_VERSION) + currentVersion, N3iwfExpectedConfigVersion) } logger.CfgLog.Infof("config version [%s]", currentVersion) diff --git a/pkg/ike/dispatcher.go b/pkg/ike/dispatcher.go index 3fde290e..e2f952d1 100644 --- a/pkg/ike/dispatcher.go +++ b/pkg/ike/dispatcher.go @@ -2,6 +2,7 @@ package ike import ( "net" + "runtime/debug" "github.com/sirupsen/logrus" @@ -17,6 +18,13 @@ func init() { } func Dispatch(udpConn *net.UDPConn, localAddr, remoteAddr *net.UDPAddr, msg []byte) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.IKELog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + // As specified in RFC 7296 section 3.1, the IKE message send from/to UDP port 4500 // should prepend a 4 bytes zero if localAddr.Port == 4500 { diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 3e66e8f3..2f0b5dbd 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -9,15 +9,18 @@ import ( "encoding/binary" "encoding/hex" "errors" + "fmt" "net" "github.com/sirupsen/logrus" + "github.com/vishvananda/netlink" "golang.org/x/sys/unix" "github.com/free5gc/n3iwf/internal/logger" ngap_message "github.com/free5gc/n3iwf/internal/ngap/message" "github.com/free5gc/n3iwf/pkg/context" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" + "github.com/free5gc/n3iwf/pkg/ike/xfrm" "github.com/free5gc/ngap/ngapType" ) @@ -1080,7 +1083,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message ikeSecurityAssociation.IKEAuthResponseSA.Proposals[0].SPI = inboundSPIByte // Consider 0x01 as the speicified index for IKE_AUTH exchange - thisUE.CreateHalfChildSA(0x01, inboundSPI) + thisUE.CreateHalfChildSA(0x01, inboundSPI, -1) childSecurityAssociationContext, err := thisUE.CompleteChildSA(0x01, outboundSPI, ikeSecurityAssociation.IKEAuthResponseSA) if err != nil { @@ -1120,7 +1123,8 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message } // Aplly XFRM rules - if err = ApplyXFRMRule(false, childSecurityAssociationContext); err != nil { + // IPsec for CP always use default XFRM interface + if err = xfrm.ApplyXFRMRule(false, n3iwfSelf.XfrmIfaceId, childSecurityAssociationContext); err != nil { ikeLog.Errorf("Applying XFRM rules failed: %+v", err) return } @@ -1433,8 +1437,37 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m childSecurityAssociationContext.NATPort = ueAddr.Port } + newXfrmiId := n3iwfSelf.XfrmIfaceId + + // The additional PDU session will be separated from default xfrm interface + // to avoid SPD entry collision + if len(thisUE.PduSessionList) > 1 { + // Setup XFRM interface for ipsec + var linkIPSec netlink.Link + n3iwfIPAddr := net.ParseIP(n3iwfSelf.IPSecGatewayAddress).To4() + n3iwfIPAddrAndSubnet := net.IPNet{IP: n3iwfIPAddr, Mask: n3iwfSelf.Subnet.Mask} + newXfrmiId += n3iwfSelf.XfrmIfaceId + n3iwfSelf.XfrmIfaceIdOffsetForUP + newXfrmiName := fmt.Sprintf("%s-%d", n3iwfSelf.XfrmIfaceName, newXfrmiId) + + if linkIPSec, err = xfrm.SetupIPsecXfrmi(newXfrmiName, n3iwfSelf.XfrmParentIfaceName, + newXfrmiId, n3iwfIPAddrAndSubnet); err != nil { + ikeLog.Errorf("Setup XFRM interface %s fail: %+v", newXfrmiName, err) + return + } + + n3iwfSelf.XfrmIfaces.LoadOrStore(newXfrmiId, linkIPSec) + childSecurityAssociationContext.XfrmIface = linkIPSec + n3iwfSelf.XfrmIfaceIdOffsetForUP++ + } else { + if linkIPSec, ok := n3iwfSelf.XfrmIfaces.Load(newXfrmiId); ok { + childSecurityAssociationContext.XfrmIface = linkIPSec.(netlink.Link) + } else { + ikeLog.Warnf("Cannot find the XFRM interface with if_id: %d", newXfrmiId) + } + } + // Aplly XFRM rules - if err = ApplyXFRMRule(true, childSecurityAssociationContext); err != nil { + if err = xfrm.ApplyXFRMRule(true, newXfrmiId, childSecurityAssociationContext); err != nil { ikeLog.Errorf("Applying XFRM rules failed: %+v", err) return } else { diff --git a/pkg/ike/message/build.go b/pkg/ike/message/build.go index 60b9b6af..e8be4ffc 100644 --- a/pkg/ike/message/build.go +++ b/pkg/ike/message/build.go @@ -178,8 +178,8 @@ func (container *TransformContainer) BuildTransform( transform.AttributeValue = *attributeValue } else if len(variableLengthAttributeValue) != 0 { transform.AttributeFormat = AttributeFormatUseTLV - transform.VariableLengthAttributeValue = - append(transform.VariableLengthAttributeValue, variableLengthAttributeValue...) + transform.VariableLengthAttributeValue = append(transform.VariableLengthAttributeValue, + variableLengthAttributeValue...) } else { return } diff --git a/pkg/ike/message/message.go b/pkg/ike/message/message.go index 748acceb..1b973203 100644 --- a/pkg/ike/message/message.go +++ b/pkg/ike/message/message.go @@ -1260,8 +1260,8 @@ func (configuration *Configuration) unmarshal(rawData []byte) error { individualConfigurationAttribute.Type = binary.BigEndian.Uint16(configurationAttributeData[0:2]) configurationAttributeData = configurationAttributeData[4:] - individualConfigurationAttribute.Value = - append(individualConfigurationAttribute.Value, configurationAttributeData[:length]...) + individualConfigurationAttribute.Value = append(individualConfigurationAttribute.Value, + configurationAttributeData[:length]...) configurationAttributeData = configurationAttributeData[length:] configuration.ConfigurationAttribute = append(configuration.ConfigurationAttribute, individualConfigurationAttribute) diff --git a/pkg/ike/service/service.go b/pkg/ike/service/service.go index 0292daa8..7105f6cb 100644 --- a/pkg/ike/service/service.go +++ b/pkg/ike/service/service.go @@ -3,6 +3,7 @@ package service import ( "errors" "net" + "runtime/debug" "github.com/sirupsen/logrus" @@ -55,6 +56,13 @@ func Run() error { } func listenAndServe(localAddr *net.UDPAddr, errChan chan<- error) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.IKELog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + listener, err := net.ListenUDP("udp", localAddr) if err != nil { ikeLog.Errorf("Listen UDP failed: %+v", err) diff --git a/pkg/ike/handler/xfrm.go b/pkg/ike/xfrm/xfrm.go similarity index 79% rename from pkg/ike/handler/xfrm.go rename to pkg/ike/xfrm/xfrm.go index 2effaa06..9baea968 100644 --- a/pkg/ike/handler/xfrm.go +++ b/pkg/ike/xfrm/xfrm.go @@ -1,14 +1,25 @@ -package handler +package xfrm import ( "errors" + "fmt" + "net" + "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/ike/message" ) +// Log +var ikeLog *logrus.Entry + +func init() { + ikeLog = logger.IKELog +} + type XFRMEncryptionAlgorithmType uint16 func (xfrmEncryptionAlgorithmType XFRMEncryptionAlgorithmType) String() string { @@ -47,16 +58,10 @@ func (xfrmIntegrityAlgorithmType XFRMIntegrityAlgorithmType) String() string { } } -func ApplyXFRMRule(n3iwf_is_initiator bool, childSecurityAssociation *context.ChildSecurityAssociation) error { - N3IWFSelf := context.N3IWFSelf() - +func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, + childSecurityAssociation *context.ChildSecurityAssociation) error { // Build XFRM information data structure for incoming traffic. - // Mark - mark := &netlink.XfrmMark{ - Value: N3IWFSelf.Mark, - } - // Direction: {private_network} -> this_server // State var xfrmEncryptionAlgorithm, xfrmIntegrityAlgorithm *netlink.XfrmStateAlgo @@ -91,7 +96,7 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, childSecurityAssociation *context.Ch xfrmState.Proto = netlink.XFRM_PROTO_ESP xfrmState.Mode = netlink.XFRM_MODE_TUNNEL xfrmState.Spi = int(childSecurityAssociation.InboundSPI) - xfrmState.Mark = mark + xfrmState.Ifid = int(xfrmiId) xfrmState.Auth = xfrmIntegrityAlgorithm xfrmState.Crypt = xfrmEncryptionAlgorithm xfrmState.ESN = childSecurityAssociation.ESN @@ -126,7 +131,7 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, childSecurityAssociation *context.Ch xfrmPolicy.Dst = &childSecurityAssociation.TrafficSelectorLocal xfrmPolicy.Proto = netlink.Proto(childSecurityAssociation.SelectedIPProtocol) xfrmPolicy.Dir = netlink.XFRM_DIR_IN - xfrmPolicy.Mark = mark + xfrmPolicy.Ifid = int(xfrmiId) xfrmPolicy.Tmpls = []netlink.XfrmPolicyTmpl{ xfrmPolicyTemplate, } @@ -179,12 +184,12 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, childSecurityAssociation *context.Ch return errors.New("Set XFRM policy rule failed") } - printSAInfo(n3iwf_is_initiator, childSecurityAssociation) + printSAInfo(n3iwf_is_initiator, xfrmiId, childSecurityAssociation) return nil } -func printSAInfo(n3iwf_is_initiator bool, childSecurityAssociation *context.ChildSecurityAssociation) { +func printSAInfo(n3iwf_is_initiator bool, xfrmiId uint32, childSecurityAssociation *context.ChildSecurityAssociation) { var InboundEncryptionKey, InboundIntegrityKey, OutboundEncryptionKey, OutboundIntegrityKey []byte if n3iwf_is_initiator { @@ -200,6 +205,7 @@ func printSAInfo(n3iwf_is_initiator bool, childSecurityAssociation *context.Chil } ikeLog.Debug("====== IPSec/Child SA Info ======") // ====== Inbound ====== + ikeLog.Debugf("XFRM interface if_id: %d", xfrmiId) ikeLog.Debugf("IPSec Inbound SPI: 0x%016x", childSecurityAssociation.InboundSPI) ikeLog.Debugf("[UE:%+v] -> [N3IWF:%+v]", childSecurityAssociation.PeerPublicIPAddr, childSecurityAssociation.LocalPublicIPAddr) @@ -207,7 +213,9 @@ func printSAInfo(n3iwf_is_initiator bool, childSecurityAssociation *context.Chil ikeLog.Debugf("IPSec Encryption Key: 0x%x", InboundEncryptionKey) ikeLog.Debugf("IPSec Integrity Algorithm: %d", childSecurityAssociation.IntegrityAlgorithm) ikeLog.Debugf("IPSec Integrity Key: 0x%x", InboundIntegrityKey) + ikeLog.Debug("====== IPSec/Child SA Info ======") // ====== Outbound ====== + ikeLog.Debugf("XFRM interface if_id: %d", xfrmiId) ikeLog.Debugf("IPSec Outbound SPI: 0x%016x", childSecurityAssociation.OutboundSPI) ikeLog.Debugf("[N3IWF:%+v] -> [UE:%+v]", childSecurityAssociation.LocalPublicIPAddr, childSecurityAssociation.PeerPublicIPAddr) @@ -216,3 +224,50 @@ func printSAInfo(n3iwf_is_initiator bool, childSecurityAssociation *context.Chil ikeLog.Debugf("IPSec Integrity Algorithm: %d", childSecurityAssociation.IntegrityAlgorithm) ikeLog.Debugf("IPSec Integrity Key: 0x%x", OutboundIntegrityKey) } + +func SetupIPsecXfrmi(xfrmIfaceName, parentIfaceName string, xfrmIfaceId uint32, + xfrmIfaceAddr net.IPNet) (netlink.Link, error) { + var ( + xfrmi, parent netlink.Link + err error + ) + + if parent, err = netlink.LinkByName(parentIfaceName); err != nil { + return nil, fmt.Errorf("Cannot find parent interface %s by name: %+v", parentIfaceName, err) + } + + // ip link add type xfrm dev if_id + link := &netlink.Xfrmi{ + LinkAttrs: netlink.LinkAttrs{ + Name: xfrmIfaceName, + ParentIndex: parent.Attrs().Index, + }, + Ifid: xfrmIfaceId, + } + + if err = netlink.LinkAdd(link); err != nil { + return nil, err + } + + if xfrmi, err = netlink.LinkByName(xfrmIfaceName); err != nil { + return nil, err + } + + ikeLog.Debugf("XFRM interface %s index is %d", xfrmIfaceName, xfrmi.Attrs().Index) + + // ip addr add xfrmIfaceAddr dev + linkIPSecAddr := &netlink.Addr{ + IPNet: &xfrmIfaceAddr, + } + + if err := netlink.AddrAdd(xfrmi, linkIPSecAddr); err != nil { + return nil, err + } + + // ip link set up + if err := netlink.LinkSetUp(xfrmi); err != nil { + return nil, err + } + + return xfrmi, nil +} diff --git a/pkg/service/init.go b/pkg/service/init.go index 9347e0b0..1d89f6d1 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -3,11 +3,18 @@ package service import ( "bufio" "fmt" + "net" + "os" "os/exec" + "os/signal" + "runtime/debug" "sync" + "syscall" + "time" "github.com/sirupsen/logrus" "github.com/urfave/cli" + "github.com/vishvananda/netlink" aperLogger "github.com/free5gc/aper/logger" "github.com/free5gc/n3iwf/internal/logger" @@ -15,8 +22,10 @@ import ( nwucp_service "github.com/free5gc/n3iwf/internal/nwucp/service" nwuup_service "github.com/free5gc/n3iwf/internal/nwuup/service" "github.com/free5gc/n3iwf/internal/util" + "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" ike_service "github.com/free5gc/n3iwf/pkg/ike/service" + "github.com/free5gc/n3iwf/pkg/ike/xfrm" ngapLogger "github.com/free5gc/ngap/logger" ) @@ -155,6 +164,29 @@ func (n3iwf *N3IWF) Start() { return } + if err := n3iwf.InitDefaultXfrmInterface(); err != nil { + logger.InitLog.Errorf("Initicating XFRM interface for control plane failed: %+v", err) + return + } + + // Graceful Shutdown + signalChannel := make(chan os.Signal, 1) + signal.Notify(signalChannel, os.Interrupt, syscall.SIGTERM) + go func() { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + + <-signalChannel + n3iwf.Terminate() + // Waiting for negotiatioon with netlink for deleting interfaces + time.Sleep(2 * time.Second) + os.Exit(0) + }() + wg := sync.WaitGroup{} // NGAP @@ -195,6 +227,60 @@ func (n3iwf *N3IWF) Start() { wg.Wait() } +func (n3iwf *N3IWF) InitDefaultXfrmInterface() error { + n3iwfContext := context.N3IWFSelf() + + // Setup default IPsec interface for Control Plane + var linkIPSec netlink.Link + var err error + n3iwfIPAddr := net.ParseIP(n3iwfContext.IPSecGatewayAddress).To4() + n3iwfIPAddrAndSubnet := net.IPNet{IP: n3iwfIPAddr, Mask: n3iwfContext.Subnet.Mask} + newXfrmiName := fmt.Sprintf("%s-default", n3iwfContext.XfrmIfaceName) + + if linkIPSec, err = xfrm.SetupIPsecXfrmi(newXfrmiName, n3iwfContext.XfrmParentIfaceName, + n3iwfContext.XfrmIfaceId, n3iwfIPAddrAndSubnet); err != nil { + logger.InitLog.Errorf("Setup XFRM interface %s fail: %+v", newXfrmiName, err) + return err + } + + route := &netlink.Route{ + LinkIndex: linkIPSec.Attrs().Index, + Dst: n3iwfContext.Subnet, + } + + if err := netlink.RouteAdd(route); err != nil { + logger.InitLog.Warnf("netlink.RouteAdd: %+v", err) + } + + logger.InitLog.Infof("Setup XFRM interface %s ", newXfrmiName) + + n3iwfContext.XfrmIfaces.LoadOrStore(n3iwfContext.XfrmIfaceId, linkIPSec) + n3iwfContext.XfrmIfaceIdOffsetForUP = 1 + + return nil +} + +func (n3iwf *N3IWF) RemoveIPsecInterfaces() { + n3iwfSelf := context.N3IWFSelf() + n3iwfSelf.XfrmIfaces.Range( + func(key, value interface{}) bool { + iface := value.(netlink.Link) + if err := netlink.LinkDel(iface); err != nil { + logger.InitLog.Errorf("Delete interface %s fail: %+v", iface.Attrs().Name, err) + } else { + logger.InitLog.Infof("Delete interface: %s", iface.Attrs().Name) + } + return true + }) +} + +func (n3iwf *N3IWF) Terminate() { + logger.InitLog.Info("Terminating N3IWF...") + logger.InitLog.Info("Deleting interfaces created by N3IWF") + n3iwf.RemoveIPsecInterfaces() + logger.InitLog.Info("N3IWF terminated") +} + func (n3iwf *N3IWF) Exec(c *cli.Context) error { // N3IWF.Initialize(cfgPath, c) @@ -211,6 +297,13 @@ func (n3iwf *N3IWF) Exec(c *cli.Context) error { logger.InitLog.Fatalln(err) } go func() { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + in := bufio.NewScanner(stdout) for in.Scan() { fmt.Println(in.Text()) @@ -223,6 +316,13 @@ func (n3iwf *N3IWF) Exec(c *cli.Context) error { logger.InitLog.Fatalln(err) } go func() { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + in := bufio.NewScanner(stderr) for in.Scan() { fmt.Println(in.Text()) @@ -231,6 +331,13 @@ func (n3iwf *N3IWF) Exec(c *cli.Context) error { }() go func() { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + logger.InitLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + if errCom := command.Start(); errCom != nil { logger.InitLog.Errorf("N3IWF start error: %v", errCom) } From 54e0e2e040bc2386463fcd4fb1b86a0db2148fb9 Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Wed, 1 Dec 2021 07:41:00 +0000 Subject: [PATCH 02/33] Add IKE Informational exchange when the deregistration procedure is triggered --- internal/ngap/handler/handler.go | 5 ++--- pkg/context/ue.go | 6 ++++++ pkg/ike/dispatcher.go | 2 ++ pkg/ike/handler/handler.go | 36 ++++++++++++++++++++++++++++++++ pkg/ike/handler/send.go | 18 ++++++++++++++++ pkg/ike/message/build.go | 10 +++++++++ pkg/ike/message/message.go | 4 +++- 7 files changed, 77 insertions(+), 4 deletions(-) diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index 54281075..c68ff492 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -1153,10 +1153,9 @@ func HandleUEContextReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAP printAndGetCause(cause) } - // TODO: release pdu session and gtp info for ue - n3iwfUe.Remove() + handler.SendUEInformationExchange(n3iwfUe) - ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) + // TODO: release pdu session and gtp info for ue } func encapNasMsgToEnvelope(nasPDU *ngapType.NASPDU) []byte { diff --git a/pkg/context/ue.go b/pkg/context/ue.go index 54a4e897..72e87033 100644 --- a/pkg/context/ue.go +++ b/pkg/context/ue.go @@ -230,6 +230,12 @@ func (ue *N3IWFUe) Remove() { n3iwfSelf.DeleteN3iwfUe(ue.RanUeNgapId) n3iwfSelf.DeleteIKESecurityAssociation(ue.N3IWFIKESecurityAssociation.LocalSPI) n3iwfSelf.DeleteInternalUEIPAddr(ue.IPSecInnerIP.String()) + + // Delete child SA + for _, childSA := range ue.N3IWFChildSecurityAssociation { + n3iwfSelf.ChildSA.Delete(childSA.InboundSPI) + } + for _, pduSession := range ue.PduSessionList { n3iwfSelf.DeleteTEID(pduSession.GTPConnection.IncomingTEID) } diff --git a/pkg/ike/dispatcher.go b/pkg/ike/dispatcher.go index e81a963f..55e5b338 100644 --- a/pkg/ike/dispatcher.go +++ b/pkg/ike/dispatcher.go @@ -54,6 +54,8 @@ func Dispatch(udpConn *net.UDPConn, localAddr, remoteAddr *net.UDPAddr, msg []by handler.HandleIKEAUTH(udpConn, localAddr, remoteAddr, ikeMessage) case ike_message.CREATE_CHILD_SA: handler.HandleCREATECHILDSA(udpConn, localAddr, remoteAddr, ikeMessage) + case ike_message.INFORMATIONAL: + handler.HandleInformational(udpConn, localAddr, remoteAddr, ikeMessage) default: ikeLog.Warnf("Unimplemented IKE message type, exchange type: %d", ikeMessage.ExchangeType) } diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index f06418e7..9732642f 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1603,6 +1603,42 @@ func HandleCREATECHILDSA(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m } } +func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message *ike_message.IKEMessage) { + ikeLog.Infoln("Handle Informational") + + if message == nil { + ikeLog.Error("IKE Message is nil") + return + } + + // Check if UE is response to a request that delete the ike SA + if len(message.Payloads) == 0 { + n3iwfSelf := context.N3IWFSelf() + ikeSecurityAssociation, ok := n3iwfSelf.IKESALoad(message.ResponderSPI) + + if !ok { + ikeLog.Warn("Unrecognized SPI") + // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) + responseIKEMessage := new(ike_message.IKEMessage) + responseIKEMessage.BuildIKEHeader(0, message.ResponderSPI, ike_message.INFORMATIONAL, + ike_message.ResponseBitCheck, message.MessageID) + responseIKEMessage.Payloads.Reset() + responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) + + SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + + return + } + + n3iwfUe := ikeSecurityAssociation.ThisUE + amf := n3iwfUe.AMF + + n3iwfUe.Remove() + + ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) + } +} + func is_supported(transformType uint8, transformID uint16, attributePresent bool, attributeValue uint16) bool { switch transformType { case ike_message.TypeEncryptionAlgorithm: diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index e9907ae7..d205a6ad 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -3,6 +3,7 @@ package handler import ( "net" + "github.com/free5gc/n3iwf/pkg/context" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" ) @@ -32,3 +33,20 @@ func SendIKEMessageToUE(udpConn *net.UDPConn, srcAddr, dstAddr *net.UDPAddr, mes return } } + +func SendUEInformationExchange( + n3iwfUe *context.N3IWFUe) { + ikeSecurityAssociation := n3iwfUe.N3IWFIKESecurityAssociation + responseIKEMessage := new(ike_message.IKEMessage) + var responseIKEPayload ike_message.IKEPayloadContainer + + // Build IKE message + responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, + ikeSecurityAssociation.LocalSPI, ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, + ikeSecurityAssociation.InitiatorMessageID) + + responseIKEPayload.BuildDeletePayload(ike_message.TypeSA, 0, 0, nil) + + SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, + n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) +} diff --git a/pkg/ike/message/build.go b/pkg/ike/message/build.go index e8be4ffc..184e573c 100644 --- a/pkg/ike/message/build.go +++ b/pkg/ike/message/build.go @@ -157,6 +157,16 @@ func (container *ProposalContainer) BuildProposal(proposalNumber uint8, protocol return proposal } +func (container *IKEPayloadContainer) BuildDeletePayload( + protocolID uint8, SPISize uint8, numberOfSPI uint16, SPIs []byte) { + deletePayload := new(Delete) + deletePayload.ProtocolID = protocolID + deletePayload.SPISize = SPISize + deletePayload.NumberOfSPI = numberOfSPI + deletePayload.SPIs = SPIs + *container = append(*container, deletePayload) +} + func (container *TransformContainer) Reset() { *container = nil } diff --git a/pkg/ike/message/message.go b/pkg/ike/message/message.go index 1b973203..f6a9899e 100644 --- a/pkg/ike/message/message.go +++ b/pkg/ike/message/message.go @@ -798,7 +798,9 @@ func (del *Delete) marshal() ([]byte, error) { deleteData[1] = del.SPISize binary.BigEndian.PutUint16(deleteData[2:4], del.NumberOfSPI) - deleteData = append(deleteData, del.SPIs...) + if int(del.NumberOfSPI) > 0 { + deleteData = append(deleteData, del.SPIs...) + } return deleteData, nil } From 2c719b3a52a288618a61083bd21d0b5f9661a1c1 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Thu, 5 May 2022 15:10:14 +0800 Subject: [PATCH 03/33] Encrypt Informational payload before sending it --- pkg/ike/handler/send.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index d205a6ad..ad25e34c 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -42,10 +42,13 @@ func SendUEInformationExchange( // Build IKE message responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, - ikeSecurityAssociation.LocalSPI, ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, - ikeSecurityAssociation.InitiatorMessageID) - - responseIKEPayload.BuildDeletePayload(ike_message.TypeSA, 0, 0, nil) + ikeSecurityAssociation.LocalSPI, ike_message.INFORMATIONAL, 0, + ikeSecurityAssociation.ResponderMessageID) + responseIKEPayload.BuildDeletePayload(1, 0, 0, nil) + if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { + ikeLog.Errorf("Encrypting IKE message failed: %+v", err) + return + } SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) From e9cb3eba50db5849be1e591c70c38bc5f222a4be Mon Sep 17 00:00:00 2001 From: allen00991 Date: Thu, 5 May 2022 15:14:08 +0800 Subject: [PATCH 04/33] Modify the method of judging the delete payload in handle informational message --- pkg/ike/handler/handler.go | 52 +++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 9732642f..7aff0f38 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1611,31 +1611,41 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m return } - // Check if UE is response to a request that delete the ike SA - if len(message.Payloads) == 0 { - n3iwfSelf := context.N3IWFSelf() - ikeSecurityAssociation, ok := n3iwfSelf.IKESALoad(message.ResponderSPI) - - if !ok { - ikeLog.Warn("Unrecognized SPI") - // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) - responseIKEMessage := new(ike_message.IKEMessage) - responseIKEMessage.BuildIKEHeader(0, message.ResponderSPI, ike_message.INFORMATIONAL, - ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) - - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + n3iwfSelf := context.N3IWFSelf() + responseIKEMessage := new(ike_message.IKEMessage) + responderSPI := message.ResponderSPI + ikeSecurityAssociation, ok := n3iwfSelf.IKESALoad(responderSPI) - return - } + if !ok { + ikeLog.Warn("Unrecognized SPI") + // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) + responseIKEMessage.BuildIKEHeader(0, message.ResponderSPI, ike_message.INFORMATIONAL, + ike_message.ResponseBitCheck, message.MessageID) + responseIKEMessage.Payloads.Reset() + responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) - n3iwfUe := ikeSecurityAssociation.ThisUE - amf := n3iwfUe.AMF + SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - n3iwfUe.Remove() + return + } - ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) + for _, ikePayload := range message.Payloads { + switch ikePayload.Type() { + case ike_message.TypeSK: + nextPayload := ikePayload.(*ike_message.Encrypted).NextPayload + + // Check if UE is response to a request that delete the ike SA + if nextPayload == 42 { + n3iwfUe := ikeSecurityAssociation.ThisUE + amf := n3iwfUe.AMF + n3iwfUe.Remove() + ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) + } + default: + ikeLog.Warnf( + "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", + ikePayload.Type()) + } } } From 10194c5908b0de4df54ab3b0cdc34b33b2a496f3 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Fri, 6 May 2022 23:45:34 +0800 Subject: [PATCH 05/33] Delete Child SA's XfrmState and XfrmPolicy when removing Ue Context --- pkg/context/ue.go | 27 +++++++++++++++++++++++++-- pkg/ike/handler/handler.go | 5 ++++- pkg/ike/xfrm/xfrm.go | 8 ++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/pkg/context/ue.go b/pkg/context/ue.go index 72e87033..1d17de20 100644 --- a/pkg/context/ue.go +++ b/pkg/context/ue.go @@ -178,6 +178,9 @@ type ChildSecurityAssociation struct { // Associated XFRM interface XfrmIface netlink.Link + XfrmStateList []netlink.XfrmState + XfrmPolicyList []netlink.XfrmPolicy + // IP address PeerPublicIPAddr net.IP LocalPublicIPAddr net.IP @@ -222,7 +225,7 @@ func (ue *N3IWFUe) init(ranUeNgapId int64) { ue.TemporaryExchangeMsgIDChildSAMapping = make(map[uint32]*ChildSecurityAssociation) } -func (ue *N3IWFUe) Remove() { +func (ue *N3IWFUe) Remove() error { // remove from AMF context ue.DetachAMF() // remove from N3IWF context @@ -233,12 +236,32 @@ func (ue *N3IWFUe) Remove() { // Delete child SA for _, childSA := range ue.N3IWFChildSecurityAssociation { - n3iwfSelf.ChildSA.Delete(childSA.InboundSPI) + iface := childSA.XfrmIface + // Delete child SA xfrmState + for _, xfrmState := range childSA.XfrmStateList { + if err := netlink.XfrmStateDel(&xfrmState); err != nil { + return fmt.Errorf("Delete xfrmstate error : %+v", err) + } + } + // Delete child SA xfrmPolicy + for _, xfrmPolicy := range childSA.XfrmPolicyList { + if err := netlink.XfrmPolicyDel(&xfrmPolicy); err != nil { + return fmt.Errorf("Delete xfrmPolicy error : %+v", err) + } + } + if iface == nil || iface.Attrs().Name == "xfrmi-default" { + } else if err := netlink.LinkDel(iface); err != nil { + return fmt.Errorf("Delete interface %s fail: %+v", iface.Attrs().Name, err) + } else { + n3iwfSelf.XfrmIfaces.Delete(uint32(childSA.XfrmStateList[0].Ifid)) + } } for _, pduSession := range ue.PduSessionList { n3iwfSelf.DeleteTEID(pduSession.GTPConnection.IncomingTEID) } + + return nil } func (ue *N3IWFUe) FindPDUSession(pduSessionID int64) *PDUSession { diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 7aff0f38..55463578 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1638,7 +1638,10 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m if nextPayload == 42 { n3iwfUe := ikeSecurityAssociation.ThisUE amf := n3iwfUe.AMF - n3iwfUe.Remove() + if err := n3iwfUe.Remove(); err != nil { + ikeLog.Errorf("Delete Ue Context error : %+v", err) + } + ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) } default: diff --git a/pkg/ike/xfrm/xfrm.go b/pkg/ike/xfrm/xfrm.go index 9baea968..453f0708 100644 --- a/pkg/ike/xfrm/xfrm.go +++ b/pkg/ike/xfrm/xfrm.go @@ -116,6 +116,8 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, return errors.New("Set XFRM state rule failed") } + childSecurityAssociation.XfrmStateList = append(childSecurityAssociation.XfrmStateList, *xfrmState) + // Policy xfrmPolicyTemplate := netlink.XfrmPolicyTmpl{ Src: xfrmState.Src, @@ -142,6 +144,8 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, return errors.New("Set XFRM policy rule failed") } + childSecurityAssociation.XfrmPolicyList = append(childSecurityAssociation.XfrmPolicyList, *xfrmPolicy) + // Direction: this_server -> {private_network} // State if n3iwf_is_initiator { @@ -168,6 +172,8 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, return errors.New("Set XFRM state rule failed") } + childSecurityAssociation.XfrmStateList = append(childSecurityAssociation.XfrmStateList, *xfrmState) + // Policy xfrmPolicyTemplate.Spi = int(childSecurityAssociation.OutboundSPI) xfrmPolicyTemplate.Src, xfrmPolicyTemplate.Dst = xfrmPolicyTemplate.Dst, xfrmPolicyTemplate.Src @@ -184,6 +190,8 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, return errors.New("Set XFRM policy rule failed") } + childSecurityAssociation.XfrmPolicyList = append(childSecurityAssociation.XfrmPolicyList, *xfrmPolicy) + printSAInfo(n3iwf_is_initiator, xfrmiId, childSecurityAssociation) return nil From 59637c21f5052251a4df9c1d6bc052f7232e8abd Mon Sep 17 00:00:00 2001 From: allen00991 Date: Sun, 8 May 2022 17:00:28 +0800 Subject: [PATCH 06/33] Change the method of judging the delete payload in handle informational message --- internal/ngap/handler/handler.go | 6 ++-- pkg/context/amf.go | 8 +++-- pkg/context/ue.go | 50 ++++++++++++++++++++------------ pkg/ike/handler/handler.go | 30 +++++++++++++++---- pkg/ike/handler/send.go | 4 +-- pkg/ike/message/message.go | 2 +- 6 files changed, 68 insertions(+), 32 deletions(-) diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index c68ff492..e17346e8 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -337,7 +337,9 @@ func HandleNGReset(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { continue } // TODO: Release Uu Interface (IPSec) - ue.Remove() + if err := ue.Remove(); err != nil { + ngapLog.Errorf("Remove UE Context error : %+v", err) + } } ngap_message.SendNGResetAcknowledge(amf, partOfNGInterface, nil) default: @@ -1153,7 +1155,7 @@ func HandleUEContextReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAP printAndGetCause(cause) } - handler.SendUEInformationExchange(n3iwfUe) + handler.SendUEInformationExchange(n3iwfUe, 1, 0, 0, nil) // TODO: release pdu session and gtp info for ue } diff --git a/pkg/context/amf.go b/pkg/context/amf.go index 158c06cb..d981cd9d 100644 --- a/pkg/context/amf.go +++ b/pkg/context/amf.go @@ -2,6 +2,7 @@ package context import ( "bytes" + "fmt" "git.cs.nctu.edu.tw/calee/sctp" @@ -59,10 +60,13 @@ func (amf *N3IWFAMF) FindUeByAmfUeNgapID(id int64) *N3IWFUe { return nil } -func (amf *N3IWFAMF) RemoveAllRelatedUe() { +func (amf *N3IWFAMF) RemoveAllRelatedUe() error { for _, ue := range amf.N3iwfUeList { - ue.Remove() + if err := ue.Remove(); err != nil { + return fmt.Errorf("RemoveAllRelatedUe error : %+v", err) + } } + return nil } func (amf *N3IWFAMF) AddAMFTNLAssociationItem(info ngapType.CPTransportLayerInformation) *AMFTNLAssociationItem { diff --git a/pkg/context/ue.go b/pkg/context/ue.go index 1d17de20..301f68ae 100644 --- a/pkg/context/ue.go +++ b/pkg/context/ue.go @@ -234,26 +234,9 @@ func (ue *N3IWFUe) Remove() error { n3iwfSelf.DeleteIKESecurityAssociation(ue.N3IWFIKESecurityAssociation.LocalSPI) n3iwfSelf.DeleteInternalUEIPAddr(ue.IPSecInnerIP.String()) - // Delete child SA for _, childSA := range ue.N3IWFChildSecurityAssociation { - iface := childSA.XfrmIface - // Delete child SA xfrmState - for _, xfrmState := range childSA.XfrmStateList { - if err := netlink.XfrmStateDel(&xfrmState); err != nil { - return fmt.Errorf("Delete xfrmstate error : %+v", err) - } - } - // Delete child SA xfrmPolicy - for _, xfrmPolicy := range childSA.XfrmPolicyList { - if err := netlink.XfrmPolicyDel(&xfrmPolicy); err != nil { - return fmt.Errorf("Delete xfrmPolicy error : %+v", err) - } - } - if iface == nil || iface.Attrs().Name == "xfrmi-default" { - } else if err := netlink.LinkDel(iface); err != nil { - return fmt.Errorf("Delete interface %s fail: %+v", iface.Attrs().Name, err) - } else { - n3iwfSelf.XfrmIfaces.Delete(uint32(childSA.XfrmStateList[0].Ifid)) + if err := ue.DeleteChilSA(childSA); err != nil { + return err } } @@ -264,6 +247,35 @@ func (ue *N3IWFUe) Remove() error { return nil } +func (ue *N3IWFUe) DeleteChilSA(childSA *ChildSecurityAssociation) error { + n3iwfSelf := N3IWFSelf() + iface := childSA.XfrmIface + + // Delete child SA xfrmState + for _, xfrmState := range childSA.XfrmStateList { + if err := netlink.XfrmStateDel(&xfrmState); err != nil { + return fmt.Errorf("Delete xfrmstate error : %+v", err) + } + } + // Delete child SA xfrmPolicy + for _, xfrmPolicy := range childSA.XfrmPolicyList { + if err := netlink.XfrmPolicyDel(&xfrmPolicy); err != nil { + return fmt.Errorf("Delete xfrmPolicy error : %+v", err) + } + } + + if iface == nil || iface.Attrs().Name == "xfrmi-default" { + } else if err := netlink.LinkDel(iface); err != nil { + return fmt.Errorf("Delete interface %s fail: %+v", iface.Attrs().Name, err) + } else { + n3iwfSelf.XfrmIfaces.Delete(uint32(childSA.XfrmStateList[0].Ifid)) + } + + delete(ue.N3IWFChildSecurityAssociation, childSA.InboundSPI) + + return nil +} + func (ue *N3IWFUe) FindPDUSession(pduSessionID int64) *PDUSession { if pduSession, ok := ue.PduSessionList[pduSessionID]; ok { return pduSession diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 55463578..9ef6b9bd 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1615,6 +1615,7 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m responseIKEMessage := new(ike_message.IKEMessage) responderSPI := message.ResponderSPI ikeSecurityAssociation, ok := n3iwfSelf.IKESALoad(responderSPI) + var encryptedPayload *ike_message.Encrypted if !ok { ikeLog.Warn("Unrecognized SPI") @@ -1632,16 +1633,32 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m for _, ikePayload := range message.Payloads { switch ikePayload.Type() { case ike_message.TypeSK: - nextPayload := ikePayload.(*ike_message.Encrypted).NextPayload + encryptedPayload = ikePayload.(*ike_message.Encrypted) + default: + ikeLog.Warnf( + "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", + ikePayload.Type()) + } + } + + decryptedIKEPayload, err := DecryptProcedure(ikeSecurityAssociation, message, encryptedPayload) + if err != nil { + ikeLog.Errorf("Decrypt IKE message failed: %+v", err) + return + } - // Check if UE is response to a request that delete the ike SA - if nextPayload == 42 { - n3iwfUe := ikeSecurityAssociation.ThisUE - amf := n3iwfUe.AMF + n3iwfUe := ikeSecurityAssociation.ThisUE + amf := n3iwfUe.AMF + for _, ikePayload := range decryptedIKEPayload { + switch ikePayload.Type() { + case ike_message.TypeD: + deletePayload := ikePayload.(*ike_message.Delete) + if deletePayload.NumberOfSPI != 0 { + + } else { // Check if UE is response to a request that delete the ike SA if err := n3iwfUe.Remove(); err != nil { ikeLog.Errorf("Delete Ue Context error : %+v", err) } - ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) } default: @@ -1650,6 +1667,7 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m ikePayload.Type()) } } + ikeSecurityAssociation.ResponderMessageID++ } func is_supported(transformType uint8, transformID uint16, attributePresent bool, attributeValue uint16) bool { diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index ad25e34c..6d28f427 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -35,7 +35,7 @@ func SendIKEMessageToUE(udpConn *net.UDPConn, srcAddr, dstAddr *net.UDPAddr, mes } func SendUEInformationExchange( - n3iwfUe *context.N3IWFUe) { + n3iwfUe *context.N3IWFUe, protocolID uint8, SPISize uint8, numberOfSPI uint16, SPIs []byte) { ikeSecurityAssociation := n3iwfUe.N3IWFIKESecurityAssociation responseIKEMessage := new(ike_message.IKEMessage) var responseIKEPayload ike_message.IKEPayloadContainer @@ -44,7 +44,7 @@ func SendUEInformationExchange( responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, ike_message.INFORMATIONAL, 0, ikeSecurityAssociation.ResponderMessageID) - responseIKEPayload.BuildDeletePayload(1, 0, 0, nil) + responseIKEPayload.BuildDeletePayload(protocolID, SPISize, numberOfSPI, SPIs) if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { ikeLog.Errorf("Encrypting IKE message failed: %+v", err) return diff --git a/pkg/ike/message/message.go b/pkg/ike/message/message.go index f6a9899e..f1647ef8 100644 --- a/pkg/ike/message/message.go +++ b/pkg/ike/message/message.go @@ -812,7 +812,7 @@ func (del *Delete) unmarshal(rawData []byte) error { if len(rawData) > 0 { ikeLog.Trace("[Delete] unmarshal(): Unmarshal 1 delete") // bounds checking - if len(rawData) <= 4 { + if len(rawData) <= 3 { return errors.New("Delete: No sufficient bytes to decode next delete") } spiSize := rawData[1] From 6b0a9d318bddb6bc0ca01976774c6e238da04dd4 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Sun, 8 May 2022 17:11:25 +0800 Subject: [PATCH 07/33] Add error check in RemoveAllRelatedUe --- internal/ngap/handler/handler.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index e17346e8..66b4b087 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -304,7 +304,9 @@ func HandleNGReset(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { ngapLog.Trace("ResetType Present: NG Interface") // TODO: Release Uu Interface related to this amf(IPSec) // Remove all Ue - amf.RemoveAllRelatedUe() + if err := amf.RemoveAllRelatedUe(); err != nil { + ngapLog.Errorf("RemoveAllRelatedUe error : %+v", err) + } ngap_message.SendNGResetAcknowledge(amf, nil, nil) case ngapType.ResetTypePresentPartOfNGInterface: ngapLog.Trace("ResetType Present: Part of NG Interface") From 95139907a22979c4db36e6ed78384d1842f822a2 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Mon, 9 May 2022 13:03:57 +0800 Subject: [PATCH 08/33] Add sending DPD in Informational message --- internal/ngap/handler/handler.go | 2 +- pkg/ike/handler/handler.go | 2 +- pkg/ike/handler/send.go | 13 +++++++------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index 66b4b087..19baca20 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -1157,7 +1157,7 @@ func HandleUEContextReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAP printAndGetCause(cause) } - handler.SendUEInformationExchange(n3iwfUe, 1, 0, 0, nil) + handler.SendUEInformationExchange(n3iwfUe, 1, 0, 0, nil, false) // TODO: release pdu session and gtp info for ue } diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 9ef6b9bd..675c9932 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1654,13 +1654,13 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m case ike_message.TypeD: deletePayload := ikePayload.(*ike_message.Delete) if deletePayload.NumberOfSPI != 0 { - } else { // Check if UE is response to a request that delete the ike SA if err := n3iwfUe.Remove(); err != nil { ikeLog.Errorf("Delete Ue Context error : %+v", err) } ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) } + case ike_message.NoNext: // DPD response default: ikeLog.Warnf( "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index 6d28f427..9bc715c1 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -35,7 +35,7 @@ func SendIKEMessageToUE(udpConn *net.UDPConn, srcAddr, dstAddr *net.UDPAddr, mes } func SendUEInformationExchange( - n3iwfUe *context.N3IWFUe, protocolID uint8, SPISize uint8, numberOfSPI uint16, SPIs []byte) { + n3iwfUe *context.N3IWFUe, protocolID uint8, SPISize uint8, numberOfSPI uint16, SPIs []byte, isDPD bool) { ikeSecurityAssociation := n3iwfUe.N3IWFIKESecurityAssociation responseIKEMessage := new(ike_message.IKEMessage) var responseIKEPayload ike_message.IKEPayloadContainer @@ -44,12 +44,13 @@ func SendUEInformationExchange( responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, ike_message.INFORMATIONAL, 0, ikeSecurityAssociation.ResponderMessageID) - responseIKEPayload.BuildDeletePayload(protocolID, SPISize, numberOfSPI, SPIs) - if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) - return + if !isDPD { + responseIKEPayload.BuildDeletePayload(protocolID, SPISize, numberOfSPI, SPIs) + if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { + ikeLog.Errorf("Encrypting IKE message failed: %+v", err) + return + } } - SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) } From c7df51a9f52f309a0dbd7a918a3dc8325c0e0ec0 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Tue, 10 May 2022 16:32:11 +0800 Subject: [PATCH 09/33] Modify the SendInformationExchange function parameter --- internal/ngap/handler/handler.go | 4 +++- pkg/ike/handler/send.go | 8 +++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index 19baca20..8090d74f 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -1157,7 +1157,9 @@ func HandleUEContextReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAP printAndGetCause(cause) } - handler.SendUEInformationExchange(n3iwfUe, 1, 0, 0, nil, false) + var deletePayload ike_message.IKEPayloadContainer + deletePayload.BuildDeletePayload(1, 0, 0, nil) + handler.SendUEInformationExchange(n3iwfUe, deletePayload) // TODO: release pdu session and gtp info for ue } diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index 9bc715c1..cfbe2a0a 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -35,18 +35,16 @@ func SendIKEMessageToUE(udpConn *net.UDPConn, srcAddr, dstAddr *net.UDPAddr, mes } func SendUEInformationExchange( - n3iwfUe *context.N3IWFUe, protocolID uint8, SPISize uint8, numberOfSPI uint16, SPIs []byte, isDPD bool) { + n3iwfUe *context.N3IWFUe, payload ike_message.IKEPayloadContainer) { ikeSecurityAssociation := n3iwfUe.N3IWFIKESecurityAssociation responseIKEMessage := new(ike_message.IKEMessage) - var responseIKEPayload ike_message.IKEPayloadContainer // Build IKE message responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, ike_message.INFORMATIONAL, 0, ikeSecurityAssociation.ResponderMessageID) - if !isDPD { - responseIKEPayload.BuildDeletePayload(protocolID, SPISize, numberOfSPI, SPIs) - if err := EncryptProcedure(ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { + if payload != nil { // This message isn't a DPD message + if err := EncryptProcedure(ikeSecurityAssociation, payload, responseIKEMessage); err != nil { ikeLog.Errorf("Encrypting IKE message failed: %+v", err) return } From 4303bf19a551aa2660d6cbd6e378379154b0cb76 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Tue, 17 May 2022 14:07:40 +0800 Subject: [PATCH 10/33] Add SendIKEDeleteRequest function --- internal/ngap/handler/handler.go | 4 +--- pkg/ike/handler/handler.go | 4 ++-- pkg/ike/handler/send.go | 6 ++++++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index 8090d74f..f867d230 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -1157,9 +1157,7 @@ func HandleUEContextReleaseCommand(amf *context.N3IWFAMF, message *ngapType.NGAP printAndGetCause(cause) } - var deletePayload ike_message.IKEPayloadContainer - deletePayload.BuildDeletePayload(1, 0, 0, nil) - handler.SendUEInformationExchange(n3iwfUe, deletePayload) + handler.SendIKEDeleteRequest(n3iwfUe) // TODO: release pdu session and gtp info for ue } diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 675c9932..fea86ce3 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1653,12 +1653,12 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m switch ikePayload.Type() { case ike_message.TypeD: deletePayload := ikePayload.(*ike_message.Delete) - if deletePayload.NumberOfSPI != 0 { - } else { // Check if UE is response to a request that delete the ike SA + if deletePayload.ProtocolID == ike_message.TypeIKE { // Check if UE is response to a request that delete the ike SA if err := n3iwfUe.Remove(); err != nil { ikeLog.Errorf("Delete Ue Context error : %+v", err) } ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) + } else if deletePayload.ProtocolID == ike_message.TypeESP { } case ike_message.NoNext: // DPD response default: diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index cfbe2a0a..7a73721a 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -52,3 +52,9 @@ func SendUEInformationExchange( SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) } + +func SendIKEDeleteRequest(n3iwfUe *context.N3IWFUe) { + var deletePayload ike_message.IKEPayloadContainer + deletePayload.BuildDeletePayload(1, 0, 0, nil) + SendUEInformationExchange(n3iwfUe, deletePayload) +} From b8126543585c13f75b9cb6a4dead3df0a786c106 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Tue, 17 May 2022 14:39:28 +0800 Subject: [PATCH 11/33] Send Informational message when PduSession Release --- internal/ngap/handler/handler.go | 3 ++- pkg/context/ue.go | 1 + pkg/ike/handler/handler.go | 1 + pkg/ike/handler/send.go | 26 +++++++++++++++++++++++++- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index f867d230..1e1804c5 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -2187,10 +2187,11 @@ func HandlePDUSessionResourceReleaseCommand(amf *context.N3IWFAMF, message *ngap releaseList.List = append(releaseList.List, releaseItem) } + handler.SendChildSADeleteRequest(ue, releaseList.List) + ue.PduSessionReleaseList = releaseList // if nASPDU != nil { // TODO: Send NAS to UE // } - ngap_message.SendPDUSessionResourceReleaseResponse(amf, ue, releaseList, nil) } func HandleErrorIndication(amf *context.N3IWFAMF, message *ngapType.NGAPPDU) { diff --git a/pkg/context/ue.go b/pkg/context/ue.go index 301f68ae..20b16e67 100644 --- a/pkg/context/ue.go +++ b/pkg/context/ue.go @@ -72,6 +72,7 @@ type N3IWFUe struct { CoreNetworkAssistanceInformation *ngapType.CoreNetworkAssistanceInformation // TS 38.413 9.3.1.15 IMSVoiceSupported int32 RRCEstablishmentCause int16 + PduSessionReleaseList ngapType.PDUSessionResourceReleasedListRelRes } type PDUSession struct { diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index fea86ce3..6f713720 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1659,6 +1659,7 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m } ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) } else if deletePayload.ProtocolID == ike_message.TypeESP { + ngap_message.SendPDUSessionResourceReleaseResponse(amf, n3iwfUe, n3iwfUe.PduSessionReleaseList, nil) } case ike_message.NoNext: // DPD response default: diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index 7a73721a..0fa76433 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -1,10 +1,12 @@ package handler import ( + "encoding/binary" "net" "github.com/free5gc/n3iwf/pkg/context" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" + "github.com/free5gc/ngap/ngapType" ) func SendIKEMessageToUE(udpConn *net.UDPConn, srcAddr, dstAddr *net.UDPAddr, message *ike_message.IKEMessage) { @@ -55,6 +57,28 @@ func SendUEInformationExchange( func SendIKEDeleteRequest(n3iwfUe *context.N3IWFUe) { var deletePayload ike_message.IKEPayloadContainer - deletePayload.BuildDeletePayload(1, 0, 0, nil) + deletePayload.BuildDeletePayload(ike_message.TypeIKE, 0, 0, nil) + SendUEInformationExchange(n3iwfUe, deletePayload) +} + +func SendChildSADeleteRequest(n3iwfUe *context.N3IWFUe, relaseList []ngapType.PDUSessionResourceReleasedItemRelRes) { + var deleteSPIs []byte + spiLen := uint16(0) + for _, releaseItem := range relaseList { + for _, childSA := range n3iwfUe.N3IWFChildSecurityAssociation { + if childSA.PDUSessionIds[0] == releaseItem.PDUSessionID.Value { + spiByte := make([]byte, 4) + binary.BigEndian.PutUint32(spiByte, uint32(childSA.XfrmStateList[0].Spi)) + deleteSPIs = append(deleteSPIs, spiByte...) + spiLen += 1 + if err := n3iwfUe.DeleteChilSA(childSA); err != nil { + ikeLog.Errorf("Delete Child SA error : %+v", err) + } + } + } + } + + var deletePayload ike_message.IKEPayloadContainer + deletePayload.BuildDeletePayload(ike_message.TypeESP, 4, spiLen, deleteSPIs) SendUEInformationExchange(n3iwfUe, deletePayload) } From 597844a93e9445aa2e767f08234b9bdecbd623d4 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Tue, 17 May 2022 18:21:48 +0800 Subject: [PATCH 12/33] Modify the function name in ue.go --- pkg/context/ue.go | 4 ++-- pkg/ike/handler/send.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/context/ue.go b/pkg/context/ue.go index 20b16e67..0addaedb 100644 --- a/pkg/context/ue.go +++ b/pkg/context/ue.go @@ -236,7 +236,7 @@ func (ue *N3IWFUe) Remove() error { n3iwfSelf.DeleteInternalUEIPAddr(ue.IPSecInnerIP.String()) for _, childSA := range ue.N3IWFChildSecurityAssociation { - if err := ue.DeleteChilSA(childSA); err != nil { + if err := ue.DeleteChildSA(childSA); err != nil { return err } } @@ -248,7 +248,7 @@ func (ue *N3IWFUe) Remove() error { return nil } -func (ue *N3IWFUe) DeleteChilSA(childSA *ChildSecurityAssociation) error { +func (ue *N3IWFUe) DeleteChildSA(childSA *ChildSecurityAssociation) error { n3iwfSelf := N3IWFSelf() iface := childSA.XfrmIface diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index 0fa76433..e78d80e5 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -71,7 +71,7 @@ func SendChildSADeleteRequest(n3iwfUe *context.N3IWFUe, relaseList []ngapType.PD binary.BigEndian.PutUint32(spiByte, uint32(childSA.XfrmStateList[0].Spi)) deleteSPIs = append(deleteSPIs, spiByte...) spiLen += 1 - if err := n3iwfUe.DeleteChilSA(childSA); err != nil { + if err := n3iwfUe.DeleteChildSA(childSA); err != nil { ikeLog.Errorf("Delete Child SA error : %+v", err) } } From 73c35c8bfa9790dd7ee6001cd467083e80e6209b Mon Sep 17 00:00:00 2001 From: allen00991 Date: Tue, 24 May 2022 21:41:14 +0800 Subject: [PATCH 13/33] Implement dead peer detection --- internal/ngap/handler/handler.go | 37 +++++++++++++++++++++++ pkg/context/timer.go | 50 ++++++++++++++++++++++++++++++++ pkg/context/ue.go | 5 ++++ pkg/factory/config.go | 42 ++++++++++++++++++++------- pkg/ike/handler/handler.go | 37 +++++++++++++---------- 5 files changed, 145 insertions(+), 26 deletions(-) create mode 100644 pkg/context/timer.go diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index 1e1804c5..41c47dae 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "math/rand" "net" + "runtime/debug" "time" "git.cs.nctu.edu.tw/calee/sctp" @@ -14,6 +15,7 @@ import ( "github.com/free5gc/n3iwf/internal/logger" ngap_message "github.com/free5gc/n3iwf/internal/ngap/message" "github.com/free5gc/n3iwf/pkg/context" + "github.com/free5gc/n3iwf/pkg/factory" "github.com/free5gc/n3iwf/pkg/ike/handler" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" "github.com/free5gc/ngap/ngapConvert" @@ -739,6 +741,8 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N // Send IKE message to UE handler.SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) + + go StartDPD(n3iwfUe) } // handlePDUSessionResourceSetupRequestTransfer parse and store needed information from NGAP @@ -2800,3 +2804,36 @@ func getPDUSessionResourceReleaseResponseTransfer() []byte { } return encodeData } + +func StartDPD(n3iwfUe *context.N3IWFUe) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + ngapLog.Errorf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + + n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose = make(chan bool) + + liveness := factory.N3iwfConfig.Configuration.LivenessCheck + if liveness.Enable { + timer := time.NewTicker(liveness.TransFreq) + for { + select { + case <-n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose: + close(n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose) + timer.Stop() + return + case <-timer.C: + handler.SendUEInformationExchange(n3iwfUe, nil) + n3iwfUe.N3IWFIKESecurityAssociation.DPDAckTimer = context.NewDPDTimer(liveness.TransFreq, liveness.MaxRetryTimes, + n3iwfUe.N3IWFIKESecurityAssociation, func() { + ngapLog.Errorf("UE is down") + cause := buildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentRadioConnectionWithUeLost) + ngap_message.SendUEContextReleaseRequest(n3iwfUe.AMF, n3iwfUe, *cause) + timer.Stop() + }) + } + } + } +} diff --git a/pkg/context/timer.go b/pkg/context/timer.go new file mode 100644 index 00000000..cee7724a --- /dev/null +++ b/pkg/context/timer.go @@ -0,0 +1,50 @@ +package context + +import ( + "fmt" + "runtime/debug" + "sync/atomic" + "time" +) + +type Timer struct { + ticker *time.Ticker + done chan bool +} + +func NewDPDTimer(d time.Duration, maxRetryTimes int32, ikeSA *IKESecurityAssociation, cancelFunc func()) *Timer { + t := &Timer{} + t.done = make(chan bool, 1) + t.ticker = time.NewTicker(d) + + go func(ticker *time.Ticker) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + fmt.Errorf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + + defer ticker.Stop() + + for { + select { + case <-t.done: + return + case <-ticker.C: + atomic.AddInt32(&ikeSA.CurrentRetryTimes, 1) + if atomic.LoadInt32(&ikeSA.CurrentRetryTimes) == maxRetryTimes { + cancelFunc() + return + } + } + } + }(t.ticker) + + return t +} + +func (t *Timer) Stop() { + t.done <- true + close(t.done) +} diff --git a/pkg/context/ue.go b/pkg/context/ue.go index 0addaedb..56d09f5b 100644 --- a/pkg/context/ue.go +++ b/pkg/context/ue.go @@ -169,6 +169,10 @@ type IKESecurityAssociation struct { // UE context ThisUE *N3IWFUe + + DPDAckTimer *Timer // The time from sending the DPD request to receiving the response + CurrentRetryTimes int32 // Accumulate the number of times the DPD response wasn't received + DPDTimerIsClose chan bool } type ChildSecurityAssociation struct { @@ -229,6 +233,7 @@ func (ue *N3IWFUe) init(ranUeNgapId int64) { func (ue *N3IWFUe) Remove() error { // remove from AMF context ue.DetachAMF() + ue.N3IWFIKESecurityAssociation.DPDTimerIsClose <- true // remove from N3IWF context n3iwfSelf := N3IWFSelf() n3iwfSelf.DeleteN3iwfUe(ue.RanUeNgapId) diff --git a/pkg/factory/config.go b/pkg/factory/config.go index 577a7618..f6559ab0 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -6,6 +6,7 @@ package factory import ( "fmt" + "time" "github.com/asaskevich/govalidator" @@ -60,17 +61,18 @@ type Configuration struct { N3IWFInfo context.N3IWFNFInfo `yaml:"N3IWFInformation" valid:"required"` AMFSCTPAddresses []context.AMFSCTPAddresses `yaml:"AMFSCTPAddresses" valid:"required"` - TCPPort uint16 `yaml:"NASTCPPort" valid:"port,required"` - IKEBindAddr string `yaml:"IKEBindAddress" valid:"host,required"` - IPSecGatewayAddr string `yaml:"IPSecTunnelAddress" valid:"host,required"` - UEIPAddressRange string `yaml:"UEIPAddressRange" valid:"cidr,required"` // e.g. 10.0.1.0/24 - XfrmIfaceName string `yaml:"XFRMInterfaceName" valid:"stringlength(1|10),optional"` // must != 0 - XfrmIfaceId uint32 `yaml:"XFRMInterfaceID" valid:"numeric,optional"` // must != 0 - GTPBindAddr string `yaml:"GTPBindAddress" valid:"host,required"` - FQDN string `yaml:"FQDN" valid:"url,required"` // e.g. n3iwf.free5gc.org - PrivateKey string `yaml:"PrivateKey" valid:"type(string),minstringlength(1),optional"` - CertificateAuthority string `yaml:"CertificateAuthority" valid:"type(string),minstringlength(1),optional"` - Certificate string `yaml:"Certificate" valid:"type(string),minstringlength(1),optional"` + TCPPort uint16 `yaml:"NASTCPPort" valid:"port,required"` + IKEBindAddr string `yaml:"IKEBindAddress" valid:"host,required"` + IPSecGatewayAddr string `yaml:"IPSecTunnelAddress" valid:"host,required"` + UEIPAddressRange string `yaml:"UEIPAddressRange" valid:"cidr,required"` // e.g. 10.0.1.0/24 + XfrmIfaceName string `yaml:"XFRMInterfaceName" valid:"stringlength(1|10),optional"` // must != 0 + XfrmIfaceId uint32 `yaml:"XFRMInterfaceID" valid:"numeric,optional"` // must != 0 + GTPBindAddr string `yaml:"GTPBindAddress" valid:"host,required"` + FQDN string `yaml:"FQDN" valid:"url,required"` // e.g. n3iwf.free5gc.org + PrivateKey string `yaml:"PrivateKey" valid:"type(string),minstringlength(1),optional"` + CertificateAuthority string `yaml:"CertificateAuthority" valid:"type(string),minstringlength(1),optional"` + Certificate string `yaml:"Certificate" valid:"type(string),minstringlength(1),optional"` + LivenessCheck TimerValue `yaml:"LivenessCheck" valid:"required"` } func (c *Configuration) validate() (bool, error) { @@ -84,6 +86,10 @@ func (c *Configuration) validate() (bool, error) { return govalidator.IsCIDR(str) }) + if _, err := c.LivenessCheck.validate(); err != nil { + return false, err + } + result, err := govalidator.ValidateStruct(c) return result, appendInvalid(err) } @@ -109,3 +115,17 @@ func (c *Config) GetVersion() string { } return "" } + +type TimerValue struct { + Enable bool `yaml:"enable" valid:"type(bool)"` + TransFreq time.Duration `yaml:"transFreq" valid:"type(time.Duration)"` + MaxRetryTimes int32 `yaml:"maxRetryTimes,omitempty" valid:"type(int32)"` +} + +func (t *TimerValue) validate() (bool, error) { + if _, err := govalidator.ValidateStruct(t); err != nil { + return false, appendInvalid(err) + } + + return true, nil +} diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 6f713720..205dccc8 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "net" + "sync/atomic" "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" @@ -1649,23 +1650,29 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m n3iwfUe := ikeSecurityAssociation.ThisUE amf := n3iwfUe.AMF - for _, ikePayload := range decryptedIKEPayload { - switch ikePayload.Type() { - case ike_message.TypeD: - deletePayload := ikePayload.(*ike_message.Delete) - if deletePayload.ProtocolID == ike_message.TypeIKE { // Check if UE is response to a request that delete the ike SA - if err := n3iwfUe.Remove(); err != nil { - ikeLog.Errorf("Delete Ue Context error : %+v", err) + + if len(decryptedIKEPayload) == 0 { // Receive DPD message + n3iwfUe.N3IWFIKESecurityAssociation.DPDAckTimer.Stop() + n3iwfUe.N3IWFIKESecurityAssociation.DPDAckTimer = nil + atomic.StoreInt32(&n3iwfUe.N3IWFIKESecurityAssociation.CurrentRetryTimes, 0) + } else { + for _, ikePayload := range decryptedIKEPayload { + switch ikePayload.Type() { + case ike_message.TypeD: + deletePayload := ikePayload.(*ike_message.Delete) + if deletePayload.ProtocolID == ike_message.TypeIKE { // Check if UE is response to a request that delete the ike SA + if err := n3iwfUe.Remove(); err != nil { + ikeLog.Errorf("Delete Ue Context error : %+v", err) + } + ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) + } else if deletePayload.ProtocolID == ike_message.TypeESP { + ngap_message.SendPDUSessionResourceReleaseResponse(amf, n3iwfUe, n3iwfUe.PduSessionReleaseList, nil) } - ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) - } else if deletePayload.ProtocolID == ike_message.TypeESP { - ngap_message.SendPDUSessionResourceReleaseResponse(amf, n3iwfUe, n3iwfUe.PduSessionReleaseList, nil) + default: + ikeLog.Warnf( + "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", + ikePayload.Type()) } - case ike_message.NoNext: // DPD response - default: - ikeLog.Warnf( - "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", - ikePayload.Type()) } } ikeSecurityAssociation.ResponderMessageID++ From d88869a5b4e8b290f92c3aa7a5c88f78faa8ccc6 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Tue, 24 May 2022 22:05:46 +0800 Subject: [PATCH 14/33] Remove defer function in DPDTimer --- pkg/context/timer.go | 9 --------- 1 file changed, 9 deletions(-) diff --git a/pkg/context/timer.go b/pkg/context/timer.go index cee7724a..182d772a 100644 --- a/pkg/context/timer.go +++ b/pkg/context/timer.go @@ -1,8 +1,6 @@ package context import ( - "fmt" - "runtime/debug" "sync/atomic" "time" ) @@ -18,13 +16,6 @@ func NewDPDTimer(d time.Duration, maxRetryTimes int32, ikeSA *IKESecurityAssocia t.ticker = time.NewTicker(d) go func(ticker *time.Ticker) { - defer func() { - if p := recover(); p != nil { - // Print stack for panic to log. Fatalf() will let program exit. - fmt.Errorf("panic: %v\n%s", p, string(debug.Stack())) - } - }() - defer ticker.Stop() for { From f631560be27f75fd0daa893efad37613b5d9969d Mon Sep 17 00:00:00 2001 From: allen00991 Date: Fri, 10 Jun 2022 18:07:26 +0800 Subject: [PATCH 15/33] Change the DPD starting time --- internal/ngap/handler/handler.go | 111 ++++++++----------------------- internal/ngap/message/build.go | 26 ++++++++ pkg/ike/handler/handler.go | 1 + pkg/ike/handler/send.go | 38 +++++++++++ 4 files changed, 93 insertions(+), 83 deletions(-) diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index 41c47dae..01ca6bd4 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -4,7 +4,6 @@ import ( "encoding/binary" "math/rand" "net" - "runtime/debug" "time" "git.cs.nctu.edu.tw/calee/sctp" @@ -15,7 +14,6 @@ import ( "github.com/free5gc/n3iwf/internal/logger" ngap_message "github.com/free5gc/n3iwf/internal/ngap/message" "github.com/free5gc/n3iwf/pkg/context" - "github.com/free5gc/n3iwf/pkg/factory" "github.com/free5gc/n3iwf/pkg/ike/handler" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" "github.com/free5gc/ngap/ngapConvert" @@ -99,7 +97,8 @@ func HandleNGSetupResponse(sctpAddr string, conn *sctp.SCTPConn, message *ngapTy if len(iesCriticalityDiagnostics.List) != 0 { ngapLog.Traceln("[NGAP] Sending error indication to AMF, because some mandatory IEs were not included") - cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, + ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) procedureCode := ngapType.ProcedureCodeNGSetup triggeringMessage := ngapType.TriggeringMessagePresentSuccessfulOutcome @@ -188,7 +187,7 @@ func HandleNGSetupFailure(sctpAddr string, conn *sctp.SCTPConn, message *ngapTyp // TODO: Send error indication ngapLog.Traceln("[NGAP] Sending error indication to AMF, because some mandatory IEs were not included") - cause = buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) + cause = ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) procedureCode := ngapType.ProcedureCodeNGSetup triggeringMessage := ngapType.TriggeringMessagePresentUnsuccessfullOutcome @@ -550,7 +549,7 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N if len(iesCriticalityDiagnostics.List) > 0 { ngapLog.Traceln("[NGAP] Sending unsuccessful outcome to AMF, because some mandatory IEs were not included") - cause := buildCause(ngapType.CausePresentProtocol, + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorFalselyConstructedMessage) criticalityDiagnostics := buildCriticalityDiagnostics(nil, nil, nil, &iesCriticalityDiagnostics) @@ -595,7 +594,7 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N n3iwfUe.Ambr = ueAggregateMaximumBitRate } else { ngapLog.Errorln("IE[UEAggregateMaximumBitRate] is nil") - cause := buildCause(ngapType.CausePresentProtocol, + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorFalselyConstructedMessage) criticalityDiagnosticsIEItem := buildCriticalityDiagnosticsIEItem(ngapType.CriticalityPresentReject, @@ -644,7 +643,7 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N if err != nil { ngapLog.Errorf("Create PDU Session Error: %+v\n", err) - cause := buildCause(ngapType.CausePresentRadioNetwork, + cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentMultiplePDUSessionIDInstances) unsuccessfulTransfer, buildErr := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) @@ -742,7 +741,7 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N handler.SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) - go StartDPD(n3iwfUe) + //go StartDPD(n3iwfUe) } // handlePDUSessionResourceSetupRequestTransfer parse and store needed information from NGAP @@ -796,7 +795,7 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio } if len(iesCriticalityDiagnostics.List) > 0 { - cause := buildCause(ngapType.CausePresentProtocol, + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorFalselyConstructedMessage) criticalityDiagnostics := buildCriticalityDiagnostics(nil, nil, nil, &iesCriticalityDiagnostics) responseTransfer, err := @@ -822,7 +821,7 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio pduSession.SecurityIntegrity = true default: ngapLog.Error("Unknown security integrity indication") - cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentSemanticError) + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentSemanticError) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) @@ -839,7 +838,7 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio pduSession.SecurityCipher = true default: ngapLog.Error("Unknown security confidentiality indication") - cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentSemanticError) + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentSemanticError) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) @@ -878,7 +877,7 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio upfUDPAddr, err := net.ResolveUDPAddr("udp", upfIPv4+":2152") if err != nil { ngapLog.Errorf("Resolve UDP address failed: %+v", err) - cause := buildCause(ngapType.CausePresentTransport, + cause := ngap_message.BuildCause(ngapType.CausePresentTransport, ngapType.CauseTransportPresentTransportResourceUnavailable) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { @@ -891,7 +890,7 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio ueTEID := n3iwfSelf.NewTEID(ue) if ueTEID == 0 { ngapLog.Error("Invalid TEID (0).") - cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentUnspecified) + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentUnspecified) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) @@ -908,7 +907,7 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio userPlaneConnection, upfUDPAddr, err := gtp_service.SetupGTPTunnelWithUPF(upfIPv4) if err != nil { ngapLog.Errorf("Setup GTP connection with UPF failed: %+v", err) - cause := buildCause(ngapType.CausePresentTransport, + cause := ngap_message.BuildCause(ngapType.CausePresentTransport, ngapType.CauseTransportPresentTransportResourceUnavailable) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { @@ -921,7 +920,7 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio ueTEID := n3iwfSelf.NewTEID(ue) if ueTEID == 0 { ngapLog.Error("Invalid TEID (0).") - cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentUnspecified) + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentUnspecified) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) @@ -941,7 +940,8 @@ func handlePDUSessionResourceSetupRequestTransfer(ue *context.N3IWFUe, pduSessio pduSession.GTPConnection = gtpConnection } else { ngapLog.Error("Cannot parse \"PDU session resource setup request transfer\" message \"UL NG-U UP TNL Information\"") - cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, + ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) responseTransfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %+v\n", err) @@ -1509,7 +1509,7 @@ func HandlePDUSessionResourceSetupRequest(amf *context.N3IWFAMF, message *ngapTy if err != nil { ngapLog.Errorf("Create PDU Session Error: %+v\n", err) - cause := buildCause(ngapType.CausePresentRadioNetwork, + cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentMultiplePDUSessionIDInstances) unsuccessfulTransfer, buildErr := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if buildErr != nil { @@ -1624,7 +1624,7 @@ func HandlePDUSessionResourceSetupRequest(amf *context.N3IWFAMF, message *ngapTy ngapLog.Errorf("Encrypting IKE message failed: %+v", err) n3iwfUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession = n3iwfUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession[1:] - cause := buildCause(ngapType.CausePresentTransport, + cause := ngap_message.BuildCause(ngapType.CausePresentTransport, ngapType.CauseTransportPresentTransportResourceUnavailable) transfer, err := ngap_message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { @@ -1766,7 +1766,8 @@ func HandlePDUSessionResourceModifyRequest(amf *context.N3IWFAMF, message *ngapT if pduSession = n3iwfUe.FindPDUSession(pduSessionID); pduSession == nil { ngapLog.Errorf("[PDUSessionID: %d] Unknown PDU session ID", pduSessionID) - cause := buildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentUnknownPDUSessionID) + cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, + ngapType.CauseRadioNetworkPresentUnknownPDUSessionID) unsuccessfulTransfer, buildErr := ngap_message.BuildPDUSessionResourceModifyUnsuccessfulTransfer(*cause, nil) if buildErr != nil { ngapLog.Errorf("Build PDUSessionResourceModifyUnsuccessfulTransfer Error: %+v\n", buildErr) @@ -1850,7 +1851,8 @@ func handlePDUSessionResourceModifyRequestTransfer( if len(iesCriticalityDiagnostics.List) != 0 { // build unsuccessful transfer - cause := buildCause(ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) + cause := ngap_message.BuildCause(ngapType.CausePresentProtocol, + ngapType.CauseProtocolPresentAbstractSyntaxErrorReject) criticalityDiagnostics := buildCriticalityDiagnostics(nil, nil, nil, &iesCriticalityDiagnostics) unsuccessfulTransfer, err := ngap_message.BuildPDUSessionResourceModifyUnsuccessfulTransfer(*cause, &criticalityDiagnostics) @@ -1889,7 +1891,7 @@ func handlePDUSessionResourceModifyRequestTransfer( } else { ngapLog.Errorf("Requested Qos flow not found, QosFlowID: %d", updateItem.QosFlowIdentifier) - cause := buildCause( + cause := ngap_message.BuildCause( ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentUnkownQosFlowID) item := ngapType.QosFlowWithCauseItem{ @@ -2152,7 +2154,8 @@ func HandlePDUSessionResourceReleaseCommand(amf *context.N3IWFAMF, message *ngap ue, ok := n3iwfSelf.UePoolLoad(rANUENGAPID.Value) if !ok { ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", rANUENGAPID.Value) - cause := buildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentUnknownLocalUENGAPID) + cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, + ngapType.CauseRadioNetworkPresentUnknownLocalUENGAPID) ngap_message.SendErrorIndication(amf, nil, nil, cause, nil) return } @@ -2160,7 +2163,7 @@ func HandlePDUSessionResourceReleaseCommand(amf *context.N3IWFAMF, message *ngap if ue.AmfUeNgapId != aMFUENGAPID.Value { ngapLog.Errorf("Inconsistent remote UE NGAP ID, AMFUENGAPID: %d, ue.AmfUeNgapId: %d", aMFUENGAPID.Value, ue.AmfUeNgapId) - cause := buildCause(ngapType.CausePresentRadioNetwork, + cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentInconsistentRemoteUENGAPID) ngap_message.SendErrorIndication(amf, nil, &rANUENGAPID.Value, cause, nil) return @@ -2339,7 +2342,8 @@ func HandleUERadioCapabilityCheckRequest(amf *context.N3IWFAMF, message *ngapTyp ue, ok := n3iwfSelf.UePoolLoad(rANUENGAPID.Value) if !ok { ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", rANUENGAPID.Value) - cause := buildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentUnknownLocalUENGAPID) + cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, + ngapType.CauseRadioNetworkPresentUnknownLocalUENGAPID) ngap_message.SendErrorIndication(amf, nil, nil, cause, nil) return } @@ -2713,32 +2717,6 @@ func buildCriticalityDiagnosticsIEItem(ieCriticality aper.Enumerated, ieID int64 return item } -func buildCause(present int, value aper.Enumerated) (cause *ngapType.Cause) { - cause = new(ngapType.Cause) - cause.Present = present - - switch present { - case ngapType.CausePresentRadioNetwork: - cause.RadioNetwork = new(ngapType.CauseRadioNetwork) - cause.RadioNetwork.Value = value - case ngapType.CausePresentTransport: - cause.Transport = new(ngapType.CauseTransport) - cause.Transport.Value = value - case ngapType.CausePresentNas: - cause.Nas = new(ngapType.CauseNas) - cause.Nas.Value = value - case ngapType.CausePresentProtocol: - cause.Protocol = new(ngapType.CauseProtocol) - cause.Protocol.Value = value - case ngapType.CausePresentMisc: - cause.Misc = new(ngapType.CauseMisc) - cause.Misc.Value = value - case ngapType.CausePresentNothing: - } - - return -} - func printAndGetCause(cause *ngapType.Cause) (present int, value aper.Enumerated) { present = cause.Present switch cause.Present { @@ -2804,36 +2782,3 @@ func getPDUSessionResourceReleaseResponseTransfer() []byte { } return encodeData } - -func StartDPD(n3iwfUe *context.N3IWFUe) { - defer func() { - if p := recover(); p != nil { - // Print stack for panic to log. Fatalf() will let program exit. - ngapLog.Errorf("panic: %v\n%s", p, string(debug.Stack())) - } - }() - - n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose = make(chan bool) - - liveness := factory.N3iwfConfig.Configuration.LivenessCheck - if liveness.Enable { - timer := time.NewTicker(liveness.TransFreq) - for { - select { - case <-n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose: - close(n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose) - timer.Stop() - return - case <-timer.C: - handler.SendUEInformationExchange(n3iwfUe, nil) - n3iwfUe.N3IWFIKESecurityAssociation.DPDAckTimer = context.NewDPDTimer(liveness.TransFreq, liveness.MaxRetryTimes, - n3iwfUe.N3IWFIKESecurityAssociation, func() { - ngapLog.Errorf("UE is down") - cause := buildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentRadioConnectionWithUeLost) - ngap_message.SendUEContextReleaseRequest(n3iwfUe.AMF, n3iwfUe, *cause) - timer.Stop() - }) - } - } - } -} diff --git a/internal/ngap/message/build.go b/internal/ngap/message/build.go index da28f58f..44a4347e 100644 --- a/internal/ngap/message/build.go +++ b/internal/ngap/message/build.go @@ -1818,3 +1818,29 @@ func BuildPDUSessionResourceModifyUnsuccessfulTransfer(cause ngapType.Cause, return aper.MarshalWithParams(transfer, "valueExt") } + +func BuildCause(present int, value aper.Enumerated) (cause *ngapType.Cause) { + cause = new(ngapType.Cause) + cause.Present = present + + switch present { + case ngapType.CausePresentRadioNetwork: + cause.RadioNetwork = new(ngapType.CauseRadioNetwork) + cause.RadioNetwork.Value = value + case ngapType.CausePresentTransport: + cause.Transport = new(ngapType.CauseTransport) + cause.Transport.Value = value + case ngapType.CausePresentNas: + cause.Nas = new(ngapType.CauseNas) + cause.Nas.Value = value + case ngapType.CausePresentProtocol: + cause.Protocol = new(ngapType.CauseProtocol) + cause.Protocol.Value = value + case ngapType.CausePresentMisc: + cause.Misc = new(ngapType.CauseMisc) + cause.Misc.Value = value + case ngapType.CausePresentNothing: + } + + return +} diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 205dccc8..cd130aeb 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1241,6 +1241,7 @@ func HandleIKEAUTH(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message // Send Initial Context Setup Response to AMF ngap_message.SendInitialContextSetupResponse(thisUE.AMF, thisUE, nil, nil, nil) } + go StartDPD(thisUE) } } diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index e78d80e5..77e73573 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -3,8 +3,12 @@ package handler import ( "encoding/binary" "net" + "runtime/debug" + "time" + ngap_message "github.com/free5gc/n3iwf/internal/ngap/message" "github.com/free5gc/n3iwf/pkg/context" + "github.com/free5gc/n3iwf/pkg/factory" ike_message "github.com/free5gc/n3iwf/pkg/ike/message" "github.com/free5gc/ngap/ngapType" ) @@ -82,3 +86,37 @@ func SendChildSADeleteRequest(n3iwfUe *context.N3IWFUe, relaseList []ngapType.PD deletePayload.BuildDeletePayload(ike_message.TypeESP, 4, spiLen, deleteSPIs) SendUEInformationExchange(n3iwfUe, deletePayload) } + +func StartDPD(n3iwfUe *context.N3IWFUe) { + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + ikeLog.Errorf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + + n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose = make(chan bool) + + liveness := factory.N3iwfConfig.Configuration.LivenessCheck + if liveness.Enable { + timer := time.NewTicker(liveness.TransFreq) + for { + select { + case <-n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose: + close(n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose) + timer.Stop() + return + case <-timer.C: + SendUEInformationExchange(n3iwfUe, nil) + n3iwfUe.N3IWFIKESecurityAssociation.DPDAckTimer = context.NewDPDTimer(liveness.TransFreq, liveness.MaxRetryTimes, + n3iwfUe.N3IWFIKESecurityAssociation, func() { + ikeLog.Errorf("UE is down") + cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, + ngapType.CauseRadioNetworkPresentRadioConnectionWithUeLost) + ngap_message.SendUEContextReleaseRequest(n3iwfUe.AMF, n3iwfUe, *cause) + timer.Stop() + }) + } + } + } +} From 551ca7730488cc4e457d59494c0984d65f62345a Mon Sep 17 00:00:00 2001 From: allen00991 Date: Sat, 11 Jun 2022 13:11:39 +0800 Subject: [PATCH 16/33] Remove redundant comment in ngap handler --- internal/ngap/handler/handler.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/ngap/handler/handler.go b/internal/ngap/handler/handler.go index 01ca6bd4..dbef1b65 100644 --- a/internal/ngap/handler/handler.go +++ b/internal/ngap/handler/handler.go @@ -740,8 +740,6 @@ func HandleInitialContextSetupRequest(amf *context.N3IWFAMF, message *ngapType.N // Send IKE message to UE handler.SendIKEMessageToUE(n3iwfUe.IKEConnection.Conn, n3iwfUe.IKEConnection.N3IWFAddr, n3iwfUe.IKEConnection.UEAddr, responseIKEMessage) - - //go StartDPD(n3iwfUe) } // handlePDUSessionResourceSetupRequestTransfer parse and store needed information from NGAP From 9f8ac37e61692e471d21a75d623019d07ba51e8b Mon Sep 17 00:00:00 2001 From: allen00991 Date: Sat, 18 Jun 2022 21:07:22 +0800 Subject: [PATCH 17/33] Modify the maxRetryTime to 0 in DPDTimer --- pkg/context/timer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/context/timer.go b/pkg/context/timer.go index 182d772a..da400d58 100644 --- a/pkg/context/timer.go +++ b/pkg/context/timer.go @@ -24,7 +24,7 @@ func NewDPDTimer(d time.Duration, maxRetryTimes int32, ikeSA *IKESecurityAssocia return case <-ticker.C: atomic.AddInt32(&ikeSA.CurrentRetryTimes, 1) - if atomic.LoadInt32(&ikeSA.CurrentRetryTimes) == maxRetryTimes { + if atomic.LoadInt32(&ikeSA.CurrentRetryTimes) > 0 { cancelFunc() return } From 25395bdea0b63a1d2d82fb42dddbbb5991bd5725 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Sat, 25 Jun 2022 21:24:47 +0800 Subject: [PATCH 18/33] Rename the context of the DPD timer --- pkg/context/timer.go | 2 +- pkg/context/ue.go | 8 ++++---- pkg/ike/handler/handler.go | 4 ++-- pkg/ike/handler/send.go | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pkg/context/timer.go b/pkg/context/timer.go index da400d58..03a2a60b 100644 --- a/pkg/context/timer.go +++ b/pkg/context/timer.go @@ -10,7 +10,7 @@ type Timer struct { done chan bool } -func NewDPDTimer(d time.Duration, maxRetryTimes int32, ikeSA *IKESecurityAssociation, cancelFunc func()) *Timer { +func NewDPDPeriodicTimer(d time.Duration, maxRetryTimes int32, ikeSA *IKESecurityAssociation, cancelFunc func()) *Timer { t := &Timer{} t.done = make(chan bool, 1) t.ticker = time.NewTicker(d) diff --git a/pkg/context/ue.go b/pkg/context/ue.go index 56d09f5b..fb9b34e2 100644 --- a/pkg/context/ue.go +++ b/pkg/context/ue.go @@ -170,9 +170,9 @@ type IKESecurityAssociation struct { // UE context ThisUE *N3IWFUe - DPDAckTimer *Timer // The time from sending the DPD request to receiving the response - CurrentRetryTimes int32 // Accumulate the number of times the DPD response wasn't received - DPDTimerIsClose chan bool + DPDReqRetransTimer *Timer // The time from sending the DPD request to receiving the response + CurrentRetryTimes int32 // Accumulate the number of times the DPD response wasn't received + IKESAClosedCh chan struct{} } type ChildSecurityAssociation struct { @@ -233,7 +233,7 @@ func (ue *N3IWFUe) init(ranUeNgapId int64) { func (ue *N3IWFUe) Remove() error { // remove from AMF context ue.DetachAMF() - ue.N3IWFIKESecurityAssociation.DPDTimerIsClose <- true + ue.N3IWFIKESecurityAssociation.IKESAClosedCh <- struct{}{} // remove from N3IWF context n3iwfSelf := N3IWFSelf() n3iwfSelf.DeleteN3iwfUe(ue.RanUeNgapId) diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index cd130aeb..3594f676 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1653,8 +1653,8 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m amf := n3iwfUe.AMF if len(decryptedIKEPayload) == 0 { // Receive DPD message - n3iwfUe.N3IWFIKESecurityAssociation.DPDAckTimer.Stop() - n3iwfUe.N3IWFIKESecurityAssociation.DPDAckTimer = nil + n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer.Stop() + n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = nil atomic.StoreInt32(&n3iwfUe.N3IWFIKESecurityAssociation.CurrentRetryTimes, 0) } else { for _, ikePayload := range decryptedIKEPayload { diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index 77e73573..3a8a6d8c 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -95,20 +95,20 @@ func StartDPD(n3iwfUe *context.N3IWFUe) { } }() - n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose = make(chan bool) + n3iwfUe.N3IWFIKESecurityAssociation.IKESAClosedCh = make(chan struct{}) liveness := factory.N3iwfConfig.Configuration.LivenessCheck if liveness.Enable { timer := time.NewTicker(liveness.TransFreq) for { select { - case <-n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose: - close(n3iwfUe.N3IWFIKESecurityAssociation.DPDTimerIsClose) + case <-n3iwfUe.N3IWFIKESecurityAssociation.IKESAClosedCh: + close(n3iwfUe.N3IWFIKESecurityAssociation.IKESAClosedCh) timer.Stop() return case <-timer.C: SendUEInformationExchange(n3iwfUe, nil) - n3iwfUe.N3IWFIKESecurityAssociation.DPDAckTimer = context.NewDPDTimer(liveness.TransFreq, liveness.MaxRetryTimes, + n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = context.NewDPDPeriodicTimer(liveness.TransFreq, liveness.MaxRetryTimes, n3iwfUe.N3IWFIKESecurityAssociation, func() { ikeLog.Errorf("UE is down") cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, From be4c4d8efcacf9ada32488b9ae039e88fbeef9c6 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Fri, 1 Jul 2022 16:36:53 +0800 Subject: [PATCH 19/33] Add the condition that the DPDReqRetransTimer should be close after receiving the UE's response --- pkg/context/timer.go | 3 ++- pkg/ike/handler/handler.go | 6 +++++- pkg/ike/handler/send.go | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/context/timer.go b/pkg/context/timer.go index 03a2a60b..b6c84f3c 100644 --- a/pkg/context/timer.go +++ b/pkg/context/timer.go @@ -10,7 +10,8 @@ type Timer struct { done chan bool } -func NewDPDPeriodicTimer(d time.Duration, maxRetryTimes int32, ikeSA *IKESecurityAssociation, cancelFunc func()) *Timer { +func NewDPDPeriodicTimer(d time.Duration, maxRetryTimes int32, ikeSA *IKESecurityAssociation, + cancelFunc func()) *Timer { t := &Timer{} t.done = make(chan bool, 1) t.ticker = time.NewTicker(d) diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 3594f676..9c6a3407 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1652,10 +1652,14 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m n3iwfUe := ikeSecurityAssociation.ThisUE amf := n3iwfUe.AMF - if len(decryptedIKEPayload) == 0 { // Receive DPD message + if n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer != nil { n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer.Stop() n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = nil atomic.StoreInt32(&n3iwfUe.N3IWFIKESecurityAssociation.CurrentRetryTimes, 0) + } + + if len(decryptedIKEPayload) == 0 { // Receive DPD message + return } else { for _, ikePayload := range decryptedIKEPayload { switch ikePayload.Type() { diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index 3a8a6d8c..373107c7 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -108,8 +108,8 @@ func StartDPD(n3iwfUe *context.N3IWFUe) { return case <-timer.C: SendUEInformationExchange(n3iwfUe, nil) - n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = context.NewDPDPeriodicTimer(liveness.TransFreq, liveness.MaxRetryTimes, - n3iwfUe.N3IWFIKESecurityAssociation, func() { + n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = context.NewDPDPeriodicTimer(liveness.TransFreq, + liveness.MaxRetryTimes, n3iwfUe.N3IWFIKESecurityAssociation, func() { ikeLog.Errorf("UE is down") cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentRadioConnectionWithUeLost) From 0cb40a91e2ca9b4bbebcbf00d6dcb09da37ec8a7 Mon Sep 17 00:00:00 2001 From: free5gc-org Date: Wed, 6 Jul 2022 05:06:40 +0000 Subject: [PATCH 20/33] remove redundant else --- pkg/ike/handler/handler.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pkg/ike/handler/handler.go b/pkg/ike/handler/handler.go index 9c6a3407..f8acfdc6 100644 --- a/pkg/ike/handler/handler.go +++ b/pkg/ike/handler/handler.go @@ -1660,24 +1660,24 @@ func HandleInformational(udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, m if len(decryptedIKEPayload) == 0 { // Receive DPD message return - } else { - for _, ikePayload := range decryptedIKEPayload { - switch ikePayload.Type() { - case ike_message.TypeD: - deletePayload := ikePayload.(*ike_message.Delete) - if deletePayload.ProtocolID == ike_message.TypeIKE { // Check if UE is response to a request that delete the ike SA - if err := n3iwfUe.Remove(); err != nil { - ikeLog.Errorf("Delete Ue Context error : %+v", err) - } - ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) - } else if deletePayload.ProtocolID == ike_message.TypeESP { - ngap_message.SendPDUSessionResourceReleaseResponse(amf, n3iwfUe, n3iwfUe.PduSessionReleaseList, nil) + } + + for _, ikePayload := range decryptedIKEPayload { + switch ikePayload.Type() { + case ike_message.TypeD: + deletePayload := ikePayload.(*ike_message.Delete) + if deletePayload.ProtocolID == ike_message.TypeIKE { // Check if UE is response to a request that delete the ike SA + if err := n3iwfUe.Remove(); err != nil { + ikeLog.Errorf("Delete Ue Context error : %+v", err) } - default: - ikeLog.Warnf( - "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", - ikePayload.Type()) + ngap_message.SendUEContextReleaseComplete(amf, n3iwfUe, nil) + } else if deletePayload.ProtocolID == ike_message.TypeESP { + ngap_message.SendPDUSessionResourceReleaseResponse(amf, n3iwfUe, n3iwfUe.PduSessionReleaseList, nil) } + default: + ikeLog.Warnf( + "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", + ikePayload.Type()) } } ikeSecurityAssociation.ResponderMessageID++ From 6b7123a28e81144a9318d7e443d58e4a7ddd0c2e Mon Sep 17 00:00:00 2001 From: allen00991 Date: Thu, 7 Jul 2022 21:44:39 +0800 Subject: [PATCH 21/33] Stop DPDReqRetransTimerin cancelFunc --- pkg/ike/handler/send.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index 373107c7..3cb3e310 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -114,6 +114,7 @@ func StartDPD(n3iwfUe *context.N3IWFUe) { cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentRadioConnectionWithUeLost) ngap_message.SendUEContextReleaseRequest(n3iwfUe.AMF, n3iwfUe, *cause) + n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer.Stop() timer.Stop() }) } From bf96a20077feebcc1e885b8d51532cc64fd7e313 Mon Sep 17 00:00:00 2001 From: allen00991 Date: Fri, 8 Jul 2022 01:02:27 +0800 Subject: [PATCH 22/33] Set the DPDReqRetransTime to make it less than DPD periodic time --- pkg/ike/handler/send.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pkg/ike/handler/send.go b/pkg/ike/handler/send.go index 3cb3e310..722b4a91 100644 --- a/pkg/ike/handler/send.go +++ b/pkg/ike/handler/send.go @@ -108,13 +108,14 @@ func StartDPD(n3iwfUe *context.N3IWFUe) { return case <-timer.C: SendUEInformationExchange(n3iwfUe, nil) - n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = context.NewDPDPeriodicTimer(liveness.TransFreq, + var DPDReqRetransTime time.Duration = 2 * time.Second + n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = context.NewDPDPeriodicTimer(DPDReqRetransTime, liveness.MaxRetryTimes, n3iwfUe.N3IWFIKESecurityAssociation, func() { ikeLog.Errorf("UE is down") cause := ngap_message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentRadioConnectionWithUeLost) ngap_message.SendUEContextReleaseRequest(n3iwfUe.AMF, n3iwfUe, *cause) - n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer.Stop() + n3iwfUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = nil timer.Stop() }) } From 0f01de9b696853407707222d28073a1d9537f0a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=B3=E6=98=B1=E7=B6=B8?= Date: Fri, 20 Sep 2024 10:17:11 +0000 Subject: [PATCH 23/33] Add NAT-T feature and refactor IKE pkg --- .golangci.yml | 3 +- go.mod | 2 + go.sum | 20 +- internal/gre/message.go | 17 +- internal/ngap/handler.go | 29 +- internal/ngap/message/build.go | 17 +- internal/nwuup/server.go | 6 +- pkg/context/context.go | 4 + pkg/context/ikeue.go | 149 ++- pkg/factory/config.go | 2 +- pkg/ike/dispatcher.go | 34 +- pkg/ike/handler.go | 1069 ++++++++------------ pkg/ike/handler_test.go | 244 ++++- pkg/ike/message/build.go | 324 ------ pkg/ike/message/message.go | 1564 ----------------------------- pkg/ike/message/message_test.go | 435 -------- pkg/ike/message/types.go | 296 ------ pkg/ike/security/security.go | 898 ----------------- pkg/ike/security/security_test.go | 135 --- pkg/ike/send.go | 73 +- pkg/ike/server.go | 190 +++- pkg/ike/server_test.go | 234 +++++ pkg/ike/xfrm/xfrm.go | 64 +- 23 files changed, 1351 insertions(+), 4458 deletions(-) delete mode 100644 pkg/ike/message/build.go delete mode 100644 pkg/ike/message/message.go delete mode 100644 pkg/ike/message/message_test.go delete mode 100644 pkg/ike/message/types.go delete mode 100644 pkg/ike/security/security.go delete mode 100644 pkg/ike/security/security_test.go diff --git a/.golangci.yml b/.golangci.yml index 02ed57d6..f839b044 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -5,7 +5,7 @@ run: # default concurrency is a available CPU number concurrency: 4 # timeout for analysis, e.g. 30s, 5m, default is 1m - timeout: 3m + timeout: 5m # exit code when at least one issue was found, default is 1 issues-exit-code: 1 # include test files or not, default is true @@ -266,6 +266,7 @@ linters: # - stylecheck # - unparam # - wsl + - gosec #disable-all: false fast: true diff --git a/go.mod b/go.mod index a5d6367b..a2f40ed1 100644 --- a/go.mod +++ b/go.mod @@ -5,11 +5,13 @@ go 1.21 require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/free5gc/aper v1.0.6-0.20240503143507-2c4c4780b98f + github.com/free5gc/ike v1.0.1-0.20240918094906-1ee5ab8d45ed github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74 github.com/free5gc/sctp v1.0.1 github.com/free5gc/util v1.0.7-0.20240713162917-350ee8f4af4c github.com/gin-contrib/pprof v1.5.0 github.com/gin-gonic/gin v1.10.0 + github.com/google/gopacket v1.1.19 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index d93d4cd2..ecdb5e46 100644 --- a/go.sum +++ b/go.sum @@ -16,6 +16,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/free5gc/aper v1.0.6-0.20240503143507-2c4c4780b98f h1:sO8FFwAq7feSw/vKN9ioY+fX1gNTXd6/xQOqaeclzsA= github.com/free5gc/aper v1.0.6-0.20240503143507-2c4c4780b98f/go.mod h1:oh3dtNsje2W4/q3pfidMWQKXbXIehXK3t6CD9tXmHx0= +github.com/free5gc/ike v1.0.1-0.20240918094906-1ee5ab8d45ed h1:SqznJMp2NP7lDX1Mx6NRLOPEAfoQvwJELDX6/6EgZrM= +github.com/free5gc/ike v1.0.1-0.20240918094906-1ee5ab8d45ed/go.mod h1:57Ujd9Xjva02mt3OVfepYKiheFHO5Y0YCQyBgB1p1Qs= github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74 h1:foSd3OVtTfDmn3EZbsBngK+U93Mv8YE+qSja7FvKEVU= github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74/go.mod h1:UsPP9LWVyNwu5sm7ZE5toAFeBNkkyj0rh+4Q3ylRBi8= github.com/free5gc/openapi v1.0.9-0.20240503143645-eac9f06c2f6b h1:+VcgZq+3apB6Xr4jEqgGf/uAECRF038SwixEvvxhYrM= @@ -49,6 +51,8 @@ github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVI github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -114,23 +118,35 @@ github.com/wmnsk/go-gtp v0.8.11-0.20240705144331-f53bfdd4233b/go.mod h1:pXocxsDk golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= diff --git a/internal/gre/message.go b/internal/gre/message.go index 86b0566e..e396b992 100644 --- a/internal/gre/message.go +++ b/internal/gre/message.go @@ -1,6 +1,11 @@ package gre -import "encoding/binary" +import ( + "encoding/binary" + "math" + + "github.com/pkg/errors" +) // [TS 24.502] 9.3.3 GRE encapsulated user data packet const ( @@ -77,8 +82,14 @@ func (p *GREPacket) setRQI(rqi bool) { } } -func (p *GREPacket) GetQFI() uint8 { - return uint8((p.key >> 24) & 0x3F) +func (p *GREPacket) GetQFI() (uint8, error) { + value := (p.key >> 24) & 0x3F + + if value > math.MaxUint8 { + return 0, errors.Errorf("GetQFI() value exceeds uint8: %d", value) + } else { + return uint8(value), nil + } } func (p *GREPacket) GetRQI() bool { diff --git a/internal/ngap/handler.go b/internal/ngap/handler.go index b4c20df6..113173d0 100644 --- a/internal/ngap/handler.go +++ b/internal/ngap/handler.go @@ -2,6 +2,7 @@ package ngap import ( "encoding/binary" + "math" "net" "time" @@ -853,8 +854,15 @@ func (s *Server) handlePDUSessionResourceSetupRequestTransfer( qosFlow.Identifier = item.QosFlowIdentifier.Value qosFlow.Parameters = item.QosFlowLevelQosParameters pduSession.QosFlows[item.QosFlowIdentifier.Value] = qosFlow + + value := item.QosFlowIdentifier.Value + if value < 0 || value > math.MaxUint8 { + ngapLog.Errorf("handlePDUSessionResourceSetupRequestTransfer() "+ + "item.QosFlowIdentifier.Value exceeds uint8 range: %d", value) + return false, nil + } // QFI List - pduSession.QFIList = append(pduSession.QFIList, uint8(item.QosFlowIdentifier.Value)) + pduSession.QFIList = append(pduSession.QFIList, uint8(value)) } // Setup GTP tunnel with UPF @@ -1157,13 +1165,19 @@ func (s *Server) releaseIkeUeAndRanUe(ranUe *n3iwf_context.N3IWFRanUe) error { } func encapNasMsgToEnvelope(nasPDU *ngapType.NASPDU) []byte { + ngapLog := logger.NgapLog // According to TS 24.502 8.2.4, // in order to transport a NAS message over the non-3GPP access between the UE and the N3IWF, // the NAS message shall be framed in a NAS message envelope as defined in subclause 9.4. // According to TS 24.502 9.4, // a NAS message envelope = Length | NAS Message nasEnv := make([]byte, 2) - binary.BigEndian.PutUint16(nasEnv, uint16(len(nasPDU.Value))) + valueLen := len(nasPDU.Value) + if valueLen > math.MaxUint16 { + ngapLog.Errorf("encapNasMsgToEnvelope nasPDU Value length has out of uint16 range: %d", valueLen) + return nil + } + binary.BigEndian.PutUint16(nasEnv, uint16(valueLen)) nasEnv = append(nasEnv, nasPDU.Value...) return nasEnv } @@ -2886,7 +2900,14 @@ func (s *Server) HandleUnmarshalEAP5GData( ranUe := n3iwfCtx.NewN3iwfRanUe() ranUe.AMF = selectedAMF if anParameters.EstablishmentCause != nil { - ranUe.RRCEstablishmentCause = int16(anParameters.EstablishmentCause.Value) + value := uint64(anParameters.EstablishmentCause.Value) + if value > uint64(math.MaxInt16) { + ngapLog.Errorf("HandleUnmarshalEAP5GData() anParameters.EstablishmentCause.Value "+ + "exceeds int16: %+v", value) + return + } else { + ranUe.RRCEstablishmentCause = int16(value) + } } s.IkeEvtCh() <- n3iwf_context.NewUnmarshalEAP5GDataResponseEvt(spi, @@ -2922,7 +2943,7 @@ func (s *Server) HandleSendInitialUEMessage( return } ranUe.IPAddrv4 = ipv4Addr - ranUe.PortNumber = int32(ipv4Port) + ranUe.PortNumber = int32(ipv4Port) // #nosec G115 message.SendInitialUEMessage(ranUe.AMF, ranUe, nasPDU) } diff --git a/internal/ngap/message/build.go b/internal/ngap/message/build.go index 103f7ae6..09398d82 100644 --- a/internal/ngap/message/build.go +++ b/internal/ngap/message/build.go @@ -4,6 +4,8 @@ import ( "encoding/binary" "encoding/hex" + "github.com/pkg/errors" + "github.com/free5gc/aper" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/internal/util" @@ -724,7 +726,12 @@ func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, ie.Value.RRCEstablishmentCause = new(ngapType.RRCEstablishmentCause) rRCEstablishmentCause := ie.Value.RRCEstablishmentCause - rRCEstablishmentCause.Value = aper.Enumerated(ranUe.RRCEstablishmentCause) + value := ranUe.RRCEstablishmentCause + if value < 0 { + return nil, errors.Errorf("BuildInitialUEMessage() ranUe.RRCEstablishmentCause "+ + "negative value: %d", value) + } + rRCEstablishmentCause.Value = aper.Enumerated(value) initialUEMessageIEs.List = append(initialUEMessageIEs.List, ie) } // FiveGSTMSI @@ -1476,7 +1483,13 @@ func BuildUERadioCapabilityCheckResponse( ie.Value.IMSVoiceSupportIndicator = new(ngapType.IMSVoiceSupportIndicator) iMSVoiceSupportIndicator := ie.Value.IMSVoiceSupportIndicator - iMSVoiceSupportIndicator.Value = aper.Enumerated(ranUe.IMSVoiceSupported) + value := ranUe.IMSVoiceSupported + if value < 0 { + return nil, errors.Errorf("BuildUERadioCapabilityCheckResponse() ranUe.IMSVoiceSupported "+ + "negative value: %d", value) + } + + iMSVoiceSupportIndicator.Value = aper.Enumerated(value) uERadioCapabilityCheckResponseIEs.List = append(uERadioCapabilityCheckResponseIEs.List, ie) } // CriticalityDiagnostics diff --git a/internal/nwuup/server.go b/internal/nwuup/server.go index 1be5de8b..bb0e16c2 100644 --- a/internal/nwuup/server.go +++ b/internal/nwuup/server.go @@ -296,7 +296,11 @@ func (s *Server) forwardUL(ueInnerIP string, ifIndex int, rawData []byte, wg *sy // Encapsulate UL PDU SESSION INFORMATION with extension header if the QoS parameters exist if grePacket.GetKeyFlag() { - qfi := grePacket.GetQFI() + qfi, err := grePacket.GetQFI() + if err != nil { + nwuupLog.Errorf("forwardUL err: %+v", err) + return + } gtpPacket, err := buildQoSGTPPacket(gtpConnection.OutgoingTEID, qfi, payload) if err != nil { nwuupLog.Errorf("buildQoSGTPPacket err: %+v", err) diff --git a/pkg/context/context.go b/pkg/context/context.go index 578b5e11..230bd735 100644 --- a/pkg/context/context.go +++ b/pkg/context/context.go @@ -411,6 +411,10 @@ func (c *N3IWFContext) NewTEID(ranUe *N3IWFRanUe) uint32 { logger.CtxLog.Errorf("New TEID failed: %+v", err) return 0 } + if teid64 < 0 || teid64 > math.MaxUint32 { + logger.CtxLog.Warnf("NewTEID teid64 out of uint32 range: %d, use maxUint32", teid64) + return 0 + } teid32 := uint32(teid64) c.AllocatedUETEID.Store(teid32, ranUe) diff --git a/pkg/context/ikeue.go b/pkg/context/ikeue.go index ebfd65f2..6d68c628 100644 --- a/pkg/context/ikeue.go +++ b/pkg/context/ikeue.go @@ -1,13 +1,15 @@ package context import ( - "errors" "fmt" + "math" "net" + "github.com/pkg/errors" "github.com/vishvananda/netlink" - ike_message "github.com/free5gc/n3iwf/pkg/ike/message" + ike_message "github.com/free5gc/ike/message" + ike_security "github.com/free5gc/ike/security" ) const ( @@ -47,6 +49,7 @@ type IkeMsgTemporaryData struct { } type IKESecurityAssociation struct { + *ike_security.IKESAKey // SPI RemoteSPI uint64 LocalSPI uint64 @@ -55,25 +58,8 @@ type IKESecurityAssociation struct { InitiatorMessageID uint32 ResponderMessageID uint32 - // Transforms for IKE SA - EncryptionAlgorithm *ike_message.Transform - PseudorandomFunction *ike_message.Transform - IntegrityAlgorithm *ike_message.Transform - DiffieHellmanGroup *ike_message.Transform - ExpandedSequenceNumber *ike_message.Transform - // Used for key generating - ConcatenatedNonce []byte - DiffieHellmanSharedKey []byte - - // Keys - SK_d []byte // used for child SA key deriving - SK_ai []byte // used by initiator for integrity checking - SK_ar []byte // used by responder for integrity checking - SK_ei []byte // used by initiator for encrypting - SK_er []byte // used by responder for encrypting - SK_pi []byte // used by initiator for IKE authentication - SK_pr []byte // used by responder for IKE authentication + ConcatenatedNonce []byte // State for IKE_AUTH State uint8 @@ -94,11 +80,8 @@ type IKESecurityAssociation struct { InitiatorSignedOctets []byte // NAT detection - // If UEIsBehindNAT == true, N3IWF should enable NAT traversal and - // TODO: should support dynamic updating network address (MOBIKE) - UEIsBehindNAT bool - // If N3IWFIsBehindNAT == true, N3IWF should send UDP keepalive periodically - N3IWFIsBehindNAT bool + UeBehindNAT bool // If true, N3IWF should enable NAT traversal and + N3iwfBehindNAT bool // TODO: If true, N3IWF should send UDP keepalive periodically // IKE UE context IkeUE *N3IWFIkeUe @@ -112,6 +95,13 @@ type IKESecurityAssociation struct { IsUseDPD bool } +func (ikeSA *IKESecurityAssociation) String() string { + return "====== IKE Security Association Info =====" + + "\nInitiator's SPI: " + fmt.Sprintf("%016x", ikeSA.RemoteSPI) + + "\nResponder's SPI: " + fmt.Sprintf("%016x", ikeSA.LocalSPI) + + "\nIKESAKey: " + ikeSA.IKESAKey.String() +} + // Temporary State Data Args const ( ArgsUEUDPConn string = "UE UDP Socket Info" @@ -138,13 +128,7 @@ type ChildSecurityAssociation struct { TrafficSelectorRemote net.IPNet // Security - EncryptionAlgorithm uint16 - InitiatorToResponderEncryptionKey []byte - ResponderToInitiatorEncryptionKey []byte - IntegrityAlgorithm uint16 - InitiatorToResponderIntegrityKey []byte - ResponderToInitiatorIntegrityKey []byte - ESN bool + *ike_security.ChildSAKey // Encapsulate EnableEncapsulate bool @@ -156,6 +140,60 @@ type ChildSecurityAssociation struct { // IKE UE context IkeUE *N3IWFIkeUe + + LocalIsInitiator bool +} + +func (childSA *ChildSecurityAssociation) String(xfrmiId uint32) string { + var inboundEncryptionKey, inboundIntegrityKey, outboundEncryptionKey, outboundIntegrityKey []byte + + if childSA.LocalIsInitiator { + inboundEncryptionKey = childSA.ResponderToInitiatorEncryptionKey + inboundIntegrityKey = childSA.ResponderToInitiatorIntegrityKey + outboundEncryptionKey = childSA.InitiatorToResponderEncryptionKey + outboundIntegrityKey = childSA.InitiatorToResponderIntegrityKey + } else { + inboundEncryptionKey = childSA.InitiatorToResponderEncryptionKey + inboundIntegrityKey = childSA.InitiatorToResponderIntegrityKey + outboundEncryptionKey = childSA.ResponderToInitiatorEncryptionKey + outboundIntegrityKey = childSA.ResponderToInitiatorIntegrityKey + } + + return fmt.Sprintf("====== IPSec/Child SA Info ======"+ + "\n====== Inbound ======"+ + "\nXFRM interface if_id: %d"+ + "\nIPSec Inbound SPI: 0x%016x"+ + "\n[UE:%+v] -> [N3IWF:%+v]"+ + "\nIPSec Encryption Algorithm: %d"+ + "\nIPSec Encryption Key: 0x%x"+ + "\nIPSec Integrity Algorithm: %d"+ + "\nIPSec Integrity Key: 0x%x"+ + "\n====== IPSec/Child SA Info ======"+ + "\n====== Outbound ======"+ + "\nXFRM interface if_id: %d"+ + "\nIPSec Outbound SPI: 0x%016x"+ + "\n[N3IWF:%+v] -> [UE:%+v]"+ + "\nIPSec Encryption Algorithm: %d"+ + "\nIPSec Encryption Key: 0x%x"+ + "\nIPSec Integrity Algorithm: %d"+ + "\nIPSec Integrity Key: 0x%x", + xfrmiId, + childSA.InboundSPI, + childSA.PeerPublicIPAddr, + childSA.LocalPublicIPAddr, + childSA.EncrKInfo.TransformID(), + inboundEncryptionKey, + childSA.IntegKInfo.TransformID(), + inboundIntegrityKey, + xfrmiId, + childSA.OutboundSPI, + childSA.LocalPublicIPAddr, + childSA.PeerPublicIPAddr, + childSA.EncrKInfo.TransformID(), + outboundEncryptionKey, + childSA.IntegKInfo.TransformID(), + outboundIntegrityKey, + ) } type UDPSocketInfo struct { @@ -189,28 +227,45 @@ func (ikeUe *N3IWFIkeUe) Remove() error { return nil } -func (ikeUe *N3IWFIkeUe) DeleteChildSA(childSA *ChildSecurityAssociation) error { +func (ikeUe *N3IWFIkeUe) DeleteChildSAXfrm(childSA *ChildSecurityAssociation) error { n3iwfCtx := ikeUe.N3iwfCtx iface := childSA.XfrmIface // Delete child SA xfrmState - for _, xfrmState := range childSA.XfrmStateList { + for idx := range childSA.XfrmStateList { + xfrmState := childSA.XfrmStateList[idx] if err := netlink.XfrmStateDel(&xfrmState); err != nil { - return fmt.Errorf("Delete xfrmstate error : %+v", err) + return errors.Wrapf(err, "Delete xfrmstate") } } // Delete child SA xfrmPolicy - for _, xfrmPolicy := range childSA.XfrmPolicyList { + for idx := range childSA.XfrmPolicyList { + xfrmPolicy := childSA.XfrmPolicyList[idx] if err := netlink.XfrmPolicyDel(&xfrmPolicy); err != nil { - return fmt.Errorf("Delete xfrmPolicy error : %+v", err) + return errors.Wrapf(err, "Delete xfrmPolicy") } } if iface == nil || iface.Attrs().Name == "xfrmi-default" { } else if err := netlink.LinkDel(iface); err != nil { - return fmt.Errorf("Delete interface %s fail: %+v", iface.Attrs().Name, err) + return errors.Wrapf(err, "Delete interface[%s]", iface.Attrs().Name) } else { - n3iwfCtx.XfrmIfaces.Delete(uint32(childSA.XfrmStateList[0].Ifid)) + ifId := childSA.XfrmStateList[0].Ifid + if ifId < 0 || ifId > math.MaxUint32 { + return errors.Errorf("DeleteChildSAXfrm Ifid has out of uint32 range value: %d", ifId) + } + n3iwfCtx.XfrmIfaces.Delete(uint32(ifId)) + } + + childSA.XfrmStateList = nil + childSA.XfrmPolicyList = nil + + return nil +} + +func (ikeUe *N3IWFIkeUe) DeleteChildSA(childSA *ChildSecurityAssociation) error { + if err := ikeUe.DeleteChildSAXfrm(childSA); err != nil { + return err } delete(ikeUe.N3IWFChildSecurityAssociation, childSA.InboundSPI) @@ -252,18 +307,10 @@ func (ikeUe *N3IWFIkeUe) CompleteChildSA(msgID uint32, outboundSPI uint32, childSA.OutboundSPI = outboundSPI - if len(chosenSecurityAssociation.Proposals[0].EncryptionAlgorithm) != 0 { - childSA.EncryptionAlgorithm = chosenSecurityAssociation.Proposals[0].EncryptionAlgorithm[0].TransformID - } - if len(chosenSecurityAssociation.Proposals[0].IntegrityAlgorithm) != 0 { - childSA.IntegrityAlgorithm = chosenSecurityAssociation.Proposals[0].IntegrityAlgorithm[0].TransformID - } - if len(chosenSecurityAssociation.Proposals[0].ExtendedSequenceNumbers) != 0 { - if chosenSecurityAssociation.Proposals[0].ExtendedSequenceNumbers[0].TransformID == 0 { - childSA.ESN = false - } else { - childSA.ESN = true - } + var err error + childSA.ChildSAKey, err = ike_security.NewChildSAKeyByProposal(chosenSecurityAssociation.Proposals[0]) + if err != nil { + return nil, errors.Wrapf(err, "CompleteChildSA") } // Record to UE context with inbound SPI as key diff --git a/pkg/factory/config.go b/pkg/factory/config.go index 2dbed9a0..4fd05807 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -333,7 +333,7 @@ func (c *Config) GetNasTcpAddr() string { func (c *Config) GetNasTcpPort() uint16 { c.RLock() defer c.RUnlock() - return uint16(c.Configuration.TCPPort) + return uint16(c.Configuration.TCPPort) // #nosec G115 } func (c *Config) GetFQDN() string { diff --git a/pkg/ike/dispatcher.go b/pkg/ike/dispatcher.go index 50f29493..50068b42 100644 --- a/pkg/ike/dispatcher.go +++ b/pkg/ike/dispatcher.go @@ -4,14 +4,16 @@ import ( "net" "runtime/debug" + ike_message "github.com/free5gc/ike/message" "github.com/free5gc/n3iwf/internal/logger" - ike_message "github.com/free5gc/n3iwf/pkg/ike/message" + n3iwf_context "github.com/free5gc/n3iwf/pkg/context" ) func (s *Server) Dispatch( udpConn *net.UDPConn, localAddr, remoteAddr *net.UDPAddr, - msg []byte, + ikeMessage *ike_message.IKEMessage, msg []byte, + ikeSA *n3iwf_context.IKESecurityAssociation, ) { ikeLog := logger.IKELog defer func() { @@ -21,37 +23,15 @@ func (s *Server) Dispatch( } }() - // As specified in RFC 7296 section 3.1, the IKE message send from/to UDP port 4500 - // should prepend a 4 bytes zero - if localAddr.Port == 4500 { - for i := 0; i < 4; i++ { - if msg[i] != 0 { - ikeLog.Warn( - "Received an IKE packet that does not prepend 4 bytes zero from UDP port 4500," + - " this packet may be the UDP encapsulated ESP. The packet will not be handled.") - return - } - } - msg = msg[4:] - } - - ikeMessage := new(ike_message.IKEMessage) - - err := ikeMessage.Decode(msg) - if err != nil { - ikeLog.Error(err) - return - } - switch ikeMessage.ExchangeType { case ike_message.IKE_SA_INIT: s.HandleIKESAINIT(udpConn, localAddr, remoteAddr, ikeMessage, msg) case ike_message.IKE_AUTH: - s.HandleIKEAUTH(udpConn, localAddr, remoteAddr, ikeMessage) + s.HandleIKEAUTH(udpConn, localAddr, remoteAddr, ikeMessage, ikeSA) case ike_message.CREATE_CHILD_SA: - s.HandleCREATECHILDSA(udpConn, localAddr, remoteAddr, ikeMessage) + s.HandleCREATECHILDSA(udpConn, localAddr, remoteAddr, ikeMessage, ikeSA) case ike_message.INFORMATIONAL: - s.HandleInformational(udpConn, localAddr, remoteAddr, ikeMessage) + s.HandleInformational(udpConn, localAddr, remoteAddr, ikeMessage, ikeSA) default: ikeLog.Warnf("Unimplemented IKE message type, exchange type: %d", ikeMessage.ExchangeType) } diff --git a/pkg/ike/handler.go b/pkg/ike/handler.go index 2b84fca3..a054f510 100644 --- a/pkg/ike/handler.go +++ b/pkg/ike/handler.go @@ -5,11 +5,11 @@ import ( "crypto" "crypto/rand" "crypto/rsa" - "crypto/sha1" + "crypto/sha1" // #nosec G505 "encoding/binary" "encoding/hex" "fmt" - math_rand "math/rand" + "math" "net" "runtime/debug" "sync/atomic" @@ -19,10 +19,14 @@ import ( "github.com/vishvananda/netlink" "golang.org/x/sys/unix" + ike_message "github.com/free5gc/ike/message" + ike_security "github.com/free5gc/ike/security" + "github.com/free5gc/ike/security/dh" + "github.com/free5gc/ike/security/encr" + "github.com/free5gc/ike/security/integ" + "github.com/free5gc/ike/security/prf" "github.com/free5gc/n3iwf/internal/logger" n3iwf_context "github.com/free5gc/n3iwf/pkg/context" - ike_message "github.com/free5gc/n3iwf/pkg/ike/message" - "github.com/free5gc/n3iwf/pkg/ike/security" "github.com/free5gc/n3iwf/pkg/ike/xfrm" ) @@ -46,33 +50,11 @@ func (s *Server) HandleIKESAINIT( // For response or needed data responseIKEMessage := new(ike_message.IKEMessage) - var sharedKeyData, localNonce, concatenatedNonce []byte + var localNonce, concatenatedNonce []byte // Chosen transform from peer's proposal - var encryptionAlgorithmTransform, pseudorandomFunctionTransform *ike_message.Transform - var integrityAlgorithmTransform, diffieHellmanGroupTransform *ike_message.Transform - // For NAT-T - var ueIsBehindNAT, n3iwfIsBehindNAT bool - - if message == nil { - ikeLog.Error("IKE Message is nil") - return - } - - // parse IKE header and setup IKE context - // check major version - majorVersion := ((message.Version & 0xf0) >> 4) - if majorVersion > 2 { - ikeLog.Warn("Received an IKE message with higher major version") - // send INFORMATIONAL type message with INVALID_MAJOR_VERSION Notify payload - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, - ike_message.INVALID_MAJOR_VERSION, nil, nil) - - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - return - } + var chooseProposal ike_message.ProposalContainer + var localPublicValue []byte + var chosenDiffieHellmanGroup uint16 for _, ikePayload := range message.Payloads { switch ikePayload.Type() { @@ -93,84 +75,8 @@ func (s *Server) HandleIKESAINIT( if securityAssociation != nil { responseSecurityAssociation := responseIKEMessage.Payloads.BuildSecurityAssociation() - - for _, proposal := range securityAssociation.Proposals { - // We need ENCR, PRF, INTEG, DH, but not ESN - encryptionAlgorithmTransform = nil - pseudorandomFunctionTransform = nil - integrityAlgorithmTransform = nil - diffieHellmanGroupTransform = nil - - if len(proposal.EncryptionAlgorithm) > 0 { - for _, transform := range proposal.EncryptionAlgorithm { - if isTransformSupported(ike_message.TypeEncryptionAlgorithm, transform.TransformID, - transform.AttributePresent, transform.AttributeValue) { - encryptionAlgorithmTransform = transform - break - } - } - if encryptionAlgorithmTransform == nil { - continue - } - } else { - continue // mandatory - } - if len(proposal.PseudorandomFunction) > 0 { - for _, transform := range proposal.PseudorandomFunction { - if isTransformSupported(ike_message.TypePseudorandomFunction, transform.TransformID, - transform.AttributePresent, transform.AttributeValue) { - pseudorandomFunctionTransform = transform - break - } - } - if pseudorandomFunctionTransform == nil { - continue - } - } else { - continue // mandatory - } - if len(proposal.IntegrityAlgorithm) > 0 { - for _, transform := range proposal.IntegrityAlgorithm { - if isTransformSupported(ike_message.TypeIntegrityAlgorithm, transform.TransformID, - transform.AttributePresent, transform.AttributeValue) { - integrityAlgorithmTransform = transform - break - } - } - if integrityAlgorithmTransform == nil { - continue - } - } else { - continue // mandatory - } - if len(proposal.DiffieHellmanGroup) > 0 { - for _, transform := range proposal.DiffieHellmanGroup { - if isTransformSupported(ike_message.TypeDiffieHellmanGroup, transform.TransformID, - transform.AttributePresent, transform.AttributeValue) { - diffieHellmanGroupTransform = transform - break - } - } - if diffieHellmanGroupTransform == nil { - continue - } - } else { - continue // mandatory - } - if len(proposal.ExtendedSequenceNumbers) > 0 { - continue // No ESN - } - - // Construct chosen proposal, with ENCR, PRF, INTEG, DH, and each - // contains one transform expectively - chosenProposal := responseSecurityAssociation.Proposals.BuildProposal( - proposal.ProposalNumber, proposal.ProtocolID, nil) - chosenProposal.EncryptionAlgorithm = append(chosenProposal.EncryptionAlgorithm, encryptionAlgorithmTransform) - chosenProposal.PseudorandomFunction = append(chosenProposal.PseudorandomFunction, pseudorandomFunctionTransform) - chosenProposal.IntegrityAlgorithm = append(chosenProposal.IntegrityAlgorithm, integrityAlgorithmTransform) - chosenProposal.DiffieHellmanGroup = append(chosenProposal.DiffieHellmanGroup, diffieHellmanGroupTransform) - break - } + chooseProposal = SelectProposal(securityAssociation.Proposals) + responseSecurityAssociation.Proposals = append(responseSecurityAssociation.Proposals, chooseProposal...) if len(responseSecurityAssociation.Proposals) == 0 { ikeLog.Warn("No proposal chosen") @@ -180,7 +86,10 @@ func (s *Server) HandleIKESAINIT( responseIKEMessage.Payloads.Reset() responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.NO_PROPOSAL_CHOSEN, nil, nil) - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + err := SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, nil) + if err != nil { + ikeLog.Errorf("HandleIKESAINIT(): %v", err) + } return } } else { @@ -190,7 +99,7 @@ func (s *Server) HandleIKESAINIT( } if keyExcahge != nil { - chosenDiffieHellmanGroup := diffieHellmanGroupTransform.TransformID + chosenDiffieHellmanGroup = chooseProposal[0].DiffieHellmanGroup[0].TransformID if chosenDiffieHellmanGroup != keyExcahge.DiffieHellmanGroup { ikeLog.Warn("The Diffie-Hellman group defined in key exchange payload not matches the one in chosen proposal") // send INVALID_KE_PAYLOAD to UE @@ -203,16 +112,12 @@ func (s *Server) HandleIKESAINIT( responseIKEMessage.Payloads.BuildNotification( ike_message.TypeNone, ike_message.INVALID_KE_PAYLOAD, nil, notificationData) - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + err := SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, nil) + if err != nil { + ikeLog.Errorf("HandleIKESAINIT(): %v", err) + } return } - - var localPublicValue []byte - localPublicValue, sharedKeyData = security.CalculateDiffieHellmanMaterials( - security.GenerateRandomNumber(), - keyExcahge.KeyExchangeData, - chosenDiffieHellmanGroup) - responseIKEMessage.Payloads.BUildKeyExchange(chosenDiffieHellmanGroup, localPublicValue) } else { ikeLog.Error("The key exchange field is nil") // TODO: send error message to UE @@ -220,7 +125,12 @@ func (s *Server) HandleIKESAINIT( } if nonce != nil { - localNonce = security.GenerateRandomNumber().Bytes() + localNonceBigInt, err := ike_security.GenerateRandomNumber() + if err != nil { + ikeLog.Errorf("HandleIKESAINIT: %v", err) + return + } + localNonce = localNonceBigInt.Bytes() concatenatedNonce = append(nonce.NonceData, localNonce...) responseIKEMessage.Payloads.BuildNonce(localNonce) @@ -230,103 +140,48 @@ func (s *Server) HandleIKESAINIT( return } - if len(notifications) != 0 { - for _, notification := range notifications { - switch notification.NotifyMessageType { - case ike_message.NAT_DETECTION_SOURCE_IP: - ikeLog.Trace("Received IKE Notify: NAT_DETECTION_SOURCE_IP") - // Calculate local NAT_DETECTION_SOURCE_IP hash - // : sha1(ispi | rspi | ueip | ueport) - localDetectionData := make([]byte, 22) - binary.BigEndian.PutUint64(localDetectionData[0:8], message.InitiatorSPI) - binary.BigEndian.PutUint64(localDetectionData[8:16], message.ResponderSPI) - copy(localDetectionData[16:20], ueAddr.IP.To4()) - binary.BigEndian.PutUint16(localDetectionData[20:22], uint16(ueAddr.Port)) - - sha1HashFunction := sha1.New() // #nosec G401 - _, err := sha1HashFunction.Write(localDetectionData) - if err != nil { - ikeLog.Errorf("Hash function write error: %v", err) - return - } - - if !bytes.Equal(notification.NotificationData, sha1HashFunction.Sum(nil)) { - ueIsBehindNAT = true - } - case ike_message.NAT_DETECTION_DESTINATION_IP: - ikeLog.Trace("Received IKE Notify: NAT_DETECTION_DESTINATION_IP") - // Calculate local NAT_DETECTION_SOURCE_IP hash - // : sha1(ispi | rspi | n3iwfip | n3iwfport) - localDetectionData := make([]byte, 22) - binary.BigEndian.PutUint64(localDetectionData[0:8], message.InitiatorSPI) - binary.BigEndian.PutUint64(localDetectionData[8:16], message.ResponderSPI) - copy(localDetectionData[16:20], n3iwfAddr.IP.To4()) - binary.BigEndian.PutUint16(localDetectionData[20:22], uint16(n3iwfAddr.Port)) - - sha1HashFunction := sha1.New() // #nosec G401 - _, err := sha1HashFunction.Write(localDetectionData) - if err != nil { - ikeLog.Errorf("Hash function write error: %v", err) - return - } - - if !bytes.Equal(notification.NotificationData, sha1HashFunction.Sum(nil)) { - n3iwfIsBehindNAT = true - } - default: - } - } + ueBehindNAT, n3iwfBehindNAT, err := s.handleNATDetect( + message.InitiatorSPI, message.ResponderSPI, + notifications, ueAddr, n3iwfAddr) + if err != nil { + ikeLog.Errorf("Handle IKE_SA_INIT: %v", err) + return } // Create new IKE security association ikeSecurityAssociation := n3iwfCtx.NewIKESecurityAssociation() ikeSecurityAssociation.RemoteSPI = message.InitiatorSPI ikeSecurityAssociation.InitiatorMessageID = message.MessageID - ikeSecurityAssociation.UEIsBehindNAT = ueIsBehindNAT - ikeSecurityAssociation.N3IWFIsBehindNAT = n3iwfIsBehindNAT - - // Record algorithm in context - ikeSecurityAssociation.EncryptionAlgorithm = encryptionAlgorithmTransform - ikeSecurityAssociation.IntegrityAlgorithm = integrityAlgorithmTransform - ikeSecurityAssociation.PseudorandomFunction = pseudorandomFunctionTransform - ikeSecurityAssociation.DiffieHellmanGroup = diffieHellmanGroupTransform - // Record concatenated nonce - ikeSecurityAssociation.ConcatenatedNonce = append(ikeSecurityAssociation.ConcatenatedNonce, concatenatedNonce...) - // Record Diffie-Hellman shared key - ikeSecurityAssociation.DiffieHellmanSharedKey = append(ikeSecurityAssociation.DiffieHellmanSharedKey, sharedKeyData...) - - err := security.GenerateKeyForIKESA(ikeSecurityAssociation) + ikeSecurityAssociation.IKESAKey, localPublicValue, err = ike_security.NewIKESAKey(chooseProposal[0], + keyExcahge.KeyExchangeData, concatenatedNonce, + ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI) if err != nil { - ikeLog.Errorf("Generate key for IKE SA failed: %v", err) + ikeLog.Errorf("Handle IKE_SA_INIT: %v", err) return } - // IKE response to UE - responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, - ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, message.MessageID) + ikeLog.Debugf(ikeSecurityAssociation.String()) - // Calculate NAT_DETECTION_SOURCE_IP for NAT-T - natDetectionSourceIP := make([]byte, 22) - binary.BigEndian.PutUint64(natDetectionSourceIP[0:8], ikeSecurityAssociation.RemoteSPI) - binary.BigEndian.PutUint64(natDetectionSourceIP[8:16], ikeSecurityAssociation.LocalSPI) - copy(natDetectionSourceIP[16:20], n3iwfAddr.IP.To4()) - binary.BigEndian.PutUint16(natDetectionSourceIP[20:22], uint16(n3iwfAddr.Port)) + // Record concatenated nonce + ikeSecurityAssociation.ConcatenatedNonce = append( + ikeSecurityAssociation.ConcatenatedNonce, concatenatedNonce...) + ikeSecurityAssociation.UeBehindNAT = ueBehindNAT + ikeSecurityAssociation.N3iwfBehindNAT = n3iwfBehindNAT - // Build and append notify payload for NAT_DETECTION_SOURCE_IP - responseIKEMessage.Payloads.BuildNotification( - ike_message.TypeNone, ike_message.NAT_DETECTION_SOURCE_IP, nil, natDetectionSourceIP) + // IKE response to UE + responseIKEMessage.BuildIKEHeader( + ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, + ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, message.MessageID) - // Calculate NAT_DETECTION_DESTINATION_IP for NAT-T - natDetectionDestinationIP := make([]byte, 22) - binary.BigEndian.PutUint64(natDetectionDestinationIP[0:8], ikeSecurityAssociation.RemoteSPI) - binary.BigEndian.PutUint64(natDetectionDestinationIP[8:16], ikeSecurityAssociation.LocalSPI) - copy(natDetectionDestinationIP[16:20], ueAddr.IP.To4()) - binary.BigEndian.PutUint16(natDetectionDestinationIP[20:22], uint16(ueAddr.Port)) + responseIKEMessage.Payloads.BUildKeyExchange(chosenDiffieHellmanGroup, localPublicValue) - // Build and append notify payload for NAT_DETECTION_DESTINATION_IP - responseIKEMessage.Payloads.BuildNotification( - ike_message.TypeNone, ike_message.NAT_DETECTION_DESTINATION_IP, nil, natDetectionDestinationIP) + err = s.buildNATDetectNotifPayload( + ikeSecurityAssociation, &responseIKEMessage.Payloads, ueAddr, n3iwfAddr) + if err != nil { + ikeLog.Warnf("Handle IKE_SA_INIT: %v", err) + return + } // Prepare authentication data - InitatorSignedOctet // InitatorSignedOctet = RealMessage1 | NonceRData | MACedIDForI @@ -337,8 +192,7 @@ func (s *Server) HandleIKESAINIT( // ResponderSignedOctet = RealMessage2 | NonceIData | MACedIDForR responseIKEMessageData, err := responseIKEMessage.Encode() if err != nil { - ikeLog.Errorln(err) - ikeLog.Error("Encoding IKE message failed") + ikeLog.Errorf("Encoding IKE message failed: %v", err) return } ikeSecurityAssociation.ResponderSignedOctets = append(responseIKEMessageData, nonce.NonceData...) @@ -347,29 +201,27 @@ func (s *Server) HandleIKESAINIT( idPayload.BuildIdentificationResponder(ike_message.ID_FQDN, []byte(cfg.GetFQDN())) idPayloadData, err := idPayload.Encode() if err != nil { - ikeLog.Errorln(err) - ikeLog.Error("Encode IKE payload failed.") + ikeLog.Errorf("Encode IKE payload failed: %v", err) return } - pseudorandomFunction, ok := security.NewPseudorandomFunction( - ikeSecurityAssociation.SK_pr, - ikeSecurityAssociation.PseudorandomFunction.TransformID) - if !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") - return - } - _, err = pseudorandomFunction.Write(idPayloadData[4:]) + + ikeSecurityAssociation.Prf_r.Reset() + _, err = ikeSecurityAssociation.Prf_r.Write(idPayloadData[4:]) if err != nil { ikeLog.Errorf("Pseudorandom function write error: %v", err) return } + ikeSecurityAssociation.ResponderSignedOctets = append(ikeSecurityAssociation.ResponderSignedOctets, - pseudorandomFunction.Sum(nil)...) + ikeSecurityAssociation.Prf_r.Sum(nil)...) ikeLog.Tracef("Local unsigned authentication data:\n%s", hex.Dump(ikeSecurityAssociation.ResponderSignedOctets)) // Send response to UE - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, nil) + if err != nil { + ikeLog.Errorf("HandleIKESAINIT(): %v", err) + } } const ( @@ -387,12 +239,11 @@ func (s *Server) HandleIKEAUTH( udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message *ike_message.IKEMessage, + ikeSecurityAssociation *n3iwf_context.IKESecurityAssociation, ) { ikeLog := logger.IKELog ikeLog.Infoln("Handle IKE_AUTH") - var encryptedPayload *ike_message.Encrypted - n3iwfCtx := s.Context() cfg := s.Config() ipsecGwAddr := cfg.GetIPSecGatewayAddr() @@ -401,59 +252,6 @@ func (s *Server) HandleIKEAUTH( responseIKEMessage := new(ike_message.IKEMessage) var responseIKEPayload ike_message.IKEPayloadContainer - if message == nil { - ikeLog.Error("IKE Message is nil") - return - } - - // parse IKE header and setup IKE context - // check major version - majorVersion := ((message.Version & 0xf0) >> 4) - if majorVersion > 2 { - ikeLog.Warn("Received an IKE message with higher major version") - // send INFORMATIONAL type message with INVALID_MAJOR_VERSION Notify payload ( OUTSIDE IKE SA ) - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_MAJOR_VERSION, nil, nil) - - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - return - } - - // Find corresponding IKE security association - localSPI := message.ResponderSPI - ikeSecurityAssociation, ok := n3iwfCtx.IKESALoad(localSPI) - if !ok { - ikeLog.Warn("Unrecognized SPI") - // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, 0, ike_message.INFORMATIONAL, - ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) - - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - return - } - - for _, ikePayload := range message.Payloads { - switch ikePayload.Type() { - case ike_message.TypeSK: - encryptedPayload = ikePayload.(*ike_message.Encrypted) - default: - ikeLog.Warnf( - "Get IKE payload (type %d) in IKE_AUTH message, this payload will not be handled by IKE handler", - ikePayload.Type()) - } - } - - decryptedIKEPayload, err := security.DecryptProcedure( - ikeSecurityAssociation, message, encryptedPayload) - if err != nil { - ikeLog.Errorf("Decrypt IKE message failed: %v", err) - return - } - // Parse payloads var initiatorID *ike_message.IdentificationInitiator var certificateRequest *ike_message.CertificateRequest @@ -464,8 +262,9 @@ func (s *Server) HandleIKEAUTH( var eap *ike_message.EAP var authentication *ike_message.Authentication var configuration *ike_message.Configuration + var ok bool - for _, ikePayload := range decryptedIKEPayload { + for _, ikePayload := range message.Payloads { switch ikePayload.Type() { case ike_message.TypeIDi: initiatorID = ikePayload.(*ike_message.IdentificationInitiator) @@ -492,8 +291,6 @@ func (s *Server) HandleIKEAUTH( } } - // NOTE: tune it - transformPseudorandomFunction := ikeSecurityAssociation.PseudorandomFunction ikeSecurityAssociation.InitiatorMessageID = message.MessageID switch ikeSecurityAssociation.State { @@ -512,20 +309,14 @@ func (s *Server) HandleIKEAUTH( ikeLog.Error("Encoding ID payload message failed.") return } - pseudorandomFunction, ok1 := security.NewPseudorandomFunction( - ikeSecurityAssociation.SK_pi, - transformPseudorandomFunction.TransformID) - if !ok1 { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") - return - } - if _, err := pseudorandomFunction.Write(idPayloadData[4:]); err != nil { + ikeSecurityAssociation.Prf_i.Reset() + if _, err := ikeSecurityAssociation.Prf_i.Write(idPayloadData[4:]); err != nil { ikeLog.Errorf("Pseudorandom function write error: %v", err) return } ikeSecurityAssociation.InitiatorSignedOctets = append( ikeSecurityAssociation.InitiatorSignedOctets, - pseudorandomFunction.Sum(nil)...) + ikeSecurityAssociation.Prf_i.Sum(nil)...) } else { ikeLog.Error("The initiator identification field is nil") // TODO: send error message to UE @@ -542,7 +333,7 @@ func (s *Server) HandleIKEAUTH( // authorities. This can be a chain of certificates. if certificateRequest != nil { ikeLog.Info("UE request N3IWF certificate") - if security.CompareRootCertificate( + if ike_security.CompareRootCertificate( n3iwfCtx.CertificateAuthority, certificateRequest.CertificateEncoding, certificateRequest.CertificationAuthority) { @@ -657,15 +448,15 @@ func (s *Server) HandleIKEAUTH( responseIKEPayload.BuildNotification( ike_message.TypeNone, ike_message.NO_PROPOSAL_CHOSEN, nil, nil) - err := security.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage) - if err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", err) - return - } + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, + responseIKEPayload...) // Send IKE message to UE - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + err := SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, + ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("HandleIKEAUTH(): %v", err) + } return } @@ -726,7 +517,7 @@ func (s *Server) HandleIKEAUTH( // EAP expanded 5G-Start var identifier uint8 for { - identifier, err = security.GenerateRandomUint8() + identifier, err = ike_security.GenerateRandomUint8() if err != nil { ikeLog.Errorf("Random number failed: %v", err) return @@ -738,18 +529,20 @@ func (s *Server) HandleIKEAUTH( } responseIKEPayload.BuildEAP5GStart(identifier) - err = security.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage) - if err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", err) - return - } + // responseIKEMessage + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, + responseIKEPayload...) // Shift state ikeSecurityAssociation.State++ // Send IKE message to UE - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, + ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("HandleIKEAUTH(): %v", err) + return + } case EAPSignalling: // If success, N3IWF will send an UPLinkNASTransport to AMF @@ -798,22 +591,22 @@ func (s *Server) HandleIKEAUTH( responseIKEMessage.Payloads.Reset() // EAP - identifier, err := security.GenerateRandomUint8() + identifier, err := ike_security.GenerateRandomUint8() if err != nil { ikeLog.Errorf("Generate random uint8 failed: %v", err) return } responseIKEPayload.BuildEAPfailure(identifier) - err = security.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage) - if err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", err) - return - } + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, + responseIKEPayload...) // Send IKE message to UE - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, + ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("HandleIKEAUTH(): %v", err) + } return } @@ -846,24 +639,14 @@ func (s *Server) HandleIKEAUTH( ikeUE := ikeSecurityAssociation.IkeUE // Prepare pseudorandom function for calculating/verifying authentication data - pseudorandomFunction, ok := security.NewPseudorandomFunction( - ikeUE.Kn3iwf, transformPseudorandomFunction.TransformID) - if !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") - return - } + pseudorandomFunction := ikeSecurityAssociation.PrfInfo.Init(ikeUE.Kn3iwf) _, err := pseudorandomFunction.Write([]byte("Key Pad for IKEv2")) if err != nil { ikeLog.Errorf("Pseudorandom function write error: %v", err) return } secret := pseudorandomFunction.Sum(nil) - pseudorandomFunction, ok = security.NewPseudorandomFunction( - secret, transformPseudorandomFunction.TransformID) - if !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") - return - } + pseudorandomFunction = ikeSecurityAssociation.PrfInfo.Init(secret) if authentication != nil { // Verifying remote AUTH @@ -888,15 +671,15 @@ func (s *Server) HandleIKEAUTH( responseIKEPayload.BuildNotification( ike_message.TypeNone, ike_message.AUTHENTICATION_FAILED, nil, nil) - err = security.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage) - if err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", err) - return - } + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, + responseIKEPayload...) // Send IKE message to UE - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, + ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("HandleIKEAUTH(): %v", err) + } return } else { ikeLog.Tracef("Peer authentication success") @@ -912,15 +695,15 @@ func (s *Server) HandleIKEAUTH( // Notification responseIKEPayload.BuildNotification(ike_message.TypeNone, ike_message.AUTHENTICATION_FAILED, nil, nil) - err = security.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage) - if err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", err) - return - } + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, + responseIKEPayload...) // Send IKE message to UE - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, + ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("HandleIKEAUTH(): %v", err) + } return } @@ -1014,10 +797,16 @@ func (s *Server) HandleIKEAUTH( var inboundSPI uint32 inboundSPIByte := make([]byte, 4) for { - randomUint64 := security.GenerateRandomNumber().Uint64() + buf := make([]byte, 4) + _, err = rand.Read(buf) + if err != nil { + ikeLog.Errorf("Handle IKE_AUTH Generate ChildSA inboundSPI: %v", err) + return + } + randomUint32 := binary.BigEndian.Uint32(buf) // check if the inbound SPI havn't been allocated by N3IWF - if _, ok1 := n3iwfCtx.ChildSA.Load(uint32(randomUint64)); !ok1 { - inboundSPI = uint32(randomUint64) + if _, ok1 := n3iwfCtx.ChildSA.Load(randomUint32); !ok1 { + inboundSPI = randomUint32 break } } @@ -1035,7 +824,7 @@ func (s *Server) HandleIKEAUTH( childSecurityAssociationContext, err := ikeUE.CompleteChildSA( 0x01, outboundSPI, ikeSecurityAssociation.IKEAuthResponseSA) if err != nil { - ikeLog.Errorf("Create child security association context failed: %v", err) + ikeLog.Errorf("HandleIKEAUTH(): Create child security association context failed: %v", err) return } err = s.parseIPAddressInformationToChildSecurityAssociation( @@ -1049,14 +838,14 @@ func (s *Server) HandleIKEAUTH( // Select TCP traffic childSecurityAssociationContext.SelectedIPProtocol = unix.IPPROTO_TCP - errGen := security.GenerateKeyForChildSA( - ikeSecurityAssociation, childSecurityAssociationContext) + errGen := childSecurityAssociationContext.ChildSAKey.GenerateKeyForChildSA(ikeSecurityAssociation.IKESAKey, + ikeSecurityAssociation.ConcatenatedNonce) if errGen != nil { ikeLog.Errorf("Generate key for child SA failed: %v", errGen) return } // NAT-T concern - if ikeSecurityAssociation.UEIsBehindNAT || ikeSecurityAssociation.N3IWFIsBehindNAT { + if ikeSecurityAssociation.UeBehindNAT || ikeSecurityAssociation.N3iwfBehindNAT { childSecurityAssociationContext.EnableEncapsulate = true childSecurityAssociationContext.N3IWFPort = n3iwfAddr.Port childSecurityAssociationContext.NATPort = ueAddr.Port @@ -1068,13 +857,10 @@ func (s *Server) HandleIKEAUTH( // Notification(NSA_TCP_PORT) responseIKEPayload.BuildNotifyNAS_TCP_PORT(cfg.GetNasTcpPort()) - errEncrypt := security.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage) - if errEncrypt != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", errEncrypt) - return - } + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, + responseIKEPayload...) + childSecurityAssociationContext.LocalIsInitiator = false // Aplly XFRM rules // IPsec for CP always use default XFRM interface err = xfrm.ApplyXFRMRule(false, cfg.GetXfrmIfaceId(), childSecurityAssociationContext) @@ -1082,9 +868,15 @@ func (s *Server) HandleIKEAUTH( ikeLog.Errorf("Applying XFRM rules failed: %v", err) return } + ikeLog.Debugf(childSecurityAssociationContext.String(cfg.GetXfrmIfaceId())) // Send IKE message to UE - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) + err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, + ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("HandleIKEAUTH(): %v", err) + return + } ranNgapId, ok := n3iwfCtx.NgapIdLoad(ikeUE.N3IWFIKESecurityAssociation.LocalSPI) if !ok { @@ -1111,68 +903,16 @@ func (s *Server) HandleCREATECHILDSA( udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message *ike_message.IKEMessage, + ikeSecurityAssociation *n3iwf_context.IKESecurityAssociation, ) { ikeLog := logger.IKELog ikeLog.Infoln("Handle CREATE_CHILD_SA") - var encryptedPayload *ike_message.Encrypted - n3iwfCtx := s.Context() - responseIKEMessage := new(ike_message.IKEMessage) - - if message == nil { - ikeLog.Error("IKE Message is nil") - return - } - - // parse IKE header and setup IKE context - // check major version - majorVersion := ((message.Version & 0xf0) >> 4) - if majorVersion > 2 { - ikeLog.Warn("Received an IKE message with higher major version") - // send INFORMATIONAL type message with INVALID_MAJOR_VERSION Notify payload ( OUTSIDE IKE SA ) - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_MAJOR_VERSION, nil, nil) - - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - return - } - - // Find corresponding IKE security association - responderSPI := message.ResponderSPI - - ikeLog.Warnf("CREATE_CHILD_SA responderSPI: %+v", responderSPI) - ikeSecurityAssociation, ok := n3iwfCtx.IKESALoad(responderSPI) - if !ok { - ikeLog.Warn("Unrecognized SPI") - // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) - responseIKEMessage.BuildIKEHeader(0, message.ResponderSPI, ike_message.INFORMATIONAL, - ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) - - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - return - } - - for _, ikePayload := range message.Payloads { - switch ikePayload.Type() { - case ike_message.TypeSK: - encryptedPayload = ikePayload.(*ike_message.Encrypted) - default: - ikeLog.Warnf( - "Get IKE payload (type %d) in CREATE_CHILD_SA message, this payload will not be handled by IKE handler", - ikePayload.Type()) - } - } - - decryptedIKEPayload, err := security.DecryptProcedure( - ikeSecurityAssociation, message, encryptedPayload) - if err != nil { - ikeLog.Errorf("Decrypt IKE message failed: %v", err) + if !ikeSecurityAssociation.IKEConnection.UEAddr.IP.Equal(ueAddr.IP) || + !ikeSecurityAssociation.IKEConnection.N3IWFAddr.IP.Equal(n3iwfAddr.IP) { + ikeLog.Warnf("Get unexpteced IP in SPI: %016x", ikeSecurityAssociation.LocalSPI) return } @@ -1182,7 +922,7 @@ func (s *Server) HandleCREATECHILDSA( var trafficSelectorInitiator *ike_message.TrafficSelectorInitiator var trafficSelectorResponder *ike_message.TrafficSelectorResponder - for _, ikePayload := range decryptedIKEPayload { + for _, ikePayload := range message.Payloads { switch ikePayload.Type() { case ike_message.TypeSA: securityAssociation = ikePayload.(*ike_message.SecurityAssociation) @@ -1314,14 +1054,14 @@ func (s *Server) continueCreateChildSA( // Select GRE traffic childSecurityAssociationContext.SelectedIPProtocol = unix.IPPROTO_GRE - err = security.GenerateKeyForChildSA( - ikeSecurityAssociation, childSecurityAssociationContext) + err = childSecurityAssociationContext.ChildSAKey.GenerateKeyForChildSA(ikeSecurityAssociation.IKESAKey, + ikeSecurityAssociation.ConcatenatedNonce) if err != nil { ikeLog.Errorf("Generate key for child SA failed: %v", err) return } // NAT-T concern - if ikeSecurityAssociation.UEIsBehindNAT || ikeSecurityAssociation.N3IWFIsBehindNAT { + if ikeSecurityAssociation.UeBehindNAT || ikeSecurityAssociation.N3iwfBehindNAT { childSecurityAssociationContext.EnableEncapsulate = true childSecurityAssociationContext.N3IWFPort = ikeConnection.N3IWFAddr.Port childSecurityAssociationContext.NATPort = ikeConnection.UEAddr.Port @@ -1363,11 +1103,13 @@ func (s *Server) continueCreateChildSA( } // Aplly XFRM rules + childSecurityAssociationContext.LocalIsInitiator = true err = xfrm.ApplyXFRMRule(true, newXfrmiId, childSecurityAssociationContext) if err != nil { ikeLog.Errorf("Applying XFRM rules failed: %v", err) return } + ikeLog.Debugf(childSecurityAssociationContext.String(newXfrmiId)) ranNgapId, ok := n3iwfCtx.NgapIdLoad(ikeSecurityAssociation.LocalSPI) if !ok { @@ -1392,50 +1134,12 @@ func (s *Server) HandleInformational( udpConn *net.UDPConn, n3iwfAddr, ueAddr *net.UDPAddr, message *ike_message.IKEMessage, + ikeSecurityAssociation *n3iwf_context.IKESecurityAssociation, ) { ikeLog := logger.IKELog ikeLog.Infoln("Handle Informational") - if message == nil { - ikeLog.Error("IKE Message is nil") - return - } - n3iwfCtx := s.Context() - responseIKEMessage := new(ike_message.IKEMessage) - responderSPI := message.ResponderSPI - ikeSecurityAssociation, ok := n3iwfCtx.IKESALoad(responderSPI) - var encryptedPayload *ike_message.Encrypted - - if !ok { - ikeLog.Warn("Unrecognized SPI") - // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) - responseIKEMessage.BuildIKEHeader(0, message.ResponderSPI, ike_message.INFORMATIONAL, - ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) - - SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage) - return - } - - for _, ikePayload := range message.Payloads { - switch ikePayload.Type() { - case ike_message.TypeSK: - encryptedPayload = ikePayload.(*ike_message.Encrypted) - default: - ikeLog.Warnf( - "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", - ikePayload.Type()) - } - } - - decryptedIKEPayload, err := security.DecryptProcedure( - ikeSecurityAssociation, message, encryptedPayload) - if err != nil { - ikeLog.Errorf("Decrypt IKE message failed: %v", err) - return - } n3iwfIke := ikeSecurityAssociation.IkeUE @@ -1445,11 +1149,11 @@ func (s *Server) HandleInformational( atomic.StoreInt32(&n3iwfIke.N3IWFIKESecurityAssociation.CurrentRetryTimes, 0) } - if len(decryptedIKEPayload) == 0 { // Receive DPD message + if len(message.Payloads) == 0 { // Receive liveness message return } - for _, ikePayload := range decryptedIKEPayload { + for _, ikePayload := range message.Payloads { switch ikePayload.Type() { case ike_message.TypeD: deletePayload := ikePayload.(*ike_message.Delete) @@ -1480,7 +1184,16 @@ func (s *Server) HandleInformational( ikePayload.Type()) } } - ikeSecurityAssociation.ResponderMessageID++ + + if (message.Flags&ike_message.InitiatorBitCheck == ike_message.InitiatorBitCheck) && + (message.Flags&ike_message.ResponseBitCheck == ike_message.ResponseBitCheck) { // Get Response from UE + ikeSecurityAssociation.ResponderMessageID++ + } else { // Get Request from UE + payload := new(ike_message.IKEPayloadContainer) + SendUEInformationExchange(ikeSecurityAssociation, payload, + ike_message.ResponseBitCheck, message.MessageID, + udpConn, ueAddr, n3iwfAddr) + } } func (s *Server) HandleEvent(ikeEvt n3iwf_context.IkeEvt) { @@ -1563,23 +1276,23 @@ func (s *Server) HandleSendEAP5GFailureMsg(ikeEvt n3iwf_context.IkeEvt) { responseIKEMessage.Payloads.Reset() // EAP - identifier, err := security.GenerateRandomUint8() + identifier, err := ike_security.GenerateRandomUint8() if err != nil { ikeLog.Errorf("Generate random uint8 failed: %v", err) return } responseIKEPayload.BuildEAPfailure(identifier) - if err := security.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", err) - return - } + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, + responseIKEPayload...) // Send IKE message to UE - SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, + err = SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, ikeSecurityAssociation.IKEConnection.N3IWFAddr, ikeSecurityAssociation.IKEConnection.UEAddr, - responseIKEMessage) + responseIKEMessage, ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("HandleSendEAP5GFailureMsg(): %v", err) + } } func (s *Server) HandleSendEAPSuccessMsg(ikeEvt n3iwf_context.IkeEvt) { @@ -1610,8 +1323,13 @@ func (s *Server) HandleSendEAPSuccessMsg(ikeEvt n3iwf_context.IkeEvt) { responseIKEMessage.Payloads.Reset() var identifier uint8 + var err error for { - identifier = uint8(math_rand.Uint32()) + identifier, err = ike_security.GenerateRandomUint8() + if err != nil { + ikeLog.Errorf("HandleSendEAPSuccessMsg() rand : %v", err) + return + } if identifier != ikeSecurityAssociation.LastEAPIdentifier { ikeSecurityAssociation.LastEAPIdentifier = identifier break @@ -1620,17 +1338,18 @@ func (s *Server) HandleSendEAPSuccessMsg(ikeEvt n3iwf_context.IkeEvt) { responseIKEPayload.BuildEAPSuccess(identifier) - err := security.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage) - if err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", err) - return - } + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, + responseIKEPayload...) // Send IKE message to UE - SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, + err = SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, ikeSecurityAssociation.IKEConnection.N3IWFAddr, - ikeSecurityAssociation.IKEConnection.UEAddr, responseIKEMessage) + ikeSecurityAssociation.IKEConnection.UEAddr, responseIKEMessage, + ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("HandleSendEAPSuccessMsg(): %v", err) + return + } ikeSecurityAssociation.State++ } @@ -1656,27 +1375,36 @@ func (s *Server) HandleSendEAPNASMsg(ikeEvt n3iwf_context.IkeEvt) { responseIKEMessage.Payloads.Reset() var identifier uint8 + var err error for { - identifier = uint8(math_rand.Uint32()) + identifier, err = ike_security.GenerateRandomUint8() + if err != nil { + ikeLog.Errorf("HandleSendEAPNASMsg() rand : %v", err) + return + } if identifier != ikeSecurityAssociation.LastEAPIdentifier { ikeSecurityAssociation.LastEAPIdentifier = identifier break } } - responseIKEPayload.BuildEAP5GNAS(identifier, nasPDU) - - err := security.EncryptProcedure( - ikeSecurityAssociation, responseIKEPayload, responseIKEMessage) + err = responseIKEPayload.BuildEAP5GNAS(identifier, nasPDU) if err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", err) + ikeLog.Errorf("HandleSendEAPNASMsg() BuildEAP5GNAS: %v", err) return } + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, + responseIKEPayload...) + // Send IKE message to UE - SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, + err = SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, ikeSecurityAssociation.IKEConnection.N3IWFAddr, - ikeSecurityAssociation.IKEConnection.UEAddr, responseIKEMessage) + ikeSecurityAssociation.IKEConnection.UEAddr, responseIKEMessage, + ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("HandleSendEAPNASMsg(): %v", err) + } } func (s *Server) HandleCreatePDUSession(ikeEvt n3iwf_context.IkeEvt) { @@ -1837,9 +1565,16 @@ func (s *Server) CreatePDUSessionChildSA( var spi uint32 spiByte := make([]byte, 4) for { - randomUint64 := security.GenerateRandomNumber().Uint64() - if _, ok := n3iwfCtx.ChildSA.Load(uint32(randomUint64)); !ok { - spi = uint32(randomUint64) + var err error + buf := make([]byte, 4) + _, err = rand.Read(buf) + if err != nil { + ikeLog.Errorf("CreatePDUSessionChildSA Generate SPI: %v", err) + return + } + randomUint32 := binary.BigEndian.Uint32(buf) + if _, ok := n3iwfCtx.ChildSA.Load(randomUint32); !ok { + spi = randomUint32 break } } @@ -1849,14 +1584,18 @@ func (s *Server) CreatePDUSessionChildSA( proposal := requestSA.Proposals.BuildProposal(1, ike_message.TypeESP, spiByte) // Encryption transform - var attributeType uint16 = ike_message.AttributeTypeKeyLength - var attributeValue uint16 = 256 - proposal.EncryptionAlgorithm.BuildTransform(ike_message.TypeEncryptionAlgorithm, - ike_message.ENCR_AES_CBC, &attributeType, &attributeValue, nil) + encrTranform, err := encr.ToTransform(ikeSecurityAssociation.EncrInfo) + if err != nil { + ikeLog.Errorf("encr ToTransform error: %v", err) + break + } + + proposal.EncryptionAlgorithm = append(proposal.EncryptionAlgorithm, + encrTranform) // Integrity transform if pduSession.SecurityIntegrity { - proposal.IntegrityAlgorithm.BuildTransform(ike_message.TypeIntegrityAlgorithm, - ikeUe.N3IWFIKESecurityAssociation.IntegrityAlgorithm.TransformID, nil, nil, nil) + proposal.IntegrityAlgorithm = append(proposal.IntegrityAlgorithm, + integ.ToTransform(ikeSecurityAssociation.IntegInfo)) } // RFC 7296 @@ -1866,12 +1605,17 @@ func (s *Server) CreatePDUSessionChildSA( // ESN transform proposal.ExtendedSequenceNumbers.BuildTransform( - ike_message.TypeExtendedSequenceNumbers, ike_message.ESN_NO, nil, nil, nil) + ike_message.TypeExtendedSequenceNumbers, ike_message.ESN_DISABLE, nil, nil, nil) ikeUe.CreateHalfChildSA(ikeMessage.MessageID, spi, pduSessionID) // Build Nonce - nonceData := security.GenerateRandomNumber().Bytes() + nonceDataBigInt, errGen := ike_security.GenerateRandomNumber() + if errGen != nil { + ikeLog.Errorf("CreatePDUSessionChildSA Build Nonce: %v", errGen) + return + } + nonceData := nonceDataBigInt.Bytes() ikePayload.BuildNonce(nonceData) // Store nonce into context @@ -1891,29 +1635,37 @@ func (s *Server) CreatePDUSessionChildSA( ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, 0, 65535, ueIPAddr.To4(), ueIPAddr.To4()) + if pduSessionID < 0 || pduSessionID > math.MaxUint8 { + ikeLog.Errorf("CreatePDUSessionChildSA pduSessionID exceeds uint8 range: %d", pduSessionID) + break + } // Notify-Qos - ikePayload.BuildNotify5G_QOS_INFO(uint8(pduSessionID), pduSession.QFIList, true, false, 0) + err = ikePayload.BuildNotify5G_QOS_INFO(uint8(pduSessionID), pduSession.QFIList, true, false, 0) + if err != nil { + ikeLog.Errorf("CreatePDUSessionChildSA error : %v", err) + break + } // Notify-UP_IP_ADDRESS ikePayload.BuildNotifyUP_IP4_ADDRESS(ipsecGwAddr) temporaryPDUSessionSetupData.Index++ - if err := security.EncryptProcedure( - ikeUe.N3IWFIKESecurityAssociation, ikePayload, ikeMessage); err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %v", err) + ikeMessage.Payloads = append(ikeMessage.Payloads, ikePayload...) + err = SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, + ikeSecurityAssociation.IKEConnection.N3IWFAddr, + ikeSecurityAssociation.IKEConnection.UEAddr, ikeMessage, + ikeSecurityAssociation.IKESAKey) + if err != nil { + ikeLog.Errorf("CreatePDUSessionChildSA error : %v", err) errStr = n3iwf_context.ErrTransportResourceUnavailable temporaryPDUSessionSetupData.FailedErrStr = append(temporaryPDUSessionSetupData.FailedErrStr, errStr) - continue + } else { + temporaryPDUSessionSetupData.FailedErrStr = append(temporaryPDUSessionSetupData.FailedErrStr, + errStr) + break } - - temporaryPDUSessionSetupData.FailedErrStr = append(temporaryPDUSessionSetupData.FailedErrStr, - errStr) - - SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, ikeSecurityAssociation.IKEConnection.N3IWFAddr, - ikeSecurityAssociation.IKEConnection.UEAddr, ikeMessage) - break } else { s.NgapEvtCh() <- n3iwf_context.NewSendPDUSessionResourceSetupResEvt( ranNgapId, @@ -1936,28 +1688,33 @@ func (s *Server) StartDPD(ikeUe *n3iwf_context.N3IWFIkeUe) { n3iwfCtx := s.Context() cfg := s.Config() + ikeSA := ikeUe.N3IWFIKESecurityAssociation liveness := cfg.GetLivenessCheck() if liveness.Enable { - ikeUe.N3IWFIKESecurityAssociation.IsUseDPD = true + ikeSA.IsUseDPD = true timer := time.NewTicker(liveness.TransFreq) for { select { - case <-ikeUe.N3IWFIKESecurityAssociation.IKESAClosedCh: - close(ikeUe.N3IWFIKESecurityAssociation.IKESAClosedCh) + case <-ikeSA.IKESAClosedCh: + close(ikeSA.IKESAClosedCh) timer.Stop() return case <-timer.C: - SendUEInformationExchange(ikeUe, nil) - var DPDReqRetransTime time.Duration = 2 * time.Second - ikeUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = n3iwf_context.NewDPDPeriodicTimer( - DPDReqRetransTime, liveness.MaxRetryTimes, ikeUe.N3IWFIKESecurityAssociation, + var payload *ike_message.IKEPayloadContainer + SendUEInformationExchange(ikeSA, payload, 0, ikeSA.ResponderMessageID, + ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.UEAddr, + ikeUe.IKEConnection.N3IWFAddr) + + var DPDReqRetransTime time.Duration = 2 * time.Second // TODO: make it configurable + ikeSA.DPDReqRetransTimer = n3iwf_context.NewDPDPeriodicTimer( + DPDReqRetransTime, liveness.MaxRetryTimes, ikeSA, func() { ikeLog.Errorf("UE is down") - ranNgapId, ok := n3iwfCtx.NgapIdLoad(ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + ranNgapId, ok := n3iwfCtx.NgapIdLoad(ikeSA.LocalSPI) if !ok { ikeLog.Infof("Cannot find ranNgapId form SPI : %+v", - ikeUe.N3IWFIKESecurityAssociation.LocalSPI) + ikeSA.LocalSPI) return } @@ -1965,7 +1722,7 @@ func (s *Server) StartDPD(ikeUe *n3iwf_context.N3IWFIkeUe) { ranNgapId, n3iwf_context.ErrRadioConnWithUeLost, ) - ikeUe.N3IWFIKESecurityAssociation.DPDReqRetransTimer = nil + ikeSA.DPDReqRetransTimer = nil timer.Stop() }) } @@ -1973,113 +1730,87 @@ func (s *Server) StartDPD(ikeUe *n3iwf_context.N3IWFIkeUe) { } } -func isTransformSupported( - transformType uint8, - transformID uint16, - attributePresent bool, - attributeValue uint16, -) bool { - switch transformType { - case ike_message.TypeEncryptionAlgorithm: - switch transformID { - case ike_message.ENCR_DES_IV64: - return false - case ike_message.ENCR_DES: - return false - case ike_message.ENCR_3DES: - return false - case ike_message.ENCR_RC5: - return false - case ike_message.ENCR_IDEA: - return false - case ike_message.ENCR_CAST: - return false - case ike_message.ENCR_BLOWFISH: - return false - case ike_message.ENCR_3IDEA: - return false - case ike_message.ENCR_DES_IV32: - return false - case ike_message.ENCR_NULL: - return false - case ike_message.ENCR_AES_CBC: - if attributePresent { - switch attributeValue { - case 128: - return true - case 192: - return true - case 256: - return true - default: - return false - } - } else { - return false +func (s *Server) handleNATDetect( + initiatorSPI, responderSPI uint64, + notifications []*ike_message.Notification, + ueAddr, n3iwfAddr *net.UDPAddr, +) (bool, bool, error) { + ikeLog := logger.IKELog + ueBehindNAT := false + n3iwfBehindNAT := false + + srcNatDData, err := s.generateNATDetectHash(initiatorSPI, responderSPI, ueAddr) + if err != nil { + return false, false, errors.Wrapf(err, "handle NATD") + } + + dstNatDData, err := s.generateNATDetectHash(initiatorSPI, responderSPI, n3iwfAddr) + if err != nil { + return false, false, errors.Wrapf(err, "handle NATD") + } + + for _, notification := range notifications { + switch notification.NotifyMessageType { + case ike_message.NAT_DETECTION_SOURCE_IP: + ikeLog.Tracef("Received IKE Notify: NAT_DETECTION_SOURCE_IP") + if !bytes.Equal(notification.NotificationData, srcNatDData) { + ikeLog.Tracef("UE(SPI: %016x) is behind NAT", responderSPI) + ueBehindNAT = true + } + case ike_message.NAT_DETECTION_DESTINATION_IP: + ikeLog.Tracef("Received IKE Notify: NAT_DETECTION_DESTINATION_IP") + if !bytes.Equal(notification.NotificationData, dstNatDData) { + ikeLog.Tracef("N3IWF is behind NAT") + n3iwfBehindNAT = true } - case ike_message.ENCR_AES_CTR: - return false - default: - return false - } - case ike_message.TypePseudorandomFunction: - switch transformID { - case ike_message.PRF_HMAC_MD5: - return true - case ike_message.PRF_HMAC_SHA1: - return true - case ike_message.PRF_HMAC_TIGER: - return false - case ike_message.PRF_HMAC_SHA2_256: - return true - default: - return false - } - case ike_message.TypeIntegrityAlgorithm: - switch transformID { - case ike_message.AUTH_NONE: - return false - case ike_message.AUTH_HMAC_MD5_96: - return true - case ike_message.AUTH_HMAC_SHA1_96: - return true - case ike_message.AUTH_DES_MAC: - return false - case ike_message.AUTH_KPDK_MD5: - return false - case ike_message.AUTH_AES_XCBC_96: - return false - case ike_message.AUTH_HMAC_SHA2_256_128: - return true - default: - return false - } - case ike_message.TypeDiffieHellmanGroup: - switch transformID { - case ike_message.DH_NONE: - return false - case ike_message.DH_768_BIT_MODP: - return false - case ike_message.DH_1024_BIT_MODP: - return true - case ike_message.DH_1536_BIT_MODP: - return false - case ike_message.DH_2048_BIT_MODP: - return true - case ike_message.DH_3072_BIT_MODP: - return false - case ike_message.DH_4096_BIT_MODP: - return false - case ike_message.DH_6144_BIT_MODP: - return false - case ike_message.DH_8192_BIT_MODP: - return false default: - return false } - default: - return false } + return ueBehindNAT, n3iwfBehindNAT, nil +} + +func (s *Server) generateNATDetectHash( + initiatorSPI, responderSPI uint64, + addr *net.UDPAddr, +) ([]byte, error) { + // Calculate NAT_DETECTION hash for NAT-T + // : sha1(ispi | rspi | ip | port) + natdData := make([]byte, 22) + binary.BigEndian.PutUint64(natdData[0:8], initiatorSPI) + binary.BigEndian.PutUint64(natdData[8:16], responderSPI) + copy(natdData[16:20], addr.IP.To4()) + binary.BigEndian.PutUint16(natdData[20:22], uint16(addr.Port)) // #nosec G115 + + sha1HashFunction := sha1.New() // #nosec G401 + _, err := sha1HashFunction.Write(natdData) + if err != nil { + return nil, errors.Wrapf(err, "generate NATD Hash") + } + return sha1HashFunction.Sum(nil), nil +} + +func (s *Server) buildNATDetectNotifPayload( + ikeSA *n3iwf_context.IKESecurityAssociation, + payload *ike_message.IKEPayloadContainer, + ueAddr, n3iwfAddr *net.UDPAddr, +) error { + srcNatDHash, err := s.generateNATDetectHash(ikeSA.RemoteSPI, ikeSA.LocalSPI, n3iwfAddr) + if err != nil { + return errors.Wrapf(err, "build NATD") + } + // Build and append notify payload for NAT_DETECTION_SOURCE_IP + payload.BuildNotification( + ike_message.TypeNone, ike_message.NAT_DETECTION_SOURCE_IP, nil, srcNatDHash) + + dstNatDHash, err := s.generateNATDetectHash(ikeSA.RemoteSPI, ikeSA.LocalSPI, ueAddr) + if err != nil { + return errors.Wrapf(err, "build NATD") + } + // Build and append notify payload for NAT_DETECTION_DESTINATION_IP + payload.BuildNotification( + ike_message.TypeNone, ike_message.NAT_DETECTION_DESTINATION_IP, nil, dstNatDHash) + + return nil } func isTransformKernelSupported( @@ -2176,32 +1907,32 @@ func isTransformKernelSupported( } case ike_message.TypeDiffieHellmanGroup: switch transformID { - case ike_message.DH_NONE: - return false - case ike_message.DH_768_BIT_MODP: - return false - case ike_message.DH_1024_BIT_MODP: - return false - case ike_message.DH_1536_BIT_MODP: - return false - case ike_message.DH_2048_BIT_MODP: - return false - case ike_message.DH_3072_BIT_MODP: - return false - case ike_message.DH_4096_BIT_MODP: - return false - case ike_message.DH_6144_BIT_MODP: - return false - case ike_message.DH_8192_BIT_MODP: - return false + // case ike_message.DH_NONE: + // return false + // case ike_message.DH_768_BIT_MODP: + // return false + // case ike_message.DH_1024_BIT_MODP: + // return false + // case ike_message.DH_1536_BIT_MODP: + // return false + // case ike_message.DH_2048_BIT_MODP: + // return false + // case ike_message.DH_3072_BIT_MODP: + // return false + // case ike_message.DH_4096_BIT_MODP: + // return false + // case ike_message.DH_6144_BIT_MODP: + // return false + // case ike_message.DH_8192_BIT_MODP: + // return false default: return false } case ike_message.TypeExtendedSequenceNumbers: switch transformID { - case ike_message.ESN_NO: + case ike_message.ESN_ENABLE: return true - case ike_message.ESN_NEED: + case ike_message.ESN_DISABLE: return true default: return false @@ -2242,3 +1973,83 @@ func (s *Server) parseIPAddressInformationToChildSecurityAssociation( return nil } + +func SelectProposal(proposals ike_message.ProposalContainer) ike_message.ProposalContainer { + var chooseProposal ike_message.ProposalContainer + + for _, proposal := range proposals { + // We need ENCR, PRF, INTEG, DH, but not ESN + + var encryptionAlgorithmTransform, pseudorandomFunctionTransform *ike_message.Transform + var integrityAlgorithmTransform, diffieHellmanGroupTransform *ike_message.Transform + var chooseDH dh.DHType + var chooseEncr encr.ENCRType + var chooseInte integ.INTEGType + var choosePrf prf.PRFType + + for _, transform := range proposal.DiffieHellmanGroup { + dhType := dh.DecodeTransform(transform) + if dhType != nil { + if diffieHellmanGroupTransform == nil { + diffieHellmanGroupTransform = transform + chooseDH = dhType + } + } + } + if chooseDH == nil { + continue // mandatory + } + + for _, transform := range proposal.EncryptionAlgorithm { + encrType := encr.DecodeTransform(transform) + if encrType != nil { + if encryptionAlgorithmTransform == nil { + encryptionAlgorithmTransform = transform + chooseEncr = encrType + } + } + } + if chooseEncr == nil { + continue // mandatory + } + + for _, transform := range proposal.IntegrityAlgorithm { + integType := integ.DecodeTransform(transform) + if integType != nil { + if integrityAlgorithmTransform == nil { + integrityAlgorithmTransform = transform + chooseInte = integType + } + } + } + if chooseInte == nil { + continue // mandatory + } + + for _, transform := range proposal.PseudorandomFunction { + prfType := prf.DecodeTransform(transform) + if prfType != nil { + if pseudorandomFunctionTransform == nil { + pseudorandomFunctionTransform = transform + choosePrf = prfType + } + } + } + if choosePrf == nil { + continue // mandatory + } + if len(proposal.ExtendedSequenceNumbers) > 0 { + continue // No ESN + } + + // Construct chosen proposal, with ENCR, PRF, INTEG, DH, and each + // contains one transform expectively + chosenProposal := chooseProposal.BuildProposal(proposal.ProposalNumber, proposal.ProtocolID, nil) + chosenProposal.EncryptionAlgorithm = append(chosenProposal.EncryptionAlgorithm, encryptionAlgorithmTransform) + chosenProposal.IntegrityAlgorithm = append(chosenProposal.IntegrityAlgorithm, integrityAlgorithmTransform) + chosenProposal.PseudorandomFunction = append(chosenProposal.PseudorandomFunction, pseudorandomFunctionTransform) + chosenProposal.DiffieHellmanGroup = append(chosenProposal.DiffieHellmanGroup, diffieHellmanGroupTransform) + break + } + return chooseProposal +} diff --git a/pkg/ike/handler_test.go b/pkg/ike/handler_test.go index 2a5a57d8..701064ca 100644 --- a/pkg/ike/handler_test.go +++ b/pkg/ike/handler_test.go @@ -1,12 +1,14 @@ package ike import ( + "net" "testing" "github.com/stretchr/testify/require" + ike_message "github.com/free5gc/ike/message" + n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" - ike_message "github.com/free5gc/n3iwf/pkg/ike/message" ) func TestRemoveIkeUe(t *testing.T) { @@ -26,7 +28,17 @@ func TestRemoveIkeUe(t *testing.T) { ikeAuth := &ike_message.SecurityAssociation{} - ikeAuth.Proposals.BuildProposal(1, 1, []byte{0, 1, 2, 3}) + proposal := ikeAuth.Proposals.BuildProposal(1, 1, []byte{0, 1, 2, 3}) + var attributeType uint16 = ike_message.AttributeTypeKeyLength + var attributeValue uint16 = 256 + proposal.EncryptionAlgorithm.BuildTransform(ike_message.TypeEncryptionAlgorithm, + ike_message.ENCR_AES_CBC, &attributeType, &attributeValue, nil) + + proposal.IntegrityAlgorithm.BuildTransform(ike_message.TypeIntegrityAlgorithm, + ike_message.AUTH_HMAC_SHA1_96, nil, nil, nil) + + proposal.ExtendedSequenceNumbers.BuildTransform( + ike_message.TypeExtendedSequenceNumbers, ike_message.ESN_DISABLE, nil, nil, nil) childSA, err := ikeUe.CompleteChildSA(1, 456, ikeAuth) require.NoError(t, err) @@ -43,3 +55,231 @@ func TestRemoveIkeUe(t *testing.T) { _, ok = ikeUe.N3IWFChildSecurityAssociation[childSA.InboundSPI] require.False(t, ok) } + +func TestGenerateNATDetectHash(t *testing.T) { + n3iwf, err := NewN3iwfTestApp(&factory.Config{}) + require.NoError(t, err) + + n3iwf.ikeServer, err = NewServer(n3iwf) + require.NoError(t, err) + + tests := []struct { + name string + initiatorSPI uint64 + responderSPI uint64 + Addr net.UDPAddr + expectedData []byte + }{ + { + name: "Generate NAT-D hash", + initiatorSPI: 0x1122334455667788, + responderSPI: 0xaabbeeddeeff1122, + Addr: net.UDPAddr{ + IP: net.ParseIP("192.168.1.1"), + Port: 4500, + }, + expectedData: []byte{ + 0xd2, 0xee, 0x40, 0x2d, 0x5d, 0x53, 0xe4, 0x4a, + 0x01, 0x2d, 0x44, 0x2a, 0x90, 0x05, 0xc1, 0xea, + 0x38, 0x8a, 0x81, 0x7e, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + data, err := n3iwf.ikeServer.generateNATDetectHash(tt.initiatorSPI, tt.responderSPI, &tt.Addr) + require.NoError(t, err) + + require.Equal(t, tt.expectedData, data) + }) + } +} + +func TestBuildNATDetectMsg(t *testing.T) { + n3iwf, err := NewN3iwfTestApp(&factory.Config{}) + require.NoError(t, err) + + n3iwf.ikeServer, err = NewServer(n3iwf) + require.NoError(t, err) + + remoteSPI := uint64(0x1234567890abcdef) + localSPI := uint64(0xfedcba0987654321) + ikeSA := &n3iwf_context.IKESecurityAssociation{ + LocalSPI: localSPI, + RemoteSPI: remoteSPI, + } + payload := &ike_message.IKEPayloadContainer{} + + ueAddr := net.UDPAddr{ + IP: net.ParseIP("192.168.1.1"), + Port: 4500, + } + n3iwfAddr := net.UDPAddr{ + IP: net.ParseIP("192.168.1.2"), + Port: 4500, + } + + err = n3iwf.ikeServer.buildNATDetectNotifPayload(ikeSA, payload, &ueAddr, &n3iwfAddr) + require.NoError(t, err) + + var notifications []*ike_message.Notification + for _, ikePayload := range *payload { + switch ikePayload.Type() { + case ike_message.TypeN: + notifications = append(notifications, ikePayload.(*ike_message.Notification)) + default: + require.Fail(t, "Get unexpected IKE payload type : %v", ikePayload.Type()) + } + } + + for _, notification := range notifications { + switch notification.NotifyMessageType { + case ike_message.NAT_DETECTION_SOURCE_IP: + expectedData := []byte{ + 0x13, 0xd8, 0x9e, 0xdc, 0xfa, 0x39, 0xe4, 0xc0, + 0x06, 0x80, 0x5f, 0xde, 0x11, 0x62, 0xd8, 0x76, + 0xee, 0xe8, 0xf2, 0x00, + } + require.Equal(t, expectedData, notification.NotificationData) + case ike_message.NAT_DETECTION_DESTINATION_IP: + expectedData := []byte{ + 0x0d, 0x36, 0x26, 0x71, 0xaf, 0x7f, 0x0b, 0x19, + 0x32, 0xec, 0xf8, 0xf3, 0xe1, 0x84, 0x87, 0xf0, + 0x47, 0x76, 0x83, 0x04, + } + require.Equal(t, expectedData, notification.NotificationData) + } + } +} + +func TestHandleNATDetect(t *testing.T) { + n3iwf, err := NewN3iwfTestApp(&factory.Config{}) + require.NoError(t, err) + + n3iwf.ikeServer, err = NewServer(n3iwf) + require.NoError(t, err) + + tests := []struct { + name string + initiatorSPI uint64 + responderSPI uint64 + notification []*ike_message.Notification + ueAddr net.UDPAddr + n3iwfAddr net.UDPAddr + expectedUeBehindNAT bool + expectedN3iwfBehindNAT bool + }{ + { + name: "UE and N3IWF is not behind NAT", + initiatorSPI: 0x1234567890abcdef, + responderSPI: 0xfedcba0987654321, + notification: []*ike_message.Notification{ + { + NotifyMessageType: ike_message.NAT_DETECTION_SOURCE_IP, + NotificationData: []byte{ + 0x0d, 0x36, 0x26, 0x71, 0xaf, 0x7f, 0x0b, 0x19, + 0x32, 0xec, 0xf8, 0xf3, 0xe1, 0x84, 0x87, 0xf0, + 0x47, 0x76, 0x83, 0x04, + }, + }, + { + NotifyMessageType: ike_message.NAT_DETECTION_DESTINATION_IP, + NotificationData: []byte{ + 0x13, 0xd8, 0x9e, 0xdc, 0xfa, 0x39, 0xe4, 0xc0, + 0x06, 0x80, 0x5f, 0xde, 0x11, 0x62, 0xd8, 0x76, + 0xee, 0xe8, 0xf2, 0x00, + }, + }, + }, + ueAddr: net.UDPAddr{ + IP: net.ParseIP("192.168.1.1"), + Port: 4500, + }, + n3iwfAddr: net.UDPAddr{ + IP: net.ParseIP("192.168.1.2"), + Port: 4500, + }, + expectedUeBehindNAT: false, + expectedN3iwfBehindNAT: false, + }, + { + name: "UE is behind NAT and N3IWF is not behind NAT", + initiatorSPI: 0x1234567890abcdef, + responderSPI: 0xfedcba0987654321, + notification: []*ike_message.Notification{ + { + NotifyMessageType: ike_message.NAT_DETECTION_SOURCE_IP, + NotificationData: []byte{ + 0x0b, 0x17, 0x2d, 0x42, 0xaf, 0x7f, 0x0b, 0x19, + 0x32, 0xec, 0xf8, 0xf3, 0xe1, 0x84, 0x87, 0xf0, + 0x47, 0x76, 0x83, 0x04, + }, + }, + { + NotifyMessageType: ike_message.NAT_DETECTION_DESTINATION_IP, + NotificationData: []byte{ + 0x13, 0xd8, 0x9e, 0xdc, 0xfa, 0x39, 0xe4, 0xc0, + 0x06, 0x80, 0x5f, 0xde, 0x11, 0x62, 0xd8, 0x76, + 0xee, 0xe8, 0xf2, 0x00, + }, + }, + }, + ueAddr: net.UDPAddr{ + IP: net.ParseIP("192.168.1.1"), + Port: 4500, + }, + n3iwfAddr: net.UDPAddr{ + IP: net.ParseIP("192.168.1.2"), + Port: 4500, + }, + expectedUeBehindNAT: true, + expectedN3iwfBehindNAT: false, + }, + { + name: "UE and N3IWF is behind NAT", + initiatorSPI: 0x1234567890abcdef, + responderSPI: 0xfedcba0987654321, + notification: []*ike_message.Notification{ + { + NotifyMessageType: ike_message.NAT_DETECTION_SOURCE_IP, + NotificationData: []byte{ + 0x0b, 0x16, 0x26, 0x71, 0xaf, 0x7f, 0x0b, 0x19, + 0x32, 0xec, 0xf8, 0xf3, 0xe1, 0x84, 0x87, 0xf0, + 0x47, 0x76, 0x83, 0x04, + }, + }, + { + NotifyMessageType: ike_message.NAT_DETECTION_DESTINATION_IP, + NotificationData: []byte{ + 0x0f, 0xd9, 0x9e, 0xdc, 0xfa, 0x39, 0xe4, 0xc0, + 0x06, 0x80, 0x5f, 0xde, 0x11, 0x62, 0xd8, 0x76, + 0xee, 0xe8, 0xf2, 0x00, + }, + }, + }, + ueAddr: net.UDPAddr{ + IP: net.ParseIP("192.168.1.1"), + Port: 4500, + }, + n3iwfAddr: net.UDPAddr{ + IP: net.ParseIP("192.168.1.2"), + Port: 4500, + }, + expectedUeBehindNAT: true, + expectedN3iwfBehindNAT: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ueBehindNAT, n3iwfBehindNAT, err := n3iwf.ikeServer.handleNATDetect( + tt.initiatorSPI, tt.responderSPI, + tt.notification, &tt.ueAddr, &tt.n3iwfAddr) + require.NoError(t, err) + + require.Equal(t, tt.expectedUeBehindNAT, ueBehindNAT) + require.Equal(t, tt.expectedN3iwfBehindNAT, n3iwfBehindNAT) + }) + } +} diff --git a/pkg/ike/message/build.go b/pkg/ike/message/build.go deleted file mode 100644 index f709324b..00000000 --- a/pkg/ike/message/build.go +++ /dev/null @@ -1,324 +0,0 @@ -package message - -import ( - "encoding/binary" - "net" - - "github.com/free5gc/n3iwf/internal/logger" -) - -func (ikeMessage *IKEMessage) BuildIKEHeader( - initiatorSPI uint64, - responsorSPI uint64, - exchangeType uint8, - flags uint8, - messageID uint32, -) { - ikeMessage.InitiatorSPI = initiatorSPI - ikeMessage.ResponderSPI = responsorSPI - ikeMessage.Version = 0x20 - ikeMessage.ExchangeType = exchangeType - ikeMessage.Flags = flags - ikeMessage.MessageID = messageID -} - -func (container *IKEPayloadContainer) Reset() { - *container = nil -} - -func (container *IKEPayloadContainer) BuildNotification( - protocolID uint8, - notifyMessageType uint16, - spi []byte, - notificationData []byte, -) { - notification := new(Notification) - notification.ProtocolID = protocolID - notification.NotifyMessageType = notifyMessageType - notification.SPI = append(notification.SPI, spi...) - notification.NotificationData = append(notification.NotificationData, notificationData...) - *container = append(*container, notification) -} - -func (container *IKEPayloadContainer) BuildCertificate(certificateEncode uint8, certificateData []byte) { - certificate := new(Certificate) - certificate.CertificateEncoding = certificateEncode - certificate.CertificateData = append(certificate.CertificateData, certificateData...) - *container = append(*container, certificate) -} - -func (container *IKEPayloadContainer) BuildEncrypted(nextPayload IKEPayloadType, encryptedData []byte) *Encrypted { - encrypted := new(Encrypted) - encrypted.NextPayload = uint8(nextPayload) - encrypted.EncryptedData = append(encrypted.EncryptedData, encryptedData...) - *container = append(*container, encrypted) - return encrypted -} - -func (container *IKEPayloadContainer) BUildKeyExchange(diffiehellmanGroup uint16, keyExchangeData []byte) { - keyExchange := new(KeyExchange) - keyExchange.DiffieHellmanGroup = diffiehellmanGroup - keyExchange.KeyExchangeData = append(keyExchange.KeyExchangeData, keyExchangeData...) - *container = append(*container, keyExchange) -} - -func (container *IKEPayloadContainer) BuildIdentificationInitiator(idType uint8, idData []byte) { - identification := new(IdentificationInitiator) - identification.IDType = idType - identification.IDData = append(identification.IDData, idData...) - *container = append(*container, identification) -} - -func (container *IKEPayloadContainer) BuildIdentificationResponder(idType uint8, idData []byte) { - identification := new(IdentificationResponder) - identification.IDType = idType - identification.IDData = append(identification.IDData, idData...) - *container = append(*container, identification) -} - -func (container *IKEPayloadContainer) BuildAuthentication(authenticationMethod uint8, authenticationData []byte) { - authentication := new(Authentication) - authentication.AuthenticationMethod = authenticationMethod - authentication.AuthenticationData = append(authentication.AuthenticationData, authenticationData...) - *container = append(*container, authentication) -} - -func (container *IKEPayloadContainer) BuildConfiguration(configurationType uint8) *Configuration { - configuration := new(Configuration) - configuration.ConfigurationType = configurationType - *container = append(*container, configuration) - return configuration -} - -func (container *ConfigurationAttributeContainer) Reset() { - *container = nil -} - -func (container *ConfigurationAttributeContainer) BuildConfigurationAttribute( - attributeType uint16, - attributeValue []byte, -) { - configurationAttribute := new(IndividualConfigurationAttribute) - configurationAttribute.Type = attributeType - configurationAttribute.Value = append(configurationAttribute.Value, attributeValue...) - *container = append(*container, configurationAttribute) -} - -func (container *IKEPayloadContainer) BuildNonce(nonceData []byte) { - nonce := new(Nonce) - nonce.NonceData = append(nonce.NonceData, nonceData...) - *container = append(*container, nonce) -} - -func (container *IKEPayloadContainer) BuildTrafficSelectorInitiator() *TrafficSelectorInitiator { - trafficSelectorInitiator := new(TrafficSelectorInitiator) - *container = append(*container, trafficSelectorInitiator) - return trafficSelectorInitiator -} - -func (container *IKEPayloadContainer) BuildTrafficSelectorResponder() *TrafficSelectorResponder { - trafficSelectorResponder := new(TrafficSelectorResponder) - *container = append(*container, trafficSelectorResponder) - return trafficSelectorResponder -} - -func (container *IndividualTrafficSelectorContainer) Reset() { - *container = nil -} - -func (container *IndividualTrafficSelectorContainer) BuildIndividualTrafficSelector( - tsType uint8, - ipProtocolID uint8, - startPort uint16, - endPort uint16, - startAddr []byte, - endAddr []byte, -) { - trafficSelector := new(IndividualTrafficSelector) - trafficSelector.TSType = tsType - trafficSelector.IPProtocolID = ipProtocolID - trafficSelector.StartPort = startPort - trafficSelector.EndPort = endPort - trafficSelector.StartAddress = append(trafficSelector.StartAddress, startAddr...) - trafficSelector.EndAddress = append(trafficSelector.EndAddress, endAddr...) - *container = append(*container, trafficSelector) -} - -func (container *IKEPayloadContainer) BuildSecurityAssociation() *SecurityAssociation { - securityAssociation := new(SecurityAssociation) - *container = append(*container, securityAssociation) - return securityAssociation -} - -func (container *ProposalContainer) Reset() { - *container = nil -} - -func (container *ProposalContainer) BuildProposal(proposalNumber uint8, protocolID uint8, spi []byte) *Proposal { - proposal := new(Proposal) - proposal.ProposalNumber = proposalNumber - proposal.ProtocolID = protocolID - proposal.SPI = append(proposal.SPI, spi...) - *container = append(*container, proposal) - return proposal -} - -func (container *IKEPayloadContainer) BuildDeletePayload( - protocolID uint8, SPISize uint8, numberOfSPI uint16, SPIs []byte, -) { - deletePayload := new(Delete) - deletePayload.ProtocolID = protocolID - deletePayload.SPISize = SPISize - deletePayload.NumberOfSPI = numberOfSPI - deletePayload.SPIs = SPIs - *container = append(*container, deletePayload) -} - -func (container *TransformContainer) Reset() { - *container = nil -} - -func (container *TransformContainer) BuildTransform( - transformType uint8, - transformID uint16, - attributeType *uint16, - attributeValue *uint16, - variableLengthAttributeValue []byte, -) { - transform := new(Transform) - transform.TransformType = transformType - transform.TransformID = transformID - if attributeType != nil { - transform.AttributePresent = true - transform.AttributeType = *attributeType - if attributeValue != nil { - transform.AttributeFormat = AttributeFormatUseTV - transform.AttributeValue = *attributeValue - } else if len(variableLengthAttributeValue) != 0 { - transform.AttributeFormat = AttributeFormatUseTLV - transform.VariableLengthAttributeValue = append(transform.VariableLengthAttributeValue, - variableLengthAttributeValue...) - } else { - return - } - } else { - transform.AttributePresent = false - } - *container = append(*container, transform) -} - -func (container *IKEPayloadContainer) BuildEAP(code uint8, identifier uint8) *EAP { - eap := new(EAP) - eap.Code = code - eap.Identifier = identifier - *container = append(*container, eap) - return eap -} - -func (container *IKEPayloadContainer) BuildEAPSuccess(identifier uint8) { - eap := new(EAP) - eap.Code = EAPCodeSuccess - eap.Identifier = identifier - *container = append(*container, eap) -} - -func (container *IKEPayloadContainer) BuildEAPfailure(identifier uint8) { - eap := new(EAP) - eap.Code = EAPCodeFailure - eap.Identifier = identifier - *container = append(*container, eap) -} - -func (container *EAPTypeDataContainer) BuildEAPExpanded(vendorID uint32, vendorType uint32, vendorData []byte) { - eapExpanded := new(EAPExpanded) - eapExpanded.VendorID = vendorID - eapExpanded.VendorType = vendorType - eapExpanded.VendorData = append(eapExpanded.VendorData, vendorData...) - *container = append(*container, eapExpanded) -} - -func (container *IKEPayloadContainer) BuildEAP5GStart(identifier uint8) { - eap := container.BuildEAP(EAPCodeRequest, identifier) - eap.EAPTypeData.BuildEAPExpanded(VendorID3GPP, VendorTypeEAP5G, []byte{EAP5GType5GStart, EAP5GSpareValue}) -} - -func (container *IKEPayloadContainer) BuildEAP5GNAS(identifier uint8, nasPDU []byte) { - ikeLog := logger.IKELog - if len(nasPDU) == 0 { - ikeLog.Error("BuildEAP5GNAS(): NASPDU is nil") - return - } - - header := make([]byte, 4) - - // Message ID - header[0] = EAP5GType5GNAS - // NASPDU length (2 octets) - binary.BigEndian.PutUint16(header[2:4], uint16(len(nasPDU))) - vendorData := append(header, nasPDU...) - - eap := container.BuildEAP(EAPCodeRequest, identifier) - eap.EAPTypeData.BuildEAPExpanded(VendorID3GPP, VendorTypeEAP5G, vendorData) -} - -func (container *IKEPayloadContainer) BuildNotify5G_QOS_INFO( - pduSessionID uint8, - qfiList []uint8, - isDefault bool, - isDSCPSpecified bool, - DSCP uint8, -) { - notifyData := make([]byte, 1) // For length - // Append PDU session ID - notifyData = append(notifyData, pduSessionID) - // Append QFI list length - notifyData = append(notifyData, uint8(len(qfiList))) - // Append QFI list - notifyData = append(notifyData, qfiList...) - // Append default and differentiated service flags - var defaultAndDifferentiatedServiceFlags uint8 - if isDefault { - defaultAndDifferentiatedServiceFlags |= NotifyType5G_QOS_INFOBitDCSICheck - } - if isDSCPSpecified { - defaultAndDifferentiatedServiceFlags |= NotifyType5G_QOS_INFOBitDSCPICheck - } - - notifyData = append(notifyData, defaultAndDifferentiatedServiceFlags) - if isDSCPSpecified { - notifyData = append(notifyData, DSCP) - } - - // Assign length - notifyData[0] = uint8(len(notifyData)) - - container.BuildNotification(TypeNone, Vendor3GPPNotifyType5G_QOS_INFO, nil, notifyData) -} - -func (container *IKEPayloadContainer) BuildNotifyNAS_IP4_ADDRESS(nasIPAddr string) { - if nasIPAddr == "" { - return - } else { - ipAddrByte := net.ParseIP(nasIPAddr).To4() - container.BuildNotification(TypeNone, Vendor3GPPNotifyTypeNAS_IP4_ADDRESS, nil, ipAddrByte) - } -} - -func (container *IKEPayloadContainer) BuildNotifyUP_IP4_ADDRESS(upIPAddr string) { - if upIPAddr == "" { - return - } else { - ipAddrByte := net.ParseIP(upIPAddr).To4() - container.BuildNotification(TypeNone, Vendor3GPPNotifyTypeUP_IP4_ADDRESS, nil, ipAddrByte) - } -} - -func (container *IKEPayloadContainer) BuildNotifyNAS_TCP_PORT(port uint16) { - if port == 0 { - return - } else { - portData := make([]byte, 2) - binary.BigEndian.PutUint16(portData, port) - container.BuildNotification(TypeNone, Vendor3GPPNotifyTypeNAS_TCP_PORT, nil, portData) - } -} diff --git a/pkg/ike/message/message.go b/pkg/ike/message/message.go deleted file mode 100644 index 413f2a17..00000000 --- a/pkg/ike/message/message.go +++ /dev/null @@ -1,1564 +0,0 @@ -package message - -import ( - "encoding/binary" - "encoding/hex" - "errors" - "fmt" - - "github.com/free5gc/n3iwf/internal/logger" -) - -type IKEMessage struct { - InitiatorSPI uint64 - ResponderSPI uint64 - Version uint8 - ExchangeType uint8 - Flags uint8 - MessageID uint32 - Payloads IKEPayloadContainer -} - -func (ikeMessage *IKEMessage) Encode() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("Encoding IKE message") - - ikeMessageData := make([]byte, 28) - - binary.BigEndian.PutUint64(ikeMessageData[0:8], ikeMessage.InitiatorSPI) - binary.BigEndian.PutUint64(ikeMessageData[8:16], ikeMessage.ResponderSPI) - ikeMessageData[17] = ikeMessage.Version - ikeMessageData[18] = ikeMessage.ExchangeType - ikeMessageData[19] = ikeMessage.Flags - binary.BigEndian.PutUint32(ikeMessageData[20:24], ikeMessage.MessageID) - - if len(ikeMessage.Payloads) > 0 { - ikeMessageData[16] = byte(ikeMessage.Payloads[0].Type()) - } else { - ikeMessageData[16] = NoNext - } - - ikeMessagePayloadData, err := ikeMessage.Payloads.Encode() - if err != nil { - return nil, fmt.Errorf("Encode(): EncodePayload failed: %+v", err) - } - - ikeMessageData = append(ikeMessageData, ikeMessagePayloadData...) - binary.BigEndian.PutUint32(ikeMessageData[24:28], uint32(len(ikeMessageData))) - - ikeLog.Tracef("Encoded %d bytes", len(ikeMessageData)) - ikeLog.Tracef("IKE message data:\n%s", hex.Dump(ikeMessageData)) - - return ikeMessageData, nil -} - -func (ikeMessage *IKEMessage) Decode(rawData []byte) error { - // IKE message packet format this implementation referenced is - // defined in RFC 7296, Section 3.1 - ikeLog := logger.IKELog - ikeLog.Info("Decoding IKE message") - ikeLog.Tracef("Received IKE message:\n%s", hex.Dump(rawData)) - - // bounds checking - if len(rawData) < 28 { - return errors.New("Decode(): Received broken IKE header") - } - ikeMessageLength := binary.BigEndian.Uint32(rawData[24:28]) - if ikeMessageLength < 28 { - return fmt.Errorf("Decode(): Illegal IKE message length %d < header length 20", ikeMessageLength) - } - // len() return int, which is 64 bit on 64-bit host and 32 bit - // on 32-bit host, so this implementation may potentially cause - // problem on 32-bit machine - if len(rawData) != int(ikeMessageLength) { - return errors.New("Decode(): The length of received message not matchs the length specified in header") - } - - nextPayload := rawData[16] - - ikeMessage.InitiatorSPI = binary.BigEndian.Uint64(rawData[:8]) - ikeMessage.ResponderSPI = binary.BigEndian.Uint64(rawData[8:16]) - ikeMessage.Version = rawData[17] - ikeMessage.ExchangeType = rawData[18] - ikeMessage.Flags = rawData[19] - ikeMessage.MessageID = binary.BigEndian.Uint32(rawData[20:24]) - - err := ikeMessage.Payloads.Decode(nextPayload, rawData[28:]) - if err != nil { - return fmt.Errorf("Decode(): DecodePayload failed: %+v", err) - } - - return nil -} - -type IKEPayloadContainer []IKEPayload - -func (container *IKEPayloadContainer) Encode() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("Encoding IKE payloads") - - ikeMessagePayloadData := make([]byte, 0) - - for index, payload := range *container { - payloadData := make([]byte, 4) // IKE payload general header - if (index + 1) < len(*container) { // if it has next payload - payloadData[0] = uint8((*container)[index+1].Type()) - } else { - if payload.Type() == TypeSK { - payloadData[0] = payload.(*Encrypted).NextPayload - } else { - payloadData[0] = NoNext - } - } - - data, err := payload.marshal() - if err != nil { - return nil, fmt.Errorf("EncodePayload(): Failed to marshal payload: %+v", err) - } - - payloadData = append(payloadData, data...) - binary.BigEndian.PutUint16(payloadData[2:4], uint16(len(payloadData))) - - ikeMessagePayloadData = append(ikeMessagePayloadData, payloadData...) - } - - return ikeMessagePayloadData, nil -} - -func (container *IKEPayloadContainer) Decode(nextPayload uint8, rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("Decoding IKE payloads") - - for len(rawData) > 0 { - // bounds checking - ikeLog.Trace("DecodePayload(): Decode 1 payload") - if len(rawData) < 4 { - return errors.New("DecodePayload(): No sufficient bytes to decode next payload") - } - payloadLength := binary.BigEndian.Uint16(rawData[2:4]) - if payloadLength < 4 { - return fmt.Errorf("DecodePayload(): Illegal payload length %d < header length 4", payloadLength) - } - if len(rawData) < int(payloadLength) { - return errors.New("DecodePayload(): The length of received message not matchs the length specified in header") - } - - criticalBit := (rawData[1] & 0x80) >> 7 - - var payload IKEPayload - - switch nextPayload { - case TypeSA: - payload = new(SecurityAssociation) - case TypeKE: - payload = new(KeyExchange) - case TypeIDi: - payload = new(IdentificationInitiator) - case TypeIDr: - payload = new(IdentificationResponder) - case TypeCERT: - payload = new(Certificate) - case TypeCERTreq: - payload = new(CertificateRequest) - case TypeAUTH: - payload = new(Authentication) - case TypeNiNr: - payload = new(Nonce) - case TypeN: - payload = new(Notification) - case TypeD: - payload = new(Delete) - case TypeV: - payload = new(VendorID) - case TypeTSi: - payload = new(TrafficSelectorInitiator) - case TypeTSr: - payload = new(TrafficSelectorResponder) - case TypeSK: - encryptedPayload := new(Encrypted) - encryptedPayload.NextPayload = rawData[0] - payload = encryptedPayload - case TypeCP: - payload = new(Configuration) - case TypeEAP: - payload = new(EAP) - default: - if criticalBit == 0 { - // Skip this payload - nextPayload = rawData[0] - rawData = rawData[payloadLength:] - continue - } else { - // TODO: Reject this IKE message - return fmt.Errorf("Unknown payload type: %d", nextPayload) - } - } - - if err := payload.unmarshal(rawData[4:payloadLength]); err != nil { - return fmt.Errorf("DecodePayload(): Unmarshal payload failed: %+v", err) - } - - *container = append(*container, payload) - - nextPayload = rawData[0] - rawData = rawData[payloadLength:] - } - - return nil -} - -type IKEPayload interface { - // Type specifies the IKE payload types - Type() IKEPayloadType - - // Called by Encode() or Decode() - marshal() ([]byte, error) - unmarshal(rawData []byte) error -} - -// Definition of Security Association - -var _ IKEPayload = &SecurityAssociation{} - -type SecurityAssociation struct { - Proposals ProposalContainer -} - -type ProposalContainer []*Proposal - -type Proposal struct { - ProposalNumber uint8 - ProtocolID uint8 - SPI []byte - EncryptionAlgorithm TransformContainer - PseudorandomFunction TransformContainer - IntegrityAlgorithm TransformContainer - DiffieHellmanGroup TransformContainer - ExtendedSequenceNumbers TransformContainer -} - -type TransformContainer []*Transform - -type Transform struct { - TransformType uint8 - TransformID uint16 - AttributePresent bool - AttributeFormat uint8 - AttributeType uint16 - AttributeValue uint16 - VariableLengthAttributeValue []byte -} - -func (securityAssociation *SecurityAssociation) Type() IKEPayloadType { return TypeSA } - -func (securityAssociation *SecurityAssociation) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[SecurityAssociation] marshal(): Start marshalling") - - securityAssociationData := make([]byte, 0) - - for proposalIndex, proposal := range securityAssociation.Proposals { - proposalData := make([]byte, 8) - - if (proposalIndex + 1) < len(securityAssociation.Proposals) { - proposalData[0] = 2 - } else { - proposalData[0] = 0 - } - - proposalData[4] = proposal.ProposalNumber - proposalData[5] = proposal.ProtocolID - - proposalData[6] = uint8(len(proposal.SPI)) - if len(proposal.SPI) > 0 { - proposalData = append(proposalData, proposal.SPI...) - } - - // combine all transforms - var transformList []*Transform - transformList = append(transformList, proposal.EncryptionAlgorithm...) - transformList = append(transformList, proposal.PseudorandomFunction...) - transformList = append(transformList, proposal.IntegrityAlgorithm...) - transformList = append(transformList, proposal.DiffieHellmanGroup...) - transformList = append(transformList, proposal.ExtendedSequenceNumbers...) - - if len(transformList) == 0 { - return nil, errors.New("One proposal has no any transform") - } - proposalData[7] = uint8(len(transformList)) - - proposalTransformData := make([]byte, 0) - - for transformIndex, transform := range transformList { - transformData := make([]byte, 8) - - if (transformIndex + 1) < len(transformList) { - transformData[0] = 3 - } else { - transformData[0] = 0 - } - - transformData[4] = transform.TransformType - binary.BigEndian.PutUint16(transformData[6:8], transform.TransformID) - - if transform.AttributePresent { - attributeData := make([]byte, 4) - - if transform.AttributeFormat == 0 { - // TLV - if len(transform.VariableLengthAttributeValue) == 0 { - return nil, errors.New("Attribute of one transform not specified") - } - attributeFormatAndType := ((uint16(transform.AttributeFormat) & 0x1) << 15) | transform.AttributeType - binary.BigEndian.PutUint16(attributeData[0:2], attributeFormatAndType) - binary.BigEndian.PutUint16(attributeData[2:4], uint16(len(transform.VariableLengthAttributeValue))) - attributeData = append(attributeData, transform.VariableLengthAttributeValue...) - } else { - // TV - attributeFormatAndType := ((uint16(transform.AttributeFormat) & 0x1) << 15) | transform.AttributeType - binary.BigEndian.PutUint16(attributeData[0:2], attributeFormatAndType) - binary.BigEndian.PutUint16(attributeData[2:4], transform.AttributeValue) - } - - transformData = append(transformData, attributeData...) - } - - binary.BigEndian.PutUint16(transformData[2:4], uint16(len(transformData))) - - proposalTransformData = append(proposalTransformData, transformData...) - } - - proposalData = append(proposalData, proposalTransformData...) - binary.BigEndian.PutUint16(proposalData[2:4], uint16(len(proposalData))) - - securityAssociationData = append(securityAssociationData, proposalData...) - } - - return securityAssociationData, nil -} - -func (securityAssociation *SecurityAssociation) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[SecurityAssociation] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[SecurityAssociation] unmarshal(): Payload length %d bytes", len(rawData)) - - for len(rawData) > 0 { - ikeLog.Trace("[SecurityAssociation] unmarshal(): Unmarshal 1 proposal") - // bounds checking - if len(rawData) < 8 { - return errors.New("Proposal: No sufficient bytes to decode next proposal") - } - proposalLength := binary.BigEndian.Uint16(rawData[2:4]) - if proposalLength < 8 { - return errors.New("Proposal: Illegal payload length %d < header length 8") - } - if len(rawData) < int(proposalLength) { - return errors.New("Proposal: The length of received message not matchs the length specified in header") - } - - // Log whether this proposal is the last - if rawData[0] == 0 { - ikeLog.Trace("[SecurityAssociation] This proposal is the last") - } - // Log the number of transform in the proposal - ikeLog.Tracef("[SecurityAssociation] This proposal contained %d transform", rawData[7]) - - proposal := new(Proposal) - var transformData []byte - - proposal.ProposalNumber = rawData[4] - proposal.ProtocolID = rawData[5] - - spiSize := rawData[6] - if spiSize > 0 { - // bounds checking - if len(rawData) < int(8+spiSize) { - return errors.New("Proposal: No sufficient bytes for unmarshalling SPI of proposal") - } - proposal.SPI = append(proposal.SPI, rawData[8:8+spiSize]...) - } - - transformData = rawData[8+spiSize : proposalLength] - - for len(transformData) > 0 { - // bounds checking - ikeLog.Trace("[SecurityAssociation] unmarshal(): Unmarshal 1 transform") - if len(transformData) < 8 { - return errors.New("Transform: No sufficient bytes to decode next transform") - } - transformLength := binary.BigEndian.Uint16(transformData[2:4]) - if transformLength < 8 { - return errors.New("Transform: Illegal payload length %d < header length 8") - } - if len(transformData) < int(transformLength) { - return errors.New("Transform: The length of received message not matchs the length specified in header") - } - - // Log whether this transform is the last - if transformData[0] == 0 { - ikeLog.Trace("[SecurityAssociation] This transform is the last") - } - - transform := new(Transform) - - transform.TransformType = transformData[4] - transform.TransformID = binary.BigEndian.Uint16(transformData[6:8]) - if transformLength > 8 { - transform.AttributePresent = true - transform.AttributeFormat = ((transformData[8] & 0x80) >> 7) - transform.AttributeType = binary.BigEndian.Uint16(transformData[8:10]) & 0x7f - - if transform.AttributeFormat == 0 { - attributeLength := binary.BigEndian.Uint16(transformData[10:12]) - // bounds checking - if (12 + attributeLength) != transformLength { - return fmt.Errorf("Illegal attribute length %d not satisfies the transform length %d", - attributeLength, transformLength) - } - copy(transform.VariableLengthAttributeValue, transformData[12:12+attributeLength]) - } else { - transform.AttributeValue = binary.BigEndian.Uint16(transformData[10:12]) - } - } - - switch transform.TransformType { - case TypeEncryptionAlgorithm: - proposal.EncryptionAlgorithm = append(proposal.EncryptionAlgorithm, transform) - case TypePseudorandomFunction: - proposal.PseudorandomFunction = append(proposal.PseudorandomFunction, transform) - case TypeIntegrityAlgorithm: - proposal.IntegrityAlgorithm = append(proposal.IntegrityAlgorithm, transform) - case TypeDiffieHellmanGroup: - proposal.DiffieHellmanGroup = append(proposal.DiffieHellmanGroup, transform) - case TypeExtendedSequenceNumbers: - proposal.ExtendedSequenceNumbers = append(proposal.ExtendedSequenceNumbers, transform) - } - - transformData = transformData[transformLength:] - } - - securityAssociation.Proposals = append(securityAssociation.Proposals, proposal) - - rawData = rawData[proposalLength:] - } - - return nil -} - -// Definition of Key Exchange - -var _ IKEPayload = &KeyExchange{} - -type KeyExchange struct { - DiffieHellmanGroup uint16 - KeyExchangeData []byte -} - -func (keyExchange *KeyExchange) Type() IKEPayloadType { return TypeKE } - -func (keyExchange *KeyExchange) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[KeyExchange] marshal(): Start marshalling") - - keyExchangeData := make([]byte, 4) - - binary.BigEndian.PutUint16(keyExchangeData[0:2], keyExchange.DiffieHellmanGroup) - keyExchangeData = append(keyExchangeData, keyExchange.KeyExchangeData...) - - return keyExchangeData, nil -} - -func (keyExchange *KeyExchange) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[KeyExchange] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[KeyExchange] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[KeyExchange] unmarshal(): Unmarshal 1 key exchange data") - // bounds checking - if len(rawData) <= 4 { - return errors.New("KeyExchange: No sufficient bytes to decode next key exchange data") - } - - keyExchange.DiffieHellmanGroup = binary.BigEndian.Uint16(rawData[0:2]) - keyExchange.KeyExchangeData = append(keyExchange.KeyExchangeData, rawData[4:]...) - } - - return nil -} - -// Definition of Identification - Initiator - -var _ IKEPayload = &IdentificationInitiator{} - -type IdentificationInitiator struct { - IDType uint8 - IDData []byte -} - -func (identification *IdentificationInitiator) Type() IKEPayloadType { return TypeIDi } - -func (identification *IdentificationInitiator) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[Identification] marshal(): Start marshalling") - - identificationData := make([]byte, 4) - - identificationData[0] = identification.IDType - identificationData = append(identificationData, identification.IDData...) - - return identificationData, nil -} - -func (identification *IdentificationInitiator) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[Identification] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Identification] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[Identification] unmarshal(): Unmarshal 1 identification") - // bounds checking - if len(rawData) <= 4 { - return errors.New("Identification: No sufficient bytes to decode next identification") - } - - identification.IDType = rawData[0] - identification.IDData = append(identification.IDData, rawData[4:]...) - } - - return nil -} - -// Definition of Identification - Responder - -var _ IKEPayload = &IdentificationResponder{} - -type IdentificationResponder struct { - IDType uint8 - IDData []byte -} - -func (identification *IdentificationResponder) Type() IKEPayloadType { return TypeIDr } - -func (identification *IdentificationResponder) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[Identification] marshal(): Start marshalling") - - identificationData := make([]byte, 4) - - identificationData[0] = identification.IDType - identificationData = append(identificationData, identification.IDData...) - - return identificationData, nil -} - -func (identification *IdentificationResponder) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[Identification] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Identification] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[Identification] unmarshal(): Unmarshal 1 identification") - // bounds checking - if len(rawData) <= 4 { - return errors.New("Identification: No sufficient bytes to decode next identification") - } - - identification.IDType = rawData[0] - identification.IDData = append(identification.IDData, rawData[4:]...) - } - - return nil -} - -// Definition of Certificate - -var _ IKEPayload = &Certificate{} - -type Certificate struct { - CertificateEncoding uint8 - CertificateData []byte -} - -func (certificate *Certificate) Type() IKEPayloadType { return TypeCERT } - -func (certificate *Certificate) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[Certificate] marshal(): Start marshalling") - - certificateData := make([]byte, 1) - - certificateData[0] = certificate.CertificateEncoding - certificateData = append(certificateData, certificate.CertificateData...) - - return certificateData, nil -} - -func (certificate *Certificate) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[Certificate] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Certificate] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[Certificate] unmarshal(): Unmarshal 1 certificate") - // bounds checking - if len(rawData) <= 1 { - return errors.New("Certificate: No sufficient bytes to decode next certificate") - } - - certificate.CertificateEncoding = rawData[0] - certificate.CertificateData = append(certificate.CertificateData, rawData[1:]...) - } - - return nil -} - -// Definition of Certificate Request - -var _ IKEPayload = &CertificateRequest{} - -type CertificateRequest struct { - CertificateEncoding uint8 - CertificationAuthority []byte -} - -func (certificateRequest *CertificateRequest) Type() IKEPayloadType { return TypeCERTreq } - -func (certificateRequest *CertificateRequest) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[CertificateRequest] marshal(): Start marshalling") - - certificateRequestData := make([]byte, 1) - - certificateRequestData[0] = certificateRequest.CertificateEncoding - certificateRequestData = append(certificateRequestData, certificateRequest.CertificationAuthority...) - - return certificateRequestData, nil -} - -func (certificateRequest *CertificateRequest) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[CertificateRequest] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[CertificateRequest] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[CertificateRequest] unmarshal(): Unmarshal 1 certificate request") - // bounds checking - if len(rawData) <= 1 { - return errors.New("CertificateRequest: No sufficient bytes to decode next certificate request") - } - - certificateRequest.CertificateEncoding = rawData[0] - certificateRequest.CertificationAuthority = append(certificateRequest.CertificationAuthority, rawData[1:]...) - } - - return nil -} - -// Definition of Authentication - -var _ IKEPayload = &Authentication{} - -type Authentication struct { - AuthenticationMethod uint8 - AuthenticationData []byte -} - -func (authentication *Authentication) Type() IKEPayloadType { return TypeAUTH } - -func (authentication *Authentication) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[Authentication] marshal(): Start marshalling") - - authenticationData := make([]byte, 4) - - authenticationData[0] = authentication.AuthenticationMethod - authenticationData = append(authenticationData, authentication.AuthenticationData...) - - return authenticationData, nil -} - -func (authentication *Authentication) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[Authentication] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Authentication] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[Authentication] unmarshal(): Unmarshal 1 authentication") - // bounds checking - if len(rawData) <= 4 { - return errors.New("Authentication: No sufficient bytes to decode next authentication") - } - - authentication.AuthenticationMethod = rawData[0] - authentication.AuthenticationData = append(authentication.AuthenticationData, rawData[4:]...) - } - - return nil -} - -// Definition of Nonce - -var _ IKEPayload = &Nonce{} - -type Nonce struct { - NonceData []byte -} - -func (nonce *Nonce) Type() IKEPayloadType { return TypeNiNr } - -func (nonce *Nonce) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[Nonce] marshal(): Start marshalling") - - nonceData := make([]byte, 0) - nonceData = append(nonceData, nonce.NonceData...) - - return nonceData, nil -} - -func (nonce *Nonce) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[Nonce] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Nonce] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[Nonce] unmarshal(): Unmarshal 1 nonce") - nonce.NonceData = append(nonce.NonceData, rawData...) - } - - return nil -} - -// Definition of Notification - -var _ IKEPayload = &Notification{} - -type Notification struct { - ProtocolID uint8 - NotifyMessageType uint16 - SPI []byte - NotificationData []byte -} - -func (notification *Notification) Type() IKEPayloadType { return TypeN } - -func (notification *Notification) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[Notification] marshal(): Start marshalling") - - notificationData := make([]byte, 4) - - notificationData[0] = notification.ProtocolID - notificationData[1] = uint8(len(notification.SPI)) - binary.BigEndian.PutUint16(notificationData[2:4], notification.NotifyMessageType) - - notificationData = append(notificationData, notification.SPI...) - notificationData = append(notificationData, notification.NotificationData...) - - return notificationData, nil -} - -func (notification *Notification) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[Notification] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Notification] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[Notification] unmarshal(): Unmarshal 1 notification") - // bounds checking - if len(rawData) < 4 { - return errors.New("Notification: No sufficient bytes to decode next notification") - } - spiSize := rawData[1] - if len(rawData) < int(4+spiSize) { - return errors.New("Notification: No sufficient bytes to get SPI according to the length specified in header") - } - - notification.ProtocolID = rawData[0] - notification.NotifyMessageType = binary.BigEndian.Uint16(rawData[2:4]) - - notification.SPI = append(notification.SPI, rawData[4:4+spiSize]...) - notification.NotificationData = append(notification.NotificationData, rawData[4+spiSize:]...) - } - - return nil -} - -// Definition of Delete - -var _ IKEPayload = &Delete{} - -type Delete struct { - ProtocolID uint8 - SPISize uint8 - NumberOfSPI uint16 - SPIs []byte -} - -func (del *Delete) Type() IKEPayloadType { return TypeD } - -func (del *Delete) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[Delete] marshal(): Start marshalling") - - if len(del.SPIs) != (int(del.SPISize) * int(del.NumberOfSPI)) { - return nil, fmt.Errorf("Total bytes of all SPIs not correct") - } - - deleteData := make([]byte, 4) - - deleteData[0] = del.ProtocolID - deleteData[1] = del.SPISize - binary.BigEndian.PutUint16(deleteData[2:4], del.NumberOfSPI) - - if int(del.NumberOfSPI) > 0 { - deleteData = append(deleteData, del.SPIs...) - } - - return deleteData, nil -} - -func (del *Delete) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[Delete] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Delete] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[Delete] unmarshal(): Unmarshal 1 delete") - // bounds checking - if len(rawData) <= 3 { - return errors.New("Delete: No sufficient bytes to decode next delete") - } - spiSize := rawData[1] - numberOfSPI := binary.BigEndian.Uint16(rawData[2:4]) - if len(rawData) < (4 + (int(spiSize) * int(numberOfSPI))) { - return errors.New("Delete: No Sufficient bytes to get SPIs according to the length specified in header") - } - - del.ProtocolID = rawData[0] - del.SPISize = spiSize - del.NumberOfSPI = numberOfSPI - - del.SPIs = append(del.SPIs, rawData[4:]...) - } - - return nil -} - -// Definition of Vendor ID - -var _ IKEPayload = &VendorID{} - -type VendorID struct { - VendorIDData []byte -} - -func (vendorID *VendorID) Type() IKEPayloadType { return TypeV } - -func (vendorID *VendorID) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[VendorID] marshal(): Start marshalling") - return vendorID.VendorIDData, nil -} - -func (vendorID *VendorID) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[VendorID] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[VendorID] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[VendorID] unmarshal(): Unmarshal 1 vendor ID") - vendorID.VendorIDData = append(vendorID.VendorIDData, rawData...) - } - - return nil -} - -// Definition of Traffic Selector - Initiator - -var _ IKEPayload = &TrafficSelectorInitiator{} - -type TrafficSelectorInitiator struct { - TrafficSelectors IndividualTrafficSelectorContainer -} - -type IndividualTrafficSelectorContainer []*IndividualTrafficSelector - -type IndividualTrafficSelector struct { - TSType uint8 - IPProtocolID uint8 - StartPort uint16 - EndPort uint16 - StartAddress []byte - EndAddress []byte -} - -func (trafficSelector *TrafficSelectorInitiator) Type() IKEPayloadType { return TypeTSi } - -func (trafficSelector *TrafficSelectorInitiator) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[TrafficSelector] marshal(): Start marshalling") - - if len(trafficSelector.TrafficSelectors) > 0 { - trafficSelectorData := make([]byte, 4) - trafficSelectorData[0] = uint8(len(trafficSelector.TrafficSelectors)) - - for _, individualTrafficSelector := range trafficSelector.TrafficSelectors { - if individualTrafficSelector.TSType == TS_IPV4_ADDR_RANGE { - // Address length checking - if len(individualTrafficSelector.StartAddress) != 4 { - ikeLog.Errorf("Address length %d", len(individualTrafficSelector.StartAddress)) - return nil, errors.New("TrafficSelector: Start IPv4 address length is not correct") - } - if len(individualTrafficSelector.EndAddress) != 4 { - return nil, errors.New("TrafficSelector: End IPv4 address length is not correct") - } - - individualTrafficSelectorData := make([]byte, 8) - - individualTrafficSelectorData[0] = individualTrafficSelector.TSType - individualTrafficSelectorData[1] = individualTrafficSelector.IPProtocolID - binary.BigEndian.PutUint16(individualTrafficSelectorData[4:6], individualTrafficSelector.StartPort) - binary.BigEndian.PutUint16(individualTrafficSelectorData[6:8], individualTrafficSelector.EndPort) - - individualTrafficSelectorData = append(individualTrafficSelectorData, individualTrafficSelector.StartAddress...) - individualTrafficSelectorData = append(individualTrafficSelectorData, individualTrafficSelector.EndAddress...) - - binary.BigEndian.PutUint16(individualTrafficSelectorData[2:4], uint16(len(individualTrafficSelectorData))) - - trafficSelectorData = append(trafficSelectorData, individualTrafficSelectorData...) - } else if individualTrafficSelector.TSType == TS_IPV6_ADDR_RANGE { - // Address length checking - if len(individualTrafficSelector.StartAddress) != 16 { - return nil, errors.New("TrafficSelector: Start IPv6 address length is not correct") - } - if len(individualTrafficSelector.EndAddress) != 16 { - return nil, errors.New("TrafficSelector: End IPv6 address length is not correct") - } - - individualTrafficSelectorData := make([]byte, 8) - - individualTrafficSelectorData[0] = individualTrafficSelector.TSType - individualTrafficSelectorData[1] = individualTrafficSelector.IPProtocolID - binary.BigEndian.PutUint16(individualTrafficSelectorData[4:6], individualTrafficSelector.StartPort) - binary.BigEndian.PutUint16(individualTrafficSelectorData[6:8], individualTrafficSelector.EndPort) - - individualTrafficSelectorData = append(individualTrafficSelectorData, individualTrafficSelector.StartAddress...) - individualTrafficSelectorData = append(individualTrafficSelectorData, individualTrafficSelector.EndAddress...) - - binary.BigEndian.PutUint16(individualTrafficSelectorData[2:4], uint16(len(individualTrafficSelectorData))) - - trafficSelectorData = append(trafficSelectorData, individualTrafficSelectorData...) - } else { - return nil, errors.New("TrafficSelector: Unsupported traffic selector type") - } - } - - return trafficSelectorData, nil - } else { - return nil, errors.New("TrafficSelector: Contains no traffic selector for marshalling message") - } -} - -func (trafficSelector *TrafficSelectorInitiator) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[TrafficSelector] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[TrafficSelector] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[TrafficSelector] unmarshal(): Unmarshal 1 traffic selector") - // bounds checking - if len(rawData) < 4 { - return errors.New("TrafficSelector: No sufficient bytes to get number of traffic selector in header") - } - - numberOfSPI := rawData[0] - - rawData = rawData[4:] - - for ; numberOfSPI > 0; numberOfSPI-- { - // bounds checking - if len(rawData) < 4 { - return errors.New( - "TrafficSelector: No sufficient bytes to decode next individual traffic selector length in header") - } - trafficSelectorType := rawData[0] - if trafficSelectorType == TS_IPV4_ADDR_RANGE { - selectorLength := binary.BigEndian.Uint16(rawData[2:4]) - if selectorLength != 16 { - return errors.New("TrafficSelector: A TS_IPV4_ADDR_RANGE type traffic selector should has length 16 bytes") - } - if len(rawData) < int(selectorLength) { - return errors.New("TrafficSelector: No sufficient bytes to decode next individual traffic selector") - } - - individualTrafficSelector := &IndividualTrafficSelector{} - - individualTrafficSelector.TSType = rawData[0] - individualTrafficSelector.IPProtocolID = rawData[1] - individualTrafficSelector.StartPort = binary.BigEndian.Uint16(rawData[4:6]) - individualTrafficSelector.EndPort = binary.BigEndian.Uint16(rawData[6:8]) - - individualTrafficSelector.StartAddress = append(individualTrafficSelector.StartAddress, rawData[8:12]...) - individualTrafficSelector.EndAddress = append(individualTrafficSelector.EndAddress, rawData[12:16]...) - - trafficSelector.TrafficSelectors = append(trafficSelector.TrafficSelectors, individualTrafficSelector) - - rawData = rawData[16:] - } else if trafficSelectorType == TS_IPV6_ADDR_RANGE { - selectorLength := binary.BigEndian.Uint16(rawData[2:4]) - if selectorLength != 40 { - return errors.New("TrafficSelector: A TS_IPV6_ADDR_RANGE type traffic selector should has length 40 bytes") - } - if len(rawData) < int(selectorLength) { - return errors.New("TrafficSelector: No sufficient bytes to decode next individual traffic selector") - } - - individualTrafficSelector := &IndividualTrafficSelector{} - - individualTrafficSelector.TSType = rawData[0] - individualTrafficSelector.IPProtocolID = rawData[1] - individualTrafficSelector.StartPort = binary.BigEndian.Uint16(rawData[4:6]) - individualTrafficSelector.EndPort = binary.BigEndian.Uint16(rawData[6:8]) - - individualTrafficSelector.StartAddress = append(individualTrafficSelector.StartAddress, rawData[8:24]...) - individualTrafficSelector.EndAddress = append(individualTrafficSelector.EndAddress, rawData[24:40]...) - - trafficSelector.TrafficSelectors = append(trafficSelector.TrafficSelectors, individualTrafficSelector) - - rawData = rawData[40:] - } else { - return errors.New("TrafficSelector: Unsupported traffic selector type") - } - } - } - - return nil -} - -// Definition of Traffic Selector - Responder - -var _ IKEPayload = &TrafficSelectorResponder{} - -type TrafficSelectorResponder struct { - TrafficSelectors IndividualTrafficSelectorContainer -} - -func (trafficSelector *TrafficSelectorResponder) Type() IKEPayloadType { return TypeTSr } - -func (trafficSelector *TrafficSelectorResponder) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[TrafficSelector] marshal(): Start marshalling") - - if len(trafficSelector.TrafficSelectors) > 0 { - trafficSelectorData := make([]byte, 4) - trafficSelectorData[0] = uint8(len(trafficSelector.TrafficSelectors)) - - for _, individualTrafficSelector := range trafficSelector.TrafficSelectors { - if individualTrafficSelector.TSType == TS_IPV4_ADDR_RANGE { - // Address length checking - if len(individualTrafficSelector.StartAddress) != 4 { - return nil, errors.New("TrafficSelector: Start IPv4 address length is not correct") - } - if len(individualTrafficSelector.EndAddress) != 4 { - return nil, errors.New("TrafficSelector: End IPv4 address length is not correct") - } - - individualTrafficSelectorData := make([]byte, 8) - - individualTrafficSelectorData[0] = individualTrafficSelector.TSType - individualTrafficSelectorData[1] = individualTrafficSelector.IPProtocolID - binary.BigEndian.PutUint16(individualTrafficSelectorData[4:6], individualTrafficSelector.StartPort) - binary.BigEndian.PutUint16(individualTrafficSelectorData[6:8], individualTrafficSelector.EndPort) - - individualTrafficSelectorData = append(individualTrafficSelectorData, individualTrafficSelector.StartAddress...) - individualTrafficSelectorData = append(individualTrafficSelectorData, individualTrafficSelector.EndAddress...) - - binary.BigEndian.PutUint16(individualTrafficSelectorData[2:4], uint16(len(individualTrafficSelectorData))) - - trafficSelectorData = append(trafficSelectorData, individualTrafficSelectorData...) - } else if individualTrafficSelector.TSType == TS_IPV6_ADDR_RANGE { - // Address length checking - if len(individualTrafficSelector.StartAddress) != 16 { - return nil, errors.New("TrafficSelector: Start IPv6 address length is not correct") - } - if len(individualTrafficSelector.EndAddress) != 16 { - return nil, errors.New("TrafficSelector: End IPv6 address length is not correct") - } - - individualTrafficSelectorData := make([]byte, 8) - - individualTrafficSelectorData[0] = individualTrafficSelector.TSType - individualTrafficSelectorData[1] = individualTrafficSelector.IPProtocolID - binary.BigEndian.PutUint16(individualTrafficSelectorData[4:6], individualTrafficSelector.StartPort) - binary.BigEndian.PutUint16(individualTrafficSelectorData[6:8], individualTrafficSelector.EndPort) - - individualTrafficSelectorData = append(individualTrafficSelectorData, individualTrafficSelector.StartAddress...) - individualTrafficSelectorData = append(individualTrafficSelectorData, individualTrafficSelector.EndAddress...) - - binary.BigEndian.PutUint16(individualTrafficSelectorData[2:4], uint16(len(individualTrafficSelectorData))) - - trafficSelectorData = append(trafficSelectorData, individualTrafficSelectorData...) - } else { - return nil, errors.New("TrafficSelector: Unsupported traffic selector type") - } - } - - return trafficSelectorData, nil - } else { - return nil, errors.New("TrafficSelector: Contains no traffic selector for marshalling message") - } -} - -func (trafficSelector *TrafficSelectorResponder) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[TrafficSelector] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[TrafficSelector] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[TrafficSelector] unmarshal(): Unmarshal 1 traffic selector") - // bounds checking - if len(rawData) < 4 { - return errors.New("TrafficSelector: No sufficient bytes to get number of traffic selector in header") - } - - numberOfSPI := rawData[0] - - rawData = rawData[4:] - - for ; numberOfSPI > 0; numberOfSPI-- { - // bounds checking - if len(rawData) < 4 { - return errors.New( - "TrafficSelector: No sufficient bytes to decode next individual traffic selector length in header") - } - trafficSelectorType := rawData[0] - if trafficSelectorType == TS_IPV4_ADDR_RANGE { - selectorLength := binary.BigEndian.Uint16(rawData[2:4]) - if selectorLength != 16 { - return errors.New("TrafficSelector: A TS_IPV4_ADDR_RANGE type traffic selector should has length 16 bytes") - } - if len(rawData) < int(selectorLength) { - return errors.New("TrafficSelector: No sufficient bytes to decode next individual traffic selector") - } - - individualTrafficSelector := &IndividualTrafficSelector{} - - individualTrafficSelector.TSType = rawData[0] - individualTrafficSelector.IPProtocolID = rawData[1] - individualTrafficSelector.StartPort = binary.BigEndian.Uint16(rawData[4:6]) - individualTrafficSelector.EndPort = binary.BigEndian.Uint16(rawData[6:8]) - - individualTrafficSelector.StartAddress = append(individualTrafficSelector.StartAddress, rawData[8:12]...) - individualTrafficSelector.EndAddress = append(individualTrafficSelector.EndAddress, rawData[12:16]...) - - trafficSelector.TrafficSelectors = append(trafficSelector.TrafficSelectors, individualTrafficSelector) - - rawData = rawData[16:] - } else if trafficSelectorType == TS_IPV6_ADDR_RANGE { - selectorLength := binary.BigEndian.Uint16(rawData[2:4]) - if selectorLength != 40 { - return errors.New("TrafficSelector: A TS_IPV6_ADDR_RANGE type traffic selector should has length 40 bytes") - } - if len(rawData) < int(selectorLength) { - return errors.New("TrafficSelector: No sufficient bytes to decode next individual traffic selector") - } - - individualTrafficSelector := &IndividualTrafficSelector{} - - individualTrafficSelector.TSType = rawData[0] - individualTrafficSelector.IPProtocolID = rawData[1] - individualTrafficSelector.StartPort = binary.BigEndian.Uint16(rawData[4:6]) - individualTrafficSelector.EndPort = binary.BigEndian.Uint16(rawData[6:8]) - - individualTrafficSelector.StartAddress = append(individualTrafficSelector.StartAddress, rawData[8:24]...) - individualTrafficSelector.EndAddress = append(individualTrafficSelector.EndAddress, rawData[24:40]...) - - trafficSelector.TrafficSelectors = append(trafficSelector.TrafficSelectors, individualTrafficSelector) - - rawData = rawData[40:] - } else { - return errors.New("TrafficSelector: Unsupported traffic selector type") - } - } - } - - return nil -} - -// Definition of Encrypted Payload - -var _ IKEPayload = &Encrypted{} - -type Encrypted struct { - NextPayload uint8 - EncryptedData []byte -} - -func (encrypted *Encrypted) Type() IKEPayloadType { return TypeSK } - -func (encrypted *Encrypted) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[Encrypted] marshal(): Start marshalling") - - if len(encrypted.EncryptedData) == 0 { - ikeLog.Warn("[Encrypted] The encrypted data is empty") - } - - return encrypted.EncryptedData, nil -} - -func (encrypted *Encrypted) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[Encrypted] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Encrypted] unmarshal(): Payload length %d bytes", len(rawData)) - encrypted.EncryptedData = append(encrypted.EncryptedData, rawData...) - return nil -} - -// Definition of Configuration - -var _ IKEPayload = &Configuration{} - -type Configuration struct { - ConfigurationType uint8 - ConfigurationAttribute ConfigurationAttributeContainer -} - -type ConfigurationAttributeContainer []*IndividualConfigurationAttribute - -type IndividualConfigurationAttribute struct { - Type uint16 - Value []byte -} - -func (configuration *Configuration) Type() IKEPayloadType { return TypeCP } - -func (configuration *Configuration) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[Configuration] marshal(): Start marshalling") - - configurationData := make([]byte, 4) - - configurationData[0] = configuration.ConfigurationType - - for _, attribute := range configuration.ConfigurationAttribute { - individualConfigurationAttributeData := make([]byte, 4) - - binary.BigEndian.PutUint16(individualConfigurationAttributeData[0:2], (attribute.Type & 0x7fff)) - binary.BigEndian.PutUint16(individualConfigurationAttributeData[2:4], uint16(len(attribute.Value))) - - individualConfigurationAttributeData = append(individualConfigurationAttributeData, attribute.Value...) - - configurationData = append(configurationData, individualConfigurationAttributeData...) - } - - return configurationData, nil -} - -func (configuration *Configuration) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[Configuration] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[Configuration] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[Configuration] unmarshal(): Unmarshal 1 configuration") - // bounds checking - if len(rawData) <= 4 { - return errors.New("Configuration: No sufficient bytes to decode next configuration") - } - configuration.ConfigurationType = rawData[0] - - configurationAttributeData := rawData[4:] - - for len(configurationAttributeData) > 0 { - ikeLog.Trace("[Configuration] unmarshal(): Unmarshal 1 configuration attribute") - // bounds checking - if len(configurationAttributeData) < 4 { - return errors.New("ConfigurationAttribute: No sufficient bytes to decode next configuration attribute") - } - length := binary.BigEndian.Uint16(configurationAttributeData[2:4]) - if len(configurationAttributeData) < int(4+length) { - return errors.New("ConfigurationAttribute: TLV attribute length error") - } - - individualConfigurationAttribute := new(IndividualConfigurationAttribute) - - individualConfigurationAttribute.Type = binary.BigEndian.Uint16(configurationAttributeData[0:2]) - configurationAttributeData = configurationAttributeData[4:] - individualConfigurationAttribute.Value = append(individualConfigurationAttribute.Value, - configurationAttributeData[:length]...) - configurationAttributeData = configurationAttributeData[length:] - - configuration.ConfigurationAttribute = append(configuration.ConfigurationAttribute, individualConfigurationAttribute) - } - } - - return nil -} - -// Definition of IKE EAP - -var _ IKEPayload = &EAP{} - -type EAP struct { - Code uint8 - Identifier uint8 - EAPTypeData EAPTypeDataContainer -} - -func (eap *EAP) Type() IKEPayloadType { return TypeEAP } - -func (eap *EAP) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[EAP] marshal(): Start marshalling") - - eapData := make([]byte, 4) - - eapData[0] = eap.Code - eapData[1] = eap.Identifier - - if len(eap.EAPTypeData) > 0 { - eapTypeData, err := eap.EAPTypeData[0].marshal() - if err != nil { - return nil, fmt.Errorf("EAP: EAP type data marshal failed: %+v", err) - } - - eapData = append(eapData, eapTypeData...) - } - - binary.BigEndian.PutUint16(eapData[2:4], uint16(len(eapData))) - - return eapData, nil -} - -func (eap *EAP) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[EAP] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - ikeLog.Trace("[EAP] unmarshal(): Unmarshal 1 EAP") - // bounds checking - if len(rawData) < 4 { - return errors.New("EAP: No sufficient bytes to decode next EAP payload") - } - eapPayloadLength := binary.BigEndian.Uint16(rawData[2:4]) - if eapPayloadLength < 4 { - return errors.New("EAP: Payload length specified in the header is too small for EAP") - } - if len(rawData) != int(eapPayloadLength) { - return errors.New("EAP: Received payload length not matches the length specified in header") - } - - eap.Code = rawData[0] - eap.Identifier = rawData[1] - - // EAP Success or Failed - if eapPayloadLength == 4 { - return nil - } - - eapType := rawData[4] - var eapTypeData EAPTypeFormat - - switch eapType { - case EAPTypeIdentity: - eapTypeData = new(EAPIdentity) - case EAPTypeNotification: - eapTypeData = new(EAPNotification) - case EAPTypeNak: - eapTypeData = new(EAPNak) - case EAPTypeExpanded: - eapTypeData = new(EAPExpanded) - default: - // TODO: Create unsupprted type to handle it - return errors.New("EAP: Not supported EAP type") - } - - if err := eapTypeData.unmarshal(rawData[4:]); err != nil { - return fmt.Errorf("EAP: Unamrshal EAP type data failed: %+v", err) - } - - eap.EAPTypeData = append(eap.EAPTypeData, eapTypeData) - } - - return nil -} - -type EAPTypeDataContainer []EAPTypeFormat - -type EAPTypeFormat interface { - // Type specifies EAP types - Type() EAPType - - // Called by EAP.marshal() or EAP.unmarshal() - marshal() ([]byte, error) - unmarshal(rawData []byte) error -} - -// Definition of EAP Identity - -var _ EAPTypeFormat = &EAPIdentity{} - -type EAPIdentity struct { - IdentityData []byte -} - -func (eapIdentity *EAPIdentity) Type() EAPType { return EAPTypeIdentity } - -func (eapIdentity *EAPIdentity) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[EAP][Identity] marshal(): Start marshalling") - - if len(eapIdentity.IdentityData) == 0 { - return nil, errors.New("EAPIdentity: EAP identity is empty") - } - - eapIdentityData := []byte{EAPTypeIdentity} - eapIdentityData = append(eapIdentityData, eapIdentity.IdentityData...) - - return eapIdentityData, nil -} - -func (eapIdentity *EAPIdentity) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[EAP][Identity] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP][Identity] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 1 { - eapIdentity.IdentityData = append(eapIdentity.IdentityData, rawData[1:]...) - } - - return nil -} - -// Definition of EAP Notification - -var _ EAPTypeFormat = &EAPNotification{} - -type EAPNotification struct { - NotificationData []byte -} - -func (eapNotification *EAPNotification) Type() EAPType { return EAPTypeNotification } - -func (eapNotification *EAPNotification) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[EAP][Notification] marshal(): Start marshalling") - - if len(eapNotification.NotificationData) == 0 { - return nil, errors.New("EAPNotification: EAP notification is empty") - } - - eapNotificationData := []byte{EAPTypeNotification} - eapNotificationData = append(eapNotificationData, eapNotification.NotificationData...) - - return eapNotificationData, nil -} - -func (eapNotification *EAPNotification) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[EAP][Notification] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP][Notification] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 1 { - eapNotification.NotificationData = append(eapNotification.NotificationData, rawData[1:]...) - } - - return nil -} - -// Definition of EAP Nak - -var _ EAPTypeFormat = &EAPNak{} - -type EAPNak struct { - NakData []byte -} - -func (eapNak *EAPNak) Type() EAPType { return EAPTypeNak } - -func (eapNak *EAPNak) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[EAP][Nak] marshal(): Start marshalling") - - if len(eapNak.NakData) == 0 { - return nil, errors.New("EAPNak: EAP nak is empty") - } - - eapNakData := []byte{EAPTypeNak} - eapNakData = append(eapNakData, eapNak.NakData...) - - return eapNakData, nil -} - -func (eapNak *EAPNak) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[EAP][Nak] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP][Nak] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 1 { - eapNak.NakData = append(eapNak.NakData, rawData[1:]...) - } - - return nil -} - -// Definition of EAP expanded - -var _ EAPTypeFormat = &EAPExpanded{} - -type EAPExpanded struct { - VendorID uint32 - VendorType uint32 - VendorData []byte -} - -func (eapExpanded *EAPExpanded) Type() EAPType { return EAPTypeExpanded } - -func (eapExpanded *EAPExpanded) marshal() ([]byte, error) { - ikeLog := logger.IKELog - ikeLog.Info("[EAP][Expanded] marshal(): Start marshalling") - - eapExpandedData := make([]byte, 8) - - vendorID := eapExpanded.VendorID & 0x00ffffff - typeAndVendorID := (uint32(EAPTypeExpanded)<<24 | vendorID) - - binary.BigEndian.PutUint32(eapExpandedData[0:4], typeAndVendorID) - binary.BigEndian.PutUint32(eapExpandedData[4:8], eapExpanded.VendorType) - - if len(eapExpanded.VendorData) == 0 { - ikeLog.Warn("[EAP][Expanded] marshal(): EAP vendor data field is empty") - return eapExpandedData, nil - } - - eapExpandedData = append(eapExpandedData, eapExpanded.VendorData...) - - return eapExpandedData, nil -} - -func (eapExpanded *EAPExpanded) unmarshal(rawData []byte) error { - ikeLog := logger.IKELog - ikeLog.Info("[EAP][Expanded] unmarshal(): Start unmarshalling received bytes") - ikeLog.Tracef("[EAP][Expanded] unmarshal(): Payload length %d bytes", len(rawData)) - - if len(rawData) > 0 { - if len(rawData) < 8 { - return errors.New("EAPExpanded: No sufficient bytes to decode the EAP expanded type") - } - - typeAndVendorID := binary.BigEndian.Uint32(rawData[0:4]) - eapExpanded.VendorID = typeAndVendorID & 0x00ffffff - - eapExpanded.VendorType = binary.BigEndian.Uint32(rawData[4:8]) - - if len(rawData) > 8 { - eapExpanded.VendorData = append(eapExpanded.VendorData, rawData[8:]...) - } - } - - return nil -} diff --git a/pkg/ike/message/message_test.go b/pkg/ike/message/message_test.go deleted file mode 100644 index 614ce1b2..00000000 --- a/pkg/ike/message/message_test.go +++ /dev/null @@ -1,435 +0,0 @@ -package message - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - Crand "crypto/rand" - "encoding/binary" - "encoding/hex" - "io" - Mrand "math/rand" - "net" - "testing" -) - -// TestEncodeDecode tests the Encode() and Decode() function using the data -// build manually. -// First, build each payload with correct value, then the IKE message for -// IKE_SA_INIT type. -// Second, encode/decode the IKE message using Encode/Decode function, and then -// re-encode the decoded message again. -// Third, send the encoded data to the UDP connection for verification with Wireshark. -// Compare the dataFirstEncode and dataSecondEncode and return the result. -func TestEncodeDecode(t *testing.T) { - conn, err := net.Dial("udp", "127.0.0.1:500") - if err != nil { - t.Fatalf("udp Dial failed: %+v", err) - } - testPacket := &IKEMessage{} - - // random an SPI - src := Mrand.NewSource(63579) - localRand := Mrand.New(src) - ispi := localRand.Uint64() - - testPacket.InitiatorSPI = ispi - testPacket.Version = 0x20 - testPacket.ExchangeType = 34 // IKE_SA_INIT - testPacket.Flags = 16 // flagI is set - testPacket.MessageID = 0 // for IKE_SA_INIT - - testSA := &SecurityAssociation{} - - testProposal1 := &Proposal{} - testProposal1.ProposalNumber = 1 // first - testProposal1.ProtocolID = 1 // IKE - - testtransform1 := &Transform{} - testtransform1.TransformType = 1 // ENCR - testtransform1.TransformID = 12 // ENCR_AES_CBC - testtransform1.AttributePresent = true - testtransform1.AttributeFormat = 1 - testtransform1.AttributeType = 14 - testtransform1.AttributeValue = 128 - - testProposal1.EncryptionAlgorithm = append(testProposal1.EncryptionAlgorithm, testtransform1) - - testtransform2 := &Transform{} - testtransform2.TransformType = 1 // ENCR - testtransform2.TransformID = 12 // ENCR_AES_CBC - testtransform2.AttributePresent = true - testtransform2.AttributeFormat = 1 - testtransform2.AttributeType = 14 - testtransform2.AttributeValue = 192 - - testProposal1.EncryptionAlgorithm = append(testProposal1.EncryptionAlgorithm, testtransform2) - - testtransform3 := &Transform{} - testtransform3.TransformType = 3 // INTEG - testtransform3.TransformID = 5 // AUTH_AES_XCBC_96 - testtransform3.AttributePresent = false - - testProposal1.IntegrityAlgorithm = append(testProposal1.IntegrityAlgorithm, testtransform3) - - testtransform4 := &Transform{} - testtransform4.TransformType = 3 // INTEG - testtransform4.TransformID = 2 // AUTH_HMAC_SHA1_96 - testtransform4.AttributePresent = false - - testProposal1.IntegrityAlgorithm = append(testProposal1.IntegrityAlgorithm, testtransform4) - - testSA.Proposals = append(testSA.Proposals, testProposal1) - - testProposal2 := &Proposal{} - testProposal2.ProposalNumber = 2 // second - testProposal2.ProtocolID = 1 // IKE - - testtransform1 = &Transform{} - testtransform1.TransformType = 1 // ENCR - testtransform1.TransformID = 12 // ENCR_AES_CBC - testtransform1.AttributePresent = true - testtransform1.AttributeFormat = 1 - testtransform1.AttributeType = 14 - testtransform1.AttributeValue = 128 - - testProposal2.EncryptionAlgorithm = append(testProposal2.EncryptionAlgorithm, testtransform1) - - testtransform2 = &Transform{} - testtransform2.TransformType = 1 // ENCR - testtransform2.TransformID = 12 // ENCR_AES_CBC - testtransform2.AttributePresent = true - testtransform2.AttributeFormat = 1 - testtransform2.AttributeType = 14 - testtransform2.AttributeValue = 192 - - testProposal2.EncryptionAlgorithm = append(testProposal2.EncryptionAlgorithm, testtransform2) - - testtransform3 = &Transform{} - testtransform3.TransformType = 3 // INTEG - testtransform3.TransformID = 1 // AUTH_HMAC_MD5_96 - testtransform3.AttributePresent = false - - testProposal2.IntegrityAlgorithm = append(testProposal2.IntegrityAlgorithm, testtransform3) - - testtransform4 = &Transform{} - testtransform4.TransformType = 3 // INTEG - testtransform4.TransformID = 2 // AUTH_HMAC_SHA1_96 - testtransform4.AttributePresent = false - - testProposal2.IntegrityAlgorithm = append(testProposal2.IntegrityAlgorithm, testtransform4) - - testSA.Proposals = append(testSA.Proposals, testProposal2) - - testPacket.Payloads = append(testPacket.Payloads, testSA) - - testKE := &KeyExchange{} - - testKE.DiffieHellmanGroup = 1 - for i := 0; i < 8; i++ { - partKeyExchangeData := make([]byte, 8) - binary.BigEndian.PutUint64(partKeyExchangeData, 7482105748278537214) - testKE.KeyExchangeData = append(testKE.KeyExchangeData, partKeyExchangeData...) - } - - testPacket.Payloads = append(testPacket.Payloads, testKE) - - testIDr := &IdentificationResponder{} - - testIDr.IDType = 3 - for i := 0; i < 8; i++ { - partIdentification := make([]byte, 8) - binary.BigEndian.PutUint64(partIdentification, 4378215321473912643) - testIDr.IDData = append(testIDr.IDData, partIdentification...) - } - - testPacket.Payloads = append(testPacket.Payloads, testIDr) - - testCert := &Certificate{} - - testCert.CertificateEncoding = 1 - for i := 0; i < 8; i++ { - partCertificate := make([]byte, 8) - binary.BigEndian.PutUint64(partCertificate, 4378217432157543265) - testCert.CertificateData = append(testCert.CertificateData, partCertificate...) - } - - testPacket.Payloads = append(testPacket.Payloads, testCert) - - testCertReq := &CertificateRequest{} - - testCertReq.CertificateEncoding = 1 - for i := 0; i < 8; i++ { - partCertificateRquest := make([]byte, 8) - binary.BigEndian.PutUint64(partCertificateRquest, 7438274381754372584) - testCertReq.CertificationAuthority = append(testCertReq.CertificationAuthority, partCertificateRquest...) - } - - testPacket.Payloads = append(testPacket.Payloads, testCertReq) - - testAuth := &Authentication{} - - testAuth.AuthenticationMethod = 1 - for i := 0; i < 8; i++ { - partAuthentication := make([]byte, 8) - binary.BigEndian.PutUint64(partAuthentication, 4632714362816473824) - testAuth.AuthenticationData = append(testAuth.AuthenticationData, partAuthentication...) - } - - testPacket.Payloads = append(testPacket.Payloads, testAuth) - - testNonce := &Nonce{} - - for i := 0; i < 8; i++ { - partNonce := make([]byte, 8) - binary.BigEndian.PutUint64(partNonce, 8984327463782167381) - testNonce.NonceData = append(testNonce.NonceData, partNonce...) - } - - testPacket.Payloads = append(testPacket.Payloads, testNonce) - - testNotification := &Notification{} - - testNotification.ProtocolID = 1 - testNotification.NotifyMessageType = 2 - - for i := 0; i < 5; i++ { - partSPI := make([]byte, 8) - binary.BigEndian.PutUint64(partSPI, 4372847328749832794) - testNotification.SPI = append(testNotification.SPI, partSPI...) - } - - for i := 0; i < 19; i++ { - partNotification := make([]byte, 8) - binary.BigEndian.PutUint64(partNotification, 9721437148392747354) - testNotification.NotificationData = append(testNotification.NotificationData, partNotification...) - } - - testPacket.Payloads = append(testPacket.Payloads, testNotification) - - testDelete := &Delete{} - - testDelete.ProtocolID = 1 - testDelete.SPISize = 9 - testDelete.NumberOfSPI = 4 - - for i := 0; i < 36; i++ { - testDelete.SPIs = append(testDelete.SPIs, 87) - } - - testPacket.Payloads = append(testPacket.Payloads, testDelete) - - testVendor := &VendorID{} - - for i := 0; i < 5; i++ { - partVendorData := make([]byte, 8) - binary.BigEndian.PutUint64(partVendorData, 5421487329873941748) - testVendor.VendorIDData = append(testVendor.VendorIDData, partVendorData...) - } - - testPacket.Payloads = append(testPacket.Payloads, testVendor) - - testTSi := &TrafficSelectorResponder{} - - testIndividualTS := &IndividualTrafficSelector{} - - testIndividualTS.TSType = 7 - testIndividualTS.IPProtocolID = 6 - testIndividualTS.StartPort = 1989 - testIndividualTS.EndPort = 2020 - - testIndividualTS.StartAddress = []byte{192, 168, 0, 15} - testIndividualTS.EndAddress = []byte{192, 168, 0, 192} - - testTSi.TrafficSelectors = append(testTSi.TrafficSelectors, testIndividualTS) - - testIndividualTS = &IndividualTrafficSelector{} - - testIndividualTS.TSType = 8 - testIndividualTS.IPProtocolID = 6 - testIndividualTS.StartPort = 2010 - testIndividualTS.EndPort = 2050 - - testIndividualTS.StartAddress = net.ParseIP("2001:db8::68") - testIndividualTS.EndAddress = net.ParseIP("2001:db8::72") - - testTSi.TrafficSelectors = append(testTSi.TrafficSelectors, testIndividualTS) - - testPacket.Payloads = append(testPacket.Payloads, testTSi) - - testCP := new(Configuration) - - testCP.ConfigurationType = 1 - - testIndividualConfigurationAttribute := new(IndividualConfigurationAttribute) - - testIndividualConfigurationAttribute.Type = 1 - testIndividualConfigurationAttribute.Value = []byte{10, 1, 14, 1} - - testCP.ConfigurationAttribute = append(testCP.ConfigurationAttribute, testIndividualConfigurationAttribute) - - testPacket.Payloads = append(testPacket.Payloads, testCP) - - testEAP := new(EAP) - - testEAP.Code = 1 - testEAP.Identifier = 123 - - // testEAPExpanded := &EAPExpanded{ - // VendorID: 26838, - // VendorType: 1, - // VendorData: []byte{9, 4, 8, 7}, - // } - - testEAPNotification := new(EAPNotification) - - rawstr := "I'm tired" - testEAPNotification.NotificationData = []byte(rawstr) - - testEAP.EAPTypeData = append(testEAP.EAPTypeData, testEAPNotification) - - testPacket.Payloads = append(testPacket.Payloads, testEAP) - - testSK := new(Encrypted) - - testSK.NextPayload = TypeSA - - ikePayload := IKEPayloadContainer{ - testSA, - testAuth, - } - - ikePayloadDataForSK, retErr := ikePayload.Encode() - if retErr != nil { - t.Fatalf("EncodePayload failed: %+v", retErr) - } - - // aes 128 key - key, retErr := hex.DecodeString("6368616e676520746869732070617373") - if retErr != nil { - t.Fatalf("HexDecoding failed: %+v", retErr) - } - block, retErr := aes.NewCipher(key) - if retErr != nil { - t.Fatalf("AES NewCipher failed: %+v", retErr) - } - - // padding plaintext - padNum := len(ikePayloadDataForSK) % aes.BlockSize - for i := 0; i < (aes.BlockSize - padNum); i++ { - ikePayloadDataForSK = append(ikePayloadDataForSK, byte(padNum)) - } - - // ciphertext - cipherText := make([]byte, aes.BlockSize+len(ikePayloadDataForSK)) - iv := cipherText[:aes.BlockSize] - _, err = io.ReadFull(Crand.Reader, iv) - if err != nil { - t.Fatalf("IO ReadFull failed: %+v", err) - } - - // CBC mode - mode := cipher.NewCBCEncrypter(block, iv) - mode.CryptBlocks(cipherText[aes.BlockSize:], ikePayloadDataForSK) - - testSK.EncryptedData = cipherText - - testPacket.Payloads = append(testPacket.Payloads, testSK) - - var dataFirstEncode, dataSecondEncode []byte - decodedPacket := new(IKEMessage) - - if dataFirstEncode, err = testPacket.Encode(); err != nil { - t.Fatalf("Encode failed: %+v", err) - } - - t.Logf("%+v", dataFirstEncode) - - if err = decodedPacket.Decode(dataFirstEncode); err != nil { - t.Fatalf("Decode failed: %+v", err) - } - - if dataSecondEncode, err = decodedPacket.Encode(); err != nil { - t.Fatalf("Encode failed: %+v", err) - } - - t.Logf("Original IKE Message: %+v", dataFirstEncode) - t.Logf("Result IKE Message: %+v", dataSecondEncode) - - _, err = conn.Write(dataFirstEncode) - if err != nil { - t.Fatalf("Error: %+v", err) - } - - if !bytes.Equal(dataFirstEncode, dataSecondEncode) { - t.FailNow() - } -} - -// TestEncodeDecodeUsingPublicData tests the Encode() and Decode() function -// using the public data. -// Decode and encode the data, and compare the verifyData and the origin -// data and return the result. -func TestEncodeDecodeUsingPublicData(t *testing.T) { - data := []byte{ - 0x86, 0x43, 0x30, 0xac, 0x30, 0xe6, 0x56, 0x4d, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x20, 0x22, 0x08, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xc9, 0x22, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x2c, 0x01, 0x01, 0x00, 0x04, 0x03, 0x00, - 0x00, 0x0c, 0x01, 0x00, 0x00, 0x0c, 0x80, 0x0e, 0x00, 0x80, - 0x03, 0x00, 0x00, 0x08, 0x02, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, - 0x08, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x04, - 0x00, 0x00, 0x02, 0x28, 0x00, 0x00, 0x88, 0x00, 0x02, 0x00, 0x00, - 0x03, 0xdc, 0xf5, 0x9a, 0x29, 0x05, 0x7b, 0x5a, 0x49, 0xbd, - 0x55, 0x8c, 0x9b, 0x14, 0x7a, 0x11, 0x0e, 0xed, 0xff, 0xe5, 0xea, - 0x2d, 0x12, 0xc2, 0x1e, 0x5c, 0x7a, 0x5f, 0x5e, 0x9c, 0x99, - 0xe3, 0xd1, 0xd3, 0x00, 0x24, 0x3c, 0x89, 0x73, 0x1e, 0x6c, 0x6d, - 0x63, 0x41, 0x7b, 0x33, 0xfa, 0xaf, 0x5a, 0xc7, 0x26, 0xe8, - 0xb6, 0xf8, 0xc3, 0xb5, 0x2a, 0x14, 0xeb, 0xec, 0xd5, 0x6f, 0x1b, - 0xd9, 0x5b, 0x28, 0x32, 0x84, 0x9e, 0x26, 0xfc, 0x59, 0xee, - 0xf1, 0x4e, 0x38, 0x5f, 0x55, 0xc2, 0x1b, 0xe8, 0xf6, 0xa3, 0xfb, - 0xc5, 0x55, 0xd7, 0x35, 0x92, 0x86, 0x24, 0x00, 0x62, 0x8b, - 0xea, 0xce, 0x23, 0xf0, 0x47, 0xaf, 0xaa, 0xf8, 0x61, 0xe4, 0x5c, - 0x42, 0xba, 0x5c, 0xa1, 0x4a, 0x52, 0x6e, 0xd8, 0xe8, 0xf1, - 0xb9, 0x74, 0xae, 0xe4, 0xd1, 0x9c, 0x9f, 0xa5, 0x9b, 0xf0, 0xd7, - 0xdb, 0x55, 0x2b, 0x00, 0x00, 0x44, 0x4c, 0xa7, 0xf3, 0x9b, - 0xcd, 0x1d, 0xc2, 0x01, 0x79, 0xfa, 0xa2, 0xe4, 0x72, 0xe0, 0x61, - 0xc4, 0x45, 0x61, 0xe6, 0x49, 0x2d, 0xb3, 0x96, 0xae, 0xc9, - 0x2c, 0xdb, 0x54, 0x21, 0xf4, 0x98, 0x4f, 0x72, 0xd2, 0x43, 0x78, - 0xab, 0x80, 0xe4, 0x6c, 0x01, 0x78, 0x6a, 0xc4, 0x64, 0x45, - 0xbc, 0xa8, 0x1f, 0x56, 0xbc, 0xed, 0xf9, 0xb5, 0xd8, 0x21, 0x95, - 0x41, 0x71, 0xe9, 0x0e, 0xb4, 0x3c, 0x4e, 0x2b, 0x00, 0x00, - 0x17, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x2d, 0x44, 0x45, 0x4c, 0x45, - 0x54, 0x45, 0x2d, 0x52, 0x45, 0x41, 0x53, 0x4f, 0x4e, 0x2b, - 0x00, 0x00, 0x3b, 0x43, 0x49, 0x53, 0x43, 0x4f, 0x28, 0x43, 0x4f, - 0x50, 0x59, 0x52, 0x49, 0x47, 0x48, 0x54, 0x29, 0x26, 0x43, - 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, - 0x29, 0x20, 0x32, 0x30, 0x30, 0x39, 0x20, 0x43, 0x69, 0x73, - 0x63, 0x6f, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2c, - 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x29, 0x00, 0x00, 0x13, 0x43, - 0x49, 0x53, 0x43, 0x4f, 0x2d, 0x47, 0x52, 0x45, 0x2d, 0x4d, 0x4f, - 0x44, 0x45, 0x02, 0x29, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x40, - 0x04, 0x7e, 0x57, 0x6c, 0xc0, 0x13, 0xd4, 0x05, 0x43, 0xa2, 0xe8, - 0x77, 0x7d, 0x00, 0x34, 0x68, 0xa5, 0xb1, 0x89, 0x0c, 0x58, - 0x2b, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x40, 0x05, 0x52, 0x64, 0x4d, - 0x87, 0xd4, 0x7c, 0x2d, 0x44, 0x23, 0xbd, 0x37, 0xe4, 0x48, - 0xa9, 0xf5, 0x17, 0x01, 0x81, 0xcb, 0x8a, 0x00, 0x00, 0x00, 0x14, - 0x40, 0x48, 0xb7, 0xd5, 0x6e, 0xbc, 0xe8, 0x85, 0x25, 0xe7, - 0xde, 0x7f, 0x00, 0xd6, 0xc2, 0xd3, - } - - ikePacket := new(IKEMessage) - err := ikePacket.Decode(data) - if err != nil { - t.Fatalf("Decode failed: %+v", err) - } - - verifyData, err := ikePacket.Encode() - if err != nil { - t.Fatalf("Encode failed: %+v", err) - } - - if !bytes.Equal(data, verifyData) { - t.FailNow() - } -} diff --git a/pkg/ike/message/types.go b/pkg/ike/message/types.go deleted file mode 100644 index 39e79ca6..00000000 --- a/pkg/ike/message/types.go +++ /dev/null @@ -1,296 +0,0 @@ -package message - -// IKE types -type IKEPayloadType uint8 - -const ( - NoNext = 0 - TypeSA = iota + 32 - TypeKE - TypeIDi - TypeIDr - TypeCERT - TypeCERTreq - TypeAUTH - TypeNiNr - TypeN - TypeD - TypeV - TypeTSi - TypeTSr - TypeSK - TypeCP - TypeEAP -) - -// EAP types -type EAPType uint8 - -const ( - EAPTypeIdentity = iota + 1 - EAPTypeNotification - EAPTypeNak - EAPTypeExpanded = 254 -) - -const ( - EAPCodeRequest = iota + 1 - EAPCodeResponse - EAPCodeSuccess - EAPCodeFailure -) - -// used for SecurityAssociation-Proposal-Transform TransformType -const ( - TypeEncryptionAlgorithm = iota + 1 - TypePseudorandomFunction - TypeIntegrityAlgorithm - TypeDiffieHellmanGroup - TypeExtendedSequenceNumbers -) - -// used for SecurityAssociation-Proposal-Transform AttributeFormat -const ( - AttributeFormatUseTLV = iota - AttributeFormatUseTV -) - -// used for SecurityAssociation-Proposal-Trandform AttributeType -const ( - AttributeTypeKeyLength = 14 -) - -// used for SecurityAssociation-Proposal-Transform TransformID -const ( - ENCR_DES_IV64 = 1 - ENCR_DES = 2 - ENCR_3DES = 3 - ENCR_RC5 = 4 - ENCR_IDEA = 5 - ENCR_CAST = 6 - ENCR_BLOWFISH = 7 - ENCR_3IDEA = 8 - ENCR_DES_IV32 = 9 - ENCR_NULL = 11 - ENCR_AES_CBC = 12 - ENCR_AES_CTR = 13 -) - -const ( - PRF_HMAC_MD5 = iota + 1 - PRF_HMAC_SHA1 - PRF_HMAC_TIGER - PRF_HMAC_SHA2_256 = 5 -) - -const ( - AUTH_NONE = iota - AUTH_HMAC_MD5_96 - AUTH_HMAC_SHA1_96 - AUTH_DES_MAC - AUTH_KPDK_MD5 - AUTH_AES_XCBC_96 - AUTH_HMAC_SHA2_256_128 = 12 -) - -const ( - DH_NONE = 0 - DH_768_BIT_MODP = 1 - DH_1024_BIT_MODP = 2 - DH_1536_BIT_MODP = 5 - DH_2048_BIT_MODP = iota + 10 - DH_3072_BIT_MODP - DH_4096_BIT_MODP - DH_6144_BIT_MODP - DH_8192_BIT_MODP -) - -const ( - ESN_NO = iota - ESN_NEED -) - -// used for TrafficSelector-Individual Traffic Selector TSType -const ( - TS_IPV4_ADDR_RANGE = 7 - TS_IPV6_ADDR_RANGE = 8 -) - -// Exchange Type -const ( - IKE_SA_INIT = iota + 34 - IKE_AUTH - CREATE_CHILD_SA - INFORMATIONAL -) - -// Notify message types -const ( - UNSUPPORTED_CRITICAL_PAYLOAD = 1 - INVALID_IKE_SPI = 4 - INVALID_MAJOR_VERSION = 5 - INVALID_SYNTAX = 7 - INVALID_MESSAGE_ID = 9 - INVALID_SPI = 11 - NO_PROPOSAL_CHOSEN = 14 - INVALID_KE_PAYLOAD = 17 - AUTHENTICATION_FAILED = 24 - SINGLE_PAIR_REQUIRED = 34 - NO_ADDITIONAL_SAS = 35 - INTERNAL_ADDRESS_FAILURE = 36 - FAILED_CP_REQUIRED = 37 - TS_UNACCEPTABLE = 38 - INVALID_SELECTORS = 39 - TEMPORARY_FAILURE = 43 - CHILD_SA_NOT_FOUND = 44 - INITIAL_CONTACT = 16384 - SET_WINDOW_SIZE = 16385 - ADDITIONAL_TS_POSSIBLE = 16386 - IPCOMP_SUPPORTED = 16387 - NAT_DETECTION_SOURCE_IP = 16388 - NAT_DETECTION_DESTINATION_IP = 16389 - COOKIE = 16390 - USE_TRANSPORT_MODE = 16391 - HTTP_CERT_LOOKUP_SUPPORTED = 16392 - REKEY_SA = 16393 - ESP_TFC_PADDING_NOT_SUPPORTED = 16394 - NON_FIRST_FRAGMENTS_ALSO = 16395 -) - -// Protocol ID -const ( - TypeNone = iota - TypeIKE - TypeAH - TypeESP -) - -// Flags -const ( - ResponseBitCheck = 0x20 - VersionBitCheck = 0x10 - InitiatorBitCheck = 0x08 -) - -// Certificate encoding -const ( - PKCS7WrappedX509Certificate = 1 - PGPCertificate = 2 - DNSSignedKey = 3 - X509CertificateSignature = 4 - KerberosToken = 6 - CertificateRevocationList = 7 - AuthorityRevocationList = 8 - SPKICertificate = 9 - X509CertificateAttribute = 10 - HashAndURLOfX509Certificate = 12 - HashAndURLOfX509Bundle = 13 -) - -// ID Types -const ( - ID_IPV4_ADDR = 1 - ID_FQDN = 2 - ID_RFC822_ADDR = 3 - ID_IPV6_ADDR = 5 - ID_DER_ASN1_DN = 9 - ID_DER_ASN1_GN = 10 - ID_KEY_ID = 11 -) - -// Authentication Methods -const ( - RSADigitalSignature = iota + 1 - SharedKeyMesageIntegrityCode - DSSDigitalSignature -) - -// Configuration types -const ( - CFG_REQUEST = 1 - CFG_REPLY = 2 - CFG_SET = 3 - CFG_ACK = 4 -) - -// Configuration attribute types -const ( - INTERNAL_IP4_ADDRESS = 1 - INTERNAL_IP4_NETMASK = 2 - INTERNAL_IP4_DNS = 3 - INTERNAL_IP4_NBNS = 4 - INTERNAL_IP4_DHCP = 6 - APPLICATION_VERSION = 7 - INTERNAL_IP6_ADDRESS = 8 - INTERNAL_IP6_DNS = 10 - INTERNAL_IP6_DHCP = 12 - INTERNAL_IP4_SUBNET = 13 - SUPPORTED_ATTRIBUTES = 14 - INTERNAL_IP6_SUBNET = 15 -) - -// IP protocols ID, used in individual traffic selector -const ( - IPProtocolAll = 0 - IPProtocolICMP = 1 - IPProtocolTCP = 6 - IPProtocolUDP = 17 - IPProtocolGRE = 47 -) - -// Types for EAP-5G -// Used in IKE EAP expanded for vendor ID -const VendorID3GPP = 10415 - -// Used in IKE EAP expanded for vendor data -const VendorTypeEAP5G = 3 - -// Used in EAP-5G for message ID -const ( - EAP5GType5GStart = 1 - EAP5GType5GNAS = 2 - EAP5GType5GStop = 4 -) - -// Used in AN-Parameter field for IE types -const ( - ANParametersTypeGUAMI = 1 - ANParametersTypeSelectedPLMNID = 2 - ANParametersTypeRequestedNSSAI = 3 - ANParametersTypeEstablishmentCause = 4 -) - -// Used for checking if AN-Parameter length field is legal -const ( - ANParametersLenGUAMI = 6 - ANParametersLenPLMNID = 3 - ANParametersLenEstCause = 1 -) - -// Used in IE Establishment Cause field for cause types -const ( - EstablishmentCauseEmergency = 0 - EstablishmentCauseHighPriorityAccess = 1 - EstablishmentCauseMO_Signalling = 3 - EstablishmentCauseMO_Data = 4 - EstablishmentCauseMPS_PriorityAccess = 8 - EstablishmentCauseMCS_PriorityAccess = 9 -) - -// Spare -const EAP5GSpareValue = 0 - -// 3GPP specified IKE Notify -// 3GPP specified IKE Notify Message Types -const ( - Vendor3GPPNotifyType5G_QOS_INFO uint16 = 55501 - Vendor3GPPNotifyTypeNAS_IP4_ADDRESS uint16 = 55502 - Vendor3GPPNotifyTypeUP_IP4_ADDRESS uint16 = 55504 - Vendor3GPPNotifyTypeNAS_TCP_PORT uint16 = 55506 -) - -// Used in NotifyType5G_QOS_INFO -const ( - NotifyType5G_QOS_INFOBitDSCPICheck uint8 = 1 - NotifyType5G_QOS_INFOBitDCSICheck uint8 = 1 << 1 -) diff --git a/pkg/ike/security/security.go b/pkg/ike/security/security.go deleted file mode 100644 index 188eeb6c..00000000 --- a/pkg/ike/security/security.go +++ /dev/null @@ -1,898 +0,0 @@ -package security - -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/hmac" - "crypto/md5" - "crypto/rand" - "crypto/sha1" // #nosec G505 - "crypto/sha256" - "encoding/binary" - "encoding/hex" - "hash" - "io" - "math/big" - "strings" - - "github.com/pkg/errors" - - "github.com/free5gc/n3iwf/internal/logger" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" - "github.com/free5gc/n3iwf/pkg/ike/message" -) - -// General data -var ( - randomNumberMaximum big.Int - randomNumberMinimum big.Int -) - -func init() { - randomNumberMaximum.SetString(strings.Repeat("F", 512), 16) - randomNumberMinimum.SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16) -} - -func GenerateRandomNumber() *big.Int { - var number *big.Int - var err error - - ikeLog := logger.IKELog - for { - number, err = rand.Int(rand.Reader, &randomNumberMaximum) - if err != nil { - ikeLog.Errorf("Error occurs when generate random number: %+v", err) - return nil - } else { - if number.Cmp(&randomNumberMinimum) == 1 { - break - } - } - } - return number -} - -func GenerateRandomUint8() (uint8, error) { - ikeLog := logger.IKELog - number := make([]byte, 1) - _, err := io.ReadFull(rand.Reader, number) - if err != nil { - ikeLog.Errorf("Read random failed: %+v", err) - return 0, errors.New("Read failed") - } - return number[0], nil -} - -// Diffie-Hellman Exchange -// The strength supplied by group 1 may not be sufficient for typical uses -const ( - Group2PrimeString string = "FFFFFFFFFFFFFFFFC90FDAA22168C234" + - "C4C6628B80DC1CD129024E088A67CC74" + - "020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F1437" + - "4FE1356D6D51C245E485B576625E7EC6" + - "F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE6" + - "49286651ECE65381FFFFFFFFFFFFFFFF" - Group2Generator = 2 - Group14PrimeString string = "FFFFFFFFFFFFFFFFC90FDAA22168C234" + - "C4C6628B80DC1CD129024E088A67CC74" + - "020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F1437" + - "4FE1356D6D51C245E485B576625E7EC6" + - "F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE6" + - "49286651ECE45B3DC2007CB8A163BF05" + - "98DA48361C55D39A69163FA8FD24CF5F" + - "83655D23DCA3AD961C62F356208552BB" + - "9ED529077096966D670C354E4ABC9804" + - "F1746C08CA18217C32905E462E36CE3B" + - "E39E772C180E86039B2783A2EC07A28F" + - "B5C55DF06F4C52C9DE2BCBF695581718" + - "3995497CEA956AE515D2261898FA0510" + - "15728E5A8AACAA68FFFFFFFFFFFFFFFF" - Group14Generator = 2 -) - -func CalculateDiffieHellmanMaterials(secret *big.Int, peerPublicValue []byte, - diffieHellmanGroupNumber uint16, -) (localPublicValue []byte, sharedKey []byte) { - ikeLog := logger.IKELog - peerPublicValueBig := new(big.Int).SetBytes(peerPublicValue) - var generator, factor *big.Int - var ok bool - - switch diffieHellmanGroupNumber { - case message.DH_1024_BIT_MODP: - generator = new(big.Int).SetUint64(Group2Generator) - factor, ok = new(big.Int).SetString(Group2PrimeString, 16) - if !ok { - ikeLog.Errorf( - "Error occurs when setting big number \"factor\" in %d group", - diffieHellmanGroupNumber) - } - case message.DH_2048_BIT_MODP: - generator = new(big.Int).SetUint64(Group14Generator) - factor, ok = new(big.Int).SetString(Group14PrimeString, 16) - if !ok { - ikeLog.Errorf( - "Error occurs when setting big number \"factor\" in %d group", - diffieHellmanGroupNumber) - } - default: - ikeLog.Errorf("Unsupported Diffie-Hellman group: %d", diffieHellmanGroupNumber) - return localPublicValue, sharedKey - } - - localPublicValue = new(big.Int).Exp(generator, secret, factor).Bytes() - prependZero := make([]byte, len(factor.Bytes())-len(localPublicValue)) - localPublicValue = append(prependZero, localPublicValue...) - - sharedKey = new(big.Int).Exp(peerPublicValueBig, secret, factor).Bytes() - prependZero = make([]byte, len(factor.Bytes())-len(sharedKey)) - sharedKey = append(prependZero, sharedKey...) - - return localPublicValue, sharedKey -} - -// Pseudorandom Function -func NewPseudorandomFunction(key []byte, algorithmType uint16) (hash.Hash, bool) { - ikeLog := logger.IKELog - switch algorithmType { - case message.PRF_HMAC_MD5: - return hmac.New(md5.New, key), true - case message.PRF_HMAC_SHA1: - return hmac.New(sha1.New, key), true // #nosec G401 - case message.PRF_HMAC_SHA2_256: - return hmac.New(sha256.New, key), true - default: - ikeLog.Errorf("Unsupported pseudo random function: %d", algorithmType) - return nil, false - } -} - -// Integrity Algorithm -func calculateIntegrity(key []byte, originData []byte, transform *message.Transform) ([]byte, error) { - expectKeyLen, ok := getKeyLength( - transform.TransformType, transform.TransformID, - transform.AttributePresent, transform.AttributeValue) - if !ok { - return nil, errors.Errorf("calculateIntegrity[%d]: unsupported algo", transform.TransformID) - } - keyLen := len(key) - if keyLen != expectKeyLen { - return nil, errors.Errorf("calculateIntegrity[%d]: Unmatched input key length[%d:%d]", - transform.TransformID, keyLen, expectKeyLen) - } - outputLen, ok := getOutputLength( - transform.TransformType, transform.TransformID, - transform.AttributePresent, transform.AttributeValue) - if !ok { - return nil, errors.Errorf("calculateIntegrity[%d]: unsupported algo", transform.TransformID) - } - - var integrityFunction hash.Hash - switch transform.TransformID { - case message.AUTH_HMAC_MD5_96: - integrityFunction = hmac.New(md5.New, key) - case message.AUTH_HMAC_SHA1_96: - integrityFunction = hmac.New(sha1.New, key) // #nosec G401 - case message.AUTH_HMAC_SHA2_256_128: - integrityFunction = hmac.New(sha256.New, key) - default: - return nil, errors.Errorf("calculateIntegrity[%d]: unsupported algo", transform.TransformID) - } - - if _, err := integrityFunction.Write(originData); err != nil { - return nil, errors.Wrapf(err, "calculateIntegrity[%d]", transform.TransformID) - } - return integrityFunction.Sum(nil)[:outputLen], nil -} - -func verifyIntegrity(key []byte, originData []byte, checksum []byte, transform *message.Transform) (bool, error) { - ikeLog := logger.IKELog - expectChecksum, err := calculateIntegrity(key, originData, transform) - if err != nil { - return false, errors.Wrapf(err, "verifyIntegrity") - } - - ikeLog.Tracef("Calculated checksum:\n%s\nReceived checksum:\n%s", - hex.Dump(expectChecksum), hex.Dump(checksum)) - return hmac.Equal(expectChecksum, checksum), nil -} - -// Encryption Algorithm -func EncryptMessage(key []byte, originData []byte, algorithmType uint16) ([]byte, error) { - ikeLog := logger.IKELog - switch algorithmType { - case message.ENCR_AES_CBC: - // padding message - originData = PKCS7Padding(originData, aes.BlockSize) - originData[len(originData)-1]-- - - block, err := aes.NewCipher(key) - if err != nil { - ikeLog.Errorf("Error occur when create new cipher: %+v", err) - return nil, errors.New("Create cipher failed") - } - - cipherText := make([]byte, aes.BlockSize+len(originData)) - initializationVector := cipherText[:aes.BlockSize] - - _, err = io.ReadFull(rand.Reader, initializationVector) - if err != nil { - ikeLog.Errorf("Read random failed: %+v", err) - return nil, errors.New("Read random initialization vector failed") - } - - cbcBlockMode := cipher.NewCBCEncrypter(block, initializationVector) - cbcBlockMode.CryptBlocks(cipherText[aes.BlockSize:], originData) - - return cipherText, nil - default: - ikeLog.Errorf("Unsupported encryption algorithm: %d", algorithmType) - return nil, errors.New("Unsupported algorithm") - } -} - -func DecryptMessage(key []byte, cipherText []byte, algorithmType uint16) ([]byte, error) { - ikeLog := logger.IKELog - switch algorithmType { - case message.ENCR_AES_CBC: - if len(cipherText) < aes.BlockSize { - ikeLog.Error("Length of cipher text is too short to decrypt") - return nil, errors.New("Cipher text is too short") - } - - initializationVector := cipherText[:aes.BlockSize] - encryptedMessage := cipherText[aes.BlockSize:] - - if len(encryptedMessage)%aes.BlockSize != 0 { - ikeLog.Error("Cipher text is not a multiple of block size") - return nil, errors.New("Cipher text length error") - } - - plainText := make([]byte, len(encryptedMessage)) - - block, err := aes.NewCipher(key) - if err != nil { - ikeLog.Errorf("Error occur when create new cipher: %+v", err) - return nil, errors.New("Create cipher failed") - } - cbcBlockMode := cipher.NewCBCDecrypter(block, initializationVector) - cbcBlockMode.CryptBlocks(plainText, encryptedMessage) - - ikeLog.Tracef("Decrypted content:\n%s", hex.Dump(plainText)) - - padding := int(plainText[len(plainText)-1]) + 1 - plainText = plainText[:len(plainText)-padding] - - ikeLog.Tracef("Decrypted content with out padding:\n%s", hex.Dump(plainText)) - - return plainText, nil - default: - ikeLog.Errorf("Unsupported encryption algorithm: %d", algorithmType) - return nil, errors.New("Unsupported algorithm") - } -} - -func PKCS7Padding(plainText []byte, blockSize int) []byte { - padding := blockSize - (len(plainText) % blockSize) - if padding == 0 { - padding = blockSize - } - paddingText := bytes.Repeat([]byte{byte(padding)}, padding) - return append(plainText, paddingText...) -} - -// Certificate -func CompareRootCertificate( - ca []byte, - certificateEncoding uint8, - requestedCertificateAuthorityHash []byte, -) bool { - ikeLog := logger.IKELog - if certificateEncoding != message.X509CertificateSignature { - ikeLog.Debugf("Not support certificate type: %d. Reject.", certificateEncoding) - return false - } - - if len(ca) == 0 { - ikeLog.Error("Certificate authority in context is empty") - return false - } - - return bytes.Equal(ca, requestedCertificateAuthorityHash) -} - -// Key Gen for IKE SA -func GenerateKeyForIKESA(ikeSecurityAssociation *n3iwf_context.IKESecurityAssociation) error { - ikeLog := logger.IKELog - // Check parameters - if ikeSecurityAssociation == nil { - return errors.New("IKE SA is nil") - } - - // Check if the context contain needed data - if ikeSecurityAssociation.EncryptionAlgorithm == nil { - return errors.New("No encryption algorithm specified") - } - if ikeSecurityAssociation.IntegrityAlgorithm == nil { - return errors.New("No integrity algorithm specified") - } - if ikeSecurityAssociation.PseudorandomFunction == nil { - return errors.New("No pseudorandom function specified") - } - if ikeSecurityAssociation.DiffieHellmanGroup == nil { - return errors.New("No Diffie-hellman group algorithm specified") - } - - if len(ikeSecurityAssociation.ConcatenatedNonce) == 0 { - return errors.New("No concatenated nonce data") - } - if len(ikeSecurityAssociation.DiffieHellmanSharedKey) == 0 { - return errors.New("No Diffie-Hellman shared key") - } - - // Transforms - transformIntegrityAlgorithm := ikeSecurityAssociation.IntegrityAlgorithm - transformEncryptionAlgorithm := ikeSecurityAssociation.EncryptionAlgorithm - transformPseudorandomFunction := ikeSecurityAssociation.PseudorandomFunction - - // Get key length of SK_d, SK_ai, SK_ar, SK_ei, SK_er, SK_pi, SK_pr - var length_SK_d, length_SK_ai, length_SK_ar, length_SK_ei, length_SK_er, length_SK_pi, length_SK_pr, totalKeyLength int - var ok bool - - if length_SK_d, ok = getKeyLength(transformPseudorandomFunction.TransformType, - transformPseudorandomFunction.TransformID, transformPseudorandomFunction.AttributePresent, - transformPseudorandomFunction.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") - return errors.New("Get key length failed") - } - if length_SK_ai, ok = getKeyLength(transformIntegrityAlgorithm.TransformType, - transformIntegrityAlgorithm.TransformID, transformIntegrityAlgorithm.AttributePresent, - transformIntegrityAlgorithm.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") - return errors.New("Get key length failed") - } - length_SK_ar = length_SK_ai - if length_SK_ei, ok = getKeyLength(transformEncryptionAlgorithm.TransformType, - transformEncryptionAlgorithm.TransformID, transformEncryptionAlgorithm.AttributePresent, - transformEncryptionAlgorithm.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") - return errors.New("Get key length failed") - } - length_SK_er = length_SK_ei - length_SK_pi, length_SK_pr = length_SK_d, length_SK_d - totalKeyLength = length_SK_d + length_SK_ai + length_SK_ar + length_SK_ei + length_SK_er + length_SK_pi + length_SK_pr - - // Generate IKE SA key as defined in RFC7296 Section 1.3 and Section 1.4 - var pseudorandomFunction hash.Hash - - if pseudorandomFunction, ok = NewPseudorandomFunction(ikeSecurityAssociation.ConcatenatedNonce, - transformPseudorandomFunction.TransformID); !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") - return errors.New("New pseudorandom function failed") - } - - ikeLog.Tracef("DH shared key:\n%s", hex.Dump(ikeSecurityAssociation.DiffieHellmanSharedKey)) - ikeLog.Tracef("Concatenated nonce:\n%s", hex.Dump(ikeSecurityAssociation.ConcatenatedNonce)) - - if _, err := pseudorandomFunction.Write(ikeSecurityAssociation.DiffieHellmanSharedKey); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) - return errors.New("Pseudorandom function write failed") - } - - SKEYSEED := pseudorandomFunction.Sum(nil) - - ikeLog.Tracef("SKEYSEED:\n%s", hex.Dump(SKEYSEED)) - - seed := concatenateNonceAndSPI(ikeSecurityAssociation.ConcatenatedNonce, - ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI) - - var keyStream, generatedKeyBlock []byte - var index byte - for index = 1; len(keyStream) < totalKeyLength; index++ { - if pseudorandomFunction, ok = NewPseudorandomFunction(SKEYSEED, transformPseudorandomFunction.TransformID); !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") - return errors.New("New pseudorandom function failed") - } - if _, err := pseudorandomFunction.Write(append(append(generatedKeyBlock, seed...), index)); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) - return errors.New("Pseudorandom function write failed") - } - generatedKeyBlock = pseudorandomFunction.Sum(nil) - keyStream = append(keyStream, generatedKeyBlock...) - } - - // Assign keys into context - ikeSecurityAssociation.SK_d = keyStream[:length_SK_d] - keyStream = keyStream[length_SK_d:] - ikeSecurityAssociation.SK_ai = keyStream[:length_SK_ai] - keyStream = keyStream[length_SK_ai:] - ikeSecurityAssociation.SK_ar = keyStream[:length_SK_ar] - keyStream = keyStream[length_SK_ar:] - ikeSecurityAssociation.SK_ei = keyStream[:length_SK_ei] - keyStream = keyStream[length_SK_ei:] - ikeSecurityAssociation.SK_er = keyStream[:length_SK_er] - keyStream = keyStream[length_SK_er:] - ikeSecurityAssociation.SK_pi = keyStream[:length_SK_pi] - keyStream = keyStream[length_SK_pi:] - ikeSecurityAssociation.SK_pr = keyStream[:length_SK_pr] - // keyStream = keyStream[length_SK_pr:] - - ikeLog.Debugln("====== IKE Security Association Info =====") - ikeLog.Debugf("Initiator's SPI: %016x", ikeSecurityAssociation.RemoteSPI) - ikeLog.Debugf("Responder's SPI: %016x", ikeSecurityAssociation.LocalSPI) - ikeLog.Debugf("Encryption Algorithm: %d", ikeSecurityAssociation.EncryptionAlgorithm.TransformID) - ikeLog.Debugf("SK_ei: %x", ikeSecurityAssociation.SK_ei) - ikeLog.Debugf("SK_er: %x", ikeSecurityAssociation.SK_er) - ikeLog.Debugf("Integrity Algorithm: %d", ikeSecurityAssociation.IntegrityAlgorithm.TransformID) - ikeLog.Debugf("SK_ai: %x", ikeSecurityAssociation.SK_ai) - ikeLog.Debugf("SK_ar: %x", ikeSecurityAssociation.SK_ar) - ikeLog.Debugf("SK_pi: %x", ikeSecurityAssociation.SK_pi) - ikeLog.Debugf("SK_pr: %x", ikeSecurityAssociation.SK_pr) - - return nil -} - -// Key Gen for child SA -func GenerateKeyForChildSA(ikeSecurityAssociation *n3iwf_context.IKESecurityAssociation, - childSecurityAssociation *n3iwf_context.ChildSecurityAssociation, -) error { - ikeLog := logger.IKELog - // Check parameters - if ikeSecurityAssociation == nil { - return errors.New("IKE SA is nil") - } - if childSecurityAssociation == nil { - return errors.New("Child SA is nil") - } - - // Check if the context contain needed data - if ikeSecurityAssociation.PseudorandomFunction == nil { - return errors.New("No pseudorandom function specified") - } - if ikeSecurityAssociation.IKEAuthResponseSA == nil { - return errors.New("No IKE_AUTH response SA specified") - } - if len(ikeSecurityAssociation.IKEAuthResponseSA.Proposals) == 0 { - return errors.New("No proposal in IKE_AUTH response SA") - } - if len(ikeSecurityAssociation.IKEAuthResponseSA.Proposals[0].EncryptionAlgorithm) == 0 { - return errors.New("No encryption algorithm specified") - } - - if len(ikeSecurityAssociation.SK_d) == 0 { - return errors.New("No key deriving key") - } - - // Transforms - transformPseudorandomFunction := ikeSecurityAssociation.PseudorandomFunction - transformEncryptionAlgorithmForIPSec := ikeSecurityAssociation.IKEAuthResponseSA.Proposals[0].EncryptionAlgorithm[0] - var transformIntegrityAlgorithmForIPSec *message.Transform - if len(ikeSecurityAssociation.IKEAuthResponseSA.Proposals[0].IntegrityAlgorithm) != 0 { - transformIntegrityAlgorithmForIPSec = ikeSecurityAssociation.IKEAuthResponseSA.Proposals[0].IntegrityAlgorithm[0] - } - - // Get key length for encryption and integrity key for IPSec - var lengthEncryptionKeyIPSec, lengthIntegrityKeyIPSec, totalKeyLength int - var ok bool - - if lengthEncryptionKeyIPSec, ok = getKeyLength(transformEncryptionAlgorithmForIPSec.TransformType, - transformEncryptionAlgorithmForIPSec.TransformID, - transformEncryptionAlgorithmForIPSec.AttributePresent, - transformEncryptionAlgorithmForIPSec.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") - return errors.New("Get key length failed") - } - if transformIntegrityAlgorithmForIPSec != nil { - if lengthIntegrityKeyIPSec, ok = getKeyLength(transformIntegrityAlgorithmForIPSec.TransformType, - transformIntegrityAlgorithmForIPSec.TransformID, - transformIntegrityAlgorithmForIPSec.AttributePresent, - transformIntegrityAlgorithmForIPSec.AttributeValue); !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") - return errors.New("Get key length failed") - } - } - totalKeyLength = lengthEncryptionKeyIPSec + lengthIntegrityKeyIPSec - totalKeyLength = totalKeyLength * 2 - - // Generate key for child security association as specified in RFC 7296 section 2.17 - seed := ikeSecurityAssociation.ConcatenatedNonce - var pseudorandomFunction hash.Hash - - var keyStream, generatedKeyBlock []byte - var index byte - for index = 1; len(keyStream) < totalKeyLength; index++ { - if pseudorandomFunction, ok = NewPseudorandomFunction(ikeSecurityAssociation.SK_d, - transformPseudorandomFunction.TransformID); !ok { - ikeLog.Error("Get an unsupported pseudorandom funcion. This may imply an unsupported transform is chosen.") - return errors.New("New pseudorandom function failed") - } - if _, err := pseudorandomFunction.Write(append(append(generatedKeyBlock, seed...), index)); err != nil { - ikeLog.Errorf("Pseudorandom function write error: %+v", err) - return errors.New("Pseudorandom function write failed") - } - generatedKeyBlock = pseudorandomFunction.Sum(nil) - keyStream = append(keyStream, generatedKeyBlock...) - } - - childSecurityAssociation.InitiatorToResponderEncryptionKey = append( - childSecurityAssociation.InitiatorToResponderEncryptionKey, - keyStream[:lengthEncryptionKeyIPSec]...) - keyStream = keyStream[lengthEncryptionKeyIPSec:] - childSecurityAssociation.InitiatorToResponderIntegrityKey = append( - childSecurityAssociation.InitiatorToResponderIntegrityKey, - keyStream[:lengthIntegrityKeyIPSec]...) - keyStream = keyStream[lengthIntegrityKeyIPSec:] - childSecurityAssociation.ResponderToInitiatorEncryptionKey = append( - childSecurityAssociation.ResponderToInitiatorEncryptionKey, - keyStream[:lengthEncryptionKeyIPSec]...) - keyStream = keyStream[lengthEncryptionKeyIPSec:] - childSecurityAssociation.ResponderToInitiatorIntegrityKey = append( - childSecurityAssociation.ResponderToInitiatorIntegrityKey, - keyStream[:lengthIntegrityKeyIPSec]...) - - return nil -} - -// Decrypt -func DecryptProcedure(ikeSecurityAssociation *n3iwf_context.IKESecurityAssociation, ikeMessage *message.IKEMessage, - encryptedPayload *message.Encrypted, -) (message.IKEPayloadContainer, error) { - ikeLog := logger.IKELog - // Check parameters - if ikeSecurityAssociation == nil { - return nil, errors.New("IKE SA is nil") - } - if ikeMessage == nil { - return nil, errors.New("IKE message is nil") - } - if encryptedPayload == nil { - return nil, errors.New("IKE encrypted payload is nil") - } - - // Check if the context contain needed data - if ikeSecurityAssociation.IntegrityAlgorithm == nil { - return nil, errors.New("No integrity algorithm specified") - } - if ikeSecurityAssociation.EncryptionAlgorithm == nil { - return nil, errors.New("No encryption algorithm specified") - } - - if len(ikeSecurityAssociation.SK_ai) == 0 { - return nil, errors.New("No initiator's integrity key") - } - if len(ikeSecurityAssociation.SK_ei) == 0 { - return nil, errors.New("No initiator's encryption key") - } - - // Load needed information - transformIntegrityAlgorithm := ikeSecurityAssociation.IntegrityAlgorithm - transformEncryptionAlgorithm := ikeSecurityAssociation.EncryptionAlgorithm - checksumLength, ok := getOutputLength(transformIntegrityAlgorithm.TransformType, - transformIntegrityAlgorithm.TransformID, transformIntegrityAlgorithm.AttributePresent, - transformIntegrityAlgorithm.AttributeValue) - if !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") - return nil, errors.New("Get key length failed") - } - - // Checksum - checksum := encryptedPayload.EncryptedData[len(encryptedPayload.EncryptedData)-checksumLength:] - - ikeMessageData, err := ikeMessage.Encode() - if err != nil { - ikeLog.Errorln(err) - ikeLog.Error("Error occur when encoding for checksum") - return nil, errors.New("Encoding IKE message failed") - } - - ok, err = verifyIntegrity(ikeSecurityAssociation.SK_ai, - ikeMessageData[:len(ikeMessageData)-checksumLength], checksum, - transformIntegrityAlgorithm) - if err != nil { - ikeLog.Errorf("Error occur when verifying checksum: %+v", err) - return nil, errors.New("Error verify checksum") - } - if !ok { - ikeLog.Warn("Message checksum failed. Drop the message.") - return nil, errors.New("Checksum failed, drop.") - } - - // Decrypt - encryptedData := encryptedPayload.EncryptedData[:len(encryptedPayload.EncryptedData)-checksumLength] - plainText, err := DecryptMessage(ikeSecurityAssociation.SK_ei, encryptedData, - transformEncryptionAlgorithm.TransformID) - if err != nil { - ikeLog.Errorf("Error occur when decrypting message: %+v", err) - return nil, errors.New("Error decrypting message") - } - - var decryptedIKEPayload message.IKEPayloadContainer - err = decryptedIKEPayload.Decode(encryptedPayload.NextPayload, plainText) - if err != nil { - ikeLog.Errorln(err) - return nil, errors.New("Decoding decrypted payload failed") - } - - return decryptedIKEPayload, nil -} - -// Encrypt -func EncryptProcedure(ikeSecurityAssociation *n3iwf_context.IKESecurityAssociation, - ikePayload message.IKEPayloadContainer, responseIKEMessage *message.IKEMessage, -) error { - ikeLog := logger.IKELog - // Check parameters - if ikeSecurityAssociation == nil { - return errors.New("IKE SA is nil") - } - if len(ikePayload) == 0 { - return errors.New("No IKE payload to be encrypted") - } - if responseIKEMessage == nil { - return errors.New("Response IKE message is nil") - } - - // Check if the context contain needed data - if ikeSecurityAssociation.IntegrityAlgorithm == nil { - return errors.New("No integrity algorithm specified") - } - if ikeSecurityAssociation.EncryptionAlgorithm == nil { - return errors.New("No encryption algorithm specified") - } - - if len(ikeSecurityAssociation.SK_ar) == 0 { - return errors.New("No responder's integrity key") - } - if len(ikeSecurityAssociation.SK_er) == 0 { - return errors.New("No responder's encryption key") - } - - // Load needed information - transformIntegrityAlgorithm := ikeSecurityAssociation.IntegrityAlgorithm - transformEncryptionAlgorithm := ikeSecurityAssociation.EncryptionAlgorithm - checksumLength, ok := getOutputLength(transformIntegrityAlgorithm.TransformType, - transformIntegrityAlgorithm.TransformID, transformIntegrityAlgorithm.AttributePresent, - transformIntegrityAlgorithm.AttributeValue) - if !ok { - ikeLog.Error("Get key length of an unsupported algorithm. This may imply an unsupported transform is chosen.") - return errors.New("Get key length failed") - } - - // Encrypting - ikePayloadData, err := ikePayload.Encode() - if err != nil { - ikeLog.Error(err) - return errors.New("Encoding IKE payload failed.") - } - - encryptedData, err := EncryptMessage(ikeSecurityAssociation.SK_er, ikePayloadData, - transformEncryptionAlgorithm.TransformID) - if err != nil { - ikeLog.Errorf("Encrypting data error: %+v", err) - return errors.New("Error encrypting message") - } - - encryptedData = append(encryptedData, make([]byte, checksumLength)...) - sk := responseIKEMessage.Payloads.BuildEncrypted(ikePayload[0].Type(), encryptedData) - - // Calculate checksum - responseIKEMessageData, err := responseIKEMessage.Encode() - if err != nil { - ikeLog.Error(err) - return errors.New("Encoding IKE message error") - } - checksumOfMessage, err := calculateIntegrity(ikeSecurityAssociation.SK_ar, - responseIKEMessageData[:len(responseIKEMessageData)-checksumLength], - transformIntegrityAlgorithm) - if err != nil { - ikeLog.Errorf("Calculating checksum failed: %+v", err) - return errors.New("Error calculating checksum") - } - checksumField := sk.EncryptedData[len(sk.EncryptedData)-checksumLength:] - copy(checksumField, checksumOfMessage) - - return nil -} - -// Get information of algorithm -func getKeyLength(transformType uint8, transformID uint16, attributePresent bool, - attributeValue uint16, -) (int, bool) { - switch transformType { - case message.TypeEncryptionAlgorithm: - switch transformID { - case message.ENCR_DES_IV64: - return 0, false - case message.ENCR_DES: - return 8, true - case message.ENCR_3DES: - return 24, true - case message.ENCR_RC5: - return 0, false - case message.ENCR_IDEA: - return 0, false - case message.ENCR_CAST: - if attributePresent { - switch attributeValue { - case 128: - return 16, true - case 256: - return 0, false - default: - return 0, false - } - } - return 0, false - case message.ENCR_BLOWFISH: // Blowfish support variable key length - if attributePresent { - if attributeValue < 40 { - return 0, false - } else if attributeValue > 448 { - return 0, false - } else { - return int(attributeValue / 8), true - } - } else { - return 0, false - } - case message.ENCR_3IDEA: - return 0, false - case message.ENCR_DES_IV32: - return 0, false - case message.ENCR_NULL: - return 0, true - case message.ENCR_AES_CBC: - if attributePresent { - switch attributeValue { - case 128: - return 16, true - case 192: - return 24, true - case 256: - return 32, true - default: - return 0, false - } - } else { - return 0, false - } - case message.ENCR_AES_CTR: - if attributePresent { - switch attributeValue { - case 128: - return 20, true - case 192: - return 28, true - case 256: - return 36, true - default: - return 0, false - } - } else { - return 0, false - } - default: - return 0, false - } - case message.TypePseudorandomFunction: - switch transformID { - case message.PRF_HMAC_MD5: - return 16, true - case message.PRF_HMAC_SHA1: - return 20, true - case message.PRF_HMAC_SHA2_256: - return 32, true - case message.PRF_HMAC_TIGER: - return 0, false - default: - return 0, false - } - case message.TypeIntegrityAlgorithm: - switch transformID { - case message.AUTH_NONE: - return 0, false - case message.AUTH_HMAC_MD5_96: - return 16, true - case message.AUTH_HMAC_SHA1_96: - return 20, true - case message.AUTH_DES_MAC: - return 0, false - case message.AUTH_KPDK_MD5: - return 0, false - case message.AUTH_AES_XCBC_96: - return 0, false - case message.AUTH_HMAC_SHA2_256_128: - return 32, true - default: - return 0, false - } - case message.TypeDiffieHellmanGroup: - switch transformID { - case message.DH_NONE: - return 0, false - case message.DH_768_BIT_MODP: - return 0, false - case message.DH_1024_BIT_MODP: - return 0, false - case message.DH_1536_BIT_MODP: - return 0, false - case message.DH_2048_BIT_MODP: - return 0, false - case message.DH_3072_BIT_MODP: - return 0, false - case message.DH_4096_BIT_MODP: - return 0, false - case message.DH_6144_BIT_MODP: - return 0, false - case message.DH_8192_BIT_MODP: - return 0, false - default: - return 0, false - } - default: - return 0, false - } -} - -func getOutputLength( - transformType uint8, - transformID uint16, - attributePresent bool, - attributeValue uint16, -) (int, bool) { - _ = attributePresent - _ = attributeValue - - switch transformType { - case message.TypePseudorandomFunction: - switch transformID { - case message.PRF_HMAC_MD5: - return 16, true - case message.PRF_HMAC_SHA1: - return 20, true - case message.PRF_HMAC_TIGER: - return 0, false - case message.PRF_HMAC_SHA2_256: - return 32, true - default: - return 0, false - } - case message.TypeIntegrityAlgorithm: - switch transformID { - case message.AUTH_NONE: - return 0, false - case message.AUTH_HMAC_MD5_96: - return 12, true - case message.AUTH_HMAC_SHA1_96: - return 12, true - case message.AUTH_DES_MAC: - return 0, false - case message.AUTH_KPDK_MD5: - return 0, false - case message.AUTH_AES_XCBC_96: - return 0, false - case message.AUTH_HMAC_SHA2_256_128: - return 16, true - default: - return 0, false - } - default: - return 0, false - } -} - -func concatenateNonceAndSPI(nonce []byte, SPI_initiator uint64, SPI_responder uint64) []byte { - spi := make([]byte, 8) - - binary.BigEndian.PutUint64(spi, SPI_initiator) - newSlice := append(nonce, spi...) - binary.BigEndian.PutUint64(spi, SPI_responder) - newSlice = append(newSlice, spi...) - - return newSlice -} diff --git a/pkg/ike/security/security_test.go b/pkg/ike/security/security_test.go deleted file mode 100644 index ad6a0007..00000000 --- a/pkg/ike/security/security_test.go +++ /dev/null @@ -1,135 +0,0 @@ -package security - -import ( - "encoding/hex" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/free5gc/n3iwf/pkg/ike/message" -) - -func TestVerifyIntegrity(t *testing.T) { - tests := []struct { - name string - key string - originData []byte - checksum string - transform *message.Transform - expectedValid bool - }{ - { - name: "HMAC MD5 96 - valid", - key: "0123456789abcdef0123456789abcdef", - originData: []byte("hello world"), - checksum: "c30f366e411540f68221d04a", - transform: &message.Transform{ - TransformType: message.TypeIntegrityAlgorithm, - TransformID: message.AUTH_HMAC_MD5_96, - }, - expectedValid: true, - }, - { - name: "HMAC MD5 96 - invalid checksum", - key: "0123456789abcdef", - originData: []byte("hello world"), - checksum: "01231875aa", - transform: &message.Transform{ - TransformType: message.TypeIntegrityAlgorithm, - TransformID: message.AUTH_HMAC_MD5_96, - }, - expectedValid: false, - }, - { - name: "HMAC MD5 96 - invalid key length", - key: "0123", - originData: []byte("hello world"), - transform: &message.Transform{ - TransformType: message.TypeIntegrityAlgorithm, - TransformID: message.AUTH_HMAC_MD5_96, - }, - expectedValid: false, - }, - { - name: "HMAC SHA1 96 - valid", - key: "0123456789abcdef0123456789abcdef01234567", - originData: []byte("hello world"), - checksum: "5089f6a86e4dafb89e3fcd23", - transform: &message.Transform{ - TransformType: message.TypeIntegrityAlgorithm, - TransformID: message.AUTH_HMAC_SHA1_96, - }, - expectedValid: true, - }, - { - name: "HMAC SHA1 96 - invalid checksum", - key: "0123456789abcdef0123456789abcdef01234567", - originData: []byte("hello world"), - checksum: "01231875aa", - transform: &message.Transform{ - TransformType: message.TypeIntegrityAlgorithm, - TransformID: message.AUTH_HMAC_SHA1_96, - }, - expectedValid: false, - }, - { - name: "HMAC SHA1 96 - invalid key length", - key: "0123", - originData: []byte("hello world"), - transform: &message.Transform{ - TransformType: message.TypeIntegrityAlgorithm, - TransformID: message.AUTH_HMAC_SHA1_96, - }, - expectedValid: false, - }, - { - name: "HMAC SHA256 128 - valid", - key: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", - originData: []byte("hello world"), - checksum: "a64166565bc1f48eb3edd4109fcaeb72", - transform: &message.Transform{ - TransformType: message.TypeIntegrityAlgorithm, - TransformID: message.AUTH_HMAC_SHA2_256_128, - }, - expectedValid: true, - }, - { - name: "HMAC SHA256 128 - invalid checksum", - key: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", - originData: []byte("hello world"), - checksum: "01231875aa", - transform: &message.Transform{ - TransformType: message.TypeIntegrityAlgorithm, - TransformID: message.AUTH_HMAC_SHA1_96, - }, - expectedValid: false, - }, - { - name: "HMAC SHA256 128 - invalid key length", - key: "0123", - originData: []byte("hello world"), - transform: &message.Transform{ - TransformType: message.TypeIntegrityAlgorithm, - TransformID: message.AUTH_HMAC_SHA1_96, - }, - expectedValid: false, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - var key, checksum []byte - var err error - checksum, err = hex.DecodeString(tt.checksum) - require.NoError(t, err, "failed to decode checksum hex string") - - key, err = hex.DecodeString(tt.key) - require.NoError(t, err, "failed to decode key hex string") - - valid, err := verifyIntegrity(key, tt.originData, checksum, tt.transform) - if tt.expectedValid { - require.NoError(t, err, "verifyIntegrity returned an error") - } - require.Equal(t, tt.expectedValid, valid) - }) - } -} diff --git a/pkg/ike/send.go b/pkg/ike/send.go index c7612d8d..148c1f48 100644 --- a/pkg/ike/send.go +++ b/pkg/ike/send.go @@ -2,26 +2,31 @@ package ike import ( "encoding/binary" + "math" "net" + "github.com/pkg/errors" + + "github.com/free5gc/ike" + "github.com/free5gc/ike/message" + ike_message "github.com/free5gc/ike/message" + "github.com/free5gc/ike/security" "github.com/free5gc/n3iwf/internal/logger" n3iwf_context "github.com/free5gc/n3iwf/pkg/context" - "github.com/free5gc/n3iwf/pkg/ike/message" - "github.com/free5gc/n3iwf/pkg/ike/security" ) func SendIKEMessageToUE( udpConn *net.UDPConn, srcAddr, dstAddr *net.UDPAddr, message *message.IKEMessage, -) { + ikeSAKey *security.IKESAKey, +) error { ikeLog := logger.IKELog ikeLog.Trace("Send IKE message to UE") ikeLog.Trace("Encoding...") - pkt, err := message.Encode() + pkt, err := ike.EncodeEncrypt(message, ikeSAKey, ike_message.Role_Responder) if err != nil { - ikeLog.Errorln(err) - return + return errors.Wrapf(err, "SendIKEMessageToUE") } // As specified in RFC 7296 section 3.1, the IKE message send from/to UDP port 4500 // should prepend a 4 bytes zero @@ -33,39 +38,39 @@ func SendIKEMessageToUE( ikeLog.Trace("Sending...") n, err := udpConn.WriteToUDP(pkt, dstAddr) if err != nil { - ikeLog.Error(err) - return + return errors.Wrapf(err, "SendIKEMessageToUE") } if n != len(pkt) { - ikeLog.Errorf("Not all of the data is sent. Total length: %d. Sent: %d.", len(pkt), n) - return + return errors.Errorf("SendIKEMessageToUE Not all of the data is sent. Total length: %d. Sent: %d.", + len(pkt), n) } + return nil } func SendUEInformationExchange( - ikeUe *n3iwf_context.N3IWFIkeUe, - payload message.IKEPayloadContainer, + ikeSA *n3iwf_context.IKESecurityAssociation, + payload *message.IKEPayloadContainer, ike_flag uint8, messageID uint32, + conn *net.UDPConn, ueAddr *net.UDPAddr, n3iwfAddr *net.UDPAddr, ) { ikeLog := logger.IKELog - ikeSA := ikeUe.N3IWFIKESecurityAssociation responseIKEMessage := new(message.IKEMessage) - + var ikeSAKey *security.IKESAKey // Build IKE message responseIKEMessage.BuildIKEHeader( ikeSA.RemoteSPI, ikeSA.LocalSPI, - message.INFORMATIONAL, 0, - ikeSA.ResponderMessageID) - if payload != nil { // This message isn't a DPD message - err := security.EncryptProcedure( - ikeSA, payload, responseIKEMessage) - if err != nil { - ikeLog.Errorf("Encrypting IKE message failed: %+v", err) - return - } + message.INFORMATIONAL, ike_flag, + messageID) + + if payload != nil && len(*payload) > 0 { + responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, *payload...) + ikeSAKey = ikeSA.IKESAKey + } + + err := SendIKEMessageToUE(conn, n3iwfAddr, ueAddr, responseIKEMessage, ikeSAKey) + if err != nil { + ikeLog.Errorf("SendUEInformationExchange err: %+v", err) + return } - SendIKEMessageToUE( - ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.N3IWFAddr, - ikeUe.IKEConnection.UEAddr, responseIKEMessage) } func SendIKEDeleteRequest(n3iwfCtx *n3iwf_context.N3IWFContext, localSPI uint64) { @@ -78,7 +83,9 @@ func SendIKEDeleteRequest(n3iwfCtx *n3iwf_context.N3IWFContext, localSPI uint64) var deletePayload message.IKEPayloadContainer deletePayload.BuildDeletePayload(message.TypeIKE, 0, 0, nil) - SendUEInformationExchange(ikeUe, deletePayload) + SendUEInformationExchange(ikeUe.N3IWFIKESecurityAssociation, &deletePayload, 0, + ikeUe.N3IWFIKESecurityAssociation.ResponderMessageID, ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.UEAddr, + ikeUe.IKEConnection.N3IWFAddr) } func SendChildSADeleteRequest( @@ -92,12 +99,18 @@ func SendChildSADeleteRequest( for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { if childSA.PDUSessionIds[0] == releaseItem { spiByte := make([]byte, 4) - binary.BigEndian.PutUint32(spiByte, uint32(childSA.XfrmStateList[0].Spi)) + spi := childSA.XfrmStateList[0].Spi + if spi < 0 || spi > math.MaxUint32 { + ikeLog.Errorf("SendChildSADeleteRequest spi out of uint32 range : %d", spi) + return + } + binary.BigEndian.PutUint32(spiByte, uint32(spi)) deleteSPIs = append(deleteSPIs, spiByte...) spiLen += 1 err := ikeUe.DeleteChildSA(childSA) if err != nil { ikeLog.Errorf("Delete Child SA error : %v", err) + return } } } @@ -105,5 +118,7 @@ func SendChildSADeleteRequest( var deletePayload message.IKEPayloadContainer deletePayload.BuildDeletePayload(message.TypeESP, 4, spiLen, deleteSPIs) - SendUEInformationExchange(ikeUe, deletePayload) + SendUEInformationExchange(ikeUe.N3IWFIKESecurityAssociation, &deletePayload, 0, + ikeUe.N3IWFIKESecurityAssociation.ResponderMessageID, ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.UEAddr, + ikeUe.IKEConnection.N3IWFAddr) } diff --git a/pkg/ike/server.go b/pkg/ike/server.go index 5b8ab7c4..ff796b16 100644 --- a/pkg/ike/server.go +++ b/pkg/ike/server.go @@ -1,13 +1,19 @@ package ike import ( + "bytes" "context" "net" "runtime/debug" "sync" + "syscall" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" "github.com/pkg/errors" + "github.com/free5gc/ike" + ike_message "github.com/free5gc/ike/message" "github.com/free5gc/n3iwf/internal/logger" n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" @@ -25,6 +31,8 @@ type n3iwf interface { NgapEvtCh() chan n3iwf_context.NgapEvt } +type EspHandler func(srcIP, dstIP *net.UDPAddr, espPkt []byte) error + type Server struct { n3iwf @@ -107,8 +115,21 @@ func (s *Server) server(wg *sync.WaitGroup) { for { select { case rcvPkt := <-s.RcvIkePktCh: - ikeLog.Tracef("Receive IKE packet") - s.Dispatch(&rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr, rcvPkt.Msg) + msg, err := s.checkMessage(rcvPkt, handleESPPacket) + if err != nil { + ikeLog.Warnln(err) + continue + } + ikeMsg, ikeSA, err := s.checkIKEMessage(msg, &rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr) + if err != nil { + ikeLog.Warnln(err) + continue + } + if ikeMsg == nil { + continue + } + s.Dispatch(&rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr, + ikeMsg, rcvPkt.Msg, ikeSA) case rcvIkeEvent := <-s.RcvEventCh: s.HandleEvent(rcvIkeEvent) case <-s.StopServer: @@ -175,3 +196,168 @@ func (s *Server) Stop() { s.StopServer <- struct{}{} } + +func (s *Server) checkMessage( + rcvPkt IkeReceivePacket, + espHandler EspHandler, +) ([]byte, error) { + ikeLog := logger.IKELog + localAddr := &rcvPkt.LocalAddr + remoteAddr := &rcvPkt.RemoteAddr + msg := rcvPkt.Msg + marker := []byte{0, 0, 0, 0} // Non-ESP Marker + + if len(msg) == 1 && msg[0] == 0xff { + ikeLog.Tracef("Get NAT-T Keepalive from IP: %v", remoteAddr.IP.String()) + return nil, nil + } else if len(msg) < len(marker) { + return nil, errors.Errorf("Received packet is too short from IP: %v", remoteAddr.IP.String()) + } + + // As specified in RFC 7296 section 3.1, the IKE message send from/to UDP port 4500 + // should prepend a 4 bytes zero + if localAddr.Port == 4500 { + if !bytes.Equal(msg[:4], marker) { + if espHandler != nil { + err := espHandler(remoteAddr, localAddr, msg) + if err != nil { + return nil, errors.Wrapf(err, "Handle ESP") + } + } + return nil, nil + } + msg = msg[4:] + } + + return msg, nil +} + +func (s *Server) checkIKEMessage( + msg []byte, udpConn *net.UDPConn, + localAddr, remoteAddr *net.UDPAddr, +) (*ike_message.IKEMessage, + *n3iwf_context.IKESecurityAssociation, error, +) { + var ikeHeader *ike_message.IKEHeader + var ikeMessage *ike_message.IKEMessage + var ikeSA *n3iwf_context.IKESecurityAssociation + var err error + + // parse IKE header and setup IKE context + ikeHeader, err = ike_message.ParseIkeHeader(msg) + if err != nil { + return nil, nil, errors.Wrapf(err, "IKE msg decode header") + } + + // check major version + if ikeHeader.MajorVersion > 2 { + // send INFORMATIONAL type message with INVALID_MAJOR_VERSION Notify payload + // For response or needed data + responseIKEMessage := new(ike_message.IKEMessage) + responseIKEMessage.BuildIKEHeader(ikeHeader.InitiatorSPI, ikeHeader.ResponderSPI, + ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, ikeHeader.MessageID) + responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, + ike_message.INVALID_MAJOR_VERSION, nil, nil) + + err = SendIKEMessageToUE(udpConn, localAddr, remoteAddr, responseIKEMessage, nil) + if err != nil { + return nil, nil, errors.Wrapf(err, "Received an IKE message with higher major version "+ + "(%d>2)", ikeHeader.MajorVersion) + } + return nil, nil, errors.Errorf("Received an IKE message with higher major version (%d>2)", ikeHeader.MajorVersion) + } + + if ikeHeader.ExchangeType == ike_message.IKE_SA_INIT { + ikeMessage, err = ike.DecodeDecrypt(msg, ikeHeader, + nil, ike_message.Role_Responder) + if err != nil { + return nil, nil, errors.Wrapf(err, "Decrypt IkeMsg error") + } + } else if ikeHeader.ExchangeType != ike_message.IKE_SA_INIT { + localSPI := ikeHeader.ResponderSPI + var ok bool + n3iwfCtx := s.Context() + + ikeSA, ok = n3iwfCtx.IKESALoad(localSPI) + if !ok { + responseIKEMessage := new(ike_message.IKEMessage) + // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) + responseIKEMessage.BuildIKEHeader(ikeHeader.InitiatorSPI, 0, ike_message.INFORMATIONAL, + ike_message.ResponseBitCheck, ikeHeader.MessageID) + responseIKEMessage.Payloads.Reset() + responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) + + err = SendIKEMessageToUE(udpConn, localAddr, remoteAddr, responseIKEMessage, nil) + if err != nil { + return nil, nil, errors.Wrapf(err, "checkIKEMessage():") + } + return nil, nil, errors.Errorf("Received an unrecognized SPI message: %d", localSPI) + } + + ikeMessage, err = ike.DecodeDecrypt(msg, ikeHeader, + ikeSA.IKESAKey, ike_message.Role_Responder) + if err != nil { + return nil, nil, errors.Wrapf(err, "Decrypt IkeMsg error") + } + } + + return ikeMessage, ikeSA, nil +} + +func constructPacketWithESP(srcIP, dstIP *net.UDPAddr, espPacket []byte) ([]byte, error) { + ipLayer := &layers.IPv4{ + SrcIP: srcIP.IP, + DstIP: dstIP.IP, + Version: 4, + TTL: 64, + Protocol: layers.IPProtocolESP, + } + + buffer := gopacket.NewSerializeBuffer() + options := gopacket.SerializeOptions{ + ComputeChecksums: true, + FixLengths: true, + } + + err := gopacket.SerializeLayers(buffer, + options, + ipLayer, + gopacket.Payload(espPacket), + ) + if err != nil { + return nil, errors.Errorf("Error serializing layers: %v", err) + } + + packetData := buffer.Bytes() + return packetData, nil +} + +func handleESPPacket(srcIP, dstIP *net.UDPAddr, espPacket []byte) error { + fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW) + if err != nil { + return errors.Errorf("socket error: %v", err) + } + + defer func() { + if err = syscall.Close(fd); err != nil { + logger.IKELog.Errorf("Close fd error : %v", err) + } + }() + + ipPacket, err := constructPacketWithESP(srcIP, dstIP, espPacket) + if err != nil { + return err + } + + addr := syscall.SockaddrInet4{ + Addr: [4]byte(dstIP.IP), + Port: dstIP.Port, + } + + err = syscall.Sendto(fd, ipPacket, 0, &addr) + if err != nil { + return errors.Errorf("sendto error: %v", err) + } + + return nil +} diff --git a/pkg/ike/server_test.go b/pkg/ike/server_test.go index a0c57030..c8f8b4bd 100644 --- a/pkg/ike/server_test.go +++ b/pkg/ike/server_test.go @@ -2,8 +2,15 @@ package ike import ( "context" + "net" "sync" + "testing" + "github.com/google/gopacket" + "github.com/google/gopacket/layers" + "github.com/stretchr/testify/require" + + ike_message "github.com/free5gc/ike/message" "github.com/free5gc/n3iwf/internal/ngap" n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" @@ -52,3 +59,230 @@ func NewN3iwfTestApp(cfg *factory.Config) (*n3iwfTestApp, error) { } return n3iwfApp, err } + +func NewTestCfg() *factory.Config { + return &factory.Config{ + Configuration: &factory.Configuration{}, + } +} + +func TestCheckMessage(t *testing.T) { + n3iwf, err := NewN3iwfTestApp(NewTestCfg()) + require.NoError(t, err) + + n3iwf.ikeServer, err = NewServer(n3iwf) + require.NoError(t, err) + ikeServer := n3iwf.ikeServer + + srcIP := &net.UDPAddr{ + IP: net.ParseIP("10.100.100.1"), + Port: 500, + } + dstIP := &net.UDPAddr{ + IP: net.ParseIP("10.100.100.2"), + Port: 500, + } + + mockConn, err := net.DialUDP("udp", nil, dstIP) + require.NoError(t, err) + + initiatorSPI := uint64(0x123) + ikeMessage := new(ike_message.IKEMessage) + ikeMessage.BuildIKEHeader(initiatorSPI, 0, + ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, 0) + + pkt, err := ikeMessage.Encode() + require.NoError(t, err) + + NonESPPkt := append([]byte{0, 0, 0, 0}, pkt...) + + tests := []struct { + name string + conn *net.UDPConn + rcvPkt IkeReceivePacket + msg *ike_message.IKEMessage + expectedErr bool + }{ + { + name: "Received NAT-T Keepalive", + rcvPkt: IkeReceivePacket{ + Listener: *mockConn, + LocalAddr: *dstIP, + RemoteAddr: *srcIP, + Msg: []byte{ + 0xff, + }, + }, + expectedErr: false, + }, + { + name: "Received packet is too short", + rcvPkt: IkeReceivePacket{ + Listener: *mockConn, + LocalAddr: *dstIP, + RemoteAddr: *srcIP, + Msg: []byte{ + 1, 2, + }, + }, + expectedErr: true, + }, + { + name: "Received IKE packet from port 4500, and no need to drop", + rcvPkt: IkeReceivePacket{ + Listener: *mockConn, + LocalAddr: net.UDPAddr{ + IP: net.ParseIP("10.100.100.2"), + Port: 4500, + }, + RemoteAddr: *srcIP, + Msg: NonESPPkt, + }, + expectedErr: false, + }, + { + name: "Received ESP packet from port 4500", + rcvPkt: IkeReceivePacket{ + Listener: *mockConn, + LocalAddr: net.UDPAddr{ + IP: net.ParseIP("10.100.100.2"), + Port: 4500, + }, + RemoteAddr: *srcIP, + Msg: []byte{ + 1, 2, 3, 4, 5, + }, + }, + expectedErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := ikeServer.checkMessage(tt.rcvPkt, nil) + if tt.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestCheckIKEMessage(t *testing.T) { + n3iwf, err := NewN3iwfTestApp(NewTestCfg()) + require.NoError(t, err) + + n3iwf.ikeServer, err = NewServer(n3iwf) + require.NoError(t, err) + ikeServer := n3iwf.ikeServer + + srcIP := &net.UDPAddr{ + IP: net.ParseIP("10.100.100.1"), + Port: 500, + } + dstIP := &net.UDPAddr{ + IP: net.ParseIP("10.100.100.2"), + Port: 500, + } + + mockConn, err := net.DialUDP("udp", nil, dstIP) + require.NoError(t, err) + + initiatorSPI := uint64(0x123) + ikeMsg := new(ike_message.IKEMessage) + nonceData := []byte("randomNonce") + ikeMsg.BuildIKEHeader(initiatorSPI, 0, + ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, 0) + ikeMsg.Payloads.Reset() + ikeMsg.Payloads.BuildNonce(nonceData) + + tests := []struct { + name string + conn *net.UDPConn + localAddr *net.UDPAddr + remoteAddr *net.UDPAddr + msg *ike_message.IKEMessage + expectedErr bool + }{ + { + name: "Receive packet has IKE version error", + conn: mockConn, + localAddr: dstIP, + remoteAddr: srcIP, + msg: &ike_message.IKEMessage{ + IKEHeader: &ike_message.IKEHeader{ + InitiatorSPI: initiatorSPI, + ExchangeType: ike_message.IKE_SA_INIT, + Flags: ike_message.ResponseBitCheck, + MajorVersion: 3, + MinorVersion: 0, + }, + }, + expectedErr: true, + }, + { + name: "Decode IKE_SA_INIT msg", + conn: mockConn, + localAddr: dstIP, + remoteAddr: srcIP, + msg: ikeMsg, + expectedErr: false, + }, + { + name: "SPI not found from IKE header", + conn: mockConn, + localAddr: dstIP, + remoteAddr: srcIP, + msg: &ike_message.IKEMessage{ + IKEHeader: &ike_message.IKEHeader{ + InitiatorSPI: initiatorSPI, + ExchangeType: ike_message.IKE_AUTH, + Flags: ike_message.ResponseBitCheck, + MajorVersion: 2, + MinorVersion: 0, + }, + Payloads: ikeMsg.Payloads, + }, + expectedErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + msg, err := tt.msg.Encode() + require.NoError(t, err) + + _, _, err = ikeServer.checkIKEMessage( + msg, tt.conn, tt.localAddr, tt.remoteAddr) + if tt.expectedErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + }) + } +} + +func TestConstructPacketWithESP(t *testing.T) { + srcIP := &net.UDPAddr{ + IP: net.IPv4(192, 168, 0, 1), + } + dstIP := &net.UDPAddr{ + IP: net.IPv4(192, 168, 0, 2), + } + + espPacket := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07} + + packet, err := constructPacketWithESP(srcIP, dstIP, espPacket) + require.NoError(t, err) + + packetParsed := gopacket.NewPacket(packet, layers.LayerTypeIPv4, gopacket.Default) + ipLayer := packetParsed.Layer(layers.LayerTypeIPv4) + require.NotNil(t, ipLayer) + + ipv4, _ := ipLayer.(*layers.IPv4) + require.Equal(t, ipv4.SrcIP.To4().String(), srcIP.IP.String()) + require.Equal(t, ipv4.DstIP.To4().String(), dstIP.IP.String()) + require.Equal(t, ipv4.Protocol, layers.IPProtocolESP) +} diff --git a/pkg/ike/xfrm/xfrm.go b/pkg/ike/xfrm/xfrm.go index c6581b15..fc3642fb 100644 --- a/pkg/ike/xfrm/xfrm.go +++ b/pkg/ike/xfrm/xfrm.go @@ -7,9 +7,9 @@ import ( "github.com/vishvananda/netlink" + "github.com/free5gc/ike/message" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/pkg/context" - "github.com/free5gc/n3iwf/pkg/ike/message" ) type XFRMEncryptionAlgorithmType uint16 @@ -63,26 +63,26 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, var xfrmEncryptionAlgorithm, xfrmIntegrityAlgorithm *netlink.XfrmStateAlgo if n3iwf_is_initiator { xfrmEncryptionAlgorithm = &netlink.XfrmStateAlgo{ - Name: XFRMEncryptionAlgorithmType(childSecurityAssociation.EncryptionAlgorithm).String(), + Name: XFRMEncryptionAlgorithmType(childSecurityAssociation.EncrKInfo.TransformID()).String(), Key: childSecurityAssociation.ResponderToInitiatorEncryptionKey, } - if childSecurityAssociation.IntegrityAlgorithm != 0 { + if childSecurityAssociation.IntegKInfo != nil { xfrmIntegrityAlgorithm = &netlink.XfrmStateAlgo{ - Name: XFRMIntegrityAlgorithmType(childSecurityAssociation.IntegrityAlgorithm).String(), + Name: XFRMIntegrityAlgorithmType(childSecurityAssociation.IntegKInfo.TransformID()).String(), Key: childSecurityAssociation.ResponderToInitiatorIntegrityKey, - TruncateLen: getTruncateLength(childSecurityAssociation.IntegrityAlgorithm), + TruncateLen: getTruncateLength(childSecurityAssociation.IntegKInfo.TransformID()), } } } else { xfrmEncryptionAlgorithm = &netlink.XfrmStateAlgo{ - Name: XFRMEncryptionAlgorithmType(childSecurityAssociation.EncryptionAlgorithm).String(), + Name: XFRMEncryptionAlgorithmType(childSecurityAssociation.EncrKInfo.TransformID()).String(), Key: childSecurityAssociation.InitiatorToResponderEncryptionKey, } - if childSecurityAssociation.IntegrityAlgorithm != 0 { + if childSecurityAssociation.IntegKInfo != nil { xfrmIntegrityAlgorithm = &netlink.XfrmStateAlgo{ - Name: XFRMIntegrityAlgorithmType(childSecurityAssociation.IntegrityAlgorithm).String(), + Name: XFRMIntegrityAlgorithmType(childSecurityAssociation.IntegKInfo.TransformID()).String(), Key: childSecurityAssociation.InitiatorToResponderIntegrityKey, - TruncateLen: getTruncateLength(childSecurityAssociation.IntegrityAlgorithm), + TruncateLen: getTruncateLength(childSecurityAssociation.IntegKInfo.TransformID()), } } } @@ -97,7 +97,7 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, xfrmState.Ifid = int(xfrmiId) xfrmState.Auth = xfrmIntegrityAlgorithm xfrmState.Crypt = xfrmEncryptionAlgorithm - xfrmState.ESN = childSecurityAssociation.ESN + xfrmState.ESN = childSecurityAssociation.EsnInfo.GetNeedESN() if childSecurityAssociation.EnableEncapsulate { xfrmState.Encap = &netlink.XfrmStateEncap{ @@ -148,12 +148,12 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, // State if n3iwf_is_initiator { xfrmEncryptionAlgorithm.Key = childSecurityAssociation.InitiatorToResponderEncryptionKey - if childSecurityAssociation.IntegrityAlgorithm != 0 { + if childSecurityAssociation.IntegKInfo != nil { xfrmIntegrityAlgorithm.Key = childSecurityAssociation.InitiatorToResponderIntegrityKey } } else { xfrmEncryptionAlgorithm.Key = childSecurityAssociation.ResponderToInitiatorEncryptionKey - if childSecurityAssociation.IntegrityAlgorithm != 0 { + if childSecurityAssociation.IntegKInfo != nil { xfrmIntegrityAlgorithm.Key = childSecurityAssociation.ResponderToInitiatorIntegrityKey } } @@ -189,49 +189,9 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, } childSecurityAssociation.XfrmPolicyList = append(childSecurityAssociation.XfrmPolicyList, *xfrmPolicy) - - printSAInfo(n3iwf_is_initiator, xfrmiId, childSecurityAssociation) - return nil } -func printSAInfo(n3iwf_is_initiator bool, xfrmiId uint32, childSecurityAssociation *context.ChildSecurityAssociation) { - ikeLog := logger.IKELog - var InboundEncryptionKey, InboundIntegrityKey, OutboundEncryptionKey, OutboundIntegrityKey []byte - - if n3iwf_is_initiator { - InboundEncryptionKey = childSecurityAssociation.ResponderToInitiatorEncryptionKey - InboundIntegrityKey = childSecurityAssociation.ResponderToInitiatorIntegrityKey - OutboundEncryptionKey = childSecurityAssociation.InitiatorToResponderEncryptionKey - OutboundIntegrityKey = childSecurityAssociation.InitiatorToResponderIntegrityKey - } else { - InboundEncryptionKey = childSecurityAssociation.InitiatorToResponderEncryptionKey - InboundIntegrityKey = childSecurityAssociation.InitiatorToResponderIntegrityKey - OutboundEncryptionKey = childSecurityAssociation.ResponderToInitiatorEncryptionKey - OutboundIntegrityKey = childSecurityAssociation.ResponderToInitiatorIntegrityKey - } - ikeLog.Debug("====== IPSec/Child SA Info ======") - // ====== Inbound ====== - ikeLog.Debugf("XFRM interface if_id: %d", xfrmiId) - ikeLog.Debugf("IPSec Inbound SPI: 0x%016x", childSecurityAssociation.InboundSPI) - ikeLog.Debugf("[UE:%+v] -> [N3IWF:%+v]", - childSecurityAssociation.PeerPublicIPAddr, childSecurityAssociation.LocalPublicIPAddr) - ikeLog.Debugf("IPSec Encryption Algorithm: %d", childSecurityAssociation.EncryptionAlgorithm) - ikeLog.Debugf("IPSec Encryption Key: 0x%x", InboundEncryptionKey) - ikeLog.Debugf("IPSec Integrity Algorithm: %d", childSecurityAssociation.IntegrityAlgorithm) - ikeLog.Debugf("IPSec Integrity Key: 0x%x", InboundIntegrityKey) - ikeLog.Debug("====== IPSec/Child SA Info ======") - // ====== Outbound ====== - ikeLog.Debugf("XFRM interface if_id: %d", xfrmiId) - ikeLog.Debugf("IPSec Outbound SPI: 0x%016x", childSecurityAssociation.OutboundSPI) - ikeLog.Debugf("[N3IWF:%+v] -> [UE:%+v]", - childSecurityAssociation.LocalPublicIPAddr, childSecurityAssociation.PeerPublicIPAddr) - ikeLog.Debugf("IPSec Encryption Algorithm: %d", childSecurityAssociation.EncryptionAlgorithm) - ikeLog.Debugf("IPSec Encryption Key: 0x%x", OutboundEncryptionKey) - ikeLog.Debugf("IPSec Integrity Algorithm: %d", childSecurityAssociation.IntegrityAlgorithm) - ikeLog.Debugf("IPSec Integrity Key: 0x%x", OutboundIntegrityKey) -} - func SetupIPsecXfrmi(xfrmIfaceName, parentIfaceName string, xfrmIfaceId uint32, xfrmIfaceAddr net.IPNet, ) (netlink.Link, error) { From 6272df31108ac9a131b6b5ece7697957eac1089b Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Mon, 23 Sep 2024 06:16:16 +0000 Subject: [PATCH 24/33] Fix warning when receive ike message from port 4500 --- pkg/ike/server.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/ike/server.go b/pkg/ike/server.go index ff796b16..57fc8cbd 100644 --- a/pkg/ike/server.go +++ b/pkg/ike/server.go @@ -120,14 +120,14 @@ func (s *Server) server(wg *sync.WaitGroup) { ikeLog.Warnln(err) continue } + if msg == nil { + continue + } ikeMsg, ikeSA, err := s.checkIKEMessage(msg, &rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr) if err != nil { ikeLog.Warnln(err) continue } - if ikeMsg == nil { - continue - } s.Dispatch(&rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr, ikeMsg, rcvPkt.Msg, ikeSA) case rcvIkeEvent := <-s.RcvEventCh: From 532420777167fb4ea6e682931371d2ea7b72150e Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Mon, 23 Sep 2024 07:53:48 +0000 Subject: [PATCH 25/33] Add ESP-in-UDP in xfrm.go --- .golangci.yml | 1 - pkg/context/context.go | 2 +- pkg/ike/xfrm/xfrm.go | 32 ++++++++++++++------------------ 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index f839b044..425896f6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -266,7 +266,6 @@ linters: # - stylecheck # - unparam # - wsl - - gosec #disable-all: false fast: true diff --git a/pkg/context/context.go b/pkg/context/context.go index 230bd735..09ba7ba2 100644 --- a/pkg/context/context.go +++ b/pkg/context/context.go @@ -4,7 +4,7 @@ import ( "context" "crypto/rand" "crypto/rsa" - "crypto/sha1" + "crypto/sha1" // #nosec G505 "crypto/x509" "encoding/pem" "fmt" diff --git a/pkg/ike/xfrm/xfrm.go b/pkg/ike/xfrm/xfrm.go index fc3642fb..abf2231a 100644 --- a/pkg/ike/xfrm/xfrm.go +++ b/pkg/ike/xfrm/xfrm.go @@ -1,10 +1,10 @@ package xfrm import ( - "errors" "fmt" "net" + "github.com/pkg/errors" "github.com/vishvananda/netlink" "github.com/free5gc/ike/message" @@ -55,7 +55,6 @@ func (xfrmIntegrityAlgorithmType XFRMIntegrityAlgorithmType) String() string { func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, childSecurityAssociation *context.ChildSecurityAssociation, ) error { - ikeLog := logger.IKELog // Build XFRM information data structure for incoming traffic. // Direction: {private_network} -> this_server @@ -99,19 +98,10 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, xfrmState.Crypt = xfrmEncryptionAlgorithm xfrmState.ESN = childSecurityAssociation.EsnInfo.GetNeedESN() - if childSecurityAssociation.EnableEncapsulate { - xfrmState.Encap = &netlink.XfrmStateEncap{ - Type: netlink.XFRM_ENCAP_ESPINUDP, - SrcPort: childSecurityAssociation.NATPort, - DstPort: childSecurityAssociation.N3IWFPort, - } - } - // Commit xfrm state to netlink var err error if err = netlink.XfrmStateAdd(xfrmState); err != nil { - ikeLog.Errorf("Set XFRM rules failed: %+v", err) - return errors.New("Set XFRM state rule failed") + return errors.Wrapf(err, "Add XFRM state") } childSecurityAssociation.XfrmStateList = append(childSecurityAssociation.XfrmStateList, *xfrmState) @@ -138,8 +128,7 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, // Commit xfrm policy to netlink if err = netlink.XfrmPolicyAdd(xfrmPolicy); err != nil { - ikeLog.Errorf("Set XFRM rules failed: %+v", err) - return errors.New("Set XFRM policy rule failed") + return errors.Wrapf(err, "Add XFRM policy") } childSecurityAssociation.XfrmPolicyList = append(childSecurityAssociation.XfrmPolicyList, *xfrmPolicy) @@ -160,14 +149,22 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, xfrmState.Spi = int(childSecurityAssociation.OutboundSPI) xfrmState.Src, xfrmState.Dst = xfrmState.Dst, xfrmState.Src + + if childSecurityAssociation.EnableEncapsulate { + xfrmState.Encap = &netlink.XfrmStateEncap{ + Type: netlink.XFRM_ENCAP_ESPINUDP, + SrcPort: childSecurityAssociation.NATPort, + DstPort: childSecurityAssociation.N3IWFPort, + } + } + if xfrmState.Encap != nil { xfrmState.Encap.SrcPort, xfrmState.Encap.DstPort = xfrmState.Encap.DstPort, xfrmState.Encap.SrcPort } // Commit xfrm state to netlink if err = netlink.XfrmStateAdd(xfrmState); err != nil { - ikeLog.Errorf("Set XFRM rules failed: %+v", err) - return errors.New("Set XFRM state rule failed") + return errors.Wrapf(err, "Add XFRM state") } childSecurityAssociation.XfrmStateList = append(childSecurityAssociation.XfrmStateList, *xfrmState) @@ -184,8 +181,7 @@ func ApplyXFRMRule(n3iwf_is_initiator bool, xfrmiId uint32, // Commit xfrm policy to netlink if err = netlink.XfrmPolicyAdd(xfrmPolicy); err != nil { - ikeLog.Errorf("Set XFRM rules failed: %+v", err) - return errors.New("Set XFRM policy rule failed") + return errors.Wrapf(err, "Add XFRM policy") } childSecurityAssociation.XfrmPolicyList = append(childSecurityAssociation.XfrmPolicyList, *xfrmPolicy) From be836cccbaf7176e5ba591a51e51f39bce9fcdf9 Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Mon, 23 Sep 2024 08:49:02 +0000 Subject: [PATCH 26/33] Update IKE pkg --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a2f40ed1..41476149 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/free5gc/aper v1.0.6-0.20240503143507-2c4c4780b98f - github.com/free5gc/ike v1.0.1-0.20240918094906-1ee5ab8d45ed + github.com/free5gc/ike v1.1.0 github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74 github.com/free5gc/sctp v1.0.1 github.com/free5gc/util v1.0.7-0.20240713162917-350ee8f4af4c diff --git a/go.sum b/go.sum index ecdb5e46..53909630 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/free5gc/aper v1.0.6-0.20240503143507-2c4c4780b98f h1:sO8FFwAq7feSw/vKN9ioY+fX1gNTXd6/xQOqaeclzsA= github.com/free5gc/aper v1.0.6-0.20240503143507-2c4c4780b98f/go.mod h1:oh3dtNsje2W4/q3pfidMWQKXbXIehXK3t6CD9tXmHx0= -github.com/free5gc/ike v1.0.1-0.20240918094906-1ee5ab8d45ed h1:SqznJMp2NP7lDX1Mx6NRLOPEAfoQvwJELDX6/6EgZrM= -github.com/free5gc/ike v1.0.1-0.20240918094906-1ee5ab8d45ed/go.mod h1:57Ujd9Xjva02mt3OVfepYKiheFHO5Y0YCQyBgB1p1Qs= +github.com/free5gc/ike v1.1.0 h1:gTbjfx8T1xkB5olPuijvIV5POD1NatLUuaNwcmWIClM= +github.com/free5gc/ike v1.1.0/go.mod h1:57Ujd9Xjva02mt3OVfepYKiheFHO5Y0YCQyBgB1p1Qs= github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74 h1:foSd3OVtTfDmn3EZbsBngK+U93Mv8YE+qSja7FvKEVU= github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74/go.mod h1:UsPP9LWVyNwu5sm7ZE5toAFeBNkkyj0rh+4Q3ylRBi8= github.com/free5gc/openapi v1.0.9-0.20240503143645-eac9f06c2f6b h1:+VcgZq+3apB6Xr4jEqgGf/uAECRF038SwixEvvxhYrM= From 2981861e79d1f6ba05ccef2131bb8014adc77ea9 Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Mon, 30 Sep 2024 01:48:37 +0000 Subject: [PATCH 27/33] refactor RanUe context and refactor event channel --- {pkg => internal}/context/3gpp_types.go | 0 {pkg => internal}/context/amf.go | 12 +- {pkg => internal}/context/context.go | 50 +- internal/context/gtp.go | 30 ++ {pkg => internal}/context/ike.go | 0 {pkg => internal}/context/ikeue.go | 0 internal/context/n3iwf_ue.go | 89 +++ {pkg => internal}/context/ngap.go | 49 +- internal/context/nwuup.go | 28 + {pkg => internal}/context/ranue.go | 86 +-- internal/context/safe_event_channel.go | 31 ++ internal/context/safe_event_channel_test.go | 43 ++ {pkg => internal}/context/testing_app.go | 0 {pkg => internal}/context/timer.go | 0 internal/gtp/message/message.go | 17 + {pkg => internal}/ike/dispatcher.go | 2 +- {pkg => internal}/ike/handler.go | 95 ++-- {pkg => internal}/ike/handler_test.go | 2 +- {pkg => internal}/ike/send.go | 2 +- {pkg => internal}/ike/server.go | 153 +++--- {pkg => internal}/ike/server_test.go | 112 ++-- {pkg => internal}/ike/xfrm/xfrm.go | 2 +- internal/logger/logger.go | 36 +- internal/nas/nas_security/security.go | 18 + internal/ngap/handler.go | 565 ++++++++++++-------- internal/ngap/handler_test.go | 10 +- internal/ngap/message/build.go | 217 ++++---- internal/ngap/message/send.go | 132 ++--- internal/ngap/server.go | 66 +-- internal/ngap/server_test.go | 27 +- internal/nwucp/server.go | 79 +-- internal/nwuup/server.go | 254 ++++----- internal/util/hash.go | 13 + pkg/app/app.go | 2 +- pkg/factory/config.go | 64 +-- pkg/service/init.go | 50 +- 36 files changed, 1383 insertions(+), 953 deletions(-) rename {pkg => internal}/context/3gpp_types.go (100%) rename {pkg => internal}/context/amf.go (94%) rename {pkg => internal}/context/context.go (92%) create mode 100644 internal/context/gtp.go rename {pkg => internal}/context/ike.go (100%) rename {pkg => internal}/context/ikeue.go (100%) create mode 100644 internal/context/n3iwf_ue.go rename {pkg => internal}/context/ngap.go (78%) create mode 100644 internal/context/nwuup.go rename {pkg => internal}/context/ranue.go (64%) create mode 100644 internal/context/safe_event_channel.go create mode 100644 internal/context/safe_event_channel_test.go rename {pkg => internal}/context/testing_app.go (100%) rename {pkg => internal}/context/timer.go (100%) rename {pkg => internal}/ike/dispatcher.go (94%) rename {pkg => internal}/ike/handler.go (96%) rename {pkg => internal}/ike/handler_test.go (99%) rename {pkg => internal}/ike/send.go (98%) rename {pkg => internal}/ike/server.go (75%) rename {pkg => internal}/ike/server_test.go (74%) rename {pkg => internal}/ike/xfrm/xfrm.go (99%) create mode 100644 internal/nas/nas_security/security.go create mode 100644 internal/util/hash.go diff --git a/pkg/context/3gpp_types.go b/internal/context/3gpp_types.go similarity index 100% rename from pkg/context/3gpp_types.go rename to internal/context/3gpp_types.go diff --git a/pkg/context/amf.go b/internal/context/amf.go similarity index 94% rename from pkg/context/amf.go rename to internal/context/amf.go index 1479b2df..61b2e7c2 100644 --- a/pkg/context/amf.go +++ b/internal/context/amf.go @@ -18,10 +18,10 @@ type N3IWFAMF struct { RelativeAMFCapacity *ngapType.RelativeAMFCapacity PLMNSupportList *ngapType.PLMNSupportList AMFTNLAssociationList map[string]*AMFTNLAssociationItem // v4+v6 as key - // Overload related + /* Overload related */ AMFOverloadContent *AMFOverloadContent - // Relative Context - N3iwfRanUeList map[int64]*N3IWFRanUe // ranUeNgapId as key + /* Relative Context */ + N3iwfRanUeList map[int64]RanUe // ranUeNgapId as key } type AMFTNLAssociationItem struct { @@ -47,12 +47,12 @@ func (amf *N3IWFAMF) init(sctpAddr string, conn *sctp.SCTPConn) { amf.SCTPAddr = sctpAddr amf.SCTPConn = conn amf.AMFTNLAssociationList = make(map[string]*AMFTNLAssociationItem) - amf.N3iwfRanUeList = make(map[int64]*N3IWFRanUe) + amf.N3iwfRanUeList = make(map[int64]RanUe) } -func (amf *N3IWFAMF) FindUeByAmfUeNgapID(id int64) *N3IWFRanUe { +func (amf *N3IWFAMF) FindUeByAmfUeNgapID(id int64) RanUe { for _, ranUe := range amf.N3iwfRanUeList { - if ranUe.AmfUeNgapId == id { + if ranUe.GetSharedCtx().AmfUeNgapId == id { return ranUe } } diff --git a/pkg/context/context.go b/internal/context/context.go similarity index 92% rename from pkg/context/context.go rename to internal/context/context.go index 09ba7ba2..f23894ef 100644 --- a/pkg/context/context.go +++ b/internal/context/context.go @@ -34,34 +34,33 @@ type n3iwf interface { type N3IWFContext struct { n3iwf - // ID generator + /* ID generator */ RANUENGAPIDGenerator *idgenerator.IDGenerator TEIDGenerator *idgenerator.IDGenerator - // Pools + /* Pools */ AMFPool sync.Map // map[string]*N3IWFAMF, SCTPAddr as key AMFReInitAvailableList sync.Map // map[string]bool, SCTPAddr as key IKESA sync.Map // map[uint64]*IKESecurityAssociation, SPI as key ChildSA sync.Map // map[uint32]*ChildSecurityAssociation, inboundSPI as key GTPConnectionWithUPF sync.Map // map[string]*gtpv1.UPlaneConn, UPF address as key AllocatedUEIPAddress sync.Map // map[string]*N3IWFIkeUe, IPAddr as key - AllocatedUETEID sync.Map // map[uint32]*N3IWFRanUe, TEID as key + AllocatedUETEID sync.Map // map[uint32]*RanUe, TEID as key IKEUePool sync.Map // map[uint64]*N3IWFIkeUe, SPI as key - RANUePool sync.Map // map[int64]*N3IWFRanUe, RanUeNgapID as key + RANUePool sync.Map // map[int64]*RanUe, RanUeNgapID as key IKESPIToNGAPId sync.Map // map[uint64]RanUeNgapID, SPI as key NGAPIdToIKESPI sync.Map // map[uint64]SPI, RanUeNgapID as key - // Security data + /* Security data */ CertificateAuthority []byte N3IWFCertificate []byte N3IWFPrivateKey *rsa.PrivateKey UeIPRange *net.IPNet - // XFRM interface + /* XFRM interface */ XfrmIfaces sync.Map // map[uint32]*netlink.Link, XfrmIfaceId as key XfrmParentIfaceName string - // Every UE's first UP IPsec will use default XFRM interface, additoinal UP IPsec will offset its XFRM id XfrmIfaceIdOffsetForUP uint32 } @@ -190,11 +189,12 @@ func (c *N3IWFContext) NewN3iwfRanUe() *N3IWFRanUe { return nil } n3iwfRanUe := &N3IWFRanUe{ - N3iwfCtx: c, + RanUeSharedCtx: RanUeSharedCtx{ + N3iwfCtx: c, + }, } n3iwfRanUe.init(ranUeNgapId) c.RANUePool.Store(ranUeNgapId, n3iwfRanUe) - n3iwfRanUe.TemporaryPDUSessionSetupData = new(PDUSessionSetupTemporaryData) return n3iwfRanUe } @@ -218,10 +218,21 @@ func (c *N3IWFContext) IkeUePoolLoad(spi uint64) (*N3IWFIkeUe, bool) { } } -func (c *N3IWFContext) RanUePoolLoad(ranUeNgapId int64) (*N3IWFRanUe, bool) { +func (c *N3IWFContext) RanUePoolLoad(id interface{}) (RanUe, bool) { + var ranUeNgapId int64 + + cfgLog := logger.CfgLog + switch id := id.(type) { + case int64: + ranUeNgapId = id + default: + cfgLog.Warnf("RanUePoolLoad unhandle type: %t", id) + return nil, false + } + ranUe, ok := c.RANUePool.Load(ranUeNgapId) if ok { - return ranUe.(*N3IWFRanUe), ok + return ranUe.(RanUe), ok } else { return nil, ok } @@ -256,7 +267,7 @@ func (c *N3IWFContext) DeleteIkeSPIFromNgapId(ranUeNgapId int64) { c.NGAPIdToIKESPI.Delete(ranUeNgapId) } -func (c *N3IWFContext) RanUeLoadFromIkeSPI(spi uint64) (*N3IWFRanUe, error) { +func (c *N3IWFContext) RanUeLoadFromIkeSPI(spi uint64) (RanUe, error) { ranNgapId, ok := c.IKESPIToNGAPId.Load(spi) if ok { ranUe, err := c.RanUePoolLoad(ranNgapId.(int64)) @@ -405,7 +416,7 @@ func (c *N3IWFContext) AllocatedUEIPAddressLoad(ipAddr string) (*N3IWFIkeUe, boo return nil, false } -func (c *N3IWFContext) NewTEID(ranUe *N3IWFRanUe) uint32 { +func (c *N3IWFContext) NewTEID(ranUe RanUe) uint32 { teid64, err := c.TEIDGenerator.Allocate() if err != nil { logger.CtxLog.Errorf("New TEID failed: %+v", err) @@ -427,10 +438,10 @@ func (c *N3IWFContext) DeleteTEID(teid uint32) { c.AllocatedUETEID.Delete(teid) } -func (c *N3IWFContext) AllocatedUETEIDLoad(teid uint32) (*N3IWFRanUe, bool) { +func (c *N3IWFContext) AllocatedUETEIDLoad(teid uint32) (RanUe, bool) { ranUe, ok := c.AllocatedUETEID.Load(teid) if ok { - return ranUe.(*N3IWFRanUe), ok + return ranUe.(RanUe), ok } return nil, false } @@ -439,9 +450,12 @@ func (c *N3IWFContext) AMFSelection( ueSpecifiedGUAMI *ngapType.GUAMI, ueSpecifiedPLMNId *ngapType.PLMNIdentity, ) *N3IWFAMF { - var availableAMF *N3IWFAMF + var availableAMF, defaultAMF *N3IWFAMF c.AMFPool.Range(func(key, value interface{}) bool { amf := value.(*N3IWFAMF) + if defaultAMF == nil { + defaultAMF = amf + } if amf.FindAvalibleAMFByCompareGUAMI(ueSpecifiedGUAMI) { availableAMF = amf return false @@ -455,6 +469,10 @@ func (c *N3IWFContext) AMFSelection( return true } }) + if availableAMF == nil && + defaultAMF != nil { + availableAMF = defaultAMF + } return availableAMF } diff --git a/internal/context/gtp.go b/internal/context/gtp.go new file mode 100644 index 00000000..e1719a66 --- /dev/null +++ b/internal/context/gtp.go @@ -0,0 +1,30 @@ +package context + +type GtpEventType int64 + +// GTP Event Type +const ( + ForwardUL GtpEventType = iota +) + +type GtpEvt interface { + Type() GtpEventType +} + +type ForwardULEvt struct { + GtpConnInfo *GTPConnectionInfo + QFI *uint8 + Payload []byte +} + +func (forwardDLEvt *ForwardULEvt) Type() GtpEventType { + return ForwardUL +} + +func NewForwardULEvt(gtpConnInfo *GTPConnectionInfo, qfi *uint8, payload []byte) *ForwardULEvt { + return &ForwardULEvt{ + GtpConnInfo: gtpConnInfo, + QFI: qfi, + Payload: payload, + } +} diff --git a/pkg/context/ike.go b/internal/context/ike.go similarity index 100% rename from pkg/context/ike.go rename to internal/context/ike.go diff --git a/pkg/context/ikeue.go b/internal/context/ikeue.go similarity index 100% rename from pkg/context/ikeue.go rename to internal/context/ikeue.go diff --git a/internal/context/n3iwf_ue.go b/internal/context/n3iwf_ue.go new file mode 100644 index 00000000..143e55c5 --- /dev/null +++ b/internal/context/n3iwf_ue.go @@ -0,0 +1,89 @@ +package context + +import ( + "net" + + "github.com/pkg/errors" + + "github.com/free5gc/ngap/ngapConvert" + "github.com/free5gc/ngap/ngapType" +) + +type N3IWFRanUe struct { + RanUeSharedCtx + + /* Temporary cached NAS message */ + // Used when NAS registration accept arrived before + // UE setup NAS TCP connection with N3IWF, and + // Forward pduSessionEstablishmentAccept to UE after + // UE send CREATE_CHILD_SA response + TemporaryCachedNASMessage []byte + + /* NAS TCP Connection Established */ + IsNASTCPConnEstablished bool + IsNASTCPConnEstablishedComplete bool + + /* NAS TCP Connection */ + TCPConnection net.Conn +} + +func (n3iwfUe *N3IWFRanUe) init(ranUeNgapId int64) { + n3iwfUe.RanUeNgapId = ranUeNgapId + n3iwfUe.AmfUeNgapId = AmfUeNgapIdUnspecified + n3iwfUe.PduSessionList = make(map[int64]*PDUSession) + n3iwfUe.TemporaryPDUSessionSetupData = new(PDUSessionSetupTemporaryData) + n3iwfUe.IsNASTCPConnEstablished = false + n3iwfUe.IsNASTCPConnEstablishedComplete = false +} + +func (ranUe *N3IWFRanUe) Remove() error { + // remove from AMF context + ranUe.DetachAMF() + + // remove from RAN UE context + n3iwfCtx := ranUe.N3iwfCtx + n3iwfCtx.DeleteRanUe(ranUe.RanUeNgapId) + + for _, pduSession := range ranUe.PduSessionList { + n3iwfCtx.DeleteTEID(pduSession.GTPConnInfo.IncomingTEID) + } + + if ranUe.TCPConnection != nil { + if err := ranUe.TCPConnection.Close(); err != nil { + return errors.Errorf("Close TCP conn error : %v", err) + } + } + + return nil +} + +func (n3iwfUe *N3IWFRanUe) AttachAMF(sctpAddr string) bool { + if amf, ok := n3iwfUe.N3iwfCtx.AMFPoolLoad(sctpAddr); ok { + amf.N3iwfRanUeList[n3iwfUe.RanUeNgapId] = n3iwfUe + n3iwfUe.AMF = amf + return true + } else { + return false + } +} + +func (n3iwfUe *N3IWFRanUe) DetachAMF() { + if n3iwfUe.AMF == nil { + return + } + delete(n3iwfUe.AMF.N3iwfRanUeList, n3iwfUe.RanUeNgapId) +} + +/* Implement RanUe interface */ +func (n3iwfUe *N3IWFRanUe) GetUserLocationInformation() *ngapType.UserLocationInformation { + userLocationInformation := new(ngapType.UserLocationInformation) + + userLocationInformation.Present = ngapType.UserLocationInformationPresentUserLocationInformationN3IWF + userLocationInformation.UserLocationInformationN3IWF = new(ngapType.UserLocationInformationN3IWF) + + userLocationInfoN3IWF := userLocationInformation.UserLocationInformationN3IWF + userLocationInfoN3IWF.IPAddress = ngapConvert.IPAddressToNgap(n3iwfUe.IPAddrv4, n3iwfUe.IPAddrv6) + userLocationInfoN3IWF.PortNumber = ngapConvert.PortNumberToNgap(n3iwfUe.PortNumber) + + return userLocationInformation +} diff --git a/pkg/context/ngap.go b/internal/context/ngap.go similarity index 78% rename from pkg/context/ngap.go rename to internal/context/ngap.go index 4627bd78..7cfe1fc1 100644 --- a/pkg/context/ngap.go +++ b/internal/context/ngap.go @@ -1,19 +1,23 @@ package context +import "github.com/free5gc/ngap/ngapType" + type NgapEventType int64 // NGAP event type const ( UnmarshalEAP5GData NgapEventType = iota + NASTCPConnEstablishedComplete + GetNGAPContext SendInitialUEMessage SendPDUSessionResourceSetupResponse SendNASMsg StartTCPSignalNASMsg - NASTCPConnEstablishedComplete SendUEContextReleaseRequest SendUEContextReleaseComplete SendPDUSessionResourceReleaseResponse - GetNGAPContext + SendUplinkNASTransport + SendInitialContextSetupResponse ) type EvtError string @@ -197,3 +201,44 @@ func NewGetNGAPContextEvt(ranUeNgapId int64, ngapCxtReqNumlist []int64) *GetNGAP NgapCxtReqNumlist: ngapCxtReqNumlist, } } + +type SendUplinkNASTransportEvt struct { + RanUeNgapId int64 + Pdu []byte +} + +func (e *SendUplinkNASTransportEvt) Type() NgapEventType { + return SendUplinkNASTransport +} + +func NewSendUplinkNASTransportEvt(ranUeNgapId int64, pdu []byte) *SendUplinkNASTransportEvt { + return &SendUplinkNASTransportEvt{ + RanUeNgapId: ranUeNgapId, + Pdu: pdu, + } +} + +type SendInitialContextSetupRespEvt struct { + RanUeNgapId int64 + ResponseList *ngapType.PDUSessionResourceSetupListCxtRes + FailedList *ngapType.PDUSessionResourceFailedToSetupListCxtRes + CriticalityDiagnostics *ngapType.CriticalityDiagnostics +} + +func (e *SendInitialContextSetupRespEvt) Type() NgapEventType { + return SendInitialContextSetupResponse +} + +func NewSendInitialContextSetupRespEvt( + ranUeNgapId int64, + responseList *ngapType.PDUSessionResourceSetupListCxtRes, + failedList *ngapType.PDUSessionResourceFailedToSetupListCxtRes, + criticalityDiagnostics *ngapType.CriticalityDiagnostics, +) *SendInitialContextSetupRespEvt { + return &SendInitialContextSetupRespEvt{ + RanUeNgapId: ranUeNgapId, + ResponseList: responseList, + FailedList: failedList, + CriticalityDiagnostics: criticalityDiagnostics, + } +} diff --git a/internal/context/nwuup.go b/internal/context/nwuup.go new file mode 100644 index 00000000..52d367eb --- /dev/null +++ b/internal/context/nwuup.go @@ -0,0 +1,28 @@ +package context + +import gtpQoSMsg "github.com/free5gc/n3iwf/internal/gtp/message" + +type NwuupEventType int64 + +// NWuup Event Type +const ( + NwuupForwardDL NwuupEventType = iota +) + +type NwuupEvt interface { + Type() NwuupEventType +} + +type NwuupForwardDLEvt struct { + Packet gtpQoSMsg.QoSTPDUPacket +} + +func (nwuupForwardDLEvt *NwuupForwardDLEvt) Type() NwuupEventType { + return NwuupForwardDL +} + +func NewNwuupForwardDLEvt(packet gtpQoSMsg.QoSTPDUPacket) *NwuupForwardDLEvt { + return &NwuupForwardDLEvt{ + Packet: packet, + } +} diff --git a/pkg/context/ranue.go b/internal/context/ranue.go similarity index 64% rename from pkg/context/ranue.go rename to internal/context/ranue.go index 1ddfa48d..b25bea57 100644 --- a/pkg/context/ranue.go +++ b/internal/context/ranue.go @@ -4,12 +4,26 @@ import ( "fmt" "net" - "github.com/pkg/errors" - "github.com/free5gc/ngap/ngapType" ) -type N3IWFRanUe struct { +type RanUe interface { + /* Get Attributes */ + GetUserLocationInformation() *ngapType.UserLocationInformation + GetSharedCtx() *RanUeSharedCtx + + /* User Plane Traffic */ + // ForwardDL(gtpQoSMsg.QoSTPDUPacket) + // ForwardUL() + + /* Others */ + CreatePDUSession(int64, ngapType.SNSSAI) (*PDUSession, error) + DeletePDUSession(int64) + FindPDUSession(int64) *PDUSession + Remove() error +} + +type RanUeSharedCtx struct { /* UE identity */ RanUeNgapId int64 AmfUeNgapId int64 @@ -32,20 +46,6 @@ type N3IWFRanUe struct { /* PDU Session Setup Temporary Data */ TemporaryPDUSessionSetupData *PDUSessionSetupTemporaryData - /* Temporary cached NAS message */ - // Used when NAS registration accept arrived before - // UE setup NAS TCP connection with N3IWF, and - // Forward pduSessionEstablishmentAccept to UE after - // UE send CREATE_CHILD_SA response - TemporaryCachedNASMessage []byte - - /* NAS TCP Connection Established */ - IsNASTCPConnEstablished bool - IsNASTCPConnEstablishedComplete bool - - /* NAS TCP Connection */ - TCPConnection net.Conn - /* Others */ Guami *ngapType.GUAMI IndexToRfsp int64 @@ -68,7 +68,7 @@ type PDUSession struct { SecurityIntegrity bool MaximumIntegrityDataRateUplink *ngapType.MaximumIntegrityProtectedDataRate MaximumIntegrityDataRateDownlink *ngapType.MaximumIntegrityProtectedDataRate - GTPConnection *GTPConnectionInfo + GTPConnInfo *GTPConnectionInfo QFIList []uint8 QosFlows map[int64]*QosFlow // QosFlowIdentifier as key } @@ -102,36 +102,11 @@ type PDUSessionSetupTemporaryData struct { Index int } -func (ranUe *N3IWFRanUe) init(ranUeNgapId int64) { - ranUe.RanUeNgapId = ranUeNgapId - ranUe.AmfUeNgapId = AmfUeNgapIdUnspecified - ranUe.PduSessionList = make(map[int64]*PDUSession) - ranUe.IsNASTCPConnEstablished = false - ranUe.IsNASTCPConnEstablishedComplete = false -} - -func (ranUe *N3IWFRanUe) Remove() error { - // remove from AMF context - ranUe.DetachAMF() - - // remove from RAN UE context - n3iwfCtx := ranUe.N3iwfCtx - n3iwfCtx.DeleteRanUe(ranUe.RanUeNgapId) - - for _, pduSession := range ranUe.PduSessionList { - n3iwfCtx.DeleteTEID(pduSession.GTPConnection.IncomingTEID) - } - - if ranUe.TCPConnection != nil { - if err := ranUe.TCPConnection.Close(); err != nil { - return errors.Errorf("Close TCP conn error : %v", err) - } - } - - return nil +func (ranUe *RanUeSharedCtx) GetSharedCtx() *RanUeSharedCtx { + return ranUe } -func (ranUe *N3IWFRanUe) FindPDUSession(pduSessionID int64) *PDUSession { +func (ranUe *RanUeSharedCtx) FindPDUSession(pduSessionID int64) *PDUSession { if pduSession, ok := ranUe.PduSessionList[pduSessionID]; ok { return pduSession } else { @@ -139,7 +114,7 @@ func (ranUe *N3IWFRanUe) FindPDUSession(pduSessionID int64) *PDUSession { } } -func (ranUe *N3IWFRanUe) CreatePDUSession(pduSessionID int64, snssai ngapType.SNSSAI) (*PDUSession, error) { +func (ranUe *RanUeSharedCtx) CreatePDUSession(pduSessionID int64, snssai ngapType.SNSSAI) (*PDUSession, error) { if _, exists := ranUe.PduSessionList[pduSessionID]; exists { return nil, fmt.Errorf("PDU Session[ID:%d] is already exists", pduSessionID) } @@ -152,19 +127,6 @@ func (ranUe *N3IWFRanUe) CreatePDUSession(pduSessionID int64, snssai ngapType.SN return pduSession, nil } -func (ranUe *N3IWFRanUe) AttachAMF(sctpAddr string) bool { - if amf, ok := ranUe.N3iwfCtx.AMFPoolLoad(sctpAddr); ok { - amf.N3iwfRanUeList[ranUe.RanUeNgapId] = ranUe - ranUe.AMF = amf - return true - } else { - return false - } -} - -func (ranUe *N3IWFRanUe) DetachAMF() { - if ranUe.AMF == nil { - return - } - delete(ranUe.AMF.N3iwfRanUeList, ranUe.RanUeNgapId) +func (ranUe *RanUeSharedCtx) DeletePDUSession(pduSessionId int64) { + delete(ranUe.PduSessionList, pduSessionId) } diff --git a/internal/context/safe_event_channel.go b/internal/context/safe_event_channel.go new file mode 100644 index 00000000..d58380e1 --- /dev/null +++ b/internal/context/safe_event_channel.go @@ -0,0 +1,31 @@ +package context + +import "fmt" + +type SafeEvtCh[chanType any] struct { + rcvEvtCh chan chanType + stopSigCh chan struct{} +} + +func (safeEvtCh *SafeEvtCh[chanType]) Init(rcvEvtCh chan chanType) { + safeEvtCh.rcvEvtCh = rcvEvtCh + safeEvtCh.stopSigCh = make(chan struct{}) +} + +func (safeEvtCh *SafeEvtCh[chanType]) SendEvt(evt chanType) error { + select { + case <-safeEvtCh.stopSigCh: + return fmt.Errorf("event channel[%T] is closed", safeEvtCh.rcvEvtCh) + default: + } + safeEvtCh.rcvEvtCh <- evt + return nil +} + +func (safeEvtCh *SafeEvtCh[chanType]) RecvEvtCh() chan chanType { + return safeEvtCh.rcvEvtCh +} + +func (safeEvtCh *SafeEvtCh[chanType]) Close() { + close(safeEvtCh.stopSigCh) +} diff --git a/internal/context/safe_event_channel_test.go b/internal/context/safe_event_channel_test.go new file mode 100644 index 00000000..aa765529 --- /dev/null +++ b/internal/context/safe_event_channel_test.go @@ -0,0 +1,43 @@ +package context_test + +import ( + "sync" + "testing" + "time" + + "github.com/stretchr/testify/require" + + n3iwf_context "github.com/free5gc/n3iwf/internal/context" +) + +// Simulate 1 receiver and N(N=2) senders situation +func TestSafeEvtCh(t *testing.T) { + safeEvtCh := new(n3iwf_context.SafeEvtCh[int]) + safeEvtCh.Init(make(chan int, 10)) + wg := sync.WaitGroup{} + + // Two senders + wg.Add(2) + for i := 0; i < 2; i++ { + go func() { + if i == 0 { + // Case: send failed + time.Sleep(1 * time.Second) + err := safeEvtCh.SendEvt(1) + t.Log(err) + require.Error(t, err) + } else { + // Case: send successed + err := safeEvtCh.SendEvt(1) + require.NoError(t, err) + } + wg.Done() + }() + } + + // One receiver + <-safeEvtCh.RecvEvtCh() + safeEvtCh.Close() + + wg.Wait() +} diff --git a/pkg/context/testing_app.go b/internal/context/testing_app.go similarity index 100% rename from pkg/context/testing_app.go rename to internal/context/testing_app.go diff --git a/pkg/context/timer.go b/internal/context/timer.go similarity index 100% rename from pkg/context/timer.go rename to internal/context/timer.go diff --git a/internal/gtp/message/message.go b/internal/gtp/message/message.go index 2dba4847..eb84a55d 100644 --- a/internal/gtp/message/message.go +++ b/internal/gtp/message/message.go @@ -79,3 +79,20 @@ func (p *QoSTPDUPacket) unmarshalExtensionHeader() error { return nil } + +func BuildQoSGTPPacket(teid uint32, qfi uint8, payload []byte) ([]byte, error) { + header := gtpMsg.NewHeader(0x34, gtpMsg.MsgTypeTPDU, teid, 0x00, payload).WithExtensionHeaders( + gtpMsg.NewExtensionHeader( + gtpMsg.ExtHeaderTypePDUSessionContainer, + []byte{UL_PDU_SESSION_INFORMATION_TYPE, qfi}, + gtpMsg.ExtHeaderTypeNoMoreExtensionHeaders, + ), + ) + + b := make([]byte, header.MarshalLen()) + if err := header.MarshalTo(b); err != nil { + return nil, errors.Wrapf(err, "go-gtp Marshal failed") + } + + return b, nil +} diff --git a/pkg/ike/dispatcher.go b/internal/ike/dispatcher.go similarity index 94% rename from pkg/ike/dispatcher.go rename to internal/ike/dispatcher.go index 50068b42..4c30d52c 100644 --- a/pkg/ike/dispatcher.go +++ b/internal/ike/dispatcher.go @@ -5,8 +5,8 @@ import ( "runtime/debug" ike_message "github.com/free5gc/ike/message" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" ) func (s *Server) Dispatch( diff --git a/pkg/ike/handler.go b/internal/ike/handler.go similarity index 96% rename from pkg/ike/handler.go rename to internal/ike/handler.go index a054f510..28b89431 100644 --- a/pkg/ike/handler.go +++ b/internal/ike/handler.go @@ -25,9 +25,9 @@ import ( "github.com/free5gc/ike/security/encr" "github.com/free5gc/ike/security/integ" "github.com/free5gc/ike/security/prf" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" + "github.com/free5gc/n3iwf/internal/ike/xfrm" "github.com/free5gc/n3iwf/internal/logger" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" - "github.com/free5gc/n3iwf/pkg/ike/xfrm" ) func (s *Server) HandleIKESAINIT( @@ -161,7 +161,7 @@ func (s *Server) HandleIKESAINIT( return } - ikeLog.Debugf(ikeSecurityAssociation.String()) + ikeLog.Debugln(ikeSecurityAssociation.String()) // Record concatenated nonce ikeSecurityAssociation.ConcatenatedNonce = append( @@ -505,7 +505,9 @@ func (s *Server) HandleIKEAUTH( return } - signedAuth, err := rsa.SignPKCS1v15( + var signedAuth []byte + + signedAuth, err = rsa.SignPKCS1v15( rand.Reader, n3iwfCtx.N3IWFPrivateKey, crypto.SHA1, sha1HashFunction.Sum(nil)) if err != nil { @@ -616,12 +618,16 @@ func (s *Server) HandleIKEAUTH( ranNgapId = 0 } - s.NgapEvtCh() <- n3iwf_context.NewUnmarshalEAP5GDataEvt( + err := s.SendNgapEvt(n3iwf_context.NewUnmarshalEAP5GDataEvt( ikeSecurityAssociation.LocalSPI, eapExpanded.VendorData, ikeSecurityAssociation.IkeUE != nil, ranNgapId, - ) + )) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Unmarshal EAP5G Data] failed: %+v", err) + return + } ikeSecurityAssociation.IKEConnection = &n3iwf_context.UDPSocketInfo{ Conn: udpConn, @@ -888,14 +894,20 @@ func (s *Server) HandleIKEAUTH( ikeSecurityAssociation.State++ // After this, N3IWF will forward NAS with Child SA (IPSec SA) - s.NgapEvtCh() <- n3iwf_context.NewStartTCPSignalNASMsgEvt( - ranNgapId, - ) + err = s.SendNgapEvt(n3iwf_context.NewStartTCPSignalNASMsgEvt(ranNgapId)) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Start TCP Signal NAS Msg] failed: %+v", err) + return + } // Get TempPDUSessionSetupData from NGAP to setup PDU session if needed - s.NgapEvtCh() <- n3iwf_context.NewGetNGAPContextEvt( + err = s.SendNgapEvt(n3iwf_context.NewGetNGAPContextEvt( ranNgapId, []int64{n3iwf_context.CxtTempPDUSessionSetupData}, - ) + )) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Get NGAP Context] failed: %+v", err) + return + } } } @@ -979,8 +991,11 @@ func (s *Server) HandleCREATECHILDSA( ngapCxtReqNumlist := []int64{n3iwf_context.CxtTempPDUSessionSetupData} - s.NgapEvtCh() <- n3iwf_context.NewGetNGAPContextEvt(ranNgapId, - ngapCxtReqNumlist) + err := s.SendNgapEvt(n3iwf_context.NewGetNGAPContextEvt(ranNgapId, ngapCxtReqNumlist)) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Get NGAP Context] failed: %+v", err) + return + } } func (s *Server) continueCreateChildSA( @@ -1109,7 +1124,7 @@ func (s *Server) continueCreateChildSA( ikeLog.Errorf("Applying XFRM rules failed: %v", err) return } - ikeLog.Debugf(childSecurityAssociationContext.String(newXfrmiId)) + ikeLog.Debugln(childSecurityAssociationContext.String(newXfrmiId)) ranNgapId, ok := n3iwfCtx.NgapIdLoad(ikeSecurityAssociation.LocalSPI) if !ok { @@ -1118,9 +1133,11 @@ func (s *Server) continueCreateChildSA( return } // Forward PDU Seesion Establishment Accept to UE - s.NgapEvtCh() <- n3iwf_context.NewSendNASMsgEvt( - ranNgapId, - ) + err = s.SendNgapEvt(n3iwf_context.NewSendNASMsgEvt(ranNgapId)) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Send NAS Msg] failed: %+v", err) + return + } temporaryPDUSessionSetupData.FailedErrStr = append(temporaryPDUSessionSetupData.FailedErrStr, n3iwf_context.ErrNil) @@ -1156,8 +1173,9 @@ func (s *Server) HandleInformational( for _, ikePayload := range message.Payloads { switch ikePayload.Type() { case ike_message.TypeD: - deletePayload := ikePayload.(*ike_message.Delete) + var err error + deletePayload := ikePayload.(*ike_message.Delete) ranNgapId, ok := n3iwfCtx.NgapIdLoad(n3iwfIke.N3IWFIKESecurityAssociation.LocalSPI) if !ok { ikeLog.Errorf("Cannot get RanNgapId from SPI : %+v", @@ -1166,17 +1184,21 @@ func (s *Server) HandleInformational( } if deletePayload.ProtocolID == ike_message.TypeIKE { // Check if UE is response to a request that delete the ike SA - err := n3iwfIke.Remove() + err = n3iwfIke.Remove() if err != nil { ikeLog.Errorf("Delete IkeUe Context error : %v", err) } - s.NgapEvtCh() <- n3iwf_context.NewSendUEContextReleaseCompleteEvt( - ranNgapId, - ) + err = s.SendNgapEvt(n3iwf_context.NewSendUEContextReleaseCompleteEvt(ranNgapId)) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Send UE Ctx Release Complete] failed: %+v", err) + return + } } else if deletePayload.ProtocolID == ike_message.TypeESP { - s.NgapEvtCh() <- n3iwf_context.NewSendPDUSessionResourceReleaseResEvt( - ranNgapId, - ) + err = s.SendNgapEvt(n3iwf_context.NewSendPDUSessionResourceReleaseResEvt(ranNgapId)) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Send PDU Sess Resource Release] failed: %+v", err) + return + } } default: ikeLog.Warnf( @@ -1247,12 +1269,16 @@ func (s *Server) HandleUnmarshalEAP5GDataResponse(ikeEvt n3iwf_context.IkeEvt) { n3iwfCtx.IkeSpiNgapIdMapping(ikeUe.N3IWFIKESecurityAssociation.LocalSPI, ranUeNgapId) - s.NgapEvtCh() <- n3iwf_context.NewSendInitialUEMessageEvt( + err := s.SendNgapEvt(n3iwf_context.NewSendInitialUEMessageEvt( ranUeNgapId, ikeSecurityAssociation.IKEConnection.UEAddr.IP.To4().String(), ikeSecurityAssociation.IKEConnection.UEAddr.Port, nasPDU, - ) + )) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Send Init UE Message] failed: %+v", err) + return + } } func (s *Server) HandleSendEAP5GFailureMsg(ikeEvt n3iwf_context.IkeEvt) { @@ -1667,9 +1693,10 @@ func (s *Server) CreatePDUSessionChildSA( break } } else { - s.NgapEvtCh() <- n3iwf_context.NewSendPDUSessionResourceSetupResEvt( - ranNgapId, - ) + err := s.SendNgapEvt(n3iwf_context.NewSendPDUSessionResourceSetupResEvt(ranNgapId)) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Send PDU Sess Resource Setup Res] failed: %+v", err) + } break } } @@ -1718,9 +1745,13 @@ func (s *Server) StartDPD(ikeUe *n3iwf_context.N3IWFIkeUe) { return } - s.NgapEvtCh() <- n3iwf_context.NewSendUEContextReleaseRequestEvt( + err := s.SendNgapEvt(n3iwf_context.NewSendUEContextReleaseRequestEvt( ranNgapId, n3iwf_context.ErrRadioConnWithUeLost, - ) + )) + if err != nil { + ikeLog.Errorf("SendNgapEvt[Send UE Ctx Release Request] failed: %+v", err) + return + } ikeSA.DPDReqRetransTimer = nil timer.Stop() diff --git a/pkg/ike/handler_test.go b/internal/ike/handler_test.go similarity index 99% rename from pkg/ike/handler_test.go rename to internal/ike/handler_test.go index 701064ca..164d8a87 100644 --- a/pkg/ike/handler_test.go +++ b/internal/ike/handler_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/require" ike_message "github.com/free5gc/ike/message" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/pkg/factory" ) diff --git a/pkg/ike/send.go b/internal/ike/send.go similarity index 98% rename from pkg/ike/send.go rename to internal/ike/send.go index 148c1f48..7e72187b 100644 --- a/pkg/ike/send.go +++ b/internal/ike/send.go @@ -11,8 +11,8 @@ import ( "github.com/free5gc/ike/message" ike_message "github.com/free5gc/ike/message" "github.com/free5gc/ike/security" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" ) func SendIKEMessageToUE( diff --git a/pkg/ike/server.go b/internal/ike/server.go similarity index 75% rename from pkg/ike/server.go rename to internal/ike/server.go index 57fc8cbd..86616b0f 100644 --- a/pkg/ike/server.go +++ b/internal/ike/server.go @@ -3,6 +3,7 @@ package ike import ( "bytes" "context" + "fmt" "net" "runtime/debug" "sync" @@ -14,21 +15,25 @@ import ( "github.com/free5gc/ike" ike_message "github.com/free5gc/ike/message" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" ) -var ( +const ( RECEIVE_IKEPACKET_CHANNEL_LEN = 512 RECEIVE_IKEEVENT_CHANNEL_LEN = 512 + + DEFAULT_IKE_PORT = 500 + DEFAULT_NATT_PORT = 4500 ) type n3iwf interface { Config() *factory.Config Context() *n3iwf_context.N3IWFContext CancelContext() context.Context - NgapEvtCh() chan n3iwf_context.NgapEvt + + SendNgapEvt(n3iwf_context.NgapEvt) error } type EspHandler func(srcIP, dstIP *net.UDPAddr, espPkt []byte) error @@ -36,10 +41,10 @@ type EspHandler func(srcIP, dstIP *net.UDPAddr, espPkt []byte) error type Server struct { n3iwf - Listener map[int]*net.UDPConn - RcvIkePktCh chan IkeReceivePacket - RcvEventCh chan n3iwf_context.IkeEvt - StopServer chan struct{} + Listener map[int]*net.UDPConn + RcvIkePktCh chan IkeReceivePacket + StopServer chan struct{} + safeRcvEvtCh *n3iwf_context.SafeEvtCh[n3iwf_context.IkeEvt] } type IkeReceivePacket struct { @@ -54,9 +59,10 @@ func NewServer(n3iwf n3iwf) (*Server, error) { n3iwf: n3iwf, Listener: make(map[int]*net.UDPConn), RcvIkePktCh: make(chan IkeReceivePacket, RECEIVE_IKEPACKET_CHANNEL_LEN), - RcvEventCh: make(chan n3iwf_context.IkeEvt, RECEIVE_IKEEVENT_CHANNEL_LEN), StopServer: make(chan struct{}), } + s.safeRcvEvtCh = new(n3iwf_context.SafeEvtCh[n3iwf_context.IkeEvt]) + s.safeRcvEvtCh.Init(make(chan n3iwf_context.IkeEvt, RECEIVE_IKEEVENT_CHANNEL_LEN)) return s, nil } @@ -65,32 +71,30 @@ func (s *Server) Run(wg *sync.WaitGroup) error { // Resolve UDP addresses ip := cfg.GetIKEBindAddr() - udpAddrPort500, err := net.ResolveUDPAddr("udp", ip+":500") + ikeAddrPort, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", ip, DEFAULT_IKE_PORT)) if err != nil { - return errors.Wrapf(err, "ResolveUDPAddr (%s:500)", ip) + return err } - udpAddrPort4500, err := net.ResolveUDPAddr("udp", ip+":4500") + nattAddrPort, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", ip, DEFAULT_NATT_PORT)) if err != nil { - return errors.Wrapf(err, "ResolveUDPAddr (%s:4500)", ip) + return err } // Listen and serve var errChan chan error - // Port 500 wg.Add(1) errChan = make(chan error) - go s.receiver(udpAddrPort500, errChan, wg) + go s.receiver(ikeAddrPort, errChan, wg) if err, ok := <-errChan; ok { - return errors.Wrapf(err, "udp 500") + return errors.Wrapf(err, "ikeAddrPort") } - // Port 4500 wg.Add(1) errChan = make(chan error) - go s.receiver(udpAddrPort4500, errChan, wg) + go s.receiver(nattAddrPort, errChan, wg) if err, ok := <-errChan; ok { - return errors.Wrapf(err, "udp 4500") + return errors.Wrapf(err, "nattAddrPort") } wg.Add(1) @@ -108,6 +112,7 @@ func (s *Server) server(wg *sync.WaitGroup) { } ikeLog.Infof("Ike server stopped") close(s.RcvIkePktCh) + s.safeRcvEvtCh.Close() close(s.StopServer) wg.Done() }() @@ -115,22 +120,15 @@ func (s *Server) server(wg *sync.WaitGroup) { for { select { case rcvPkt := <-s.RcvIkePktCh: - msg, err := s.checkMessage(rcvPkt, handleESPPacket) - if err != nil { - ikeLog.Warnln(err) - continue - } - if msg == nil { - continue - } - ikeMsg, ikeSA, err := s.checkIKEMessage(msg, &rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr) + ikeMsg, ikeSA, err := s.checkIKEMessage( + rcvPkt.Msg, &rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr) if err != nil { ikeLog.Warnln(err) continue } s.Dispatch(&rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr, ikeMsg, rcvPkt.Msg, ikeSA) - case rcvIkeEvent := <-s.RcvEventCh: + case rcvIkeEvent := <-s.safeRcvEvtCh.RecvEvtCh(): s.HandleEvent(rcvIkeEvent) case <-s.StopServer: return @@ -164,72 +162,91 @@ func (s *Server) receiver( s.Listener[localAddr.Port] = listener - data := make([]byte, 65535) + buf := make([]byte, factory.MAX_BUF_MSG_LEN) for { - n, remoteAddr, err := listener.ReadFromUDP(data) + n, remoteAddr, err := listener.ReadFromUDP(buf) if err != nil { ikeLog.Errorf("ReadFromUDP failed: %+v", err) return } - forwardData := make([]byte, n) - copy(forwardData, data[:n]) + msgBuf := make([]byte, n) + copy(msgBuf, buf) + + // As specified in RFC 7296 section 3.1, the IKE message send from/to UDP port 4500 + // should prepend a 4 bytes zero + if localAddr.Port == DEFAULT_NATT_PORT { + msgBuf, err = handleNattMsg(msgBuf, remoteAddr, localAddr, handleESPPacket) + if err != nil { + ikeLog.Errorf("Handle NATT msg: %v", err) + continue + } + if msgBuf == nil { + continue + } + } + + if len(msgBuf) < ike_message.IKE_HEADER_LEN { + ikeLog.Warnf("Received IKE msg is too short from %s", remoteAddr) + continue + } + s.RcvIkePktCh <- IkeReceivePacket{ RemoteAddr: *remoteAddr, Listener: *listener, LocalAddr: *localAddr, - Msg: forwardData, + Msg: msgBuf, } } } -func (s *Server) Stop() { - ikeLog := logger.IKELog - ikeLog.Infof("Close Ike server...") +func handleNattMsg( + msgBuf []byte, + rAddr, lAddr *net.UDPAddr, + espHandler EspHandler, +) ([]byte, error) { + if len(msgBuf) == 1 && msgBuf[0] == 0xff { + // skip NAT-T Keepalive + return nil, nil + } - for _, ikeServerListener := range s.Listener { - if err := ikeServerListener.Close(); err != nil { - ikeLog.Errorf("Stop ike server : %s error : %+v", err, ikeServerListener.LocalAddr().String()) + nonEspMarker := []byte{0, 0, 0, 0} // Non-ESP Marker + nonEspMarkerLen := len(nonEspMarker) + if len(msgBuf) < nonEspMarkerLen { + return nil, errors.Errorf("Received msg is too short") + } + if !bytes.Equal(msgBuf[:nonEspMarkerLen], nonEspMarker) { + // ESP packet + if espHandler != nil { + err := espHandler(rAddr, lAddr, msgBuf) + if err != nil { + return nil, errors.Wrapf(err, "Handle ESP") + } } + return nil, nil } - s.StopServer <- struct{}{} + // IKE message: skip Non-ESP Marker + msgBuf = msgBuf[nonEspMarkerLen:] + return msgBuf, nil } -func (s *Server) checkMessage( - rcvPkt IkeReceivePacket, - espHandler EspHandler, -) ([]byte, error) { - ikeLog := logger.IKELog - localAddr := &rcvPkt.LocalAddr - remoteAddr := &rcvPkt.RemoteAddr - msg := rcvPkt.Msg - marker := []byte{0, 0, 0, 0} // Non-ESP Marker +func (s *Server) SendIkeEvt(evt n3iwf_context.IkeEvt) error { + return s.safeRcvEvtCh.SendEvt(evt) +} - if len(msg) == 1 && msg[0] == 0xff { - ikeLog.Tracef("Get NAT-T Keepalive from IP: %v", remoteAddr.IP.String()) - return nil, nil - } else if len(msg) < len(marker) { - return nil, errors.Errorf("Received packet is too short from IP: %v", remoteAddr.IP.String()) - } +func (s *Server) Stop() { + ikeLog := logger.IKELog + ikeLog.Infof("Close Ike server...") - // As specified in RFC 7296 section 3.1, the IKE message send from/to UDP port 4500 - // should prepend a 4 bytes zero - if localAddr.Port == 4500 { - if !bytes.Equal(msg[:4], marker) { - if espHandler != nil { - err := espHandler(remoteAddr, localAddr, msg) - if err != nil { - return nil, errors.Wrapf(err, "Handle ESP") - } - } - return nil, nil + for _, ikeServerListener := range s.Listener { + if err := ikeServerListener.Close(); err != nil { + ikeLog.Errorf("Stop ike server : %s error : %+v", err, ikeServerListener.LocalAddr().String()) } - msg = msg[4:] } - return msg, nil + s.StopServer <- struct{}{} } func (s *Server) checkIKEMessage( diff --git a/pkg/ike/server_test.go b/internal/ike/server_test.go similarity index 74% rename from pkg/ike/server_test.go rename to internal/ike/server_test.go index c8f8b4bd..19b79b60 100644 --- a/pkg/ike/server_test.go +++ b/internal/ike/server_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/require" ike_message "github.com/free5gc/ike/message" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/ngap" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" ) @@ -38,8 +38,8 @@ func (a *n3iwfTestApp) CancelContext() context.Context { return a.ctx } -func (a *n3iwfTestApp) NgapEvtCh() chan n3iwf_context.NgapEvt { - return a.ngapServer.RcvEventCh +func (a *n3iwfTestApp) SendNgapEvt(evt n3iwf_context.NgapEvt) error { + return a.ngapServer.SendNgapEvt(evt) } func NewN3iwfTestApp(cfg *factory.Config) (*n3iwfTestApp, error) { @@ -66,26 +66,7 @@ func NewTestCfg() *factory.Config { } } -func TestCheckMessage(t *testing.T) { - n3iwf, err := NewN3iwfTestApp(NewTestCfg()) - require.NoError(t, err) - - n3iwf.ikeServer, err = NewServer(n3iwf) - require.NoError(t, err) - ikeServer := n3iwf.ikeServer - - srcIP := &net.UDPAddr{ - IP: net.ParseIP("10.100.100.1"), - Port: 500, - } - dstIP := &net.UDPAddr{ - IP: net.ParseIP("10.100.100.2"), - Port: 500, - } - - mockConn, err := net.DialUDP("udp", nil, dstIP) - require.NoError(t, err) - +func TestHandleNattMsg(t *testing.T) { initiatorSPI := uint64(0x123) ikeMessage := new(ike_message.IKEMessage) ikeMessage.BuildIKEHeader(initiatorSPI, 0, @@ -97,61 +78,62 @@ func TestCheckMessage(t *testing.T) { NonESPPkt := append([]byte{0, 0, 0, 0}, pkt...) tests := []struct { - name string - conn *net.UDPConn - rcvPkt IkeReceivePacket - msg *ike_message.IKEMessage - expectedErr bool + name string + conn *net.UDPConn + rcvPkt []byte + lAddr, rAddr *net.UDPAddr + msg *ike_message.IKEMessage + expectedErr bool }{ { - name: "Received NAT-T Keepalive", - rcvPkt: IkeReceivePacket{ - Listener: *mockConn, - LocalAddr: *dstIP, - RemoteAddr: *srcIP, - Msg: []byte{ - 0xff, - }, + name: "Received NAT-T Keepalive", + rcvPkt: []byte{0xff}, + lAddr: &net.UDPAddr{ + IP: net.ParseIP("10.100.100.2"), + Port: 4500, + }, + rAddr: &net.UDPAddr{ + IP: net.ParseIP("10.100.100.1"), + Port: 4500, }, expectedErr: false, }, { - name: "Received packet is too short", - rcvPkt: IkeReceivePacket{ - Listener: *mockConn, - LocalAddr: *dstIP, - RemoteAddr: *srcIP, - Msg: []byte{ - 1, 2, - }, + name: "Received NAT-T Msg is too short", + rcvPkt: []byte{0x01, 0x02}, + lAddr: &net.UDPAddr{ + IP: net.ParseIP("10.100.100.2"), + Port: 4500, + }, + rAddr: &net.UDPAddr{ + IP: net.ParseIP("10.100.100.1"), + Port: 4500, }, expectedErr: true, }, { - name: "Received IKE packet from port 4500, and no need to drop", - rcvPkt: IkeReceivePacket{ - Listener: *mockConn, - LocalAddr: net.UDPAddr{ - IP: net.ParseIP("10.100.100.2"), - Port: 4500, - }, - RemoteAddr: *srcIP, - Msg: NonESPPkt, + name: "Received IKE packet from port 4500, and no need to drop", + rcvPkt: NonESPPkt, + lAddr: &net.UDPAddr{ + IP: net.ParseIP("10.100.100.2"), + Port: 4500, + }, + rAddr: &net.UDPAddr{ + IP: net.ParseIP("10.100.100.1"), + Port: 4500, }, expectedErr: false, }, { - name: "Received ESP packet from port 4500", - rcvPkt: IkeReceivePacket{ - Listener: *mockConn, - LocalAddr: net.UDPAddr{ - IP: net.ParseIP("10.100.100.2"), - Port: 4500, - }, - RemoteAddr: *srcIP, - Msg: []byte{ - 1, 2, 3, 4, 5, - }, + name: "Received ESP packet from port 4500", + rcvPkt: []byte{0x1, 0x2, 0x3, 0x4, 0x5}, + lAddr: &net.UDPAddr{ + IP: net.ParseIP("10.100.100.2"), + Port: 4500, + }, + rAddr: &net.UDPAddr{ + IP: net.ParseIP("10.100.100.1"), + Port: 4500, }, expectedErr: false, }, @@ -159,7 +141,7 @@ func TestCheckMessage(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - _, err := ikeServer.checkMessage(tt.rcvPkt, nil) + _, err := handleNattMsg(tt.rcvPkt, tt.rAddr, tt.lAddr, nil) if tt.expectedErr { require.Error(t, err) } else { diff --git a/pkg/ike/xfrm/xfrm.go b/internal/ike/xfrm/xfrm.go similarity index 99% rename from pkg/ike/xfrm/xfrm.go rename to internal/ike/xfrm/xfrm.go index abf2231a..7657aa0f 100644 --- a/pkg/ike/xfrm/xfrm.go +++ b/internal/ike/xfrm/xfrm.go @@ -8,8 +8,8 @@ import ( "github.com/vishvananda/netlink" "github.com/free5gc/ike/message" + "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" - "github.com/free5gc/n3iwf/pkg/context" ) type XFRMEncryptionAlgorithmType uint16 diff --git a/internal/logger/logger.go b/internal/logger/logger.go index cca85e34..bb946ea3 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -8,12 +8,13 @@ import ( var ( Log *logrus.Logger - NfLog *logrus.Entry + N3iwfLog *logrus.Entry MainLog *logrus.Entry InitLog *logrus.Entry CfgLog *logrus.Entry CtxLog *logrus.Entry GinLog *logrus.Entry + NasLog *logrus.Entry NgapLog *logrus.Entry IKELog *logrus.Entry GTPLog *logrus.Entry @@ -21,23 +22,24 @@ var ( NWuUPLog *logrus.Entry RelayLog *logrus.Entry UtilLog *logrus.Entry + GmmLog *logrus.Entry ) -func UpdateNfLog(s string) { - NfLog = Log.WithField(logger_util.FieldNF, s) - // update logs created from NfLog - MainLog = NfLog.WithField(logger_util.FieldCategory, "Main") - InitLog = NfLog.WithField(logger_util.FieldCategory, "Init") - CfgLog = NfLog.WithField(logger_util.FieldCategory, "CFG") - CtxLog = NfLog.WithField(logger_util.FieldCategory, "CTX") - GinLog = NfLog.WithField(logger_util.FieldCategory, "GIN") - NgapLog = NfLog.WithField(logger_util.FieldCategory, "NGAP") - IKELog = NfLog.WithField(logger_util.FieldCategory, "IKE") - GTPLog = NfLog.WithField(logger_util.FieldCategory, "GTP") - NWuCPLog = NfLog.WithField(logger_util.FieldCategory, "NWuCP") - NWuUPLog = NfLog.WithField(logger_util.FieldCategory, "NWuUP") - RelayLog = NfLog.WithField(logger_util.FieldCategory, "Relay") - UtilLog = NfLog.WithField(logger_util.FieldCategory, "Util") +func UpdateN3iwfLog() { + N3iwfLog = Log.WithField(logger_util.FieldNF, "N3IWF") + // update logs created from N3iwfLog + MainLog = N3iwfLog.WithField(logger_util.FieldCategory, "Main") + InitLog = N3iwfLog.WithField(logger_util.FieldCategory, "Init") + CfgLog = N3iwfLog.WithField(logger_util.FieldCategory, "CFG") + CtxLog = N3iwfLog.WithField(logger_util.FieldCategory, "CTX") + GinLog = N3iwfLog.WithField(logger_util.FieldCategory, "GIN") + NgapLog = N3iwfLog.WithField(logger_util.FieldCategory, "NGAP") + IKELog = N3iwfLog.WithField(logger_util.FieldCategory, "IKE") + GTPLog = N3iwfLog.WithField(logger_util.FieldCategory, "GTP") + NWuCPLog = N3iwfLog.WithField(logger_util.FieldCategory, "NWuCP") + NWuUPLog = N3iwfLog.WithField(logger_util.FieldCategory, "NWuUP") + RelayLog = N3iwfLog.WithField(logger_util.FieldCategory, "Relay") + UtilLog = N3iwfLog.WithField(logger_util.FieldCategory, "Util") } func init() { @@ -46,5 +48,5 @@ func init() { logger_util.FieldCategory, } Log = logger_util.New(fieldsOrder) - UpdateNfLog("N3IWF") + UpdateN3iwfLog() } diff --git a/internal/nas/nas_security/security.go b/internal/nas/nas_security/security.go new file mode 100644 index 00000000..6670babe --- /dev/null +++ b/internal/nas/nas_security/security.go @@ -0,0 +1,18 @@ +package nas_security + +import ( + "encoding/binary" +) + +// API for N3IWF +func EncapNasMsgToEnvelope(nasPDU []byte) []byte { + // According to TS 24.502 8.2.4, + // in order to transport a NAS message over the non-3GPP access between the UE and the N3IWF, + // the NAS message shall be framed in a NAS message envelope as defined in subclause 9.4. + // According to TS 24.502 9.4, + // a NAS message envelope = Length | NAS Message + nasEnv := make([]byte, 2) + binary.BigEndian.PutUint16(nasEnv, uint16(len(nasPDU))) + nasEnv = append(nasEnv, nasPDU...) + return nasEnv +} diff --git a/internal/ngap/handler.go b/internal/ngap/handler.go index 113173d0..1b967d38 100644 --- a/internal/ngap/handler.go +++ b/internal/ngap/handler.go @@ -10,9 +10,10 @@ import ( "github.com/wmnsk/go-gtp/gtpv1" "github.com/free5gc/aper" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" + "github.com/free5gc/n3iwf/internal/nas/nas_security" "github.com/free5gc/n3iwf/internal/ngap/message" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/ngap/ngapConvert" "github.com/free5gc/ngap/ngapType" "github.com/free5gc/sctp" @@ -24,7 +25,7 @@ func (s *Server) HandleNGSetupResponse( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle NG Setup Response") + ngapLog.Infoln("Handle NG Setup Response") var amfName *ngapType.AMFName var servedGUAMIList *ngapType.ServedGUAMIList @@ -137,7 +138,7 @@ func (s *Server) HandleNGSetupFailure( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle NG Setup Failure") + ngapLog.Infoln("Handle NG Setup Failure") var cause *ngapType.Cause var timeToWait *ngapType.TimeToWait @@ -244,7 +245,7 @@ func (s *Server) HandleNGReset( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle NG Reset") + ngapLog.Infoln("Handle NG Reset") var cause *ngapType.Cause var resetType *ngapType.ResetType @@ -321,7 +322,7 @@ func (s *Server) HandleNGReset( return } - var ranUe *n3iwf_context.N3IWFRanUe + var ranUe n3iwf_context.RanUe for _, ueAssociatedLogicalNGConnectionItem := range partOfNGInterface.List { if ueAssociatedLogicalNGConnectionItem.RANUENGAPID != nil { @@ -358,7 +359,7 @@ func (s *Server) HandleNGResetAcknowledge( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle NG Reset Acknowledge") + ngapLog.Infoln("Handle NG Reset Acknowledge") var uEAssociatedLogicalNGConnectionList *ngapType.UEAssociatedLogicalNGConnectionList var criticalityDiagnostics *ngapType.CriticalityDiagnostics @@ -420,7 +421,7 @@ func (s *Server) HandleInitialContextSetupRequest( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle Initial Context Setup Request") + ngapLog.Infoln("Handle Initial Context Setup Request") var amfUeNgapID *ngapType.AMFUENGAPID var ranUeNgapID *ngapType.RANUENGAPID @@ -440,7 +441,9 @@ func (s *Server) HandleInitialContextSetupRequest( var emergencyFallbackIndicator *ngapType.EmergencyFallbackIndicator var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList - var ranUe *n3iwf_context.N3IWFRanUe + var ranUe n3iwf_context.RanUe + var ranUeCtx *n3iwf_context.RanUeSharedCtx + n3iwfCtx := s.Context() if pdu == nil { @@ -590,7 +593,8 @@ func (s *Server) HandleInitialContextSetupRequest( // Cause: Unknown local UE NGAP ID return } - if ranUe.AmfUeNgapId != amfUeNgapID.Value { + ranUeCtx = ranUe.GetSharedCtx() + if ranUeCtx.AmfUeNgapId != amfUeNgapID.Value { // TODO: build cause and handle error // Cause: Inconsistent remote UE NGAP ID return @@ -602,12 +606,12 @@ func (s *Server) HandleInitialContextSetupRequest( return } - ranUe.AmfUeNgapId = amfUeNgapID.Value - ranUe.RanUeNgapId = ranUeNgapID.Value + ranUeCtx.AmfUeNgapId = amfUeNgapID.Value + ranUeCtx.RanUeNgapId = ranUeNgapID.Value if pduSessionResourceSetupListCxtReq != nil { if ueAggregateMaximumBitRate != nil { - ranUe.Ambr = ueAggregateMaximumBitRate + ranUeCtx.Ambr = ueAggregateMaximumBitRate } else { ngapLog.Errorln("IE[UEAggregateMaximumBitRate] is nil") cause := message.BuildCause(ngapType.CausePresentProtocol, @@ -636,11 +640,11 @@ func (s *Server) HandleInitialContextSetupRequest( failedListCxtRes := new(ngapType.PDUSessionResourceFailedToSetupListCxtRes) // UE temporary data for PDU session setup response - ranUe.TemporaryPDUSessionSetupData.SetupListCxtRes = setupListCxtRes - ranUe.TemporaryPDUSessionSetupData.FailedListCxtRes = failedListCxtRes - ranUe.TemporaryPDUSessionSetupData.Index = 0 - ranUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession = nil - ranUe.TemporaryPDUSessionSetupData.NGAPProcedureCode.Value = ngapType.ProcedureCodeInitialContextSetup + ranUeCtx.TemporaryPDUSessionSetupData.SetupListCxtRes = setupListCxtRes + ranUeCtx.TemporaryPDUSessionSetupData.FailedListCxtRes = failedListCxtRes + ranUeCtx.TemporaryPDUSessionSetupData.Index = 0 + ranUeCtx.TemporaryPDUSessionSetupData.UnactivatedPDUSession = nil + ranUeCtx.TemporaryPDUSessionSetupData.NGAPProcedureCode.Value = ngapType.ProcedureCodeInitialContextSetup for _, item := range pduSessionResourceSetupListCxtReq.List { pduSessionID := item.PDUSessionID.Value @@ -655,7 +659,7 @@ func (s *Server) HandleInitialContextSetupRequest( pduSessionID, err) } - pduSession, err := ranUe.CreatePDUSession(pduSessionID, snssai) + pduSession, err := ranUeCtx.CreatePDUSession(pduSessionID, snssai) if err != nil { ngapLog.Errorf("Create PDU Session Error: %v\n", err) @@ -671,16 +675,15 @@ func (s *Server) HandleInitialContextSetupRequest( continue } - success, resTransfer := s.handlePDUSessionResourceSetupRequestTransfer( - ranUe, pduSession, transfer) + success, resTransfer := s.handlePDUSessionResourceSetupRequestTransfer(ranUe, pduSession, transfer) if success { // Append this PDU session to unactivated PDU session list - ranUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession = append( - ranUe.TemporaryPDUSessionSetupData.UnactivatedPDUSession, + ranUeCtx.TemporaryPDUSessionSetupData.UnactivatedPDUSession = append( + ranUeCtx.TemporaryPDUSessionSetupData.UnactivatedPDUSession, pduSession) } else { // Delete the pdusession store in UE conext - delete(ranUe.PduSessionList, pduSessionID) + delete(ranUeCtx.PduSessionList, pduSessionID) message. AppendPDUSessionResourceFailedToSetupListCxtRes(failedListCxtRes, pduSessionID, resTransfer) } @@ -692,46 +695,51 @@ func (s *Server) HandleInitialContextSetupRequest( } if guami != nil { - ranUe.Guami = guami + ranUeCtx.Guami = guami } if allowedNSSAI != nil { - ranUe.AllowedNssai = allowedNSSAI + ranUeCtx.AllowedNssai = allowedNSSAI } if maskedIMEISV != nil { - ranUe.MaskedIMEISV = maskedIMEISV + ranUeCtx.MaskedIMEISV = maskedIMEISV } if ueRadioCapability != nil { - ranUe.RadioCapability = ueRadioCapability + ranUeCtx.RadioCapability = ueRadioCapability } if coreNetworkAssistanceInformation != nil { - ranUe.CoreNetworkAssistanceInformation = coreNetworkAssistanceInformation + ranUeCtx.CoreNetworkAssistanceInformation = coreNetworkAssistanceInformation } if indexToRFSP != nil { - ranUe.IndexToRfsp = indexToRFSP.Value + ranUeCtx.IndexToRfsp = indexToRFSP.Value } if ueSecurityCapabilities != nil { - ranUe.SecurityCapabilities = ueSecurityCapabilities - } - - spi, ok := n3iwfCtx.IkeSpiLoad(ranUe.RanUeNgapId) - if !ok { - ngapLog.Errorf("Cannot get spi from ngapid : %+v", ranUe.RanUeNgapId) - return + ranUeCtx.SecurityCapabilities = ueSecurityCapabilities } - // if nasPDU != nil { - // TODO: Send NAS UE - // } - // Send EAP Success to UE - s.IkeEvtCh() <- n3iwf_context.NewSendEAPSuccessMsgEvt(spi, securityKey.Value.Bytes, - len(ranUe.PduSessionList)) + switch ue := ranUe.(type) { + case *n3iwf_context.N3IWFRanUe: + spi, ok := n3iwfCtx.IkeSpiLoad(ranUeCtx.RanUeNgapId) + if !ok { + ngapLog.Errorf("Cannot get spi from ngapid : %+v", ranUeCtx.RanUeNgapId) + return + } + + err := s.SendIkeEvt(n3iwf_context.NewSendEAPSuccessMsgEvt( + spi, securityKey.Value.Bytes, len(ranUeCtx.PduSessionList), + )) + if err != nil { + ngapLog.Errorf("SendIkeEvt[Send EAP Success Msg] failed: %+v", err) + } + default: + ngapLog.Errorf("Unknown UE type: %T", ue) + } } // handlePDUSessionResourceSetupRequestTransfer parse and store needed information from NGAP @@ -743,7 +751,7 @@ func (s *Server) HandleInitialContextSetupRequest( // a status value indicate whether the handlling is "success" :: // if failed, an unsuccessfulTransfer is set, otherwise, set to nil func (s *Server) handlePDUSessionResourceSetupRequestTransfer( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, pduSession *n3iwf_context.PDUSession, transfer ngapType.PDUSessionResourceSetupRequestTransfer, ) (bool, []byte) { @@ -869,7 +877,7 @@ func (s *Server) handlePDUSessionResourceSetupRequestTransfer( // TODO: Support IPv6 upfIPv4, _ := ngapConvert.IPAddressToString(ulNGUUPTNLInformation.GTPTunnel.TransportLayerAddress) if upfIPv4 != "" { - gtpConnection := &n3iwf_context.GTPConnectionInfo{ + gtpConnInfo := &n3iwf_context.GTPConnectionInfo{ UPFIPAddr: upfIPv4, OutgoingTEID: binary.BigEndian.Uint32(ulNGUUPTNLInformation.GTPTunnel.GTPTEID.Value), } @@ -903,10 +911,10 @@ func (s *Server) handlePDUSessionResourceSetupRequestTransfer( } // Setup GTP connection with UPF - gtpConnection.UPFUDPAddr = upfUDPAddr - gtpConnection.IncomingTEID = ueTEID + gtpConnInfo.UPFUDPAddr = upfUDPAddr + gtpConnInfo.IncomingTEID = ueTEID - pduSession.GTPConnection = gtpConnection + pduSession.GTPConnInfo = gtpConnInfo } else { ngapLog.Error( "Cannot parse \"PDU session resource setup request transfer\" message \"UL NG-U UP TNL Information\"") @@ -927,7 +935,7 @@ func (s *Server) HandleUEContextModificationRequest( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle UE Context Modification Request") + ngapLog.Infoln("Handle UE Context Modification Request") if amf == nil { ngapLog.Error("Corresponding AMF context not found") @@ -943,7 +951,9 @@ func (s *Server) HandleUEContextModificationRequest( var indexToRFSP *ngapType.IndexToRFSP var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList - var ranUe *n3iwf_context.N3IWFRanUe + var ranUe n3iwf_context.RanUe + var ranUeCtx *n3iwf_context.RanUeSharedCtx + n3iwfCtx := s.Context() if pdu == nil { @@ -1022,7 +1032,8 @@ func (s *Server) HandleUEContextModificationRequest( // Cause: Unknown local UE NGAP ID return } - if ranUe.AmfUeNgapId != amfUeNgapID.Value { + ranUeCtx = ranUe.GetSharedCtx() + if ranUeCtx.AmfUeNgapId != amfUeNgapID.Value { // TODO: build cause and handle error // Cause: Inconsistent remote UE NGAP ID return @@ -1031,34 +1042,36 @@ func (s *Server) HandleUEContextModificationRequest( if newAmfUeNgapID != nil { ngapLog.Debugf("New AmfUeNgapID[%d]\n", newAmfUeNgapID.Value) - ranUe.AmfUeNgapId = newAmfUeNgapID.Value + ranUeCtx.AmfUeNgapId = newAmfUeNgapID.Value } if ueAggregateMaximumBitRate != nil { - ranUe.Ambr = ueAggregateMaximumBitRate + ranUeCtx.Ambr = ueAggregateMaximumBitRate // TODO: use the received UE Aggregate Maximum Bit Rate for all non-GBR QoS flows } if ueSecurityCapabilities != nil { - ranUe.SecurityCapabilities = ueSecurityCapabilities + ranUeCtx.SecurityCapabilities = ueSecurityCapabilities } // TODO: use new security key to update security context if indexToRFSP != nil { - ranUe.IndexToRfsp = indexToRFSP.Value + ranUeCtx.IndexToRfsp = indexToRFSP.Value } message.SendUEContextModificationResponse(ranUe, nil) - spi, ok := n3iwfCtx.IkeSpiLoad(ranUe.RanUeNgapId) + spi, ok := n3iwfCtx.IkeSpiLoad(ranUeCtx.RanUeNgapId) if !ok { - ngapLog.Errorf("Cannot get spi from ngapid : %+v", ranUe.RanUeNgapId) + ngapLog.Errorf("Cannot get spi from ngapid : %+v", ranUeCtx.RanUeNgapId) return } - s.IkeEvtCh() <- n3iwf_context.NewIKEContextUpdateEvt(spi, - securityKey.Value.Bytes) // Kn3iwf + err := s.SendIkeEvt(n3iwf_context.NewIKEContextUpdateEvt(spi, securityKey.Value.Bytes)) // Kn3iwf + if err != nil { + ngapLog.Errorf("SendIkeEvt[IKE Ctx Update] failed: %+v", err) + } } func (s *Server) HandleUEContextReleaseCommand( @@ -1066,7 +1079,7 @@ func (s *Server) HandleUEContextReleaseCommand( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle UE Context Release Command") + ngapLog.Infoln("Handle UE Context Release Command") if amf == nil { ngapLog.Error("Corresponding AMF context not found") @@ -1076,8 +1089,8 @@ func (s *Server) HandleUEContextReleaseCommand( var ueNgapIDs *ngapType.UENGAPIDs var cause *ngapType.Cause var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList + var ranUe n3iwf_context.RanUe - var ranUe *n3iwf_context.N3IWFRanUe n3iwfCtx := s.Context() if pdu == nil { @@ -1143,51 +1156,45 @@ func (s *Server) HandleUEContextReleaseCommand( printAndGetCause(cause) } - message.SendUEContextReleaseComplete(ranUe, nil) + ranUeCtx := ranUe.GetSharedCtx() + + localSPI, ok := n3iwfCtx.IkeSpiLoad(ranUeCtx.RanUeNgapId) + if !ok { + ngapLog.Errorf("Cannot get SPI from RanUeNgapID : %+v", ranUeCtx.RanUeNgapId) + return + } - err := s.releaseIkeUeAndRanUe(ranUe) + err := s.SendIkeEvt(n3iwf_context.NewIKEDeleteRequestEvt(localSPI)) if err != nil { - ngapLog.Warnf("HandleUEContextReleaseCommand(): %v", err) + ngapLog.Errorf("SendIkeEvt[IKE Delete Req] failed: %+v", err) } + // TODO: release pdu session and gtp info for ue } -func (s *Server) releaseIkeUeAndRanUe(ranUe *n3iwf_context.N3IWFRanUe) error { +func (s *Server) releaseIkeUeAndRanUe(ranUe n3iwf_context.RanUe) error { n3iwfCtx := s.Context() - localSPI, ok := n3iwfCtx.IkeSpiLoad(ranUe.RanUeNgapId) + ranUeNgapID := ranUe.GetSharedCtx().RanUeNgapId + + localSPI, ok := n3iwfCtx.IkeSpiLoad(ranUeNgapID) if ok { - s.IkeEvtCh() <- n3iwf_context.NewIKEDeleteRequestEvt(localSPI) + err := s.SendIkeEvt(n3iwf_context.NewIKEDeleteRequestEvt(localSPI)) + if err != nil { + return errors.Wrapf(err, "SendIkeEvt[IKE Delete Req] failed") + } } if err := ranUe.Remove(); err != nil { - return errors.Wrapf(err, "releaseIkeUeAndRanUe RanUeNgapId[%016x]", ranUe.RanUeNgapId) + return errors.Wrapf(err, "releaseIkeUeAndRanUe RanUeNgapId[%016x]", ranUeNgapID) } return nil } -func encapNasMsgToEnvelope(nasPDU *ngapType.NASPDU) []byte { - ngapLog := logger.NgapLog - // According to TS 24.502 8.2.4, - // in order to transport a NAS message over the non-3GPP access between the UE and the N3IWF, - // the NAS message shall be framed in a NAS message envelope as defined in subclause 9.4. - // According to TS 24.502 9.4, - // a NAS message envelope = Length | NAS Message - nasEnv := make([]byte, 2) - valueLen := len(nasPDU.Value) - if valueLen > math.MaxUint16 { - ngapLog.Errorf("encapNasMsgToEnvelope nasPDU Value length has out of uint16 range: %d", valueLen) - return nil - } - binary.BigEndian.PutUint16(nasEnv, uint16(valueLen)) - nasEnv = append(nasEnv, nasPDU.Value...) - return nasEnv -} - func (s *Server) HandleDownlinkNASTransport( amf *n3iwf_context.N3IWFAMF, pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle Downlink NAS Transport") + ngapLog.Infoln("Handle Downlink NAS Transport") if amf == nil { ngapLog.Error("Corresponding AMF context not found") @@ -1202,8 +1209,8 @@ func (s *Server) HandleDownlinkNASTransport( var ueAggregateMaximumBitRate *ngapType.UEAggregateMaximumBitRate var allowedNSSAI *ngapType.AllowedNSSAI var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList + var ranUe n3iwf_context.RanUe - var ranUe *n3iwf_context.N3IWFRanUe n3iwfCtx := s.Context() if pdu == nil { @@ -1279,13 +1286,14 @@ func (s *Server) HandleDownlinkNASTransport( return } } + ranUeCtx := ranUe.GetSharedCtx() if amfUeNgapID != nil { - if ranUe.AmfUeNgapId == n3iwf_context.AmfUeNgapIdUnspecified { + if ranUeCtx.AmfUeNgapId == n3iwf_context.AmfUeNgapIdUnspecified { ngapLog.Tracef("Create new logical UE-associated NG-connection") - ranUe.AmfUeNgapId = amfUeNgapID.Value + ranUeCtx.AmfUeNgapId = amfUeNgapID.Value } else { - if ranUe.AmfUeNgapId != amfUeNgapID.Value { + if ranUeCtx.AmfUeNgapId != amfUeNgapID.Value { ngapLog.Warn("AMFUENGAPID unmatched") return } @@ -1297,46 +1305,51 @@ func (s *Server) HandleDownlinkNASTransport( } if indexToRFSP != nil { - ranUe.IndexToRfsp = indexToRFSP.Value + ranUeCtx.IndexToRfsp = indexToRFSP.Value } if ueAggregateMaximumBitRate != nil { - ranUe.Ambr = ueAggregateMaximumBitRate + ranUeCtx.Ambr = ueAggregateMaximumBitRate } if allowedNSSAI != nil { - ranUe.AllowedNssai = allowedNSSAI + ranUeCtx.AllowedNssai = allowedNSSAI } if nasPDU != nil { - // TODO: Send NAS PDU to UE - - // Send EAP5G NAS to UE - spi, ok := n3iwfCtx.IkeSpiLoad(ranUe.RanUeNgapId) - if !ok { - ngapLog.Errorf("Cannot get SPI from RanUeNGAPId : %+v", ranUe.RanUeNgapId) - return - } + switch ue := ranUe.(type) { + case *n3iwf_context.N3IWFRanUe: + // Send EAP5G NAS to UE + spi, ok := n3iwfCtx.IkeSpiLoad(ue.RanUeNgapId) + if !ok { + ngapLog.Errorf("Cannot get SPI from RanUeNGAPId : %+v", ue.RanUeNgapId) + return + } - if !ranUe.IsNASTCPConnEstablished { - s.IkeEvtCh() <- n3iwf_context.NewSendEAPNASMsgEvt(spi, - []byte(nasPDU.Value)) - } else { - // Using a "NAS message envelope" to transport a NAS message - // over the non-3GPP access between the UE and the N3IWF - nasEnv := encapNasMsgToEnvelope(nasPDU) - - if ranUe.IsNASTCPConnEstablishedComplete { - // Send to UE - if n, err := ranUe.TCPConnection.Write(nasEnv); err != nil { - ngapLog.Errorf("Writing via IPSec signalling SA failed: %v", err) - } else { - ngapLog.Trace("Forward NWu <- N2") - ngapLog.Tracef("Wrote %d bytes", n) + if !ue.IsNASTCPConnEstablished { + err := s.SendIkeEvt(n3iwf_context.NewSendEAPNASMsgEvt(spi, []byte(nasPDU.Value))) + if err != nil { + ngapLog.Errorf("SendIkeEvt[Send EAP NAS Msg] failed: %+v", err) } } else { - ranUe.TemporaryCachedNASMessage = nasEnv + // Using a "NAS message envelope" to transport a NAS message + // over the non-3GPP access between the UE and the N3IWF + nasEnv := nas_security.EncapNasMsgToEnvelope([]byte(nasPDU.Value)) + + if ue.IsNASTCPConnEstablishedComplete { + // Send to UE + if n, err := ue.TCPConnection.Write(nasEnv); err != nil { + ngapLog.Errorf("Writing via IPSec signalling SA failed: %v", err) + } else { + ngapLog.Trace("Forward NWu <- N2") + ngapLog.Tracef("Wrote %d bytes", n) + } + } else { + ue.TemporaryCachedNASMessage = nasEnv + } } + default: + ngapLog.Errorf("Unknown UE type: %T", ue) } } } @@ -1346,7 +1359,7 @@ func (s *Server) HandlePDUSessionResourceSetupRequest( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle PDU Session Resource Setup Request") + ngapLog.Infoln("Handle PDU Session Resource Setup Request") if amf == nil { ngapLog.Error("Corresponding AMF context not found") @@ -1359,8 +1372,9 @@ func (s *Server) HandlePDUSessionResourceSetupRequest( var pduSessionResourceSetupListSUReq *ngapType.PDUSessionResourceSetupListSUReq var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList var pduSessionEstablishmentAccept *ngapType.NASPDU + var ranUe n3iwf_context.RanUe + var ranUeCtx *n3iwf_context.RanUeSharedCtx - var ranUe *n3iwf_context.N3IWFRanUe n3iwfCtx := s.Context() if pdu == nil { @@ -1431,7 +1445,8 @@ func (s *Server) HandlePDUSessionResourceSetupRequest( // Cause: Unknown local UE NGAP ID return } - if ranUe.AmfUeNgapId != amfUeNgapID.Value { + ranUeCtx = ranUe.GetSharedCtx() + if ranUeCtx.AmfUeNgapId != amfUeNgapID.Value { // TODO: build cause and handle error // Cause: Inconsistent remote UE NGAP ID return @@ -1439,17 +1454,21 @@ func (s *Server) HandlePDUSessionResourceSetupRequest( } if nasPDU != nil { - // TODO: Send NAS to UE - if ranUe.TCPConnection == nil { + n3iwfUe, ok := ranUe.(*n3iwf_context.N3IWFRanUe) + if !ok { + ngapLog.Errorln("HandlePDUSessionResourceSetupRequest(): [Type Assertion] RanUe -> N3iwfRanUe failed") + return + } + if n3iwfUe.TCPConnection == nil { ngapLog.Error("No IPSec NAS signalling SA for this UE") return } // Using a "NAS message envelope" to transport a NAS message // over the non-3GPP access between the UE and the N3IWF - nasEnv := encapNasMsgToEnvelope(nasPDU) + nasEnv := nas_security.EncapNasMsgToEnvelope([]byte(nasPDU.Value)) - n, err := ranUe.TCPConnection.Write(nasEnv) + n, err := n3iwfUe.TCPConnection.Write(nasEnv) if err != nil { ngapLog.Errorf("Send NAS to UE failed: %v", err) return @@ -1457,7 +1476,7 @@ func (s *Server) HandlePDUSessionResourceSetupRequest( ngapLog.Tracef("Wrote %d bytes", n) } - tempPDUSessionSetupData := ranUe.TemporaryPDUSessionSetupData + tempPDUSessionSetupData := ranUeCtx.TemporaryPDUSessionSetupData tempPDUSessionSetupData.NGAPProcedureCode.Value = ngapType.ProcedureCodeInitialContextSetup if pduSessionResourceSetupListSUReq != nil { @@ -1482,7 +1501,7 @@ func (s *Server) HandlePDUSessionResourceSetupRequest( pduSessionID, err) } - pduSession, err := ranUe.CreatePDUSession(pduSessionID, snssai) + pduSession, err := ranUeCtx.CreatePDUSession(pduSessionID, snssai) if err != nil { ngapLog.Errorf("Create PDU Session Error: %v\n", err) @@ -1498,6 +1517,7 @@ func (s *Server) HandlePDUSessionResourceSetupRequest( continue } + // Process the message for AN success, resTransfer := s.handlePDUSessionResourceSetupRequestTransfer( ranUe, pduSession, transfer) if success { @@ -1507,29 +1527,39 @@ func (s *Server) HandlePDUSessionResourceSetupRequest( pduSession) } else { // Delete the pdusession store in UE conext - delete(ranUe.PduSessionList, pduSessionID) + delete(ranUeCtx.PduSessionList, pduSessionID) message.AppendPDUSessionResourceFailedToSetupListSURes( failedListSURes, pduSessionID, resTransfer) } } } - if tempPDUSessionSetupData != nil { - spi, ok := n3iwfCtx.IkeSpiLoad(ranUe.RanUeNgapId) - if !ok { - ngapLog.Errorf("Cannot get SPI from ranNgapID : %+v", ranUeNgapID) - return - } - s.IkeEvtCh() <- n3iwf_context.NewCreatePDUSessionEvt(spi, - len(ranUe.PduSessionList), ranUe.TemporaryPDUSessionSetupData) + if tempPDUSessionSetupData != nil && len(tempPDUSessionSetupData.UnactivatedPDUSession) != 0 { + switch ue := ranUe.(type) { + case *n3iwf_context.N3IWFRanUe: + spi, ok := n3iwfCtx.IkeSpiLoad(ue.RanUeNgapId) + if !ok { + ngapLog.Errorf("Cannot get SPI from ranNgapID : %+v", ranUeNgapID) + return + } - // TS 23.501 4.12.5 Requested PDU Session Establishment via Untrusted non-3GPP Access - // After all IPsec Child SAs are established, the N3IWF shall forward to UE via the signalling IPsec SA - // the PDU Session Establishment Accept message - nasEnv := encapNasMsgToEnvelope(pduSessionEstablishmentAccept) + err := s.SendIkeEvt(n3iwf_context.NewCreatePDUSessionEvt(spi, + len(ue.PduSessionList), + ue.TemporaryPDUSessionSetupData), + ) + if err != nil { + ngapLog.Errorf("SendIkeEvt[Create PDU Session] failed: %+v", err) + return + } + + // TS 23.501 4.12.5 Requested PDU Session Establishment via Untrusted non-3GPP Access + // After all IPsec Child SAs are established, the N3IWF shall forward to UE via the signalling IPsec SA + // the PDU Session Establishment Accept message + nasEnv := nas_security.EncapNasMsgToEnvelope([]byte(pduSessionEstablishmentAccept.Value)) - // Cache the pduSessionEstablishmentAccept and forward to the UE after all CREATE_CHILD_SAs finish - ranUe.TemporaryCachedNASMessage = nasEnv + // Cache the pduSessionEstablishmentAccept and forward to the UE after all CREATE_CHILD_SAs finish + ue.TemporaryCachedNASMessage = nasEnv + } } } @@ -1538,7 +1568,7 @@ func (s *Server) HandlePDUSessionResourceModifyRequest( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle PDU Session Resource Modify Request") + ngapLog.Infoln("Handle PDU Session Resource Modify Request") if amf == nil { ngapLog.Error("Corresponding AMF context not found") @@ -1549,8 +1579,9 @@ func (s *Server) HandlePDUSessionResourceModifyRequest( var ranUeNgapID *ngapType.RANUENGAPID var pduSessionResourceModifyListModReq *ngapType.PDUSessionResourceModifyListModReq var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList + var ranUe n3iwf_context.RanUe + var ranUeCtx *n3iwf_context.RanUeSharedCtx - var ranUe *n3iwf_context.N3IWFRanUe n3iwfCtx := s.Context() if pdu == nil { @@ -1618,7 +1649,8 @@ func (s *Server) HandlePDUSessionResourceModifyRequest( // Cause: Unknown local UE NGAP ID return } - if ranUe.AmfUeNgapId != amfUeNgapID.Value { + ranUeCtx = ranUe.GetSharedCtx() + if ranUeCtx.AmfUeNgapId != amfUeNgapID.Value { // TODO: build cause and send error indication // Cause: Inconsistent remote UE NGAP ID return @@ -1641,7 +1673,7 @@ func (s *Server) HandlePDUSessionResourceModifyRequest( pduSessionID, err) } - if pduSession = ranUe.FindPDUSession(pduSessionID); pduSession == nil { + if pduSession = ranUeCtx.FindPDUSession(pduSessionID); pduSession == nil { ngapLog.Errorf("[PDUSessionID: %d] Unknown PDU session ID", pduSessionID) cause := message.BuildCause(ngapType.CausePresentRadioNetwork, @@ -1677,7 +1709,7 @@ func (s *Server) handlePDUSessionResourceModifyRequestTransfer( success bool, responseTransfer []byte, ) { ngapLog := logger.NgapLog - ngapLog.Trace("[N3IWF] Handle PDU Session Resource Modify Request Transfer") + ngapLog.Trace("Handle PDU Session Resource Modify Request Transfer") var pduSessionAMBR *ngapType.PDUSessionAggregateMaximumBitRate var ulNGUUPTNLModifyList *ngapType.ULNGUUPTNLModifyList @@ -1833,7 +1865,7 @@ func (s *Server) HandlePDUSessionResourceModifyConfirm( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle PDU Session Resource Modify Confirm") + ngapLog.Infoln("Handle PDU Session Resource Modify Confirm") var aMFUENGAPID *ngapType.AMFUENGAPID var rANUENGAPID *ngapType.RANUENGAPID @@ -1841,6 +1873,8 @@ func (s *Server) HandlePDUSessionResourceModifyConfirm( var pDUSessionResourceFailedToModifyListModCfm *ngapType.PDUSessionResourceFailedToModifyListModCfm var criticalityDiagnostics *ngapType.CriticalityDiagnostics // var iesCriticalityDiagnostics ngapType.CriticalityDiagnosticsIEList + var ranUe n3iwf_context.RanUe + var ranUeCtx *n3iwf_context.RanUeSharedCtx n3iwfCtx := s.Context() @@ -1886,8 +1920,6 @@ func (s *Server) HandlePDUSessionResourceModifyConfirm( } } - var ranUe *n3iwf_context.N3IWFRanUe - if rANUENGAPID != nil { var ok bool ranUe, ok = n3iwfCtx.RanUePoolLoad(rANUENGAPID.Value) @@ -1895,12 +1927,14 @@ func (s *Server) HandlePDUSessionResourceModifyConfirm( ngapLog.Errorf("Unknown local UE NGAP ID. RanUENGAPID: %d", rANUENGAPID.Value) return } + ranUeCtx = ranUe.GetSharedCtx() } + if aMFUENGAPID != nil { if ranUe != nil { - if ranUe.AmfUeNgapId != aMFUENGAPID.Value { + if ranUeCtx.AmfUeNgapId != aMFUENGAPID.Value { ngapLog.Errorf("Inconsistent remote UE NGAP ID, AMFUENGAPID: %d, RanUe.AmfUeNgapId: %d", - aMFUENGAPID.Value, ranUe.AmfUeNgapId) + aMFUENGAPID.Value, ranUeCtx.AmfUeNgapId) return } } else { @@ -1912,18 +1946,20 @@ func (s *Server) HandlePDUSessionResourceModifyConfirm( } } } + if ranUe == nil { ngapLog.Warn("RANUENGAPID and AMFUENGAPID are both nil") return } + if pDUSessionResourceModifyListModCfm != nil { for _, item := range pDUSessionResourceModifyListModCfm.List { pduSessionId := item.PDUSessionID.Value ngapLog.Tracef("PDU Session Id[%d] in Pdu Session Resource Modification Confrim List", pduSessionId) - sess, exist := ranUe.PduSessionList[pduSessionId] + sess, exist := ranUeCtx.PduSessionList[pduSessionId] if !exist { ngapLog.Warnf( - "PDU Session Id[%d] is not exist in Ue[ranUeNgapId:%d]", pduSessionId, ranUe.RanUeNgapId) + "PDU Session Id[%d] is not exist in Ue[ranUeNgapId:%d]", pduSessionId, ranUeCtx.RanUeNgapId) } else { transfer := ngapType.PDUSessionResourceModifyConfirmTransfer{} err := aper.UnmarshalWithParams(item.PDUSessionResourceModifyConfirmTransfer, &transfer, "valueExt") @@ -1957,7 +1993,7 @@ func (s *Server) HandlePDUSessionResourceModifyConfirm( } ngapLog.Tracef( "Release PDU Session Id[%d] due to PDU Session Resource Modify Indication Unsuccessful", pduSessionId) - delete(ranUe.PduSessionList, pduSessionId) + delete(ranUeCtx.PduSessionList, pduSessionId) } } @@ -1971,7 +2007,7 @@ func (s *Server) HandlePDUSessionResourceReleaseCommand( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle PDU Session Resource Release Command") + ngapLog.Infoln("Handle PDU Session Resource Release Command") var aMFUENGAPID *ngapType.AMFUENGAPID var rANUENGAPID *ngapType.RANUENGAPID // var rANPagingPriority *ngapType.RANPagingPriority @@ -2060,10 +2096,11 @@ func (s *Server) HandlePDUSessionResourceReleaseCommand( message.SendErrorIndication(amf, nil, nil, cause, nil) return } + ranUeCtx := ranUe.GetSharedCtx() - if ranUe.AmfUeNgapId != aMFUENGAPID.Value { + if ranUeCtx.AmfUeNgapId != aMFUENGAPID.Value { ngapLog.Errorf("Inconsistent remote UE NGAP ID, AMFUENGAPID: %d, RanUe.AmfUeNgapId: %d", - aMFUENGAPID.Value, ranUe.AmfUeNgapId) + aMFUENGAPID.Value, ranUeCtx.AmfUeNgapId) cause := message.BuildCause(ngapType.CausePresentRadioNetwork, ngapType.CauseRadioNetworkPresentInconsistentRemoteUENGAPID) message.SendErrorIndication(amf, nil, &rANUENGAPID.Value, cause, nil) @@ -2088,7 +2125,7 @@ func (s *Server) HandlePDUSessionResourceReleaseCommand( printAndGetCause(&transfer.Cause) } ngapLog.Tracef("Release PDU Session Id[%d] due to PDU Session Resource Release Command", pduSessionId) - delete(ranUe.PduSessionList, pduSessionId) + delete(ranUeCtx.PduSessionList, pduSessionId) // response list releaseItem := ngapType.PDUSessionResourceReleasedItemRelRes{ @@ -2106,10 +2143,13 @@ func (s *Server) HandlePDUSessionResourceReleaseCommand( return } - s.IkeEvtCh() <- n3iwf_context.NewSendChildSADeleteRequestEvt( - localSPI, releaseIdList) + err := s.SendIkeEvt(n3iwf_context.NewSendChildSADeleteRequestEvt(localSPI, releaseIdList)) + if err != nil { + ngapLog.Errorf("SendIkeEvt[Send ChildSA Delete Request] failed: %+v", err) + return + } - ranUe.PduSessionReleaseList = releaseList + ranUeCtx.PduSessionReleaseList = releaseList // if nASPDU != nil { // TODO: Send NAS to UE // } @@ -2120,7 +2160,7 @@ func (s *Server) HandleErrorIndication( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle Error Indication") + ngapLog.Infoln("Handle Error Indication") var aMFUENGAPID *ngapType.AMFUENGAPID var rANUENGAPID *ngapType.RANUENGAPID @@ -2212,7 +2252,7 @@ func (s *Server) HandleUERadioCapabilityCheckRequest( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle UE Radio Capability Check Request") + ngapLog.Infoln("Handle UE Radio Capability Check Request") var aMFUENGAPID *ngapType.AMFUENGAPID var rANUENGAPID *ngapType.RANUENGAPID var uERadioCapability *ngapType.UERadioCapability @@ -2287,7 +2327,7 @@ func (s *Server) HandleUERadioCapabilityCheckRequest( return } - ranUe.RadioCapability = uERadioCapability + ranUe.GetSharedCtx().RadioCapability = uERadioCapability } func (s *Server) HandleAMFConfigurationUpdate( @@ -2295,7 +2335,7 @@ func (s *Server) HandleAMFConfigurationUpdate( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle AMF Configuration Updaet") + ngapLog.Infoln("Handle AMF Configuration Updaet") var aMFName *ngapType.AMFName var servedGUAMIList *ngapType.ServedGUAMIList @@ -2419,7 +2459,7 @@ func (s *Server) HandleRANConfigurationUpdateAcknowledge( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle RAN Configuration Update Acknowledge") + ngapLog.Infoln("Handle RAN Configuration Update Acknowledge") var criticalityDiagnostics *ngapType.CriticalityDiagnostics @@ -2463,7 +2503,7 @@ func (s *Server) HandleRANConfigurationUpdateFailure( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle RAN Configuration Update Failure") + ngapLog.Infoln("Handle RAN Configuration Update Failure") var cause *ngapType.Cause var timeToWait *ngapType.TimeToWait @@ -2550,35 +2590,35 @@ func (s *Server) HandleDownlinkRANConfigurationTransfer( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle Downlink RAN Configuration Transfer") + ngapLog.Infoln("Handle Downlink RAN Configuration Transfer") } func (s *Server) HandleDownlinkRANStatusTransfer( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle Downlink RAN Status Transfer") + ngapLog.Infoln("Handle Downlink RAN Status Transfer") } func (s *Server) HandleAMFStatusIndication( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle AMF Status Indication") + ngapLog.Infoln("Handle AMF Status Indication") } func (s *Server) HandleLocationReportingControl( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle Location Reporting Control") + ngapLog.Infoln("Handle Location Reporting Control") } func (s *Server) HandleUETNLAReleaseRequest( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle UE TNLA Release Request") + ngapLog.Infoln("Handle UE TNLA Release Request") } func (s *Server) HandleOverloadStart( @@ -2586,7 +2626,7 @@ func (s *Server) HandleOverloadStart( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle Overload Start") + ngapLog.Infoln("Handle Overload Start") var aMFOverloadResponse *ngapType.OverloadResponse var aMFTrafficLoadReductionIndication *ngapType.TrafficLoadReductionIndication @@ -2636,7 +2676,7 @@ func (s *Server) HandleOverloadStop( pdu *ngapType.NGAPPDU, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Handle Overload Stop") + ngapLog.Infoln("Handle Overload Stop") if amf == nil { ngapLog.Error("AMF Context is nil") @@ -2798,6 +2838,10 @@ func (s *Server) HandleEvent(ngapEvent n3iwf_context.NgapEvt) { s.HandleSendPDUSessionResourceReleaseRes(ngapEvent) case n3iwf_context.GetNGAPContext: s.HandleGetNGAPContext(ngapEvent) + case n3iwf_context.SendUplinkNASTransport: + s.HandleSendUplinkNASTransport(ngapEvent) + case n3iwf_context.SendInitialContextSetupResponse: + s.HandleSendInitialContextSetupResponse(ngapEvent) default: ngapLog.Errorf("Undefine NGAP event type") return @@ -2810,9 +2854,9 @@ func (s *Server) HandleGetNGAPContext( ngapLog := logger.NgapLog ngapLog.Tracef("Handle HandleGetNGAPContext Event") - getNGAPContextEvt := ngapEvent.(*n3iwf_context.GetNGAPContextEvt) - ranUeNgapId := getNGAPContextEvt.RanUeNgapId - ngapCxtReqNumlist := getNGAPContextEvt.NgapCxtReqNumlist + evt := ngapEvent.(*n3iwf_context.GetNGAPContextEvt) + ranUeNgapId := evt.RanUeNgapId + ngapCxtReqNumlist := evt.NgapCxtReqNumlist n3iwfCtx := s.Context() ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) @@ -2826,7 +2870,7 @@ func (s *Server) HandleGetNGAPContext( for _, num := range ngapCxtReqNumlist { switch num { case n3iwf_context.CxtTempPDUSessionSetupData: - ngapCxt = append(ngapCxt, ranUe.TemporaryPDUSessionSetupData) + ngapCxt = append(ngapCxt, ranUe.GetSharedCtx().TemporaryPDUSessionSetupData) default: ngapLog.Errorf("Receive undefine NGAP Context Request number : %d", num) } @@ -2838,8 +2882,11 @@ func (s *Server) HandleGetNGAPContext( return } - s.IkeEvtCh() <- n3iwf_context.NewGetNGAPContextRepEvt(spi, - ngapCxtReqNumlist, ngapCxt) + err := s.SendIkeEvt(n3iwf_context.NewGetNGAPContextRepEvt(spi, ngapCxtReqNumlist, ngapCxt)) + if err != nil { + ngapLog.Errorf("SendIkeEvt[Get NGAP Context Rep] failed: %+v", err) + return + } } func (s *Server) HandleUnmarshalEAP5GData( @@ -2848,10 +2895,10 @@ func (s *Server) HandleUnmarshalEAP5GData( ngapLog := logger.NgapLog ngapLog.Tracef("Handle UnmarshalEAP5GData Event") - unmarshalEAP5GDataEvt := ngapEvent.(*n3iwf_context.UnmarshalEAP5GDataEvt) - spi := unmarshalEAP5GDataEvt.LocalSPI - eapVendorData := unmarshalEAP5GDataEvt.EAPVendorData - isInitialUE := unmarshalEAP5GDataEvt.IsInitialUE + evt := ngapEvent.(*n3iwf_context.UnmarshalEAP5GDataEvt) + spi := evt.LocalSPI + eapVendorData := evt.EAPVendorData + isInitialUE := evt.IsInitialUE n3iwfCtx := s.Context() @@ -2895,10 +2942,14 @@ func (s *Server) HandleUnmarshalEAP5GData( selectedAMF := n3iwfCtx.AMFSelection(anParameters.GUAMI, anParameters.SelectedPLMNID) if selectedAMF == nil { - s.IkeEvtCh() <- n3iwf_context.NewSendEAP5GFailureMsgEvt(spi, n3iwf_context.ErrAMFSelection) + err := s.SendIkeEvt(n3iwf_context.NewSendEAP5GFailureMsgEvt(spi, n3iwf_context.ErrAMFSelection)) + if err != nil { + ngapLog.Errorf("SendIkeEvt[Send EAP5G Failure Msg] failed: %+v", err) + return + } } else { - ranUe := n3iwfCtx.NewN3iwfRanUe() - ranUe.AMF = selectedAMF + n3iwfUe := n3iwfCtx.NewN3iwfRanUe() + n3iwfUe.AMF = selectedAMF if anParameters.EstablishmentCause != nil { value := uint64(anParameters.EstablishmentCause.Value) if value > uint64(math.MaxInt16) { @@ -2906,15 +2957,18 @@ func (s *Server) HandleUnmarshalEAP5GData( "exceeds int16: %+v", value) return } else { - ranUe.RRCEstablishmentCause = int16(value) + n3iwfUe.RRCEstablishmentCause = int16(value) } } - s.IkeEvtCh() <- n3iwf_context.NewUnmarshalEAP5GDataResponseEvt(spi, - ranUe.RanUeNgapId, nasPDU) + err := s.SendIkeEvt(n3iwf_context.NewUnmarshalEAP5GDataResponseEvt(spi, n3iwfUe.RanUeNgapId, nasPDU)) + if err != nil { + ngapLog.Errorf("SendIkeEvt[Unmarshal EAP5G Data Response] failed: %+v", err) + return + } } } else { - ranUeNgapId := unmarshalEAP5GDataEvt.RanUeNgapId + ranUeNgapId := evt.RanUeNgapId ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) if !ok { ngapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) @@ -2930,11 +2984,11 @@ func (s *Server) HandleSendInitialUEMessage( ngapLog := logger.NgapLog ngapLog.Tracef("Handle SendInitialUEMessage Event") - sendInitialUEMessageEvt := ngapEvent.(*n3iwf_context.SendInitialUEMessageEvt) - ranUeNgapId := sendInitialUEMessageEvt.RanUeNgapId - ipv4Addr := sendInitialUEMessageEvt.IPv4Addr - ipv4Port := sendInitialUEMessageEvt.IPv4Port - nasPDU := sendInitialUEMessageEvt.NasPDU + evt := ngapEvent.(*n3iwf_context.SendInitialUEMessageEvt) + ranUeNgapId := evt.RanUeNgapId + ipv4Addr := evt.IPv4Addr + ipv4Port := evt.IPv4Port + nasPDU := evt.NasPDU n3iwfCtx := s.Context() ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) @@ -2942,9 +2996,11 @@ func (s *Server) HandleSendInitialUEMessage( ngapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) return } - ranUe.IPAddrv4 = ipv4Addr - ranUe.PortNumber = int32(ipv4Port) // #nosec G115 - message.SendInitialUEMessage(ranUe.AMF, ranUe, nasPDU) + ranUeCtx := ranUe.GetSharedCtx() + + ranUeCtx.IPAddrv4 = ipv4Addr + ranUeCtx.PortNumber = int32(ipv4Port) // #nosec G115 + message.SendInitialUEMessage(ranUeCtx.AMF, ranUe, nasPDU) } func (s *Server) HandleSendPDUSessionResourceSetupResponse( @@ -2953,18 +3009,18 @@ func (s *Server) HandleSendPDUSessionResourceSetupResponse( ngapLog := logger.NgapLog ngapLog.Tracef("Handle SendPDUSessionResourceSetupResponse Event") - sendPDUSessionResourceSetupResEvt := ngapEvent.(*n3iwf_context.SendPDUSessionResourceSetupResEvt) - ranUeNgapId := sendPDUSessionResourceSetupResEvt.RanUeNgapId + evt := ngapEvent.(*n3iwf_context.SendPDUSessionResourceSetupResEvt) + ranUeNgapId := evt.RanUeNgapId n3iwfCtx := s.Context() - cfg := s.Config() ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) if !ok { ngapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) return } + ranUeCtx := ranUe.GetSharedCtx() - temporaryPDUSessionSetupData := ranUe.TemporaryPDUSessionSetupData + temporaryPDUSessionSetupData := ranUeCtx.TemporaryPDUSessionSetupData if len(temporaryPDUSessionSetupData.UnactivatedPDUSession) != 0 { for index, pduSession := range temporaryPDUSessionSetupData.UnactivatedPDUSession { @@ -2998,9 +3054,15 @@ func (s *Server) HandleSendPDUSessionResourceSetupResponse( temporaryPDUSessionSetupData.FailedListSURes, pduSession.Id, transfer) } } else { + var gtpAddr string + switch ranUe.(type) { + case *n3iwf_context.N3IWFRanUe: + gtpAddr = s.Config().GetN3iwfGtpBindAddress() + } + // Append NGAP PDU session resource setup response transfer transfer, err := message.BuildPDUSessionResourceSetupResponseTransfer( - pduSession, cfg.GetGTPBindAddr()) + pduSession, gtpAddr) if err != nil { ngapLog.Errorf("Build PDU session resource setup response transfer failed: %v", err) return @@ -3035,8 +3097,8 @@ func (s *Server) HandleSendNASMsg( ngapLog := logger.NgapLog ngapLog.Tracef("Handle SendNASMsg Event") - sendNASMsgEvt := ngapEvent.(*n3iwf_context.SendNASMsgEvt) - ranUeNgapId := sendNASMsgEvt.RanUeNgapId + evt := ngapEvent.(*n3iwf_context.SendNASMsgEvt) + ranUeNgapId := evt.RanUeNgapId n3iwfCtx := s.Context() ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) @@ -3045,11 +3107,17 @@ func (s *Server) HandleSendNASMsg( return } - if n, ikeErr := ranUe.TCPConnection.Write(ranUe.TemporaryCachedNASMessage); ikeErr != nil { + n3iwfUe, ok := ranUe.(*n3iwf_context.N3IWFRanUe) + if !ok { + ngapLog.Errorln("HandleSendNASMsg(): [Type Assertion] RanUe -> N3iwfUe failed") + return + } + + if n, ikeErr := n3iwfUe.TCPConnection.Write(n3iwfUe.TemporaryCachedNASMessage); ikeErr != nil { ngapLog.Errorf("Writing via IPSec signalling SA failed: %v", ikeErr) } else { ngapLog.Tracef("Forward PDU Seesion Establishment Accept to UE. Wrote %d bytes", n) - ranUe.TemporaryCachedNASMessage = nil + n3iwfUe.TemporaryCachedNASMessage = nil } } @@ -3059,8 +3127,8 @@ func (s *Server) HandleStartTCPSignalNASMsg( ngapLog := logger.NgapLog ngapLog.Tracef("Handle StartTCPSignalNASMsg Event") - startTCPSignalNASMsgEvt := ngapEvent.(*n3iwf_context.StartTCPSignalNASMsgEvt) - ranUeNgapId := startTCPSignalNASMsgEvt.RanUeNgapId + evt := ngapEvent.(*n3iwf_context.StartTCPSignalNASMsgEvt) + ranUeNgapId := evt.RanUeNgapId n3iwfCtx := s.Context() ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) @@ -3069,7 +3137,13 @@ func (s *Server) HandleStartTCPSignalNASMsg( return } - ranUe.IsNASTCPConnEstablished = true + n3iwfUe, ok := ranUe.(*n3iwf_context.N3IWFRanUe) + if !ok { + ngapLog.Errorln("HandleStartTCPSignalNASMsg(): [Type Assertion] RanUe -> N3iwfUe failed") + return + } + + n3iwfUe.IsNASTCPConnEstablished = true } func (s *Server) HandleNASTCPConnEstablishedComplete( @@ -3078,8 +3152,8 @@ func (s *Server) HandleNASTCPConnEstablishedComplete( ngapLog := logger.NgapLog ngapLog.Tracef("Handle NASTCPConnEstablishedComplete Event") - nasTCPConnEstablishedCompleteEvt := ngapEvent.(*n3iwf_context.NASTCPConnEstablishedCompleteEvt) - ranUeNgapId := nasTCPConnEstablishedCompleteEvt.RanUeNgapId + evt := ngapEvent.(*n3iwf_context.NASTCPConnEstablishedCompleteEvt) + ranUeNgapId := evt.RanUeNgapId n3iwfCtx := s.Context() ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) @@ -3087,18 +3161,23 @@ func (s *Server) HandleNASTCPConnEstablishedComplete( ngapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) return } + n3iwfUe, ok := ranUe.(*n3iwf_context.N3IWFRanUe) + if !ok { + ngapLog.Errorln("HandleNASTCPConnEstablishedComplete(): [Type Assertion] RanUe -> N3iwfUe failed") + return + } - ranUe.IsNASTCPConnEstablishedComplete = true + n3iwfUe.IsNASTCPConnEstablishedComplete = true - if ranUe.TemporaryCachedNASMessage != nil { + if n3iwfUe.TemporaryCachedNASMessage != nil { // Send to UE - if n, err := ranUe.TCPConnection.Write(ranUe.TemporaryCachedNASMessage); err != nil { + if n, err := n3iwfUe.TCPConnection.Write(n3iwfUe.TemporaryCachedNASMessage); err != nil { ngapLog.Errorf("Writing via IPSec signalling SA failed: %v", err) } else { ngapLog.Trace("Forward NWu <- N2") ngapLog.Tracef("Wrote %d bytes", n) } - ranUe.TemporaryCachedNASMessage = nil + n3iwfUe.TemporaryCachedNASMessage = nil } } @@ -3108,10 +3187,10 @@ func (s *Server) HandleSendUEContextReleaseRequest( ngapLog := logger.NgapLog ngapLog.Tracef("Handle SendUEContextReleaseRequest Event") - sendUEContextReleaseReqEvt := ngapEvent.(*n3iwf_context.SendUEContextReleaseRequestEvt) + evt := ngapEvent.(*n3iwf_context.SendUEContextReleaseRequestEvt) - ranUeNgapId := sendUEContextReleaseReqEvt.RanUeNgapId - errMsg := sendUEContextReleaseReqEvt.ErrMsg + ranUeNgapId := evt.RanUeNgapId + errMsg := evt.ErrMsg var cause *ngapType.Cause switch errMsg { @@ -3140,8 +3219,8 @@ func (s *Server) HandleSendUEContextReleaseComplete( ngapLog := logger.NgapLog ngapLog.Tracef("Handle SendUEContextReleaseComplete Event") - sendUEContextReleaseCompleteEvt := ngapEvent.(*n3iwf_context.SendUEContextReleaseCompleteEvt) - ranUeNgapId := sendUEContextReleaseCompleteEvt.RanUeNgapId + evt := ngapEvent.(*n3iwf_context.SendUEContextReleaseCompleteEvt) + ranUeNgapId := evt.RanUeNgapId n3iwfCtx := s.Context() ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) @@ -3162,9 +3241,45 @@ func (s *Server) HandleSendPDUSessionResourceReleaseRes( ngapLog := logger.NgapLog ngapLog.Tracef("Handle SendPDUSessionResourceReleaseResponse Event") - sendPDUSessionResourceReleaseResEvt := ngapEvent.(*n3iwf_context.SendPDUSessionResourceReleaseResEvt) - ranUeNgapId := sendPDUSessionResourceReleaseResEvt.RanUeNgapId + evt := ngapEvent.(*n3iwf_context.SendPDUSessionResourceReleaseResEvt) + ranUeNgapId := evt.RanUeNgapId + + n3iwfCtx := s.Context() + ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) + if !ok { + ngapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + message.SendPDUSessionResourceReleaseResponse(ranUe, ranUe.GetSharedCtx().PduSessionReleaseList, nil) +} + +func (s *Server) HandleSendUplinkNASTransport( + ngapEvent n3iwf_context.NgapEvt, +) { + ngapLog := logger.NgapLog + ngapLog.Tracef("Handle SendUplinkNASTransport Event") + + evt := ngapEvent.(*n3iwf_context.SendUplinkNASTransportEvt) + ranUeNgapId := evt.RanUeNgapId + n3iwfCtx := s.Context() + ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) + if !ok { + ngapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + message.SendUplinkNASTransport(ranUe, evt.Pdu) +} + +func (s *Server) HandleSendInitialContextSetupResponse( + ngapEvent n3iwf_context.NgapEvt, +) { + ngapLog := logger.NgapLog + ngapLog.Tracef("Handle SendInitialContextSetupResponse Event") + evt := ngapEvent.(*n3iwf_context.SendInitialContextSetupRespEvt) + ranUeNgapId := evt.RanUeNgapId n3iwfCtx := s.Context() ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) if !ok { @@ -3172,5 +3287,5 @@ func (s *Server) HandleSendPDUSessionResourceReleaseRes( return } - message.SendPDUSessionResourceReleaseResponse(ranUe, ranUe.PduSessionReleaseList, nil) + message.SendInitialContextSetupResponse(ranUe, evt.ResponseList, evt.FailedList, evt.CriticalityDiagnostics) } diff --git a/internal/ngap/handler_test.go b/internal/ngap/handler_test.go index 9c675221..75049d15 100644 --- a/internal/ngap/handler_test.go +++ b/internal/ngap/handler_test.go @@ -5,9 +5,9 @@ import ( "github.com/stretchr/testify/require" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" + "github.com/free5gc/n3iwf/internal/ike" "github.com/free5gc/n3iwf/pkg/factory" - "github.com/free5gc/n3iwf/pkg/ike" ) func TestReleaseIkeUeAndRanUe(t *testing.T) { @@ -22,7 +22,9 @@ func TestReleaseIkeUeAndRanUe(t *testing.T) { n3iwfCtx := n3iwf.n3iwfCtx ranUe := &n3iwf_context.N3IWFRanUe{ - N3iwfCtx: n3iwfCtx, + RanUeSharedCtx: n3iwf_context.RanUeSharedCtx{ + N3iwfCtx: n3iwfCtx, + }, } ranUeNgapId := int64(0x1234567890ABCDEF) @@ -39,7 +41,7 @@ func TestReleaseIkeUeAndRanUe(t *testing.T) { select { case <-stopCh: return - case rcvEvt := <-n3iwf.ikeServer.RcvEventCh: + case rcvEvt := <-n3iwf.mockIkeEvtCh.RecvEvtCh(): if rcvEvt.Type() != n3iwf_context.IKEDeleteRequest { t.Errorf("Receive Wrong Event") } diff --git a/internal/ngap/message/build.go b/internal/ngap/message/build.go index 09398d82..0f5374c2 100644 --- a/internal/ngap/message/build.go +++ b/internal/ngap/message/build.go @@ -7,9 +7,9 @@ import ( "github.com/pkg/errors" "github.com/free5gc/aper" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/internal/util" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" "github.com/free5gc/ngap" "github.com/free5gc/ngap/ngapConvert" @@ -237,11 +237,13 @@ func BuildNGResetAcknowledge( } func BuildInitialContextSetupResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, responseList *ngapType.PDUSessionResourceSetupListCxtRes, failedList *ngapType.PDUSessionResourceFailedToSetupListCxtRes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentSuccessfulOutcome pdu.SuccessfulOutcome = new(ngapType.SuccessfulOutcome) @@ -264,7 +266,7 @@ func BuildInitialContextSetupResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId initialContextSetupResponseIEs.List = append(initialContextSetupResponseIEs.List, ie) @@ -276,7 +278,7 @@ func BuildInitialContextSetupResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId initialContextSetupResponseIEs.List = append(initialContextSetupResponseIEs.List, ie) @@ -313,11 +315,13 @@ func BuildInitialContextSetupResponse( } func BuildInitialContextSetupFailure( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, cause ngapType.Cause, failedList *ngapType.PDUSessionResourceFailedToSetupListCxtFail, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentUnsuccessfulOutcome pdu.UnsuccessfulOutcome = new(ngapType.UnsuccessfulOutcome) @@ -340,7 +344,7 @@ func BuildInitialContextSetupFailure( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId initialContextSetupFailureIEs.List = append(initialContextSetupFailureIEs.List, ie) @@ -352,7 +356,7 @@ func BuildInitialContextSetupFailure( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId initialContextSetupFailureIEs.List = append(initialContextSetupFailureIEs.List, ie) @@ -387,8 +391,10 @@ func BuildInitialContextSetupFailure( } func BuildUEContextModificationResponse( - ranUe *n3iwf_context.N3IWFRanUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, + ranUe n3iwf_context.RanUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentSuccessfulOutcome pdu.SuccessfulOutcome = new(ngapType.SuccessfulOutcome) @@ -411,7 +417,7 @@ func BuildUEContextModificationResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId uEContextModificationResponseIEs.List = append(uEContextModificationResponseIEs.List, ie) @@ -423,7 +429,7 @@ func BuildUEContextModificationResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId uEContextModificationResponseIEs.List = append(uEContextModificationResponseIEs.List, ie) @@ -437,9 +443,11 @@ func BuildUEContextModificationResponse( return ngap.Encoder(pdu) } -func BuildUEContextModificationFailure(ranUe *n3iwf_context.N3IWFRanUe, cause ngapType.Cause, +func BuildUEContextModificationFailure(ranUe n3iwf_context.RanUe, cause ngapType.Cause, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentUnsuccessfulOutcome pdu.UnsuccessfulOutcome = new(ngapType.UnsuccessfulOutcome) @@ -462,7 +470,7 @@ func BuildUEContextModificationFailure(ranUe *n3iwf_context.N3IWFRanUe, cause ng ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId uEContextModificationFailureIEs.List = append(uEContextModificationFailureIEs.List, ie) @@ -474,7 +482,7 @@ func BuildUEContextModificationFailure(ranUe *n3iwf_context.N3IWFRanUe, cause ng ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId uEContextModificationFailureIEs.List = append(uEContextModificationFailureIEs.List, ie) @@ -496,9 +504,11 @@ func BuildUEContextModificationFailure(ranUe *n3iwf_context.N3IWFRanUe, cause ng return ngap.Encoder(pdu) } -func BuildUEContextReleaseComplete(ranUe *n3iwf_context.N3IWFRanUe, +func BuildUEContextReleaseComplete(ranUe n3iwf_context.RanUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentSuccessfulOutcome pdu.SuccessfulOutcome = new(ngapType.SuccessfulOutcome) @@ -521,7 +531,7 @@ func BuildUEContextReleaseComplete(ranUe *n3iwf_context.N3IWFRanUe, ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId uEContextReleaseCompleteIEs.List = append(uEContextReleaseCompleteIEs.List, ie) @@ -533,7 +543,7 @@ func BuildUEContextReleaseComplete(ranUe *n3iwf_context.N3IWFRanUe, ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId uEContextReleaseCompleteIEs.List = append(uEContextReleaseCompleteIEs.List, ie) @@ -542,20 +552,12 @@ func BuildUEContextReleaseComplete(ranUe *n3iwf_context.N3IWFRanUe, ie.Id.Value = ngapType.ProtocolIEIDUserLocationInformation ie.Criticality.Value = ngapType.CriticalityPresentIgnore ie.Value.Present = ngapType.UEContextReleaseCompleteIEsPresentUserLocationInformation - ie.Value.UserLocationInformation = new(ngapType.UserLocationInformation) - - userLocationInformation := ie.Value.UserLocationInformation - userLocationInformation.Present = ngapType.UserLocationInformationPresentUserLocationInformationN3IWF - userLocationInformation.UserLocationInformationN3IWF = new(ngapType.UserLocationInformationN3IWF) - - userLocationInfoN3IWF := userLocationInformation.UserLocationInformationN3IWF - userLocationInfoN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6) - userLocationInfoN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ranUe.PortNumber) + ie.Value.UserLocationInformation = ranUe.GetUserLocationInformation() uEContextReleaseCompleteIEs.List = append(uEContextReleaseCompleteIEs.List, ie) // PDU Session Resource List (optional) - if len(ranUe.PduSessionList) > 0 { + if len(ranUeCtx.PduSessionList) > 0 { ie = ngapType.UEContextReleaseCompleteIEs{} ie.Id.Value = ngapType.ProtocolIEIDPDUSessionResourceListCxtRelCpl ie.Criticality.Value = ngapType.CriticalityPresentReject @@ -565,7 +567,7 @@ func BuildUEContextReleaseComplete(ranUe *n3iwf_context.N3IWFRanUe, pDUSessionResourceListCxtRelCpl := ie.Value.PDUSessionResourceListCxtRelCpl // PDU Session Resource Item (in PDU Session Resource List) - for _, pduSession := range ranUe.PduSessionList { + for _, pduSession := range ranUeCtx.PduSessionList { pDUSessionResourceItemCxtRelCpl := ngapType.PDUSessionResourceItemCxtRelCpl{} pDUSessionResourceItemCxtRelCpl.PDUSessionID.Value = pduSession.Id pDUSessionResourceListCxtRelCpl.List = append(pDUSessionResourceListCxtRelCpl.List, @@ -587,7 +589,9 @@ func BuildUEContextReleaseComplete(ranUe *n3iwf_context.N3IWFRanUe, return ngap.Encoder(pdu) } -func BuildUEContextReleaseRequest(ranUe *n3iwf_context.N3IWFRanUe, cause ngapType.Cause) ([]byte, error) { +func BuildUEContextReleaseRequest(ranUe n3iwf_context.RanUe, cause ngapType.Cause) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentInitiatingMessage pdu.InitiatingMessage = new(ngapType.InitiatingMessage) @@ -610,7 +614,7 @@ func BuildUEContextReleaseRequest(ranUe *n3iwf_context.N3IWFRanUe, cause ngapTyp ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId uEContextReleaseRequestIEs.List = append(uEContextReleaseRequestIEs.List, ie) @@ -622,7 +626,7 @@ func BuildUEContextReleaseRequest(ranUe *n3iwf_context.N3IWFRanUe, cause ngapTyp ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId uEContextReleaseRequestIEs.List = append(uEContextReleaseRequestIEs.List, ie) @@ -636,7 +640,7 @@ func BuildUEContextReleaseRequest(ranUe *n3iwf_context.N3IWFRanUe, cause ngapTyp pDUSessionResourceListCxtRelReq := ie.Value.PDUSessionResourceListCxtRelReq // PDU Session Resource Item in PDU session Resource List - for _, pduSession := range ranUe.PduSessionList { + for _, pduSession := range ranUeCtx.PduSessionList { pDUSessionResourceItem := ngapType.PDUSessionResourceItemCxtRelReq{} pDUSessionResourceItem.PDUSessionID.Value = pduSession.Id pDUSessionResourceListCxtRelReq.List = append(pDUSessionResourceListCxtRelReq.List, @@ -655,11 +659,13 @@ func BuildUEContextReleaseRequest(ranUe *n3iwf_context.N3IWFRanUe, cause ngapTyp return ngap.Encoder(pdu) } -func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, +func BuildInitialUEMessage(ranUe n3iwf_context.RanUe, nasPdu []byte, allowedNSSAI *ngapType.AllowedNSSAI, ) ([]byte, error) { ngapLog := logger.NgapLog + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentInitiatingMessage pdu.InitiatingMessage = new(ngapType.InitiatingMessage) @@ -682,7 +688,7 @@ func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId initialUEMessageIEs.List = append(initialUEMessageIEs.List, ie) } @@ -705,15 +711,7 @@ func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, ie.Id.Value = ngapType.ProtocolIEIDUserLocationInformation ie.Criticality.Value = ngapType.CriticalityPresentReject ie.Value.Present = ngapType.InitialUEMessageIEsPresentUserLocationInformation - ie.Value.UserLocationInformation = new(ngapType.UserLocationInformation) - - userLocationInformation := ie.Value.UserLocationInformation - userLocationInformation.Present = ngapType.UserLocationInformationPresentUserLocationInformationN3IWF - userLocationInformation.UserLocationInformationN3IWF = new(ngapType.UserLocationInformationN3IWF) - - userLocationInfoN3IWF := userLocationInformation.UserLocationInformationN3IWF - userLocationInfoN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6) - userLocationInfoN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ranUe.PortNumber) + ie.Value.UserLocationInformation = ranUe.GetUserLocationInformation() initialUEMessageIEs.List = append(initialUEMessageIEs.List, ie) } @@ -726,7 +724,7 @@ func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, ie.Value.RRCEstablishmentCause = new(ngapType.RRCEstablishmentCause) rRCEstablishmentCause := ie.Value.RRCEstablishmentCause - value := ranUe.RRCEstablishmentCause + value := ranUeCtx.RRCEstablishmentCause if value < 0 { return nil, errors.Errorf("BuildInitialUEMessage() ranUe.RRCEstablishmentCause "+ "negative value: %d", value) @@ -735,7 +733,7 @@ func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, initialUEMessageIEs.List = append(initialUEMessageIEs.List, ie) } // FiveGSTMSI - if len(ranUe.Guti) != 0 { + if len(ranUeCtx.Guti) != 0 { ie := ngapType.InitialUEMessageIEs{} ie.Id.Value = ngapType.ProtocolIEIDFiveGSTMSI ie.Criticality.Value = ngapType.CriticalityPresentReject @@ -745,12 +743,12 @@ func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, fiveGSTMSI := ie.Value.FiveGSTMSI var amfID string var tmsi string - if len(ranUe.Guti) == 19 { - amfID = ranUe.Guti[5:11] - tmsi = ranUe.Guti[11:] + if len(ranUeCtx.Guti) == 19 { + amfID = ranUeCtx.Guti[5:11] + tmsi = ranUeCtx.Guti[11:] } else { - amfID = ranUe.Guti[6:12] - tmsi = ranUe.Guti[12:] + amfID = ranUeCtx.Guti[6:12] + tmsi = ranUeCtx.Guti[12:] } _, amfSetID, amfPointer := ngapConvert.AmfIdToNgap(amfID) @@ -764,7 +762,7 @@ func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, initialUEMessageIEs.List = append(initialUEMessageIEs.List, ie) } // AMFSetID - if len(ranUe.Guti) != 0 { + if len(ranUeCtx.Guti) != 0 { ie := ngapType.InitialUEMessageIEs{} ie.Id.Value = ngapType.ProtocolIEIDAMFSetID ie.Criticality.Value = ngapType.CriticalityPresentIgnore @@ -776,10 +774,10 @@ func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, // is 3 bytes, is 3 bytes // 1 byte is 2 characters var amfID string - if len(ranUe.Guti) == 19 { // MNC is 2 char - amfID = ranUe.Guti[5:11] + if len(ranUeCtx.Guti) == 19 { // MNC is 2 char + amfID = ranUeCtx.Guti[5:11] } else { - amfID = ranUe.Guti[6:12] + amfID = ranUeCtx.Guti[6:12] } _, aMFSetID.Value, _ = ngapConvert.AmfIdToNgap(amfID) @@ -812,7 +810,9 @@ func BuildInitialUEMessage(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, return ngap.Encoder(pdu) } -func BuildUplinkNASTransport(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte) ([]byte, error) { +func BuildUplinkNASTransport(ranUe n3iwf_context.RanUe, nasPdu []byte) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentInitiatingMessage pdu.InitiatingMessage = new(ngapType.InitiatingMessage) @@ -835,7 +835,7 @@ func BuildUplinkNASTransport(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte) ([] ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId uplinkNasTransportIEs.List = append(uplinkNasTransportIEs.List, ie) @@ -847,7 +847,7 @@ func BuildUplinkNASTransport(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte) ([] ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId uplinkNasTransportIEs.List = append(uplinkNasTransportIEs.List, ie) @@ -866,14 +866,7 @@ func BuildUplinkNASTransport(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte) ([] ie.Id.Value = ngapType.ProtocolIEIDUserLocationInformation ie.Criticality.Value = ngapType.CriticalityPresentIgnore ie.Value.Present = ngapType.UplinkNASTransportIEsPresentUserLocationInformation - ie.Value.UserLocationInformation = new(ngapType.UserLocationInformation) - - userLocationInformation := ie.Value.UserLocationInformation - userLocationInformation.Present = ngapType.UserLocationInformationPresentUserLocationInformationN3IWF - userLocationInformation.UserLocationInformationN3IWF = new(ngapType.UserLocationInformationN3IWF) - userLocationInformationN3IWF := userLocationInformation.UserLocationInformationN3IWF - userLocationInformationN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6) - userLocationInformationN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ranUe.PortNumber) + ie.Value.UserLocationInformation = ranUe.GetUserLocationInformation() uplinkNasTransportIEs.List = append(uplinkNasTransportIEs.List, ie) @@ -881,9 +874,11 @@ func BuildUplinkNASTransport(ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte) ([] } func BuildNASNonDeliveryIndication( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, nasPdu []byte, cause ngapType.Cause, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentInitiatingMessage pdu.InitiatingMessage = new(ngapType.InitiatingMessage) @@ -906,7 +901,7 @@ func BuildNASNonDeliveryIndication( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId nASNonDeliveryIndicationIEs.List = append(nASNonDeliveryIndicationIEs.List, ie) } @@ -919,7 +914,7 @@ func BuildNASNonDeliveryIndication( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId nASNonDeliveryIndicationIEs.List = append(nASNonDeliveryIndicationIEs.List, ie) } @@ -957,11 +952,13 @@ func BuildRerouteNASRequest() ([]byte, error) { } func BuildPDUSessionResourceSetupResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, responseList *ngapType.PDUSessionResourceSetupListSURes, failedList *ngapType.PDUSessionResourceFailedToSetupListSURes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentSuccessfulOutcome pdu.SuccessfulOutcome = new(ngapType.SuccessfulOutcome) @@ -984,7 +981,7 @@ func BuildPDUSessionResourceSetupResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId pduSessionResourceSetupResponseIEs.List = append(pduSessionResourceSetupResponseIEs.List, ie) @@ -996,7 +993,7 @@ func BuildPDUSessionResourceSetupResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId pduSessionResourceSetupResponseIEs.List = append(pduSessionResourceSetupResponseIEs.List, ie) @@ -1033,11 +1030,13 @@ func BuildPDUSessionResourceSetupResponse( } func BuildPDUSessionResourceModifyResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, responseList *ngapType.PDUSessionResourceModifyListModRes, failedList *ngapType.PDUSessionResourceFailedToModifyListModRes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentSuccessfulOutcome pdu.SuccessfulOutcome = new(ngapType.SuccessfulOutcome) @@ -1058,7 +1057,7 @@ func BuildPDUSessionResourceModifyResponse( ie.Criticality.Value = ngapType.CriticalityPresentIgnore ie.Value.Present = ngapType.PDUSessionResourceModifyResponseIEsPresentAMFUENGAPID ie.Value.AMFUENGAPID = &ngapType.AMFUENGAPID{ - Value: ranUe.AmfUeNgapId, + Value: ranUeCtx.AmfUeNgapId, } pduSessionResourceModifyResponseIEs.List = append(pduSessionResourceModifyResponseIEs.List, ie) @@ -1068,7 +1067,7 @@ func BuildPDUSessionResourceModifyResponse( ie.Criticality.Value = ngapType.CriticalityPresentIgnore ie.Value.Present = ngapType.PDUSessionResourceModifyResponseIEsPresentRANUENGAPID ie.Value.RANUENGAPID = &ngapType.RANUENGAPID{ - Value: ranUe.RanUeNgapId, + Value: ranUeCtx.RanUeNgapId, } pduSessionResourceModifyResponseIEs.List = append(pduSessionResourceModifyResponseIEs.List, ie) @@ -1097,15 +1096,7 @@ func BuildPDUSessionResourceModifyResponse( ie.Id.Value = ngapType.ProtocolIEIDUserLocationInformation ie.Criticality.Value = ngapType.CriticalityPresentIgnore ie.Value.Present = ngapType.PDUSessionResourceModifyResponseIEsPresentUserLocationInformation - ie.Value.UserLocationInformation = new(ngapType.UserLocationInformation) - - userLocationInformation := ie.Value.UserLocationInformation - userLocationInformation.Present = ngapType.UserLocationInformationPresentUserLocationInformationN3IWF - userLocationInformation.UserLocationInformationN3IWF = new(ngapType.UserLocationInformationN3IWF) - - userLocationInformationN3IWF := userLocationInformation.UserLocationInformationN3IWF - userLocationInformationN3IWF.IPAddress = ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6) - userLocationInformationN3IWF.PortNumber = ngapConvert.PortNumberToNgap(ranUe.PortNumber) + ie.Value.UserLocationInformation = ranUe.GetUserLocationInformation() pduSessionResourceModifyResponseIEs.List = append(pduSessionResourceModifyResponseIEs.List, ie) @@ -1122,9 +1113,11 @@ func BuildPDUSessionResourceModifyResponse( } func BuildPDUSessionResourceModifyIndication( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, modifyList []ngapType.PDUSessionResourceModifyItemModInd, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentInitiatingMessage pdu.InitiatingMessage = new(ngapType.InitiatingMessage) @@ -1147,7 +1140,7 @@ func BuildPDUSessionResourceModifyIndication( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId pDUSessionResourceModifyIndicationIEs.List = append(pDUSessionResourceModifyIndicationIEs.List, ie) } @@ -1160,7 +1153,7 @@ func BuildPDUSessionResourceModifyIndication( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId pDUSessionResourceModifyIndicationIEs.List = append(pDUSessionResourceModifyIndicationIEs.List, ie) } @@ -1182,10 +1175,12 @@ func BuildPDUSessionResourceModifyIndication( } func BuildPDUSessionResourceNotify( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, notiList *ngapType.PDUSessionResourceNotifyList, relList *ngapType.PDUSessionResourceReleasedListNot, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentInitiatingMessage pdu.InitiatingMessage = new(ngapType.InitiatingMessage) @@ -1208,7 +1203,7 @@ func BuildPDUSessionResourceNotify( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId pDUSessionResourceNotifyIEs.List = append(pDUSessionResourceNotifyIEs.List, ie) } @@ -1221,7 +1216,7 @@ func BuildPDUSessionResourceNotify( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId pDUSessionResourceNotifyIEs.List = append(pDUSessionResourceNotifyIEs.List, ie) } @@ -1252,21 +1247,12 @@ func BuildPDUSessionResourceNotify( pDUSessionResourceNotifyIEs.List = append(pDUSessionResourceNotifyIEs.List, ie) } // UserLocationInformation - if (ranUe.IPAddrv4 != "" || ranUe.IPAddrv6 != "") && ranUe.PortNumber != 0 { + if (ranUeCtx.IPAddrv4 != "" || ranUeCtx.IPAddrv6 != "") && ranUeCtx.PortNumber != 0 { ie := ngapType.PDUSessionResourceNotifyIEs{} ie.Id.Value = ngapType.ProtocolIEIDUserLocationInformation ie.Criticality.Value = ngapType.CriticalityPresentIgnore ie.Value.Present = ngapType.PDUSessionResourceNotifyIEsPresentUserLocationInformation - ie.Value.UserLocationInformation = new(ngapType.UserLocationInformation) - - userLocationInformation := ie.Value.UserLocationInformation - *userLocationInformation = ngapType.UserLocationInformation{ - Present: ngapType.UserLocationInformationPresentUserLocationInformationN3IWF, - UserLocationInformationN3IWF: &ngapType.UserLocationInformationN3IWF{ - IPAddress: ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6), - PortNumber: ngapConvert.PortNumberToNgap(ranUe.PortNumber), - }, - } + ie.Value.UserLocationInformation = ranUe.GetUserLocationInformation() pDUSessionResourceNotifyIEs.List = append(pDUSessionResourceNotifyIEs.List, ie) } @@ -1275,10 +1261,12 @@ func BuildPDUSessionResourceNotify( } func BuildPDUSessionResourceReleaseResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, relList ngapType.PDUSessionResourceReleasedListRelRes, diagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentSuccessfulOutcome pdu.SuccessfulOutcome = new(ngapType.SuccessfulOutcome) @@ -1301,7 +1289,7 @@ func BuildPDUSessionResourceReleaseResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId pDUSessionResourceReleaseResponseIEs.List = append(pDUSessionResourceReleaseResponseIEs.List, ie) } @@ -1314,7 +1302,7 @@ func BuildPDUSessionResourceReleaseResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId pDUSessionResourceReleaseResponseIEs.List = append(pDUSessionResourceReleaseResponseIEs.List, ie) } @@ -1332,21 +1320,12 @@ func BuildPDUSessionResourceReleaseResponse( pDUSessionResourceReleaseResponseIEs.List = append(pDUSessionResourceReleaseResponseIEs.List, ie) } // UserLocationInformation - if (ranUe.IPAddrv4 != "" || ranUe.IPAddrv6 != "") && ranUe.PortNumber != 0 { + if (ranUeCtx.IPAddrv4 != "" || ranUeCtx.IPAddrv6 != "") && ranUeCtx.PortNumber != 0 { ie := ngapType.PDUSessionResourceReleaseResponseIEs{} ie.Id.Value = ngapType.ProtocolIEIDUserLocationInformation ie.Criticality.Value = ngapType.CriticalityPresentIgnore ie.Value.Present = ngapType.PDUSessionResourceReleaseResponseIEsPresentUserLocationInformation - ie.Value.UserLocationInformation = new(ngapType.UserLocationInformation) - - userLocationInformation := ie.Value.UserLocationInformation - *userLocationInformation = ngapType.UserLocationInformation{ - Present: ngapType.UserLocationInformationPresentUserLocationInformationN3IWF, - UserLocationInformationN3IWF: &ngapType.UserLocationInformationN3IWF{ - IPAddress: ngapConvert.IPAddressToNgap(ranUe.IPAddrv4, ranUe.IPAddrv6), - PortNumber: ngapConvert.PortNumberToNgap(ranUe.PortNumber), - }, - } + ie.Value.UserLocationInformation = ranUe.GetUserLocationInformation() pDUSessionResourceReleaseResponseIEs.List = append(pDUSessionResourceReleaseResponseIEs.List, ie) } @@ -1434,9 +1413,11 @@ func BuildUERadioCapabilityInfoIndication() ([]byte, error) { } func BuildUERadioCapabilityCheckResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, diagnostics *ngapType.CriticalityDiagnostics, ) ([]byte, error) { + ranUeCtx := ranUe.GetSharedCtx() + var pdu ngapType.NGAPPDU pdu.Present = ngapType.NGAPPDUPresentSuccessfulOutcome pdu.SuccessfulOutcome = new(ngapType.SuccessfulOutcome) @@ -1459,7 +1440,7 @@ func BuildUERadioCapabilityCheckResponse( ie.Value.AMFUENGAPID = new(ngapType.AMFUENGAPID) aMFUENGAPID := ie.Value.AMFUENGAPID - aMFUENGAPID.Value = ranUe.AmfUeNgapId + aMFUENGAPID.Value = ranUeCtx.AmfUeNgapId uERadioCapabilityCheckResponseIEs.List = append(uERadioCapabilityCheckResponseIEs.List, ie) } // RANUENGAPID @@ -1471,7 +1452,7 @@ func BuildUERadioCapabilityCheckResponse( ie.Value.RANUENGAPID = new(ngapType.RANUENGAPID) rANUENGAPID := ie.Value.RANUENGAPID - rANUENGAPID.Value = ranUe.RanUeNgapId + rANUENGAPID.Value = ranUeCtx.RanUeNgapId uERadioCapabilityCheckResponseIEs.List = append(uERadioCapabilityCheckResponseIEs.List, ie) } // IMSVoiceSupportIndicator @@ -1483,7 +1464,7 @@ func BuildUERadioCapabilityCheckResponse( ie.Value.IMSVoiceSupportIndicator = new(ngapType.IMSVoiceSupportIndicator) iMSVoiceSupportIndicator := ie.Value.IMSVoiceSupportIndicator - value := ranUe.IMSVoiceSupported + value := ranUeCtx.IMSVoiceSupported if value < 0 { return nil, errors.Errorf("BuildUERadioCapabilityCheckResponse() ranUe.IMSVoiceSupported "+ "negative value: %d", value) @@ -1771,7 +1752,7 @@ func BuildPDUSessionResourceSetupResponseTransfer( gtpTunnel := qosFlowPerTNLInformation.UPTransportLayerInformation.GTPTunnel teid := make([]byte, 4) - binary.BigEndian.PutUint32(teid, pduSession.GTPConnection.IncomingTEID) + binary.BigEndian.PutUint32(teid, pduSession.GTPConnInfo.IncomingTEID) gtpTunnel.GTPTEID.Value = teid gtpTunnel.TransportLayerAddress = ngapConvert.IPAddressToNgap(gtpBindIPv4, "") diff --git a/internal/ngap/message/send.go b/internal/ngap/message/send.go index 9050a82d..f7dcd306 100644 --- a/internal/ngap/message/send.go +++ b/internal/ngap/message/send.go @@ -3,8 +3,8 @@ package message import ( "runtime/debug" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/ngap/ngapType" "github.com/free5gc/sctp" ) @@ -12,7 +12,7 @@ import ( func SendToAmf(amf *n3iwf_context.N3IWFAMF, pkt []byte) { ngapLog := logger.NgapLog if amf == nil { - ngapLog.Errorf("[N3IWF] AMF Context is nil ") + ngapLog.Errorf("AMF Context is nil ") } else { if n, err := amf.SCTPConn.Write(pkt); err != nil { ngapLog.Errorf("Write to SCTP socket failed: %+v", err) @@ -34,14 +34,14 @@ func SendNGSetupRequest( } }() - ngapLog.Infoln("[N3IWF] Send NG Setup Request") + ngapLog.Infoln("Send NG Setup Request") cfg := n3iwfCtx.Config() sctpAddr := conn.RemoteAddr().String() if available, _ := n3iwfCtx.AMFReInitAvailableListLoad(sctpAddr); !available { ngapLog.Warnf( - "[N3IWF] Please Wait at least for the indicated time before reinitiating toward same AMF[%s]", + "Please Wait at least for the indicated time before reinitiating toward same AMF[%s]", sctpAddr) return } @@ -69,7 +69,7 @@ func SendNGReset( partOfNGInterface *ngapType.UEAssociatedLogicalNGConnectionList, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send NG Reset") + ngapLog.Infoln("Send NG Reset") pkt, err := BuildNGReset(cause, partOfNGInterface) if err != nil { @@ -86,7 +86,7 @@ func SendNGResetAcknowledge( diagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send NG Reset Acknowledge") + ngapLog.Infoln("Send NG Reset Acknowledge") if partOfNGInterface != nil && len(partOfNGInterface.List) == 0 { ngapLog.Error("length of partOfNGInterface is 0") @@ -103,13 +103,13 @@ func SendNGResetAcknowledge( } func SendInitialContextSetupResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, responseList *ngapType.PDUSessionResourceSetupListCxtRes, failedList *ngapType.PDUSessionResourceFailedToSetupListCxtRes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Initial Context Setup Response") + ngapLog.Infoln("Send Initial Context Setup Response") if responseList != nil && len(responseList.List) > n3iwf_context.MaxNumOfPDUSessions { ngapLog.Errorln("Pdu List out of range") @@ -127,17 +127,17 @@ func SendInitialContextSetupResponse( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendInitialContextSetupFailure( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, cause ngapType.Cause, failedList *ngapType.PDUSessionResourceFailedToSetupListCxtFail, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Initial Context Setup Failure") + ngapLog.Infoln("Send Initial Context Setup Failure") if failedList != nil && len(failedList.List) > n3iwf_context.MaxNumOfPDUSessions { ngapLog.Errorln("Pdu List out of range") @@ -150,15 +150,15 @@ func SendInitialContextSetupFailure( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendUEContextModificationResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send UE Context Modification Response") + ngapLog.Infoln("Send UE Context Modification Response") pkt, err := BuildUEContextModificationResponse(ranUe, criticalityDiagnostics) if err != nil { @@ -166,16 +166,16 @@ func SendUEContextModificationResponse( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendUEContextModificationFailure( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, cause ngapType.Cause, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send UE Context Modification Failure") + ngapLog.Infoln("Send UE Context Modification Failure") pkt, err := BuildUEContextModificationFailure(ranUe, cause, criticalityDiagnostics) if err != nil { @@ -183,15 +183,15 @@ func SendUEContextModificationFailure( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendUEContextReleaseComplete( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send UE Context Release Complete") + ngapLog.Infoln("Send UE Context Release Complete") pkt, err := BuildUEContextReleaseComplete(ranUe, criticalityDiagnostics) if err != nil { @@ -199,14 +199,14 @@ func SendUEContextReleaseComplete( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendUEContextReleaseRequest( - ranUe *n3iwf_context.N3IWFRanUe, cause ngapType.Cause, + ranUe n3iwf_context.RanUe, cause ngapType.Cause, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send UE Context Release Request") + ngapLog.Infoln("Send UE Context Release Request") pkt, err := BuildUEContextReleaseRequest(ranUe, cause) if err != nil { @@ -214,14 +214,14 @@ func SendUEContextReleaseRequest( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendInitialUEMessage(amf *n3iwf_context.N3IWFAMF, - ranUe *n3iwf_context.N3IWFRanUe, nasPdu []byte, + ranUe n3iwf_context.RanUe, nasPdu []byte, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Initial UE Message") + ngapLog.Infoln("Send Initial UE Message") // Attach To AMF pkt, err := BuildInitialUEMessage(ranUe, nasPdu, nil) @@ -230,16 +230,16 @@ func SendInitialUEMessage(amf *n3iwf_context.N3IWFAMF, return } - SendToAmf(ranUe.AMF, pkt) - // ranUe.AttachAMF() + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) + // ranUe.AttachAMF() // TODO: Check AttachAMF if is necessary } func SendUplinkNASTransport( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, nasPdu []byte, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Uplink NAS Transport") + ngapLog.Infoln("Send Uplink NAS Transport") if len(nasPdu) == 0 { ngapLog.Errorln("NAS Pdu is nil") @@ -252,16 +252,16 @@ func SendUplinkNASTransport( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendNASNonDeliveryIndication( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, nasPdu []byte, cause ngapType.Cause, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send NAS NonDelivery Indication") + ngapLog.Infoln("Send NAS NonDelivery Indication") if len(nasPdu) == 0 { ngapLog.Errorln("NAS Pdu is nil") @@ -270,26 +270,26 @@ func SendNASNonDeliveryIndication( pkt, err := BuildNASNonDeliveryIndication(ranUe, nasPdu, cause) if err != nil { - ngapLog.Errorf("Build Uplink NAS Transport failed : %+v\n", err) + ngapLog.Errorf("Build NAS Non Delivery Indication failed : %+v\n", err) return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendRerouteNASRequest() { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Reroute NAS Request") + ngapLog.Infoln("Send Reroute NAS Request") } func SendPDUSessionResourceSetupResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, responseList *ngapType.PDUSessionResourceSetupListSURes, failedListSURes *ngapType.PDUSessionResourceFailedToSetupListSURes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send PDU Session Resource Setup Response") + ngapLog.Infoln("Send PDU Session Resource Setup Response") if ranUe == nil { ngapLog.Error("UE context is nil, this information is mandatory.") @@ -302,17 +302,17 @@ func SendPDUSessionResourceSetupResponse( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendPDUSessionResourceModifyResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, responseList *ngapType.PDUSessionResourceModifyListModRes, failedList *ngapType.PDUSessionResourceFailedToModifyListModRes, criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send PDU Session Resource Modify Response") + ngapLog.Infoln("Send PDU Session Resource Modify Response") if ranUe == nil && criticalityDiagnostics == nil { ngapLog.Error("UE context is nil, this information is mandatory") @@ -325,15 +325,15 @@ func SendPDUSessionResourceModifyResponse( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendPDUSessionResourceModifyIndication( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, modifyList []ngapType.PDUSessionResourceModifyItemModInd, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send PDU Session Resource Modify Indication") + ngapLog.Infoln("Send PDU Session Resource Modify Indication") if ranUe == nil { ngapLog.Error("UE context is nil, this information is mandatory") @@ -351,16 +351,16 @@ func SendPDUSessionResourceModifyIndication( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendPDUSessionResourceNotify( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, notiList *ngapType.PDUSessionResourceNotifyList, relList *ngapType.PDUSessionResourceReleasedListNot, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send PDU Session Resource Notify") + ngapLog.Infoln("Send PDU Session Resource Notify") if ranUe == nil { ngapLog.Error("UE context is nil, this information is mandatory") @@ -373,16 +373,16 @@ func SendPDUSessionResourceNotify( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendPDUSessionResourceReleaseResponse( - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, relList ngapType.PDUSessionResourceReleasedListRelRes, diagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send PDU Session Resource Release Response") + ngapLog.Infoln("Send PDU Session Resource Release Response") if ranUe == nil { ngapLog.Error("UE context is nil, this information is mandatory") @@ -400,7 +400,7 @@ func SendPDUSessionResourceReleaseResponse( return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendErrorIndication( @@ -411,7 +411,7 @@ func SendErrorIndication( criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Error Indication") + ngapLog.Infoln("Send Error Indication") if (cause == nil) && (criticalityDiagnostics == nil) { ngapLog.Errorln("Both cause and criticality is nil. This message shall contain at least one of them.") @@ -435,7 +435,7 @@ func SendErrorIndicationWithSctpConn( criticalityDiagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Error Indication") + ngapLog.Infoln("Send Error Indication") if (cause == nil) && (criticalityDiagnostics == nil) { ngapLog.Errorln("Both cause and criticality is nil. This message shall contain at least one of them.") @@ -457,23 +457,23 @@ func SendErrorIndicationWithSctpConn( func SendUERadioCapabilityInfoIndication() { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send UE Radio Capability Info Indication") + ngapLog.Infoln("Send UE Radio Capability Info Indication") } func SendUERadioCapabilityCheckResponse( amf *n3iwf_context.N3IWFAMF, - ranUe *n3iwf_context.N3IWFRanUe, + ranUe n3iwf_context.RanUe, diagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send UE Radio Capability Check Response") + ngapLog.Infoln("Send UE Radio Capability Check Response") pkt, err := BuildUERadioCapabilityCheckResponse(ranUe, diagnostics) if err != nil { ngapLog.Errorf("Build UERadio Capability Check Response failed : %+v\n", err) return } - SendToAmf(ranUe.AMF, pkt) + SendToAmf(ranUe.GetSharedCtx().AMF, pkt) } func SendAMFConfigurationUpdateAcknowledge( @@ -483,7 +483,7 @@ func SendAMFConfigurationUpdateAcknowledge( diagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send AMF Configuration Update Acknowledge") + ngapLog.Infoln("Send AMF Configuration Update Acknowledge") pkt, err := BuildAMFConfigurationUpdateAcknowledge(setupList, failList, diagnostics) if err != nil { @@ -501,7 +501,7 @@ func SendAMFConfigurationUpdateFailure( diagnostics *ngapType.CriticalityDiagnostics, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send AMF Configuration Update Failure") + ngapLog.Infoln("Send AMF Configuration Update Failure") pkt, err := BuildAMFConfigurationUpdateFailure(ngCause, time, diagnostics) if err != nil { ngapLog.Errorf("Build AMF Configuration Update Failure failed : %+v\n", err) @@ -516,12 +516,12 @@ func SendRANConfigurationUpdate( amf *n3iwf_context.N3IWFAMF, ) { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send RAN Configuration Update") + ngapLog.Infoln("Send RAN Configuration Update") available, _ := n3iwfCtx.AMFReInitAvailableListLoad(amf.SCTPAddr) if !available { ngapLog.Warnf( - "[N3IWF] Please Wait at least for the indicated time before reinitiating toward same AMF[%s]", + "Please Wait at least for the indicated time before reinitiating toward same AMF[%s]", amf.SCTPAddr) return } @@ -540,25 +540,25 @@ func SendRANConfigurationUpdate( func SendUplinkRANConfigurationTransfer() { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Uplink RAN Configuration Transfer") + ngapLog.Infoln("Send Uplink RAN Configuration Transfer") } func SendUplinkRANStatusTransfer() { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Uplink RAN Status Transfer") + ngapLog.Infoln("Send Uplink RAN Status Transfer") } func SendLocationReportingFailureIndication() { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Location Reporting Failure Indication") + ngapLog.Infoln("Send Location Reporting Failure Indication") } func SendLocationReport() { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send Location Report") + ngapLog.Infoln("Send Location Report") } func SendRRCInactiveTransitionReport() { ngapLog := logger.NgapLog - ngapLog.Infoln("[N3IWF] Send RRC Inactive Transition Report") + ngapLog.Infoln("Send RRC Inactive Transition Report") } diff --git a/internal/ngap/server.go b/internal/ngap/server.go index e8e58b52..e515121a 100644 --- a/internal/ngap/server.go +++ b/internal/ngap/server.go @@ -8,15 +8,15 @@ import ( "sync" "time" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/internal/ngap/message" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" lib_ngap "github.com/free5gc/ngap" "github.com/free5gc/sctp" ) -var ( +const ( RECEIVE_NGAPPACKET_CHANNEL_LEN = 512 RECEIVE_NGAPEVENT_CHANNEL_LEN = 512 ) @@ -25,15 +25,16 @@ type n3iwf interface { Config() *factory.Config Context() *n3iwf_context.N3IWFContext CancelContext() context.Context - IkeEvtCh() chan n3iwf_context.IkeEvt + + SendIkeEvt(n3iwf_context.IkeEvt) error } type Server struct { n3iwf - Conn []*sctp.SCTPConn - RcvNgapPktCh chan ReceiveNGAPPacket - RcvEventCh chan n3iwf_context.NgapEvt + conn []*sctp.SCTPConn + rcvNgapPktCh chan ReceiveNGAPPacket + safeRcvEvtCh *n3iwf_context.SafeEvtCh[n3iwf_context.NgapEvt] } type ReceiveNGAPPacket struct { @@ -44,9 +45,10 @@ type ReceiveNGAPPacket struct { func NewServer(n3iwf n3iwf) (*Server, error) { s := &Server{ n3iwf: n3iwf, - RcvNgapPktCh: make(chan ReceiveNGAPPacket, RECEIVE_NGAPPACKET_CHANNEL_LEN), - RcvEventCh: make(chan n3iwf_context.NgapEvt, RECEIVE_NGAPEVENT_CHANNEL_LEN), + rcvNgapPktCh: make(chan ReceiveNGAPPacket, RECEIVE_NGAPPACKET_CHANNEL_LEN), } + s.safeRcvEvtCh = new(n3iwf_context.SafeEvtCh[n3iwf_context.NgapEvt]) + s.safeRcvEvtCh.Init(make(chan n3iwf_context.NgapEvt, RECEIVE_NGAPEVENT_CHANNEL_LEN)) return s, nil } @@ -80,19 +82,19 @@ func (s *Server) runNgapEventHandler(wg *sync.WaitGroup) { ngapLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) } ngapLog.Infof("NGAP server stopped") - close(s.RcvEventCh) - close(s.RcvNgapPktCh) + s.safeRcvEvtCh.Close() + close(s.rcvNgapPktCh) wg.Done() }() for { select { - case rcvPkt := <-s.RcvNgapPktCh: + case rcvPkt := <-s.rcvNgapPktCh: if len(rcvPkt.Buf) == 0 { // receiver closed return } s.NGAPDispatch(rcvPkt.Conn, rcvPkt.Buf) - case rcvEvt := <-s.RcvEventCh: + case rcvEvt := <-s.safeRcvEvtCh.RecvEvtCh(): s.HandleEvent(rcvEvt) } } @@ -175,12 +177,11 @@ func (s *Server) listenAndServe( close(errChan) - s.Conn = append(s.Conn, conn) + s.conn = append(s.conn, conn) - data := make([]byte, 65535) + buf := make([]byte, factory.MAX_BUF_MSG_LEN) for { - n, info, _, err := conn.SCTPRead(data) - + n, info, _, err := conn.SCTPRead(buf) if err != nil { ngapLog.Debugf("[SCTP] AMF SCTP address: %s", remoteAddr) if err == io.EOF || err == io.ErrUnexpectedEOF { @@ -189,34 +190,39 @@ func (s *Server) listenAndServe( if errConn != nil { ngapLog.Errorf("conn close error: %+v", errConn) } - s.RcvNgapPktCh <- ReceiveNGAPPacket{} + s.rcvNgapPktCh <- ReceiveNGAPPacket{} return } ngapLog.Errorf("[SCTP] Read from SCTP connection failed: %+v", err) - } else { - ngapLog.Tracef("[SCTP] Successfully read %d bytes.", n) + return + } - if info == nil || info.PPID != lib_ngap.PPID { - ngapLog.Warn("Received SCTP PPID != 60") - continue - } + ngapLog.Tracef("[SCTP] Successfully read %d bytes.", n) - forwardData := make([]byte, n) - copy(forwardData, data[:n]) + if info == nil || info.PPID != lib_ngap.PPID { + ngapLog.Warn("Received SCTP PPID != 60") + continue + } - s.RcvNgapPktCh <- ReceiveNGAPPacket{ - Conn: conn, - Buf: forwardData[:n], - } + forwardData := make([]byte, n) + copy(forwardData, buf[:n]) + + s.rcvNgapPktCh <- ReceiveNGAPPacket{ + Conn: conn, + Buf: forwardData[:n], } } } +func (s *Server) SendNgapEvt(evt n3iwf_context.NgapEvt) error { + return s.safeRcvEvtCh.SendEvt(evt) +} + func (s *Server) Stop() { ngapLog := logger.NgapLog ngapLog.Infof("Close NGAP server....") - for _, ngapServerConn := range s.Conn { + for _, ngapServerConn := range s.conn { if err := ngapServerConn.Close(); err != nil { ngapLog.Errorf("Stop ngap server error : %+v", err) } diff --git a/internal/ngap/server_test.go b/internal/ngap/server_test.go index 5c54a3c1..72540f0f 100644 --- a/internal/ngap/server_test.go +++ b/internal/ngap/server_test.go @@ -4,19 +4,22 @@ import ( "context" "sync" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" + "github.com/free5gc/n3iwf/internal/ike" "github.com/free5gc/n3iwf/pkg/factory" - "github.com/free5gc/n3iwf/pkg/ike" ) type n3iwfTestApp struct { - cfg *factory.Config - n3iwfCtx *n3iwf_context.N3IWFContext + cfg *factory.Config + n3iwfCtx *n3iwf_context.N3IWFContext + ctx context.Context + cancel context.CancelFunc + wg *sync.WaitGroup + ngapServer *Server ikeServer *ike.Server - ctx context.Context - cancel context.CancelFunc - wg *sync.WaitGroup + + mockIkeEvtCh *n3iwf_context.SafeEvtCh[n3iwf_context.IkeEvt] } func (a *n3iwfTestApp) Config() *factory.Config { @@ -31,12 +34,12 @@ func (a *n3iwfTestApp) CancelContext() context.Context { return a.ctx } -func (a *n3iwfTestApp) NgapEvtCh() chan n3iwf_context.NgapEvt { - return a.ngapServer.RcvEventCh +func (a *n3iwfTestApp) SendNgapEvt(evt n3iwf_context.NgapEvt) error { + return a.ngapServer.SendNgapEvt(evt) } -func (a *n3iwfTestApp) IkeEvtCh() chan n3iwf_context.IkeEvt { - return a.ikeServer.RcvEventCh +func (a *n3iwfTestApp) SendIkeEvt(evt n3iwf_context.IkeEvt) error { + return a.mockIkeEvtCh.SendEvt(evt) } func NewN3iwfTestApp(cfg *factory.Config) (*n3iwfTestApp, error) { @@ -49,6 +52,8 @@ func NewN3iwfTestApp(cfg *factory.Config) (*n3iwfTestApp, error) { cancel: cancel, wg: &sync.WaitGroup{}, } + n3iwfApp.mockIkeEvtCh = new(n3iwf_context.SafeEvtCh[n3iwf_context.IkeEvt]) + n3iwfApp.mockIkeEvtCh.Init(make(chan n3iwf_context.IkeEvt, 10)) n3iwfApp.n3iwfCtx, err = n3iwf_context.NewTestContext(n3iwfApp) if err != nil { diff --git a/internal/nwucp/server.go b/internal/nwucp/server.go index 159b9486..2609fad5 100644 --- a/internal/nwucp/server.go +++ b/internal/nwucp/server.go @@ -1,17 +1,18 @@ package nwucp import ( + "bufio" "context" "encoding/binary" - "encoding/hex" + "io" "net" "runtime/debug" "strings" "sync" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/internal/ngap/message" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" ) @@ -19,7 +20,8 @@ type n3iwf interface { Config() *factory.Config Context() *n3iwf_context.N3IWFContext CancelContext() context.Context - NgapEvtCh() chan n3iwf_context.NgapEvt + + SendNgapEvt(n3iwf_context.NgapEvt) error } type Server struct { @@ -92,54 +94,49 @@ func (s *Server) listenAndServe(wg *sync.WaitGroup) { ranUe, err := n3iwfCtx.RanUeLoadFromIkeSPI(ikeUe.N3IWFIKESecurityAssociation.LocalSPI) if err != nil { - nwucpLog.Errorf("RanUe context not found : %+v", err) + nwucpLog.Errorf("RanUe context not found : %v", err) + continue + } + + n3iwfUe, ok := ranUe.(*n3iwf_context.N3IWFRanUe) + if !ok { + nwucpLog.Errorf("listenAndServe(): [Type Assertion] RanUe -> N3iwfUe failed") continue } + // Store connection - ranUe.TCPConnection = connection + n3iwfUe.TCPConnection = connection - s.NgapEvtCh() <- n3iwf_context.NewNASTCPConnEstablishedCompleteEvt( - ranUe.RanUeNgapId, - ) + err = s.SendNgapEvt(n3iwf_context.NewNASTCPConnEstablishedCompleteEvt(n3iwfUe.RanUeNgapId)) + if err != nil { + nwucpLog.Errorf("SendNgapEvt failed: %v", err) + } wg.Add(1) - go serveConn(ranUe, connection, wg) + go serveConn(n3iwfUe, connection, wg) } } -func decapNasMsgFromEnvelope(envelop []byte) []byte { - // According to TS 24.502 8.2.4, - // in order to transport a NAS message over the non-3GPP access between the UE and the N3IWF, - // the NAS message shall be framed in a NAS message envelope as defined in subclause 9.4. - // According to TS 24.502 9.4, - // a NAS message envelope = Length | NAS Message - - // Get NAS Message Length - nasLen := binary.BigEndian.Uint16(envelop[:2]) - nasMsg := make([]byte, nasLen) - copy(nasMsg, envelop[2:2+nasLen]) - - return nasMsg -} - func (s *Server) Stop() { nwucpLog := logger.NWuCPLog nwucpLog.Infof("Close Nwucp server...") if err := s.tcpListener.Close(); err != nil { - nwucpLog.Errorf("Stop nwuup server error : %+v", err) + nwucpLog.Errorf("Stop nwucp server error : %+v", err) } + // TODO: [Bug] TCPConnection may close twice, need to check s.Context().RANUePool.Range( func(key, value interface{}) bool { - ranUe := value.(*n3iwf_context.N3IWFRanUe) - if ranUe.TCPConnection != nil { + ranUe, ok := value.(*n3iwf_context.N3IWFRanUe) + if ok && ranUe.TCPConnection != nil { if err := ranUe.TCPConnection.Close(); err != nil { logger.InitLog.Errorf("Stop nwucp server error : %+v", err) } } return true - }) + }, + ) } // serveConn handle accepted TCP connection. It reads NAS packets @@ -160,21 +157,33 @@ func serveConn(ranUe *n3iwf_context.N3IWFRanUe, connection net.Conn, wg *sync.Wa wg.Done() }() - data := make([]byte, 65535) + connReader := bufio.NewReader(connection) + buf := make([]byte, factory.MAX_BUF_MSG_LEN) for { - n, err := connection.Read(data) + // Read the length of NAS message + n, err := io.ReadFull(connReader, buf[:2]) if err != nil { - nwucpLog.Errorf("Read TCP connection failed: %+v", err) + nwucpLog.Errorf("Read the length of NAS message failed: %+v", err) ranUe.TCPConnection = nil return } - nwucpLog.Tracef("Get NAS PDU from UE:\nNAS length: %d\nNAS content:\n%s", n, hex.Dump(data[:n])) + nasLen := binary.BigEndian.Uint16(buf[:n]) + if uint64(nasLen) > uint64(cap(buf)) { + buf = make([]byte, 0, nasLen) + } - // Decap Nas envelope - forwardData := decapNasMsgFromEnvelope(data) + // Read the NAS message + n, err = io.ReadFull(connReader, buf[:nasLen]) + if err != nil { + nwucpLog.Errorf("Read the NAS message failed: %+v", err) + ranUe.TCPConnection = nil + return + } + fwdNas := make([]byte, n) + copy(fwdNas, buf[:n]) wg.Add(1) - go forward(ranUe, forwardData, wg) + go forward(ranUe, fwdNas, wg) } } diff --git a/internal/nwuup/server.go b/internal/nwuup/server.go index bb0e16c2..ec8c37a4 100644 --- a/internal/nwuup/server.go +++ b/internal/nwuup/server.go @@ -7,14 +7,15 @@ import ( "sync" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "github.com/wmnsk/go-gtp/gtpv1" gtpMsg "github.com/wmnsk/go-gtp/gtpv1/message" "golang.org/x/net/ipv4" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/gre" gtpQoSMsg "github.com/free5gc/n3iwf/internal/gtp/message" "github.com/free5gc/n3iwf/internal/logger" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" ) @@ -27,13 +28,15 @@ type n3iwf interface { type Server struct { n3iwf - gtpuConn *gtpv1.UPlaneConn greConn *ipv4.PacketConn + gtpuConn *gtpv1.UPlaneConn + log *logrus.Entry } func NewServer(n3iwf n3iwf) (*Server, error) { s := &Server{ n3iwf: n3iwf, + log: logger.NWuUPLog, } return s, nil } @@ -62,8 +65,7 @@ func (s *Server) Run(wg *sync.WaitGroup) error { } func (s *Server) newGreConn() error { - cfg := s.Config() - listenAddr := cfg.GetIPSecGatewayAddr() + listenAddr := s.Config().GetIPSecGatewayAddr() // Setup IPv4 packet connection socket // This socket will only capture GRE encapsulated packet @@ -79,8 +81,7 @@ func (s *Server) newGreConn() error { } func (s *Server) newGtpuConn() error { - cfg := s.Config() - gtpuAddr := cfg.GetGTPBindAddr() + gtpv1.GTPUPort + gtpuAddr := s.Config().GetN3iwfGtpBindAddress() + gtpv1.GTPUPort laddr, err := net.ResolveUDPAddr("udp", gtpuAddr) if err != nil { @@ -94,111 +95,10 @@ func (s *Server) newGtpuConn() error { return nil } -// Parse the fields not supported by go-gtp and forward data to UE. -func (s *Server) handleQoSTPDU(c gtpv1.Conn, senderAddr net.Addr, msg gtpMsg.Message) error { - pdu := gtpQoSMsg.QoSTPDUPacket{} - err := pdu.Unmarshal(msg.(*gtpMsg.TPDU)) - if err != nil { - return err - } - - s.forwardDL(pdu) - return nil -} - -// Forward user plane packets from N3 to UE with GRE header and new IP header encapsulated -func (s *Server) forwardDL(packet gtpQoSMsg.QoSTPDUPacket) { - gtpLog := logger.GTPLog - - defer func() { - if p := recover(); p != nil { - // Print stack for panic to log. Fatalf() will let program exit. - gtpLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) - } - }() - - n3iwfCtx := s.Context() - - pktTEID := packet.GetTEID() - gtpLog.Tracef("pkt teid : %d", pktTEID) - - // Find UE information - ranUe, ok := n3iwfCtx.AllocatedUETEIDLoad(pktTEID) - if !ok { - gtpLog.Errorf("Cannot find RanUE context from QosPacket TEID : %+v", pktTEID) - return - } - - ikeUe, err := n3iwfCtx.IkeUeLoadFromNgapId(ranUe.RanUeNgapId) - if err != nil { - gtpLog.Errorf("Cannot find IkeUe context from RanUe , NgapID : %+v", ranUe.RanUeNgapId) - return - } - - // UE inner IP in IPSec - ueInnerIPAddr := ikeUe.IPSecInnerIPAddr - - var cm *ipv4.ControlMessage - for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { - pdusession := ranUe.FindPDUSession(childSA.PDUSessionIds[0]) - if pdusession != nil && pdusession.GTPConnection.IncomingTEID == pktTEID { - gtpLog.Tracef("forwarding IPSec xfrm interfaceid : %d", childSA.XfrmIface.Attrs().Index) - cm = &ipv4.ControlMessage{ - IfIndex: childSA.XfrmIface.Attrs().Index, - } - break - } - } - - var ( - qfi uint8 - rqi bool - ) - - // QoS Related Parameter - if packet.HasQoS() { - qfi, rqi = packet.GetQoSParameters() - gtpLog.Tracef("QFI: %v, RQI: %v", qfi, rqi) - } - - // Encasulate IPv4 packet with GRE header before forward to UE through IPsec - grePacket := gre.GREPacket{} - - // TODO:[24.502(v15.7) 9.3.3 ] The Protocol Type field should be set to zero - grePacket.SetPayload(packet.GetPayload(), gre.IPv4) - grePacket.SetQoS(qfi, rqi) - forwardData := grePacket.Marshal() - - // Send to UE through Nwu - if n, err := s.greConn.WriteTo(forwardData, cm, ueInnerIPAddr); err != nil { - gtpLog.Errorf("Write to UE failed: %+v", err) - return - } else { - gtpLog.Trace("Forward NWu <- N3") - gtpLog.Tracef("Wrote %d bytes", n) - } -} - -func (s *Server) gtpuListenAndServe(wg *sync.WaitGroup) { - nwuupLog := logger.NWuUPLog - defer func() { - if p := recover(); p != nil { - // Print stack for panic to log. Fatalf() will let program exit. - nwuupLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) - } - - wg.Done() - }() - - if err := s.gtpuConn.ListenAndServe(context.Background()); err != nil { - nwuupLog.Errorf("GTP-U server err: %v", err) - } -} - // listenAndServe read from socket and call forward() to // forward packet. func (s *Server) greListenAndServe(wg *sync.WaitGroup) { - nwuupLog := logger.NWuUPLog + nwuupLog := s.log defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. @@ -212,7 +112,7 @@ func (s *Server) greListenAndServe(wg *sync.WaitGroup) { wg.Done() }() - buffer := make([]byte, 65535) + buf := make([]byte, factory.MAX_BUF_MSG_LEN) err := s.greConn.SetControlMessage(ipv4.FlagInterface|ipv4.FlagTTL, true) if err != nil { @@ -221,7 +121,7 @@ func (s *Server) greListenAndServe(wg *sync.WaitGroup) { } for { - n, cm, src, err := s.greConn.ReadFrom(buffer) + n, cm, src, err := s.greConn.ReadFrom(buf) nwuupLog.Tracef("Read %d bytes, %s", n, cm) if err != nil { nwuupLog.Errorf("Error read from IPv4 packet connection: %+v", err) @@ -229,17 +129,33 @@ func (s *Server) greListenAndServe(wg *sync.WaitGroup) { } forwardData := make([]byte, n) - copy(forwardData, buffer) + copy(forwardData, buf) wg.Add(1) go s.forwardUL(src.String(), cm.IfIndex, forwardData, wg) } } +func (s *Server) gtpuListenAndServe(wg *sync.WaitGroup) { + nwuupLog := s.log + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + nwuupLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + + wg.Done() + }() + + if err := s.gtpuConn.ListenAndServe(context.Background()); err != nil { + nwuupLog.Errorf("GTP-U server err: %v", err) + } +} + // forward forwards user plane packets from NWu to UPF // with GTP header encapsulated func (s *Server) forwardUL(ueInnerIP string, ifIndex int, rawData []byte, wg *sync.WaitGroup) { - nwuupLog := logger.NWuUPLog + nwuupLog := s.log defer func() { if p := recover(); p != nil { // Print stack for panic to log. Fatalf() will let program exit. @@ -268,7 +184,7 @@ func (s *Server) forwardUL(ueInnerIP string, ifIndex int, rawData []byte, wg *sy // Check which child SA the packet come from with interface index, // and find the corresponding PDU session if childSA.XfrmIface != nil && childSA.XfrmIface.Attrs().Index == ifIndex { - pduSession = ranUe.PduSessionList[childSA.PDUSessionIds[0]] + pduSession = ranUe.GetSharedCtx().PduSessionList[childSA.PDUSessionIds[0]] break } } @@ -278,7 +194,7 @@ func (s *Server) forwardUL(ueInnerIP string, ifIndex int, rawData []byte, wg *sy return } - gtpConnection := pduSession.GTPConnection + gtpConnection := pduSession.GTPConnInfo // Decapsulate GRE header and extract QoS Parameters if exist grePacket := gre.GREPacket{} @@ -301,7 +217,7 @@ func (s *Server) forwardUL(ueInnerIP string, ifIndex int, rawData []byte, wg *sy nwuupLog.Errorf("forwardUL err: %+v", err) return } - gtpPacket, err := buildQoSGTPPacket(gtpConnection.OutgoingTEID, qfi, payload) + gtpPacket, err := gtpQoSMsg.BuildQoSGTPPacket(gtpConnection.OutgoingTEID, qfi, payload) if err != nil { nwuupLog.Errorf("buildQoSGTPPacket err: %+v", err) return @@ -325,34 +241,100 @@ func (s *Server) forwardUL(ueInnerIP string, ifIndex int, rawData []byte, wg *sy nwuupLog.Tracef("Wrote %d bytes", n) } -func buildQoSGTPPacket(teid uint32, qfi uint8, payload []byte) ([]byte, error) { - nwuupLog := logger.NWuUPLog - header := gtpMsg.NewHeader(0x34, gtpMsg.MsgTypeTPDU, teid, 0x00, payload).WithExtensionHeaders( - gtpMsg.NewExtensionHeader( - gtpMsg.ExtHeaderTypePDUSessionContainer, - []byte{gtpQoSMsg.UL_PDU_SESSION_INFORMATION_TYPE, qfi}, - gtpMsg.ExtHeaderTypeNoMoreExtensionHeaders, - ), - ) - - b := make([]byte, header.MarshalLen()) - - if err := header.MarshalTo(b); err != nil { - nwuupLog.Errorf("go-gtp MarshalTo err: %v", err) - return nil, err - } - - return b, nil -} - func (s *Server) Stop() { - nwuupLog := logger.NWuUPLog + nwuupLog := s.log nwuupLog.Infof("Close Nwuup server...") if err := s.greConn.Close(); err != nil { nwuupLog.Errorf("Stop nwuup greConn error : %v", err) } + if err := s.gtpuConn.Close(); err != nil { nwuupLog.Errorf("Stop nwuup gtpuConn error : %v", err) } } + +// Parse the fields not supported by go-gtp and forward data to UE. +func (s *Server) handleQoSTPDU(c gtpv1.Conn, senderAddr net.Addr, msg gtpMsg.Message) error { + pdu := gtpQoSMsg.QoSTPDUPacket{} + err := pdu.Unmarshal(msg.(*gtpMsg.TPDU)) + if err != nil { + return err + } + + s.forwardDL(pdu) + return nil +} + +// Forward user plane packets from N3 to UE with GRE header and new IP header encapsulated +func (s *Server) forwardDL(packet gtpQoSMsg.QoSTPDUPacket) { + nwuupLog := s.log + + defer func() { + if p := recover(); p != nil { + // Print stack for panic to log. Fatalf() will let program exit. + nwuupLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) + } + }() + + n3iwfCtx := s.Context() + pktTEID := packet.GetTEID() + nwuupLog.Tracef("pkt teid : %d", pktTEID) + + // Find UE information + ranUe, ok := n3iwfCtx.AllocatedUETEIDLoad(pktTEID) + if !ok { + nwuupLog.Errorf("Cannot find RanUE context from QosPacket TEID : %+v", pktTEID) + return + } + ranUeNgapID := ranUe.GetSharedCtx().RanUeNgapId + + ikeUe, err := n3iwfCtx.IkeUeLoadFromNgapId(ranUeNgapID) + if err != nil { + nwuupLog.Errorf("Cannot find IkeUe context from RanUe , NgapID : %+v", ranUeNgapID) + return + } + + // UE inner IP in IPSec + ueInnerIPAddr := ikeUe.IPSecInnerIPAddr + + var cm *ipv4.ControlMessage + for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { + pdusession := ranUe.FindPDUSession(childSA.PDUSessionIds[0]) + if pdusession != nil && pdusession.GTPConnInfo.IncomingTEID == pktTEID { + nwuupLog.Tracef("forwarding IPSec xfrm interfaceid : %d", childSA.XfrmIface.Attrs().Index) + cm = &ipv4.ControlMessage{ + IfIndex: childSA.XfrmIface.Attrs().Index, + } + break + } + } + + var ( + qfi uint8 + rqi bool + ) + + // QoS Related Parameter + if packet.HasQoS() { + qfi, rqi = packet.GetQoSParameters() + nwuupLog.Tracef("QFI: %v, RQI: %v", qfi, rqi) + } + + // Encasulate IPv4 packet with GRE header before forward to UE through IPsec + grePacket := gre.GREPacket{} + + // TODO:[24.502(v15.7) 9.3.3 ] The Protocol Type field should be set to zero + grePacket.SetPayload(packet.GetPayload(), gre.IPv4) + grePacket.SetQoS(qfi, rqi) + forwardData := grePacket.Marshal() + + // Send to UE through Nwu + if n, err := s.greConn.WriteTo(forwardData, cm, ueInnerIPAddr); err != nil { + nwuupLog.Errorf("Write to UE failed: %+v", err) + return + } else { + nwuupLog.Trace("Forward NWu <- N3") + nwuupLog.Tracef("Wrote %d bytes", n) + } +} diff --git a/internal/util/hash.go b/internal/util/hash.go new file mode 100644 index 00000000..20abc936 --- /dev/null +++ b/internal/util/hash.go @@ -0,0 +1,13 @@ +package util + +import "hash/crc32" + +func HashCRC32(text string) (uint32, error) { + h := crc32.NewIEEE() + _, err := h.Write([]byte(text)) + if err != nil { + return 0, err + } + + return h.Sum32(), nil +} diff --git a/pkg/app/app.go b/pkg/app/app.go index b6961007..cabfc06a 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -1,7 +1,7 @@ package app import ( - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/pkg/factory" ) diff --git a/pkg/factory/config.go b/pkg/factory/config.go index 4fd05807..8b815ee9 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -26,46 +26,48 @@ const ( N3iwfDefaultConfigPath string = "./config/n3iwfcfg.yaml" N3iwfDefaultXfrmIfaceName string = "ipsec" N3iwfDefaultXfrmIfaceId uint32 = 7 + + MAX_BUF_MSG_LEN int = 65535 ) type N3IWFNFInfo struct { - GlobalN3IWFID *GlobalN3IWFID `yaml:"GlobalN3IWFID" valid:"required"` - RanNodeName string `yaml:"Name,omitempty" valid:"optional"` - SupportedTAList []SupportedTAItem `yaml:"SupportedTAList" valid:"required"` + GlobalN3IWFID *GlobalN3IWFID `yaml:"globalN3IWFID" valid:"required"` + RanNodeName string `yaml:"name,omitempty" valid:"optional"` + SupportedTAList []SupportedTAItem `yaml:"supportedTAList" valid:"required"` } type GlobalN3IWFID struct { - PLMNID *PLMNID `yaml:"PLMNID" valid:"required"` - N3IWFID uint16 `yaml:"N3IWFID" valid:"range(0|65535),required"` // with length 2 bytes + PLMNID *PLMNID `yaml:"plmnID" valid:"required"` + N3IWFID uint16 `yaml:"n3iwfID" valid:"range(0|65535),required"` // with length 2 bytes } type SupportedTAItem struct { - TAC string `yaml:"TAC" valid:"hexadecimal,stringlength(6|6),required"` - BroadcastPLMNList []BroadcastPLMNItem `yaml:"BroadcastPLMNList" valid:"required"` + TAC string `yaml:"tac" valid:"hexadecimal,stringlength(6|6),required"` + BroadcastPLMNList []BroadcastPLMNItem `yaml:"broadcastPlmnList" valid:"required"` } type BroadcastPLMNItem struct { - PLMNID *PLMNID `yaml:"PLMNID" valid:"required"` - TAISliceSupportList []SliceSupportItem `yaml:"TAISliceSupportList" valid:"required"` + PLMNID *PLMNID `yaml:"plmnID" valid:"required"` + TAISliceSupportList []SliceSupportItem `yaml:"taiSliceSupportList" valid:"required"` } type PLMNID struct { - Mcc string `yaml:"MCC" valid:"numeric,stringlength(3|3),required"` - Mnc string `yaml:"MNC" valid:"numeric,stringlength(2|3),required"` + Mcc string `yaml:"mcc" valid:"numeric,stringlength(3|3),required"` + Mnc string `yaml:"mnc" valid:"numeric,stringlength(2|3),required"` } type SliceSupportItem struct { - SNSSAI SNSSAIItem `yaml:"SNSSAI" valid:"required"` + SNSSAI SNSSAIItem `yaml:"snssai" valid:"required"` } type SNSSAIItem struct { - SST int32 `yaml:"SST" valid:"required"` - SD string `yaml:"SD,omitempty" valid:"required,hexadecimal,stringlength(6|6)"` + SST int32 `yaml:"sst" valid:"required"` + SD string `yaml:"sd,omitempty" valid:"required,hexadecimal,stringlength(6|6)"` } type AMFSCTPAddresses struct { - IPAddresses []string `yaml:"IP" valid:"required"` - Port int `yaml:"Port,omitempty" valid:"port,optional"` // Default port is 38412 if not defined. + IPAddresses []string `yaml:"ip" valid:"required"` + Port int `yaml:"port,omitempty" valid:"port,optional"` // Default port is 38412 if not defined. } func (a *AMFSCTPAddresses) validate() error { @@ -115,22 +117,22 @@ type Info struct { } type Configuration struct { - N3IWFInfo *N3IWFNFInfo `yaml:"N3IWFInformation" valid:"required"` + N3IWFInfo *N3IWFNFInfo `yaml:"n3iwfInformation" valid:"required"` LocalSctpAddr string `yaml:"localSctpAddr,omitempty" valid:"optional,host"` AMFSCTPAddresses []AMFSCTPAddresses `yaml:"AMFSCTPAddresses" valid:"required"` - TCPPort int `yaml:"NASTCPPort" valid:"required,port"` - IKEBindAddr string `yaml:"IKEBindAddress" valid:"required,host"` - IPSecGatewayAddr string `yaml:"IPSecTunnelAddress" valid:"required,host"` - UEIPAddressRange string `yaml:"UEIPAddressRange" valid:"required,cidr"` // e.g. 10.0.1.0/24 - XfrmIfaceName string `yaml:"XFRMInterfaceName" valid:"optional,stringlength(1|10)"` // must != 0 - XfrmIfaceId uint32 `yaml:"XFRMInterfaceID" valid:"optional"` // must != 0 - GTPBindAddr string `yaml:"GTPBindAddress" valid:"required,host"` - FQDN string `yaml:"FQDN" valid:"required,host"` // e.g. n3iwf.Saviah.com - PrivateKey string `yaml:"PrivateKey" valid:"optional"` - CertificateAuthority string `yaml:"CertificateAuthority" valid:"optional"` - Certificate string `yaml:"Certificate" valid:"optional"` - LivenessCheck *TimerValue `yaml:"LivenessCheck" valid:"required"` + TCPPort int `yaml:"nasTcpPort" valid:"required,port"` + IKEBindAddr string `yaml:"ikeBindAddress" valid:"required,host"` + UEIPAddressRange string `yaml:"ueIpAddressRange" valid:"required,cidr"` // e.g. 10.0.1.0/24 + IPSecGatewayAddr string `yaml:"ipSecTunnelAddress" valid:"required,host"` + XfrmIfaceName string `yaml:"xfrmInterfaceName" valid:"optional,stringlength(1|10)"` // must != 0 + XfrmIfaceId uint32 `yaml:"xfrmInterfaceID" valid:"optional"` // must != 0 + N3IWFGTPBindAddress string `yaml:"n3iwfGtpBindAddress" valid:"required,host"` + FQDN string `yaml:"fqdn" valid:"required,host"` // e.g. n3iwf.Saviah.com + PrivateKey string `yaml:"privateKey" valid:"optional"` + CertificateAuthority string `yaml:"certificateAuthority" valid:"optional"` + Certificate string `yaml:"certificate" valid:"optional"` + LivenessCheck *TimerValue `yaml:"livenessCheck" valid:"required"` } type Logger struct { @@ -318,10 +320,10 @@ func (c *Config) GetIPSecGatewayAddr() string { return c.Configuration.IPSecGatewayAddr } -func (c *Config) GetGTPBindAddr() string { +func (c *Config) GetN3iwfGtpBindAddress() string { c.RLock() defer c.RUnlock() - return c.Configuration.GTPBindAddr + return c.Configuration.N3IWFGTPBindAddress } func (c *Config) GetNasTcpAddr() string { diff --git a/pkg/service/init.go b/pkg/service/init.go index 5d16f87a..87e5fb3b 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -13,15 +13,15 @@ import ( "github.com/sirupsen/logrus" "github.com/vishvananda/netlink" + n3iwf_context "github.com/free5gc/n3iwf/internal/context" + "github.com/free5gc/n3iwf/internal/ike" + "github.com/free5gc/n3iwf/internal/ike/xfrm" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/internal/ngap" "github.com/free5gc/n3iwf/internal/nwucp" "github.com/free5gc/n3iwf/internal/nwuup" "github.com/free5gc/n3iwf/pkg/app" - n3iwf_context "github.com/free5gc/n3iwf/pkg/context" "github.com/free5gc/n3iwf/pkg/factory" - "github.com/free5gc/n3iwf/pkg/ike" - "github.com/free5gc/n3iwf/pkg/ike/xfrm" ) var N3IWF *N3iwfApp @@ -106,12 +106,13 @@ func (a *N3iwfApp) SetLogEnable(enable bool) { func (a *N3iwfApp) SetLogLevel(level string) { lvl, err := logrus.ParseLevel(level) + mainLog := logger.MainLog if err != nil { - logger.MainLog.Warnf("Log level [%s] is invalid", level) + mainLog.Warnf("Log level [%s] is invalid", level) return } - logger.MainLog.Infof("Log level is set to [%s]", level) + mainLog.Infof("Log level is set to [%s]", level) if lvl == logger.Log.GetLevel() { return } @@ -134,6 +135,7 @@ func (a *N3iwfApp) Run() error { if err := a.initDefaultXfrmInterface(); err != nil { return err } + mainLog := logger.MainLog a.wg.Add(1) go a.listenShutdownEvent() @@ -142,28 +144,28 @@ func (a *N3iwfApp) Run() error { if err := a.ngapServer.Run(&a.wg); err != nil { return errors.Wrapf(err, "Run()") } - logger.MainLog.Infof("NGAP service running.") + mainLog.Infof("NGAP service running.") // Relay listeners // Control plane if err := a.nwucpServer.Run(&a.wg); err != nil { return errors.Wrapf(err, "Listen NWu control plane traffic failed") } - logger.MainLog.Infof("NAS TCP server successfully started.") + mainLog.Infof("NAS TCP server successfully started.") - // User plane + // User plane of N3IWF if err := a.nwuupServer.Run(&a.wg); err != nil { return errors.Wrapf(err, "Listen NWu user plane traffic failed") } - logger.MainLog.Infof("Listening NWu user plane traffic") + mainLog.Infof("Listening NWu user plane traffic") // IKE if err := a.ikeServer.Run(&a.wg); err != nil { return errors.Wrapf(err, "Start IKE service failed") } - logger.MainLog.Infof("IKE service running") + mainLog.Infof("IKE service running") - logger.MainLog.Infof("N3IWF started") + mainLog.Infof("N3IWF started") a.WaitRoutineStopped() return nil @@ -201,13 +203,14 @@ func (a *N3iwfApp) initDefaultXfrmInterface() error { var err error n3iwfCtx := a.n3iwfCtx cfg := a.Config() + mainLog := logger.MainLog n3iwfIPAddr := net.ParseIP(cfg.GetIPSecGatewayAddr()).To4() n3iwfIPAddrAndSubnet := net.IPNet{IP: n3iwfIPAddr, Mask: n3iwfCtx.UeIPRange.Mask} newXfrmiName := fmt.Sprintf("%s-default", cfg.GetXfrmIfaceName()) if linkIPSec, err = xfrm.SetupIPsecXfrmi(newXfrmiName, n3iwfCtx.XfrmParentIfaceName, cfg.GetXfrmIfaceId(), n3iwfIPAddrAndSubnet); err != nil { - logger.MainLog.Errorf("Setup XFRM interface %s fail: %+v", newXfrmiName, err) + mainLog.Errorf("Setup XFRM interface %s fail: %+v", newXfrmiName, err) return err } @@ -217,10 +220,10 @@ func (a *N3iwfApp) initDefaultXfrmInterface() error { } if err := netlink.RouteAdd(route); err != nil { - logger.MainLog.Warnf("netlink.RouteAdd: %+v", err) + mainLog.Warnf("netlink.RouteAdd: %+v", err) } - logger.MainLog.Infof("Setup XFRM interface %s ", newXfrmiName) + mainLog.Infof("Setup XFRM interface %s ", newXfrmiName) n3iwfCtx.XfrmIfaces.LoadOrStore(cfg.GetXfrmIfaceId(), linkIPSec) n3iwfCtx.XfrmIfaceIdOffsetForUP = 1 @@ -229,16 +232,18 @@ func (a *N3iwfApp) initDefaultXfrmInterface() error { } func (a *N3iwfApp) removeIPsecInterfaces() { + mainLog := logger.MainLog a.n3iwfCtx.XfrmIfaces.Range( func(key, value interface{}) bool { iface := value.(netlink.Link) if err := netlink.LinkDel(iface); err != nil { - logger.MainLog.Errorf("Delete interface %s fail: %+v", iface.Attrs().Name, err) + mainLog.Errorf("Delete interface %s fail: %+v", iface.Attrs().Name, err) } else { - logger.MainLog.Infof("Delete interface: %s", iface.Attrs().Name) + mainLog.Infof("Delete interface: %s", iface.Attrs().Name) } return true - }) + }, + ) } func (a *N3iwfApp) Terminate() { @@ -249,18 +254,15 @@ func (a *N3iwfApp) terminateProcedure() { logger.MainLog.Info("Stopping service created by N3IWF") a.ngapServer.Stop() - a.nwucpServer.Stop() - a.nwuupServer.Stop() - a.ikeServer.Stop() } -func (a *N3iwfApp) NgapEvtCh() chan n3iwf_context.NgapEvt { - return a.ngapServer.RcvEventCh +func (a *N3iwfApp) SendNgapEvt(evt n3iwf_context.NgapEvt) error { + return a.ngapServer.SendNgapEvt(evt) } -func (a *N3iwfApp) IkeEvtCh() chan n3iwf_context.IkeEvt { - return a.ikeServer.RcvEventCh +func (a *N3iwfApp) SendIkeEvt(evt n3iwf_context.IkeEvt) error { + return a.ikeServer.SendIkeEvt(evt) } From 29a94ec121ac5dbaaa70c98f434878f3d4ab277c Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Mon, 30 Sep 2024 02:03:02 +0000 Subject: [PATCH 28/33] Modify configuration struct tage to lower case --- pkg/factory/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/factory/config.go b/pkg/factory/config.go index 8b815ee9..0c954460 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -119,7 +119,7 @@ type Info struct { type Configuration struct { N3IWFInfo *N3IWFNFInfo `yaml:"n3iwfInformation" valid:"required"` LocalSctpAddr string `yaml:"localSctpAddr,omitempty" valid:"optional,host"` - AMFSCTPAddresses []AMFSCTPAddresses `yaml:"AMFSCTPAddresses" valid:"required"` + AMFSCTPAddresses []AMFSCTPAddresses `yaml:"amfSCTPAddresses" valid:"required"` TCPPort int `yaml:"nasTcpPort" valid:"required,port"` IKEBindAddr string `yaml:"ikeBindAddress" valid:"required,host"` From c382ace7e6e37fc119df9499689ee1bba8236405 Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Mon, 30 Sep 2024 02:56:22 +0000 Subject: [PATCH 29/33] Fix safe event channel UT --- internal/context/safe_event_channel_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/context/safe_event_channel_test.go b/internal/context/safe_event_channel_test.go index aa765529..969fcd48 100644 --- a/internal/context/safe_event_channel_test.go +++ b/internal/context/safe_event_channel_test.go @@ -19,7 +19,7 @@ func TestSafeEvtCh(t *testing.T) { // Two senders wg.Add(2) for i := 0; i < 2; i++ { - go func() { + go func(i int) { if i == 0 { // Case: send failed time.Sleep(1 * time.Second) @@ -32,7 +32,7 @@ func TestSafeEvtCh(t *testing.T) { require.NoError(t, err) } wg.Done() - }() + }(i) } // One receiver From cbed9ce1a8a92a46852a1a53dad2c0c62ff89c6b Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Thu, 17 Oct 2024 04:59:08 +0000 Subject: [PATCH 30/33] Add Informational msg request check and send N2 release context release req after receive informational request --- go.mod | 2 +- go.sum | 4 +- internal/context/ikeue.go | 4 +- internal/context/ngap.go | 36 +++- internal/context/ranue.go | 18 ++ internal/ike/handler.go | 317 ++++++++++++++++++--------------- internal/ike/send.go | 37 ++-- internal/ike/server.go | 19 +- internal/ike/server_test.go | 18 +- internal/ngap/handler.go | 74 +++++++- internal/ngap/message/build.go | 28 +-- internal/nwuup/server.go | 4 + 12 files changed, 349 insertions(+), 212 deletions(-) diff --git a/go.mod b/go.mod index 41476149..05e468a6 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.21 require ( github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/free5gc/aper v1.0.6-0.20240503143507-2c4c4780b98f - github.com/free5gc/ike v1.1.0 + github.com/free5gc/ike v1.1.1-0.20241014015325-083f89768f43 github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74 github.com/free5gc/sctp v1.0.1 github.com/free5gc/util v1.0.7-0.20240713162917-350ee8f4af4c diff --git a/go.sum b/go.sum index 53909630..f756cb5b 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/free5gc/aper v1.0.6-0.20240503143507-2c4c4780b98f h1:sO8FFwAq7feSw/vKN9ioY+fX1gNTXd6/xQOqaeclzsA= github.com/free5gc/aper v1.0.6-0.20240503143507-2c4c4780b98f/go.mod h1:oh3dtNsje2W4/q3pfidMWQKXbXIehXK3t6CD9tXmHx0= -github.com/free5gc/ike v1.1.0 h1:gTbjfx8T1xkB5olPuijvIV5POD1NatLUuaNwcmWIClM= -github.com/free5gc/ike v1.1.0/go.mod h1:57Ujd9Xjva02mt3OVfepYKiheFHO5Y0YCQyBgB1p1Qs= +github.com/free5gc/ike v1.1.1-0.20241014015325-083f89768f43 h1:cgpG06umqWTAwYy/bLXXcdNg+k7+qkinsElCVZzuOSI= +github.com/free5gc/ike v1.1.1-0.20241014015325-083f89768f43/go.mod h1:57Ujd9Xjva02mt3OVfepYKiheFHO5Y0YCQyBgB1p1Qs= github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74 h1:foSd3OVtTfDmn3EZbsBngK+U93Mv8YE+qSja7FvKEVU= github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74/go.mod h1:UsPP9LWVyNwu5sm7ZE5toAFeBNkkyj0rh+4Q3ylRBi8= github.com/free5gc/openapi v1.0.9-0.20240503143645-eac9f06c2f6b h1:+VcgZq+3apB6Xr4jEqgGf/uAECRF038SwixEvvxhYrM= diff --git a/internal/context/ikeue.go b/internal/context/ikeue.go index 6d68c628..9c64f890 100644 --- a/internal/context/ikeue.go +++ b/internal/context/ikeue.go @@ -162,7 +162,7 @@ func (childSA *ChildSecurityAssociation) String(xfrmiId uint32) string { return fmt.Sprintf("====== IPSec/Child SA Info ======"+ "\n====== Inbound ======"+ "\nXFRM interface if_id: %d"+ - "\nIPSec Inbound SPI: 0x%016x"+ + "\nIPSec Inbound SPI: 0x%08x"+ "\n[UE:%+v] -> [N3IWF:%+v]"+ "\nIPSec Encryption Algorithm: %d"+ "\nIPSec Encryption Key: 0x%x"+ @@ -171,7 +171,7 @@ func (childSA *ChildSecurityAssociation) String(xfrmiId uint32) string { "\n====== IPSec/Child SA Info ======"+ "\n====== Outbound ======"+ "\nXFRM interface if_id: %d"+ - "\nIPSec Outbound SPI: 0x%016x"+ + "\nIPSec Outbound SPI: 0x%08x"+ "\n[N3IWF:%+v] -> [UE:%+v]"+ "\nIPSec Encryption Algorithm: %d"+ "\nIPSec Encryption Key: 0x%x"+ diff --git a/internal/context/ngap.go b/internal/context/ngap.go index 7cfe1fc1..f697a907 100644 --- a/internal/context/ngap.go +++ b/internal/context/ngap.go @@ -1,6 +1,8 @@ package context -import "github.com/free5gc/ngap/ngapType" +import ( + "github.com/free5gc/ngap/ngapType" +) type NgapEventType int64 @@ -13,8 +15,10 @@ const ( SendPDUSessionResourceSetupResponse SendNASMsg StartTCPSignalNASMsg + SendUEContextRelease SendUEContextReleaseRequest SendUEContextReleaseComplete + SendPDUSessionResourceRelease SendPDUSessionResourceReleaseResponse SendUplinkNASTransport SendInitialContextSetupResponse @@ -242,3 +246,33 @@ func NewSendInitialContextSetupRespEvt( CriticalityDiagnostics: criticalityDiagnostics, } } + +type SendUEContextReleaseEvt struct { + RanUeNgapId int64 +} + +func (e *SendUEContextReleaseEvt) Type() NgapEventType { + return SendUEContextRelease +} + +func NewSendUEContextReleaseEvt(ranUeNgapId int64) *SendUEContextReleaseEvt { + return &SendUEContextReleaseEvt{ + RanUeNgapId: ranUeNgapId, + } +} + +type SendPDUSessionResourceReleaseEvt struct { + RanUeNgapId int64 + DeletPduIds []int64 +} + +func (e *SendPDUSessionResourceReleaseEvt) Type() NgapEventType { + return SendPDUSessionResourceRelease +} + +func NewendPDUSessionResourceReleaseEvt(ranUeNgapId int64, deletPduIds []int64) *SendPDUSessionResourceReleaseEvt { + return &SendPDUSessionResourceReleaseEvt{ + RanUeNgapId: ranUeNgapId, + DeletPduIds: deletPduIds, + } +} diff --git a/internal/context/ranue.go b/internal/context/ranue.go index b25bea57..e7012938 100644 --- a/internal/context/ranue.go +++ b/internal/context/ranue.go @@ -7,6 +7,22 @@ import ( "github.com/free5gc/ngap/ngapType" ) +type UeCtxRelState bool + +const ( + // NGAP has already received UE Context release command + UeCtxRelStateNone UeCtxRelState = false + UeCtxRelStateOngoing UeCtxRelState = true +) + +type PduSessResRelState bool + +const ( + // NGAP has not received Pdu Session resouces release request + PduSessResRelStateNone PduSessResRelState = false + PduSessResRelStateOngoing PduSessResRelState = true +) + type RanUe interface { /* Get Attributes */ GetUserLocationInformation() *ngapType.UserLocationInformation @@ -56,6 +72,8 @@ type RanUeSharedCtx struct { IMSVoiceSupported int32 RRCEstablishmentCause int16 PduSessionReleaseList ngapType.PDUSessionResourceReleasedListRelRes + UeCtxRelState UeCtxRelState + PduSessResRelState PduSessResRelState } type PDUSession struct { diff --git a/internal/ike/handler.go b/internal/ike/handler.go index 28b89431..6e73d4a0 100644 --- a/internal/ike/handler.go +++ b/internal/ike/handler.go @@ -49,7 +49,7 @@ func (s *Server) HandleIKESAINIT( cfg := s.Config() // For response or needed data - responseIKEMessage := new(ike_message.IKEMessage) + var responseIKEPayload ike_message.IKEPayloadContainer var localNonce, concatenatedNonce []byte // Chosen transform from peer's proposal var chooseProposal ike_message.ProposalContainer @@ -74,17 +74,17 @@ func (s *Server) HandleIKESAINIT( } if securityAssociation != nil { - responseSecurityAssociation := responseIKEMessage.Payloads.BuildSecurityAssociation() + responseSecurityAssociation := responseIKEPayload.BuildSecurityAssociation() chooseProposal = SelectProposal(securityAssociation.Proposals) responseSecurityAssociation.Proposals = append(responseSecurityAssociation.Proposals, chooseProposal...) if len(responseSecurityAssociation.Proposals) == 0 { ikeLog.Warn("No proposal chosen") // Respond NO_PROPOSAL_CHOSEN to UE - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.NO_PROPOSAL_CHOSEN, nil, nil) + responseIKEPayload.Reset() + responseIKEPayload.BuildNotification(ike_message.TypeNone, ike_message.NO_PROPOSAL_CHOSEN, nil, nil) + responseIKEMessage := ike_message.NewMessage(message.InitiatorSPI, message.ResponderSPI, + ike_message.IKE_SA_INIT, true, false, message.MessageID, responseIKEPayload) err := SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, nil) if err != nil { @@ -103,15 +103,16 @@ func (s *Server) HandleIKESAINIT( if chosenDiffieHellmanGroup != keyExcahge.DiffieHellmanGroup { ikeLog.Warn("The Diffie-Hellman group defined in key exchange payload not matches the one in chosen proposal") // send INVALID_KE_PAYLOAD to UE - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() + responseIKEPayload.Reset() notificationData := make([]byte, 2) binary.BigEndian.PutUint16(notificationData, chosenDiffieHellmanGroup) - responseIKEMessage.Payloads.BuildNotification( + responseIKEPayload.BuildNotification( ike_message.TypeNone, ike_message.INVALID_KE_PAYLOAD, nil, notificationData) + responseIKEMessage := ike_message.NewMessage(message.InitiatorSPI, message.ResponderSPI, + ike_message.IKE_SA_INIT, true, false, message.MessageID, responseIKEPayload) + err := SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, nil) if err != nil { ikeLog.Errorf("HandleIKESAINIT(): %v", err) @@ -133,7 +134,7 @@ func (s *Server) HandleIKESAINIT( localNonce = localNonceBigInt.Bytes() concatenatedNonce = append(nonce.NonceData, localNonce...) - responseIKEMessage.Payloads.BuildNonce(localNonce) + responseIKEPayload.BuildNonce(localNonce) } else { ikeLog.Error("The nonce field is nil") // TODO: send error message to UE @@ -169,20 +170,18 @@ func (s *Server) HandleIKESAINIT( ikeSecurityAssociation.UeBehindNAT = ueBehindNAT ikeSecurityAssociation.N3iwfBehindNAT = n3iwfBehindNAT - // IKE response to UE - responseIKEMessage.BuildIKEHeader( - ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, - ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, message.MessageID) - - responseIKEMessage.Payloads.BUildKeyExchange(chosenDiffieHellmanGroup, localPublicValue) - + responseIKEPayload.BUildKeyExchange(chosenDiffieHellmanGroup, localPublicValue) err = s.buildNATDetectNotifPayload( - ikeSecurityAssociation, &responseIKEMessage.Payloads, ueAddr, n3iwfAddr) + ikeSecurityAssociation, &responseIKEPayload, ueAddr, n3iwfAddr) if err != nil { ikeLog.Warnf("Handle IKE_SA_INIT: %v", err) return } + // IKE response to UE + responseIKEMessage := ike_message.NewMessage(message.InitiatorSPI, ikeSecurityAssociation.LocalSPI, + ike_message.IKE_SA_INIT, true, false, message.MessageID, responseIKEPayload) + // Prepare authentication data - InitatorSignedOctet // InitatorSignedOctet = RealMessage1 | NonceRData | MACedIDForI // MACedIDForI is acquired in IKE_AUTH exchange @@ -249,7 +248,6 @@ func (s *Server) HandleIKEAUTH( ipsecGwAddr := cfg.GetIPSecGatewayAddr() // Used for response - responseIKEMessage := new(ike_message.IKEMessage) var responseIKEPayload ike_message.IKEPayloadContainer // Parse payloads @@ -434,22 +432,13 @@ func (s *Server) HandleIKEAUTH( if len(responseSecurityAssociation.Proposals) == 0 { ikeLog.Warn("No proposal chosen") // Respond NO_PROPOSAL_CHOSEN to UE - // Build IKE message - responseIKEMessage.BuildIKEHeader( - message.InitiatorSPI, message.ResponderSPI, - ike_message.IKE_AUTH, ike_message.ResponseBitCheck, - message.MessageID) - responseIKEMessage.Payloads.Reset() - - // Build response - responseIKEPayload.Reset() - // Notification responseIKEPayload.BuildNotification( ike_message.TypeNone, ike_message.NO_PROPOSAL_CHOSEN, nil, nil) - responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, - responseIKEPayload...) + // Build IKE message + responseIKEMessage := ike_message.NewMessage(message.InitiatorSPI, message.ResponderSPI, + ike_message.IKE_AUTH, true, false, message.MessageID, responseIKEPayload) // Send IKE message to UE err := SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, @@ -483,11 +472,7 @@ func (s *Server) HandleIKEAUTH( ikeLog.Info("Received traffic selector initiator from UE") ikeSecurityAssociation.TrafficSelectorResponder = trafficSelectorResponder - // Build response IKE message - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.IKE_AUTH, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() - + responseIKEPayload.Reset() // Identification responseIKEPayload.BuildIdentificationResponder(ike_message.ID_FQDN, []byte(cfg.GetFQDN())) @@ -531,9 +516,9 @@ func (s *Server) HandleIKEAUTH( } responseIKEPayload.BuildEAP5GStart(identifier) - // responseIKEMessage - responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, - responseIKEPayload...) + // Build IKE message + responseIKEMessage := ike_message.NewMessage(message.InitiatorSPI, message.ResponderSPI, + ike_message.IKE_AUTH, true, false, message.MessageID, responseIKEPayload) // Shift state ikeSecurityAssociation.State++ @@ -587,10 +572,7 @@ func (s *Server) HandleIKEAUTH( if eap5GMessageID == ike_message.EAP5GType5GStop { // Send EAP failure - // Build IKE message - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.IKE_AUTH, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() + responseIKEPayload.Reset() // EAP identifier, err := ike_security.GenerateRandomUint8() @@ -600,8 +582,9 @@ func (s *Server) HandleIKEAUTH( } responseIKEPayload.BuildEAPfailure(identifier) - responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, - responseIKEPayload...) + // Build IKE message + responseIKEMessage := ike_message.NewMessage(message.InitiatorSPI, message.ResponderSPI, + ike_message.IKE_AUTH, true, false, message.MessageID, responseIKEPayload) // Send IKE message to UE err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, @@ -664,21 +647,22 @@ func (s *Server) HandleIKEAUTH( } expectedAuthenticationData := pseudorandomFunction.Sum(nil) + ikeLog.Tracef("Kn3iwf:\n%s", hex.Dump(ikeUE.Kn3iwf)) + ikeLog.Tracef("secret:\n%s", hex.Dump(secret)) + ikeLog.Tracef("InitiatorSignedOctets:\n%s", hex.Dump(ikeSecurityAssociation.InitiatorSignedOctets)) ikeLog.Tracef("Expected Authentication Data:\n%s", hex.Dump(expectedAuthenticationData)) if !bytes.Equal(authentication.AuthenticationData, expectedAuthenticationData) { ikeLog.Warn("Peer authentication failed.") // Inform UE the authentication has failed - // Build IKE message - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.IKE_AUTH, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() + responseIKEPayload.Reset() // Notification responseIKEPayload.BuildNotification( ike_message.TypeNone, ike_message.AUTHENTICATION_FAILED, nil, nil) - responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, - responseIKEPayload...) + // Build IKE message + responseIKEMessage := ike_message.NewMessage(message.InitiatorSPI, message.ResponderSPI, + ike_message.IKE_AUTH, true, false, message.MessageID, responseIKEPayload) // Send IKE message to UE err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, @@ -693,16 +677,14 @@ func (s *Server) HandleIKEAUTH( } else { ikeLog.Warn("Peer authentication failed.") // Inform UE the authentication has failed - // Build IKE message - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.IKE_AUTH, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() + responseIKEPayload.Reset() // Notification responseIKEPayload.BuildNotification(ike_message.TypeNone, ike_message.AUTHENTICATION_FAILED, nil, nil) - responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, - responseIKEPayload...) + // Build IKE message + responseIKEMessage := ike_message.NewMessage(message.InitiatorSPI, message.ResponderSPI, + ike_message.IKE_AUTH, true, false, message.MessageID, responseIKEPayload) // Send IKE message to UE err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, @@ -737,10 +719,7 @@ func (s *Server) HandleIKEAUTH( ikeLog.Warn("Configuration is nil. UE did not sent any configuration request.") } - // Build response IKE message - responseIKEMessage.BuildIKEHeader(message.InitiatorSPI, message.ResponderSPI, - ike_message.IKE_AUTH, ike_message.ResponseBitCheck, message.MessageID) - responseIKEMessage.Payloads.Reset() + responseIKEPayload.Reset() // Calculate local AUTH pseudorandomFunction.Reset() @@ -819,7 +798,7 @@ func (s *Server) HandleIKEAUTH( binary.BigEndian.PutUint32(inboundSPIByte, inboundSPI) outboundSPI := binary.BigEndian.Uint32(ikeSecurityAssociation.IKEAuthResponseSA.Proposals[0].SPI) - ikeLog.Infof("Inbound SPI: %+v, Outbound SPI: %+v", inboundSPI, outboundSPI) + ikeLog.Infof("Inbound SPI: 0x%08x, Outbound SPI: 0x%08x", inboundSPI, outboundSPI) // SPI field of IKEAuthResponseSA is used to save outbound SPI temporarily. // After N3IWF produced its inbound SPI, the field will be overwritten with the SPI. @@ -863,8 +842,9 @@ func (s *Server) HandleIKEAUTH( // Notification(NSA_TCP_PORT) responseIKEPayload.BuildNotifyNAS_TCP_PORT(cfg.GetNasTcpPort()) - responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, - responseIKEPayload...) + // Build IKE message + responseIKEMessage := ike_message.NewMessage(message.InitiatorSPI, message.ResponderSPI, + ike_message.IKE_AUTH, true, false, message.MessageID, responseIKEPayload) childSecurityAssociationContext.LocalIsInitiator = false // Aplly XFRM rules @@ -1156,7 +1136,9 @@ func (s *Server) HandleInformational( ikeLog := logger.IKELog ikeLog.Infoln("Handle Informational") - n3iwfCtx := s.Context() + var deletePayload *ike_message.Delete + var err error + responseIKEPayload := new(ike_message.IKEPayloadContainer) n3iwfIke := ikeSecurityAssociation.IkeUE @@ -1166,40 +1148,11 @@ func (s *Server) HandleInformational( atomic.StoreInt32(&n3iwfIke.N3IWFIKESecurityAssociation.CurrentRetryTimes, 0) } - if len(message.Payloads) == 0 { // Receive liveness message - return - } - for _, ikePayload := range message.Payloads { switch ikePayload.Type() { case ike_message.TypeD: - var err error + deletePayload = ikePayload.(*ike_message.Delete) - deletePayload := ikePayload.(*ike_message.Delete) - ranNgapId, ok := n3iwfCtx.NgapIdLoad(n3iwfIke.N3IWFIKESecurityAssociation.LocalSPI) - if !ok { - ikeLog.Errorf("Cannot get RanNgapId from SPI : %+v", - n3iwfIke.N3IWFIKESecurityAssociation.LocalSPI) - return - } - - if deletePayload.ProtocolID == ike_message.TypeIKE { // Check if UE is response to a request that delete the ike SA - err = n3iwfIke.Remove() - if err != nil { - ikeLog.Errorf("Delete IkeUe Context error : %v", err) - } - err = s.SendNgapEvt(n3iwf_context.NewSendUEContextReleaseCompleteEvt(ranNgapId)) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Send UE Ctx Release Complete] failed: %+v", err) - return - } - } else if deletePayload.ProtocolID == ike_message.TypeESP { - err = s.SendNgapEvt(n3iwf_context.NewSendPDUSessionResourceReleaseResEvt(ranNgapId)) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Send PDU Sess Resource Release] failed: %+v", err) - return - } - } default: ikeLog.Warnf( "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", @@ -1207,13 +1160,19 @@ func (s *Server) HandleInformational( } } - if (message.Flags&ike_message.InitiatorBitCheck == ike_message.InitiatorBitCheck) && - (message.Flags&ike_message.ResponseBitCheck == ike_message.ResponseBitCheck) { // Get Response from UE + if deletePayload != nil { + responseIKEPayload, err = s.handleDeletePayload(deletePayload, message.IsResponse(), ikeSecurityAssociation) + if err != nil { + ikeLog.Errorf("HandleInformational(): %v", err) + return + } + } + + if message.IsResponse() { ikeSecurityAssociation.ResponderMessageID++ - } else { // Get Request from UE - payload := new(ike_message.IKEPayloadContainer) - SendUEInformationExchange(ikeSecurityAssociation, payload, - ike_message.ResponseBitCheck, message.MessageID, + } else { // Get Request message + SendUEInformationExchange(ikeSecurityAssociation, ikeSecurityAssociation.IKESAKey, + responseIKEPayload, false, true, message.MessageID, udpConn, ueAddr, n3iwfAddr) } } @@ -1293,13 +1252,8 @@ func (s *Server) HandleSendEAP5GFailureMsg(ikeEvt n3iwf_context.IkeEvt) { ikeSecurityAssociation, _ := n3iwfCtx.IKESALoad(localSPI) ikeLog.Warnf("EAP Failure : %s", errMsg.Error()) - responseIKEMessage := new(ike_message.IKEMessage) var responseIKEPayload ike_message.IKEPayloadContainer // Send EAP failure - // Build IKE message - responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, - ike_message.IKE_AUTH, ike_message.ResponseBitCheck, ikeSecurityAssociation.InitiatorMessageID) - responseIKEMessage.Payloads.Reset() // EAP identifier, err := ike_security.GenerateRandomUint8() @@ -1309,8 +1263,9 @@ func (s *Server) HandleSendEAP5GFailureMsg(ikeEvt n3iwf_context.IkeEvt) { } responseIKEPayload.BuildEAPfailure(identifier) - responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, - responseIKEPayload...) + // Build IKE message + responseIKEMessage := ike_message.NewMessage(ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, + ike_message.IKE_AUTH, true, false, ikeSecurityAssociation.InitiatorMessageID, responseIKEPayload) // Send IKE message to UE err = SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, @@ -1339,14 +1294,9 @@ func (s *Server) HandleSendEAPSuccessMsg(ikeEvt n3iwf_context.IkeEvt) { ikeSecurityAssociation.IkeUE.PduSessionListLen = pduSessionListLen - responseIKEMessage := new(ike_message.IKEMessage) var responseIKEPayload ike_message.IKEPayloadContainer - // Build IKE message - responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, - ikeSecurityAssociation.LocalSPI, ike_message.IKE_AUTH, ike_message.ResponseBitCheck, - ikeSecurityAssociation.InitiatorMessageID) - responseIKEMessage.Payloads.Reset() + responseIKEPayload.Reset() var identifier uint8 var err error @@ -1364,8 +1314,10 @@ func (s *Server) HandleSendEAPSuccessMsg(ikeEvt n3iwf_context.IkeEvt) { responseIKEPayload.BuildEAPSuccess(identifier) - responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, - responseIKEPayload...) + // Build IKE message + responseIKEMessage := ike_message.NewMessage(ikeSecurityAssociation.RemoteSPI, + ikeSecurityAssociation.LocalSPI, ike_message.IKE_AUTH, true, false, + ikeSecurityAssociation.InitiatorMessageID, responseIKEPayload) // Send IKE message to UE err = SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, @@ -1391,14 +1343,8 @@ func (s *Server) HandleSendEAPNASMsg(ikeEvt n3iwf_context.IkeEvt) { n3iwfCtx := s.Context() ikeSecurityAssociation, _ := n3iwfCtx.IKESALoad(localSPI) - responseIKEMessage := new(ike_message.IKEMessage) var responseIKEPayload ike_message.IKEPayloadContainer - - // Build IKE message - responseIKEMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, - ikeSecurityAssociation.LocalSPI, ike_message.IKE_AUTH, ike_message.ResponseBitCheck, - ikeSecurityAssociation.InitiatorMessageID) - responseIKEMessage.Payloads.Reset() + responseIKEPayload.Reset() var identifier uint8 var err error @@ -1420,8 +1366,10 @@ func (s *Server) HandleSendEAPNASMsg(ikeEvt n3iwf_context.IkeEvt) { return } - responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, - responseIKEPayload...) + // Build IKE message + responseIKEMessage := ike_message.NewMessage(ikeSecurityAssociation.RemoteSPI, + ikeSecurityAssociation.LocalSPI, ike_message.IKE_AUTH, true, false, + ikeSecurityAssociation.InitiatorMessageID, responseIKEPayload) // Send IKE message to UE err = SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, @@ -1574,18 +1522,13 @@ func (s *Server) CreatePDUSessionChildSA( pduSessionID := pduSession.Id // Send CREATE_CHILD_SA to UE - ikeMessage := new(ike_message.IKEMessage) - var ikePayload ike_message.IKEPayloadContainer + var responseIKEPayload ike_message.IKEPayloadContainer errStr := n3iwf_context.ErrNil - // Build IKE message - ikeMessage.BuildIKEHeader(ikeSecurityAssociation.RemoteSPI, - ikeSecurityAssociation.LocalSPI, ike_message.CREATE_CHILD_SA, - 0, ikeSecurityAssociation.ResponderMessageID) - ikeMessage.Payloads.Reset() + responseIKEPayload.Reset() // Build SA - requestSA := ikePayload.BuildSecurityAssociation() + requestSA := responseIKEPayload.BuildSecurityAssociation() // Allocate SPI var spi uint32 @@ -1633,7 +1576,7 @@ func (s *Server) CreatePDUSessionChildSA( proposal.ExtendedSequenceNumbers.BuildTransform( ike_message.TypeExtendedSequenceNumbers, ike_message.ESN_DISABLE, nil, nil, nil) - ikeUe.CreateHalfChildSA(ikeMessage.MessageID, spi, pduSessionID) + ikeUe.CreateHalfChildSA(ikeSecurityAssociation.ResponderMessageID, spi, pduSessionID) // Build Nonce nonceDataBigInt, errGen := ike_security.GenerateRandomNumber() @@ -1642,21 +1585,21 @@ func (s *Server) CreatePDUSessionChildSA( return } nonceData := nonceDataBigInt.Bytes() - ikePayload.BuildNonce(nonceData) + responseIKEPayload.BuildNonce(nonceData) // Store nonce into context ikeSecurityAssociation.ConcatenatedNonce = nonceData // TSi n3iwfIPAddr := net.ParseIP(ipsecGwAddr) - tsi := ikePayload.BuildTrafficSelectorInitiator() + tsi := responseIKEPayload.BuildTrafficSelectorInitiator() tsi.TrafficSelectors.BuildIndividualTrafficSelector( ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, 0, 65535, n3iwfIPAddr.To4(), n3iwfIPAddr.To4()) // TSr ueIPAddr := ikeUe.IPSecInnerIP - tsr := ikePayload.BuildTrafficSelectorResponder() + tsr := responseIKEPayload.BuildTrafficSelectorResponder() tsr.TrafficSelectors.BuildIndividualTrafficSelector( ike_message.TS_IPV4_ADDR_RANGE, ike_message.IPProtocolAll, 0, 65535, ueIPAddr.To4(), ueIPAddr.To4()) @@ -1666,18 +1609,22 @@ func (s *Server) CreatePDUSessionChildSA( break } // Notify-Qos - err = ikePayload.BuildNotify5G_QOS_INFO(uint8(pduSessionID), pduSession.QFIList, true, false, 0) + err = responseIKEPayload.BuildNotify5G_QOS_INFO(uint8(pduSessionID), pduSession.QFIList, true, false, 0) if err != nil { ikeLog.Errorf("CreatePDUSessionChildSA error : %v", err) break } // Notify-UP_IP_ADDRESS - ikePayload.BuildNotifyUP_IP4_ADDRESS(ipsecGwAddr) + responseIKEPayload.BuildNotifyUP_IP4_ADDRESS(ipsecGwAddr) temporaryPDUSessionSetupData.Index++ - ikeMessage.Payloads = append(ikeMessage.Payloads, ikePayload...) + // Build IKE message + ikeMessage := ike_message.NewMessage(ikeSecurityAssociation.RemoteSPI, ikeSecurityAssociation.LocalSPI, + ike_message.CREATE_CHILD_SA, false, false, ikeSecurityAssociation.ResponderMessageID, + responseIKEPayload) + err = SendIKEMessageToUE(ikeSecurityAssociation.IKEConnection.Conn, ikeSecurityAssociation.IKEConnection.N3IWFAddr, ikeSecurityAssociation.IKEConnection.UEAddr, ikeMessage, @@ -1729,8 +1676,8 @@ func (s *Server) StartDPD(ikeUe *n3iwf_context.N3IWFIkeUe) { return case <-timer.C: var payload *ike_message.IKEPayloadContainer - SendUEInformationExchange(ikeSA, payload, 0, ikeSA.ResponderMessageID, - ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.UEAddr, + SendUEInformationExchange(ikeSA, ikeSA.IKESAKey, payload, false, false, + ikeSA.ResponderMessageID, ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.UEAddr, ikeUe.IKEConnection.N3IWFAddr) var DPDReqRetransTime time.Duration = 2 * time.Second // TODO: make it configurable @@ -1844,6 +1791,55 @@ func (s *Server) buildNATDetectNotifPayload( return nil } +func (s *Server) handleDeletePayload(payload *ike_message.Delete, isResponse bool, + ikeSecurityAssociation *n3iwf_context.IKESecurityAssociation) ( + *ike_message.IKEPayloadContainer, error, +) { + var evt n3iwf_context.NgapEvt + var err error + n3iwfCtx := s.Context() + n3iwfIke := ikeSecurityAssociation.IkeUE + responseIKEPayload := new(ike_message.IKEPayloadContainer) + + ranNgapId, ok := n3iwfCtx.NgapIdLoad(n3iwfIke.N3IWFIKESecurityAssociation.LocalSPI) + if !ok { + return nil, errors.Errorf("handleDeletePayload: Cannot get RanNgapId from SPI : %+v", + n3iwfIke.N3IWFIKESecurityAssociation.LocalSPI) + } + + switch payload.ProtocolID { + case ike_message.TypeIKE: + if !isResponse { + err = n3iwfIke.Remove() + if err != nil { + return nil, errors.Wrapf(err, "handleDeletePayload: Delete IkeUe Context error") + } + } + + evt = n3iwf_context.NewSendUEContextReleaseEvt(ranNgapId) + case ike_message.TypeESP: + var deletSPIs []uint32 + var deletPduIds []int64 + if !isResponse { + deletSPIs, deletPduIds, err = s.deleteChildSAFromSPIList(n3iwfIke, payload.SPIs) + if err != nil { + return nil, errors.Wrapf(err, "handleDeletePayload") + } + responseIKEPayload.BuildDeletePayload(ike_message.TypeESP, 4, uint16(len(deletSPIs)), deletSPIs) + } + + evt = n3iwf_context.NewendPDUSessionResourceReleaseEvt(ranNgapId, deletPduIds) + default: + return nil, errors.Errorf("Get Protocol ID %d in Informational delete payload, "+ + "this payload will not be handled by IKE handler", payload.ProtocolID) + } + err = s.SendNgapEvt(evt) + if err != nil { + return nil, errors.Wrapf(err, "handleDeletePayload: SendNgapEvt failed") + } + return responseIKEPayload, nil +} + func isTransformKernelSupported( transformType uint8, transformID uint16, @@ -2084,3 +2080,38 @@ func SelectProposal(proposals ike_message.ProposalContainer) ike_message.Proposa } return chooseProposal } + +func (s *Server) deleteChildSAFromSPIList(ikeUe *n3iwf_context.N3IWFIkeUe, spiList []uint32) ( + []uint32, []int64, error, +) { + ikeLog := logger.IKELog + var deleteSPIs []uint32 + var deletePduIds []int64 + + for _, spi := range spiList { + found := false + for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { + if childSA.OutboundSPI == spi { + found = true + deleteSPIs = append(deleteSPIs, childSA.InboundSPI) + + if len(childSA.PDUSessionIds) == 0 { + return nil, nil, errors.Errorf("Child_SA SPI: 0x%08x doesn't have PDU Session ID", + spi) + } + deletePduIds = append(deletePduIds, childSA.PDUSessionIds[0]) + + err := ikeUe.DeleteChildSA(childSA) + if err != nil { + return nil, nil, errors.Wrapf(err, "DeleteChildSAFromSPIList") + } + break + } + } + if !found { + ikeLog.Warnf("deleteChildSAFromSPIList(): Get unknown Child_SA with SPI: 0x%08x", spi) + } + } + + return deleteSPIs, deletePduIds, nil +} diff --git a/internal/ike/send.go b/internal/ike/send.go index 7e72187b..387cb516 100644 --- a/internal/ike/send.go +++ b/internal/ike/send.go @@ -1,7 +1,6 @@ package ike import ( - "encoding/binary" "math" "net" @@ -18,7 +17,7 @@ import ( func SendIKEMessageToUE( udpConn *net.UDPConn, srcAddr, dstAddr *net.UDPAddr, - message *message.IKEMessage, + message *ike_message.IKEMessage, ikeSAKey *security.IKESAKey, ) error { ikeLog := logger.IKELog @@ -49,21 +48,19 @@ func SendIKEMessageToUE( func SendUEInformationExchange( ikeSA *n3iwf_context.IKESecurityAssociation, - payload *message.IKEPayloadContainer, ike_flag uint8, messageID uint32, - conn *net.UDPConn, ueAddr *net.UDPAddr, n3iwfAddr *net.UDPAddr, + ikeSAKey *security.IKESAKey, + payload *ike_message.IKEPayloadContainer, initiator bool, + response bool, messageID uint32, conn *net.UDPConn, + ueAddr *net.UDPAddr, n3iwfAddr *net.UDPAddr, ) { ikeLog := logger.IKELog - responseIKEMessage := new(message.IKEMessage) - var ikeSAKey *security.IKESAKey + // Build IKE message - responseIKEMessage.BuildIKEHeader( - ikeSA.RemoteSPI, ikeSA.LocalSPI, - message.INFORMATIONAL, ike_flag, - messageID) + responseIKEMessage := ike_message.NewMessage(ikeSA.RemoteSPI, ikeSA.LocalSPI, + ike_message.INFORMATIONAL, response, initiator, messageID, nil) if payload != nil && len(*payload) > 0 { responseIKEMessage.Payloads = append(responseIKEMessage.Payloads, *payload...) - ikeSAKey = ikeSA.IKESAKey } err := SendIKEMessageToUE(conn, n3iwfAddr, ueAddr, responseIKEMessage, ikeSAKey) @@ -83,9 +80,9 @@ func SendIKEDeleteRequest(n3iwfCtx *n3iwf_context.N3IWFContext, localSPI uint64) var deletePayload message.IKEPayloadContainer deletePayload.BuildDeletePayload(message.TypeIKE, 0, 0, nil) - SendUEInformationExchange(ikeUe.N3IWFIKESecurityAssociation, &deletePayload, 0, - ikeUe.N3IWFIKESecurityAssociation.ResponderMessageID, ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.UEAddr, - ikeUe.IKEConnection.N3IWFAddr) + SendUEInformationExchange(ikeUe.N3IWFIKESecurityAssociation, ikeUe.N3IWFIKESecurityAssociation.IKESAKey, + &deletePayload, false, false, ikeUe.N3IWFIKESecurityAssociation.ResponderMessageID, + ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.UEAddr, ikeUe.IKEConnection.N3IWFAddr) } func SendChildSADeleteRequest( @@ -93,19 +90,17 @@ func SendChildSADeleteRequest( relaseList []int64, ) { ikeLog := logger.IKELog - var deleteSPIs []byte + var deleteSPIs []uint32 spiLen := uint16(0) for _, releaseItem := range relaseList { for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { if childSA.PDUSessionIds[0] == releaseItem { - spiByte := make([]byte, 4) spi := childSA.XfrmStateList[0].Spi if spi < 0 || spi > math.MaxUint32 { ikeLog.Errorf("SendChildSADeleteRequest spi out of uint32 range : %d", spi) return } - binary.BigEndian.PutUint32(spiByte, uint32(spi)) - deleteSPIs = append(deleteSPIs, spiByte...) + deleteSPIs = append(deleteSPIs, uint32(spi)) spiLen += 1 err := ikeUe.DeleteChildSA(childSA) if err != nil { @@ -118,7 +113,7 @@ func SendChildSADeleteRequest( var deletePayload message.IKEPayloadContainer deletePayload.BuildDeletePayload(message.TypeESP, 4, spiLen, deleteSPIs) - SendUEInformationExchange(ikeUe.N3IWFIKESecurityAssociation, &deletePayload, 0, - ikeUe.N3IWFIKESecurityAssociation.ResponderMessageID, ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.UEAddr, - ikeUe.IKEConnection.N3IWFAddr) + SendUEInformationExchange(ikeUe.N3IWFIKESecurityAssociation, ikeUe.N3IWFIKESecurityAssociation.IKESAKey, + &deletePayload, false, false, ikeUe.N3IWFIKESecurityAssociation.ResponderMessageID, + ikeUe.IKEConnection.Conn, ikeUe.IKEConnection.UEAddr, ikeUe.IKEConnection.N3IWFAddr) } diff --git a/internal/ike/server.go b/internal/ike/server.go index 86616b0f..bc977914 100644 --- a/internal/ike/server.go +++ b/internal/ike/server.go @@ -261,7 +261,7 @@ func (s *Server) checkIKEMessage( var err error // parse IKE header and setup IKE context - ikeHeader, err = ike_message.ParseIkeHeader(msg) + ikeHeader, err = ike_message.ParseHeader(msg) if err != nil { return nil, nil, errors.Wrapf(err, "IKE msg decode header") } @@ -270,11 +270,11 @@ func (s *Server) checkIKEMessage( if ikeHeader.MajorVersion > 2 { // send INFORMATIONAL type message with INVALID_MAJOR_VERSION Notify payload // For response or needed data - responseIKEMessage := new(ike_message.IKEMessage) - responseIKEMessage.BuildIKEHeader(ikeHeader.InitiatorSPI, ikeHeader.ResponderSPI, - ike_message.INFORMATIONAL, ike_message.ResponseBitCheck, ikeHeader.MessageID) - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, + payload := new(ike_message.IKEPayloadContainer) + payload.BuildNotification(ike_message.TypeNone, ike_message.INVALID_MAJOR_VERSION, nil, nil) + responseIKEMessage := ike_message.NewMessage(ikeHeader.InitiatorSPI, ikeHeader.ResponderSPI, + ike_message.INFORMATIONAL, true, false, ikeHeader.MessageID, *payload) err = SendIKEMessageToUE(udpConn, localAddr, remoteAddr, responseIKEMessage, nil) if err != nil { @@ -297,12 +297,11 @@ func (s *Server) checkIKEMessage( ikeSA, ok = n3iwfCtx.IKESALoad(localSPI) if !ok { - responseIKEMessage := new(ike_message.IKEMessage) + payload := new(ike_message.IKEPayloadContainer) // send INFORMATIONAL type message with INVALID_IKE_SPI Notify payload ( OUTSIDE IKE SA ) - responseIKEMessage.BuildIKEHeader(ikeHeader.InitiatorSPI, 0, ike_message.INFORMATIONAL, - ike_message.ResponseBitCheck, ikeHeader.MessageID) - responseIKEMessage.Payloads.Reset() - responseIKEMessage.Payloads.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) + payload.BuildNotification(ike_message.TypeNone, ike_message.INVALID_IKE_SPI, nil, nil) + responseIKEMessage := ike_message.NewMessage(ikeHeader.InitiatorSPI, ikeHeader.ResponderSPI, + ike_message.INFORMATIONAL, true, false, ikeHeader.MessageID, *payload) err = SendIKEMessageToUE(udpConn, localAddr, remoteAddr, responseIKEMessage, nil) if err != nil { diff --git a/internal/ike/server_test.go b/internal/ike/server_test.go index 19b79b60..fd34c75a 100644 --- a/internal/ike/server_test.go +++ b/internal/ike/server_test.go @@ -68,10 +68,8 @@ func NewTestCfg() *factory.Config { func TestHandleNattMsg(t *testing.T) { initiatorSPI := uint64(0x123) - ikeMessage := new(ike_message.IKEMessage) - ikeMessage.BuildIKEHeader(initiatorSPI, 0, - ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, 0) - + ikeMessage := ike_message.NewMessage(initiatorSPI, 0, ike_message.IKE_SA_INIT, + true, false, 0, nil) pkt, err := ikeMessage.Encode() require.NoError(t, err) @@ -172,12 +170,12 @@ func TestCheckIKEMessage(t *testing.T) { require.NoError(t, err) initiatorSPI := uint64(0x123) - ikeMsg := new(ike_message.IKEMessage) nonceData := []byte("randomNonce") - ikeMsg.BuildIKEHeader(initiatorSPI, 0, - ike_message.IKE_SA_INIT, ike_message.ResponseBitCheck, 0) - ikeMsg.Payloads.Reset() - ikeMsg.Payloads.BuildNonce(nonceData) + payload := new(ike_message.IKEPayloadContainer) + payload.BuildNonce(nonceData) + + ikeMsg := ike_message.NewMessage(initiatorSPI, 0, ike_message.IKE_SA_INIT, + true, false, 0, *payload) tests := []struct { name string @@ -196,7 +194,7 @@ func TestCheckIKEMessage(t *testing.T) { IKEHeader: &ike_message.IKEHeader{ InitiatorSPI: initiatorSPI, ExchangeType: ike_message.IKE_SA_INIT, - Flags: ike_message.ResponseBitCheck, + Flags: 0, MajorVersion: 3, MinorVersion: 0, }, diff --git a/internal/ngap/handler.go b/internal/ngap/handler.go index 1b967d38..4cca7c78 100644 --- a/internal/ngap/handler.go +++ b/internal/ngap/handler.go @@ -1156,19 +1156,14 @@ func (s *Server) HandleUEContextReleaseCommand( printAndGetCause(cause) } - ranUeCtx := ranUe.GetSharedCtx() + ranUe.GetSharedCtx().UeCtxRelState = n3iwf_context.UeCtxRelStateOngoing - localSPI, ok := n3iwfCtx.IkeSpiLoad(ranUeCtx.RanUeNgapId) - if !ok { - ngapLog.Errorf("Cannot get SPI from RanUeNgapID : %+v", ranUeCtx.RanUeNgapId) - return - } + message.SendUEContextReleaseComplete(ranUe, nil) - err := s.SendIkeEvt(n3iwf_context.NewIKEDeleteRequestEvt(localSPI)) + err := s.releaseIkeUeAndRanUe(ranUe) if err != nil { - ngapLog.Errorf("SendIkeEvt[IKE Delete Req] failed: %+v", err) + ngapLog.Warnf("HandleUEContextReleaseCommand(): %v", err) } - // TODO: release pdu session and gtp info for ue } func (s *Server) releaseIkeUeAndRanUe(ranUe n3iwf_context.RanUe) error { @@ -2142,6 +2137,7 @@ func (s *Server) HandlePDUSessionResourceReleaseCommand( ngapLog.Errorf("Cannot get SPI from RanUeNgapID : %+v", rANUENGAPID.Value) return } + ranUe.GetSharedCtx().PduSessResRelState = n3iwf_context.PduSessResRelStateOngoing err := s.SendIkeEvt(n3iwf_context.NewSendChildSADeleteRequestEvt(localSPI, releaseIdList)) if err != nil { @@ -2830,10 +2826,14 @@ func (s *Server) HandleEvent(ngapEvent n3iwf_context.NgapEvt) { s.HandleStartTCPSignalNASMsg(ngapEvent) case n3iwf_context.NASTCPConnEstablishedComplete: s.HandleNASTCPConnEstablishedComplete(ngapEvent) + case n3iwf_context.SendUEContextRelease: + s.HandleSendSendUEContextRelease(ngapEvent) case n3iwf_context.SendUEContextReleaseRequest: s.HandleSendUEContextReleaseRequest(ngapEvent) case n3iwf_context.SendUEContextReleaseComplete: s.HandleSendUEContextReleaseComplete(ngapEvent) + case n3iwf_context.SendPDUSessionResourceRelease: + s.HandleSendSendPDUSessionResourceRelease(ngapEvent) case n3iwf_context.SendPDUSessionResourceReleaseResponse: s.HandleSendPDUSessionResourceReleaseRes(ngapEvent) case n3iwf_context.GetNGAPContext: @@ -3289,3 +3289,59 @@ func (s *Server) HandleSendInitialContextSetupResponse( message.SendInitialContextSetupResponse(ranUe, evt.ResponseList, evt.FailedList, evt.CriticalityDiagnostics) } + +func (s *Server) HandleSendSendUEContextRelease( + ngapEvent n3iwf_context.NgapEvt, +) { + ngapLog := logger.NgapLog + ngapLog.Tracef("Handle SendSendUEContextRelease Event") + + evt := ngapEvent.(*n3iwf_context.SendUEContextReleaseEvt) + ranUeNgapId := evt.RanUeNgapId + n3iwfCtx := s.Context() + ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) + if !ok { + ngapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + if ranUe.GetSharedCtx().UeCtxRelState { + if err := ranUe.Remove(); err != nil { + ngapLog.Errorf("Delete RanUe Context error : %v", err) + } + message.SendUEContextReleaseComplete(ranUe, nil) + ranUe.GetSharedCtx().UeCtxRelState = n3iwf_context.UeCtxRelStateNone + } else { + cause := message.BuildCause(ngapType.CausePresentRadioNetwork, + ngapType.CauseRadioNetworkPresentRadioConnectionWithUeLost) + message.SendUEContextReleaseRequest(ranUe, *cause) + ranUe.GetSharedCtx().UeCtxRelState = n3iwf_context.UeCtxRelStateOngoing + } +} + +func (s *Server) HandleSendSendPDUSessionResourceRelease( + ngapEvent n3iwf_context.NgapEvt, +) { + ngapLog := logger.NgapLog + ngapLog.Tracef("Handle SendSendPDUSessionResourceRelease Event") + + evt := ngapEvent.(*n3iwf_context.SendPDUSessionResourceReleaseEvt) + ranUeNgapId := evt.RanUeNgapId + deletPduIds := evt.DeletPduIds + n3iwfCtx := s.Context() + ranUe, ok := n3iwfCtx.RanUePoolLoad(ranUeNgapId) + if !ok { + ngapLog.Errorf("Cannot get RanUE from ranUeNgapId : %+v", ranUeNgapId) + return + } + + if ranUe.GetSharedCtx().PduSessResRelState { + message.SendPDUSessionResourceReleaseResponse(ranUe, ranUe.GetSharedCtx().PduSessionReleaseList, nil) + ranUe.GetSharedCtx().PduSessResRelState = n3iwf_context.PduSessResRelStateNone + } else { + for _, id := range deletPduIds { + ranUe.GetSharedCtx().DeletePDUSession(id) + } + ranUe.GetSharedCtx().PduSessResRelState = n3iwf_context.PduSessResRelStateOngoing + } +} diff --git a/internal/ngap/message/build.go b/internal/ngap/message/build.go index 0f5374c2..1e10561c 100644 --- a/internal/ngap/message/build.go +++ b/internal/ngap/message/build.go @@ -631,22 +631,24 @@ func BuildUEContextReleaseRequest(ranUe n3iwf_context.RanUe, cause ngapType.Caus uEContextReleaseRequestIEs.List = append(uEContextReleaseRequestIEs.List, ie) // PDU Session Resource List - ie = ngapType.UEContextReleaseRequestIEs{} - ie.Id.Value = ngapType.ProtocolIEIDPDUSessionResourceListCxtRelReq - ie.Criticality.Value = ngapType.CriticalityPresentReject - ie.Value.Present = ngapType.UEContextReleaseRequestIEsPresentPDUSessionResourceListCxtRelReq - ie.Value.PDUSessionResourceListCxtRelReq = new(ngapType.PDUSessionResourceListCxtRelReq) + if len(ranUeCtx.PduSessionList) > 0 { + ie = ngapType.UEContextReleaseRequestIEs{} + ie.Id.Value = ngapType.ProtocolIEIDPDUSessionResourceListCxtRelReq + ie.Criticality.Value = ngapType.CriticalityPresentReject + ie.Value.Present = ngapType.UEContextReleaseRequestIEsPresentPDUSessionResourceListCxtRelReq + ie.Value.PDUSessionResourceListCxtRelReq = new(ngapType.PDUSessionResourceListCxtRelReq) - pDUSessionResourceListCxtRelReq := ie.Value.PDUSessionResourceListCxtRelReq + pDUSessionResourceListCxtRelReq := ie.Value.PDUSessionResourceListCxtRelReq - // PDU Session Resource Item in PDU session Resource List - for _, pduSession := range ranUeCtx.PduSessionList { - pDUSessionResourceItem := ngapType.PDUSessionResourceItemCxtRelReq{} - pDUSessionResourceItem.PDUSessionID.Value = pduSession.Id - pDUSessionResourceListCxtRelReq.List = append(pDUSessionResourceListCxtRelReq.List, - pDUSessionResourceItem) + // PDU Session Resource Item in PDU session Resource List + for _, pduSession := range ranUeCtx.PduSessionList { + pDUSessionResourceItem := ngapType.PDUSessionResourceItemCxtRelReq{} + pDUSessionResourceItem.PDUSessionID.Value = pduSession.Id + pDUSessionResourceListCxtRelReq.List = append(pDUSessionResourceListCxtRelReq.List, + pDUSessionResourceItem) + } + uEContextReleaseRequestIEs.List = append(uEContextReleaseRequestIEs.List, ie) } - uEContextReleaseRequestIEs.List = append(uEContextReleaseRequestIEs.List, ie) // Cause ie = ngapType.UEContextReleaseRequestIEs{} diff --git a/internal/nwuup/server.go b/internal/nwuup/server.go index ec8c37a4..fbcc59ef 100644 --- a/internal/nwuup/server.go +++ b/internal/nwuup/server.go @@ -309,6 +309,10 @@ func (s *Server) forwardDL(packet gtpQoSMsg.QoSTPDUPacket) { break } } + if cm == nil { + nwuupLog.Warnf("forwardDL(): Cannot match TEID(%d) to ChildSA", pktTEID) + return + } var ( qfi uint8 From 7d4c6f2850ea96821b577f8e5032b5e58ce1ab73 Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Thu, 17 Oct 2024 05:08:59 +0000 Subject: [PATCH 31/33] Fix IPSec allocate error --- go.mod | 2 +- go.sum | 4 +- internal/context/context.go | 59 +++++++---------- internal/context/context_test.go | 106 +++++++++++++++++++++++++++++++ internal/context/ikeue.go | 5 ++ internal/ike/handler.go | 13 ++-- internal/ike/handler_test.go | 7 ++ internal/ike/server.go | 7 +- pkg/service/init.go | 4 +- 9 files changed, 161 insertions(+), 46 deletions(-) create mode 100644 internal/context/context_test.go diff --git a/go.mod b/go.mod index 05e468a6..b7fa5eae 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/free5gc/ike v1.1.1-0.20241014015325-083f89768f43 github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74 github.com/free5gc/sctp v1.0.1 - github.com/free5gc/util v1.0.7-0.20240713162917-350ee8f4af4c + github.com/free5gc/util v1.0.7-0.20241016064137-5698cc626593 github.com/gin-contrib/pprof v1.5.0 github.com/gin-gonic/gin v1.10.0 github.com/google/gopacket v1.1.19 diff --git a/go.sum b/go.sum index f756cb5b..c40e4166 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/free5gc/openapi v1.0.9-0.20240503143645-eac9f06c2f6b h1:+VcgZq+3apB6X github.com/free5gc/openapi v1.0.9-0.20240503143645-eac9f06c2f6b/go.mod h1:0qRW+H1/Nyzw5tjjvyp+90m+2SOZZefGQC9QV8iPwu8= github.com/free5gc/sctp v1.0.1 h1:g8WDO97r8B9ubkT5Hyk9b4I1fZUOii9Z39gQ2eRaASo= github.com/free5gc/sctp v1.0.1/go.mod h1:7QXfRWCmlkBGD0EIu3qL5o71bslfIakydz4h2QDZdjQ= -github.com/free5gc/util v1.0.7-0.20240713162917-350ee8f4af4c h1:baToZn4hxGKoCm3BWwYlRuZoCQ74cMZUJzg9BVLEdE0= -github.com/free5gc/util v1.0.7-0.20240713162917-350ee8f4af4c/go.mod h1:IHKIBd4OM9rwSJ0fG/hv6pXbVC+Eu4Lcaq++BWkfSsY= +github.com/free5gc/util v1.0.7-0.20241016064137-5698cc626593 h1:Wp32mLckyP25feOmwHBTS32pSkIAjuZgq8iP7njbe/k= +github.com/free5gc/util v1.0.7-0.20241016064137-5698cc626593/go.mod h1:IHKIBd4OM9rwSJ0fG/hv6pXbVC+Eu4Lcaq++BWkfSsY= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gin-contrib/pprof v1.5.0 h1:E/Oy7g+kNw94KfdCy3bZxQFtyDnAX2V7axRS7sNYVrU= diff --git a/internal/context/context.go b/internal/context/context.go index f23894ef..40310865 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -24,6 +24,7 @@ import ( "github.com/free5gc/ngap/ngapType" "github.com/free5gc/sctp" "github.com/free5gc/util/idgenerator" + "github.com/free5gc/util/ippool" ) type n3iwf interface { @@ -56,7 +57,8 @@ type N3IWFContext struct { N3IWFCertificate []byte N3IWFPrivateKey *rsa.PrivateKey - UeIPRange *net.IPNet + IPSecInnerIPPool *ippool.IPPool + // TODO: [TWIF] TwifUe may has its own IP address pool /* XFRM interface */ XfrmIfaces sync.Map // map[uint32]*netlink.Link, XfrmIfaceId as key @@ -119,11 +121,11 @@ func NewContext(n3iwf n3iwf) (*N3IWFContext, error) { n.N3IWFCertificate = block.Bytes // UE IP address range - _, ueIPRange, err := net.ParseCIDR(cfg.GetUEIPAddrRange()) + ueIPPool, err := ippool.NewIPPool(cfg.GetUEIPAddrRange()) if err != nil { - return nil, errors.Errorf("Parse CIDR failed: %+v", err) + return nil, errors.Errorf("NewContext(): %+v", err) } - n.UeIPRange = ueIPRange + n.IPSecInnerIPPool = ueIPPool // XFRM related ikeBindIfaceName, err := getInterfaceName(cfg.GetIKEBindAddr()) @@ -382,26 +384,30 @@ func (c *N3IWFContext) GTPConnectionWithUPFStore(upfAddr string, conn *gtpv1.UPl c.GTPConnectionWithUPF.Store(upfAddr, conn) } -func (c *N3IWFContext) NewInternalUEIPAddr(ikeUe *N3IWFIkeUe) net.IP { +func (c *N3IWFContext) NewIPsecInnerUEIP(ikeUe *N3IWFIkeUe) (net.IP, error) { var ueIPAddr net.IP - + var err error cfg := c.Config() ipsecGwAddr := cfg.GetIPSecGatewayAddr() - // TODO: Check number of allocated IP to detect running out of IPs + for { - ueIPAddr = generateRandomIPinRange(c.UeIPRange) - if ueIPAddr != nil { - if ueIPAddr.String() == ipsecGwAddr { - continue - } - _, ok := c.AllocatedUEIPAddress.LoadOrStore(ueIPAddr.String(), ikeUe) - if !ok { - break - } + ueIPAddr, err = c.IPSecInnerIPPool.Allocate(nil) + if err != nil { + return nil, errors.Wrapf(err, "NewIPsecInnerUEIP()") + } + if ueIPAddr.String() == ipsecGwAddr { + continue + } + _, ok := c.AllocatedUEIPAddress.LoadOrStore(ueIPAddr.String(), ikeUe) + if ok { + logger.CtxLog.Warnf("NewIPsecInnerUEIP(): IP(%v) is used by other IkeUE", + ueIPAddr.String()) + } else { + break } } - return ueIPAddr + return ueIPAddr, nil } func (c *N3IWFContext) DeleteInternalUEIPAddr(ipAddr string) { @@ -475,22 +481,3 @@ func (c *N3IWFContext) AMFSelection( } return availableAMF } - -func generateRandomIPinRange(subnet *net.IPNet) net.IP { - ipAddr := make([]byte, 4) - randomNumber := make([]byte, 4) - - _, err := rand.Read(randomNumber) - if err != nil { - logger.CtxLog.Errorf("Generate random number for IP address failed: %+v", err) - return nil - } - - // TODO: elimenate network name, gateway, and broadcast - for i := 0; i < 4; i++ { - alter := randomNumber[i] & (subnet.Mask[i] ^ 255) - ipAddr[i] = subnet.IP[i] + alter - } - - return net.IPv4(ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]) -} diff --git a/internal/context/context_test.go b/internal/context/context_test.go new file mode 100644 index 00000000..da321d30 --- /dev/null +++ b/internal/context/context_test.go @@ -0,0 +1,106 @@ +package context_test + +import ( + "context" + "net" + "sync" + "testing" + + "github.com/stretchr/testify/require" + + n3iwf_context "github.com/free5gc/n3iwf/internal/context" + "github.com/free5gc/n3iwf/pkg/factory" + "github.com/free5gc/util/ippool" +) + +type n3iwfTestApp struct { + cfg *factory.Config + n3iwfCtx *n3iwf_context.N3IWFContext + ctx context.Context + cancel context.CancelFunc + wg *sync.WaitGroup +} + +func (a *n3iwfTestApp) Config() *factory.Config { + return a.cfg +} + +func (a *n3iwfTestApp) Context() *n3iwf_context.N3IWFContext { + return a.n3iwfCtx +} + +func (a *n3iwfTestApp) CancelContext() context.Context { + return a.ctx +} + +func NewN3iwfTestApp(cfg *factory.Config) (*n3iwfTestApp, error) { + var err error + ctx, cancel := context.WithCancel(context.Background()) + + n3iwfApp := &n3iwfTestApp{ + cfg: cfg, + ctx: ctx, + cancel: cancel, + wg: &sync.WaitGroup{}, + } + + n3iwfApp.n3iwfCtx, err = n3iwf_context.NewTestContext(n3iwfApp) + if err != nil { + return nil, err + } + return n3iwfApp, err +} + +func NewTestCfg() *factory.Config { + return &factory.Config{ + Configuration: &factory.Configuration{ + IPSecGatewayAddr: "10.0.0.1", + UEIPAddressRange: "10.0.0.0/24", + }, + } +} + +func TestNewInternalUEIPAddr(t *testing.T) { + cfg := NewTestCfg() + var app *n3iwfTestApp + var err error + var ip, invalidIP, invalidIP2 net.IP + + app, err = NewN3iwfTestApp(cfg) + require.NoError(t, err) + + n3iwfCtx := app.n3iwfCtx + + invalidIP = net.ParseIP("10.0.0.0") + invalidIP2 = net.ParseIP("10.0.0.255") + n3iwfCtx.IPSecInnerIPPool, err = ippool.NewIPPool("10.0.0.0/24") + require.NoError(t, err) + + for i := 1; i <= 253; i++ { + ip, err = n3iwfCtx.NewIPsecInnerUEIP(&n3iwf_context.N3IWFIkeUe{}) + require.NoError(t, err) + require.NotEqual(t, cfg.GetIPSecGatewayAddr(), ip.String()) + require.NotEqual(t, ip, invalidIP) + require.NotEqual(t, ip, invalidIP2) + } + + _, err = n3iwfCtx.NewIPsecInnerUEIP(&n3iwf_context.N3IWFIkeUe{}) + require.Error(t, err) + + n3iwfCtx.AllocatedUEIPAddress = sync.Map{} + + n3iwfCtx.IPSecInnerIPPool, err = ippool.NewIPPool("10.0.0.0/16") + require.NoError(t, err) + + invalidIP2 = net.ParseIP("10.0.255.255") + for i := 1; i <= 65533; i++ { + ip, err = n3iwfCtx.NewIPsecInnerUEIP(&n3iwf_context.N3IWFIkeUe{}) + require.NoError(t, err) + require.NotEqual(t, cfg.GetIPSecGatewayAddr(), ip.String()) + require.NotEqual(t, ip, invalidIP) + require.NotEqual(t, ip, invalidIP2) + } + + _, err = n3iwfCtx.NewIPsecInnerUEIP(&n3iwf_context.N3IWFIkeUe{}) + require.Error(t, err) +} diff --git a/internal/context/ikeue.go b/internal/context/ikeue.go index 9c64f890..ecdb262d 100644 --- a/internal/context/ikeue.go +++ b/internal/context/ikeue.go @@ -217,6 +217,11 @@ func (ikeUe *N3IWFIkeUe) Remove() error { n3iwfCtx.DeleteIKESecurityAssociation(ikeUe.N3IWFIKESecurityAssociation.LocalSPI) n3iwfCtx.DeleteInternalUEIPAddr(ikeUe.IPSecInnerIP.String()) + err := n3iwfCtx.IPSecInnerIPPool.Release(net.ParseIP(ikeUe.IPSecInnerIP.String()).To4()) + if err != nil { + return errors.Wrapf(err, "N3IWFIkeUe Remove()") + } + for _, childSA := range ikeUe.N3IWFChildSecurityAssociation { if err := ikeUe.DeleteChildSA(childSA); err != nil { return err diff --git a/internal/ike/handler.go b/internal/ike/handler.go index 6e73d4a0..621d7aa1 100644 --- a/internal/ike/handler.go +++ b/internal/ike/handler.go @@ -737,7 +737,13 @@ func (s *Server) HandleIKEAUTH( var ueIPAddr, n3iwfIPAddr net.IP if addrRequest { // IP addresses (IPSec) - ueIPAddr = n3iwfCtx.NewInternalUEIPAddr(ikeUE).To4() + var ueIp net.IP + ueIp, err = n3iwfCtx.NewIPsecInnerUEIP(ikeUE) + if err != nil { + ikeLog.Errorf("HandleIKEAUTH(): %v", err) + return + } + ueIPAddr = ueIp.To4() n3iwfIPAddr = net.ParseIP(ipsecGwAddr).To4() responseConfiguration := responseIKEPayload.BuildConfiguration( @@ -745,7 +751,7 @@ func (s *Server) HandleIKEAUTH( responseConfiguration.ConfigurationAttribute.BuildConfigurationAttribute( ike_message.INTERNAL_IP4_ADDRESS, ueIPAddr) responseConfiguration.ConfigurationAttribute.BuildConfigurationAttribute( - ike_message.INTERNAL_IP4_NETMASK, n3iwfCtx.UeIPRange.Mask) + ike_message.INTERNAL_IP4_NETMASK, n3iwfCtx.IPSecInnerIPPool.IPSubnet.Mask) var ipsecInnerIPAddr *net.IPAddr ikeUE.IPSecInnerIP = ueIPAddr @@ -1072,7 +1078,7 @@ func (s *Server) continueCreateChildSA( // Setup XFRM interface for ipsec var linkIPSec netlink.Link n3iwfIPAddr := net.ParseIP(ipsecGwAddr).To4() - n3iwfIPAddrAndSubnet := net.IPNet{IP: n3iwfIPAddr, Mask: n3iwfCtx.UeIPRange.Mask} + n3iwfIPAddrAndSubnet := net.IPNet{IP: n3iwfIPAddr, Mask: n3iwfCtx.IPSecInnerIPPool.IPSubnet.Mask} newXfrmiId += cfg.GetXfrmIfaceId() + n3iwfCtx.XfrmIfaceIdOffsetForUP newXfrmiName := fmt.Sprintf("%s-%d", cfg.GetXfrmIfaceName(), newXfrmiId) @@ -1152,7 +1158,6 @@ func (s *Server) HandleInformational( switch ikePayload.Type() { case ike_message.TypeD: deletePayload = ikePayload.(*ike_message.Delete) - default: ikeLog.Warnf( "Get IKE payload (type %d) in Inoformational message, this payload will not be handled by IKE handler", diff --git a/internal/ike/handler_test.go b/internal/ike/handler_test.go index 164d8a87..1c1c6559 100644 --- a/internal/ike/handler_test.go +++ b/internal/ike/handler_test.go @@ -9,6 +9,7 @@ import ( ike_message "github.com/free5gc/ike/message" n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/pkg/factory" + "github.com/free5gc/util/ippool" ) func TestRemoveIkeUe(t *testing.T) { @@ -22,8 +23,14 @@ func TestRemoveIkeUe(t *testing.T) { ikeSA := n3iwfCtx.NewIKESecurityAssociation() ikeUe := n3iwfCtx.NewN3iwfIkeUe(ikeSA.LocalSPI) ikeUe.N3IWFIKESecurityAssociation = ikeSA + ikeUe.IPSecInnerIP = net.ParseIP("10.0.0.1") ikeSA.IsUseDPD = false + n3iwfCtx.IPSecInnerIPPool, err = ippool.NewIPPool("10.0.0.0/24") + require.NoError(t, err) + _, err = n3iwfCtx.IPSecInnerIPPool.Allocate(nil) + require.NoError(t, err) + ikeUe.CreateHalfChildSA(1, 123, 1) ikeAuth := &ike_message.SecurityAssociation{} diff --git a/internal/ike/server.go b/internal/ike/server.go index bc977914..fd5ee936 100644 --- a/internal/ike/server.go +++ b/internal/ike/server.go @@ -3,6 +3,7 @@ package ike import ( "bytes" "context" + "encoding/hex" "fmt" "net" "runtime/debug" @@ -173,6 +174,7 @@ func (s *Server) receiver( msgBuf := make([]byte, n) copy(msgBuf, buf) + ikeLog.Tracef("recv from port(%d):\n%s", localAddr.Port, hex.Dump(msgBuf)) // As specified in RFC 7296 section 3.1, the IKE message send from/to UDP port 4500 // should prepend a 4 bytes zero @@ -349,6 +351,9 @@ func constructPacketWithESP(srcIP, dstIP *net.UDPAddr, espPacket []byte) ([]byte } func handleESPPacket(srcIP, dstIP *net.UDPAddr, espPacket []byte) error { + ikeLog := logger.IKELog + ikeLog.Tracef("Handle ESPPacket") + fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW) if err != nil { return errors.Errorf("socket error: %v", err) @@ -356,7 +361,7 @@ func handleESPPacket(srcIP, dstIP *net.UDPAddr, espPacket []byte) error { defer func() { if err = syscall.Close(fd); err != nil { - logger.IKELog.Errorf("Close fd error : %v", err) + ikeLog.Errorf("Close fd error : %v", err) } }() diff --git a/pkg/service/init.go b/pkg/service/init.go index 87e5fb3b..fae3aea7 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -205,7 +205,7 @@ func (a *N3iwfApp) initDefaultXfrmInterface() error { cfg := a.Config() mainLog := logger.MainLog n3iwfIPAddr := net.ParseIP(cfg.GetIPSecGatewayAddr()).To4() - n3iwfIPAddrAndSubnet := net.IPNet{IP: n3iwfIPAddr, Mask: n3iwfCtx.UeIPRange.Mask} + n3iwfIPAddrAndSubnet := net.IPNet{IP: n3iwfIPAddr, Mask: n3iwfCtx.IPSecInnerIPPool.IPSubnet.Mask} newXfrmiName := fmt.Sprintf("%s-default", cfg.GetXfrmIfaceName()) if linkIPSec, err = xfrm.SetupIPsecXfrmi(newXfrmiName, n3iwfCtx.XfrmParentIfaceName, @@ -216,7 +216,7 @@ func (a *N3iwfApp) initDefaultXfrmInterface() error { route := &netlink.Route{ LinkIndex: linkIPSec.Attrs().Index, - Dst: n3iwfCtx.UeIPRange, + Dst: n3iwfCtx.IPSecInnerIPPool.IPSubnet, } if err := netlink.RouteAdd(route); err != nil { From 288eae8796a9a6bed072a6e02c51349db3cc980f Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Thu, 17 Oct 2024 08:05:50 +0000 Subject: [PATCH 32/33] Update util pkg --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b7fa5eae..07b0fd7e 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/free5gc/ike v1.1.1-0.20241014015325-083f89768f43 github.com/free5gc/ngap v1.0.9-0.20240708062829-734d184eed74 github.com/free5gc/sctp v1.0.1 - github.com/free5gc/util v1.0.7-0.20241016064137-5698cc626593 + github.com/free5gc/util v1.0.7-0.20241017071924-da29aef99a1c github.com/gin-contrib/pprof v1.5.0 github.com/gin-gonic/gin v1.10.0 github.com/google/gopacket v1.1.19 diff --git a/go.sum b/go.sum index c40e4166..199902dd 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/free5gc/openapi v1.0.9-0.20240503143645-eac9f06c2f6b h1:+VcgZq+3apB6X github.com/free5gc/openapi v1.0.9-0.20240503143645-eac9f06c2f6b/go.mod h1:0qRW+H1/Nyzw5tjjvyp+90m+2SOZZefGQC9QV8iPwu8= github.com/free5gc/sctp v1.0.1 h1:g8WDO97r8B9ubkT5Hyk9b4I1fZUOii9Z39gQ2eRaASo= github.com/free5gc/sctp v1.0.1/go.mod h1:7QXfRWCmlkBGD0EIu3qL5o71bslfIakydz4h2QDZdjQ= -github.com/free5gc/util v1.0.7-0.20241016064137-5698cc626593 h1:Wp32mLckyP25feOmwHBTS32pSkIAjuZgq8iP7njbe/k= -github.com/free5gc/util v1.0.7-0.20241016064137-5698cc626593/go.mod h1:IHKIBd4OM9rwSJ0fG/hv6pXbVC+Eu4Lcaq++BWkfSsY= +github.com/free5gc/util v1.0.7-0.20241017071924-da29aef99a1c h1:vJ3IJPvW4gt7i7d3y8KMp42jypeKsfUG+CqSiFRoXAU= +github.com/free5gc/util v1.0.7-0.20241017071924-da29aef99a1c/go.mod h1:IHKIBd4OM9rwSJ0fG/hv6pXbVC+Eu4Lcaq++BWkfSsY= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gin-contrib/pprof v1.5.0 h1:E/Oy7g+kNw94KfdCy3bZxQFtyDnAX2V7axRS7sNYVrU= From 6a57f668004d750970ad2aa47ad52664613ee30e Mon Sep 17 00:00:00 2001 From: Allen00991 Date: Fri, 18 Oct 2024 07:14:43 +0000 Subject: [PATCH 33/33] align coding convention & fix gosec issues --- internal/context/amf.go | 4 +- internal/context/context.go | 8 +-- internal/context/ikeue.go | 10 ++-- internal/context/n3iwf_ue.go | 8 +-- internal/context/ranue.go | 18 +++---- internal/context/safe_event_channel.go | 31 ----------- internal/context/safe_event_channel_test.go | 43 --------------- internal/ike/handler.go | 54 ++++--------------- internal/ike/handler_test.go | 6 ++- internal/ike/server.go | 40 +++++++------- internal/ike/server_test.go | 4 +- internal/ngap/handler.go | 58 ++++++--------------- internal/ngap/handler_test.go | 3 +- internal/ngap/message/build.go | 30 +++++------ internal/ngap/server.go | 36 +++++++------ internal/ngap/server_test.go | 15 +++--- internal/nwucp/server.go | 7 +-- pkg/factory/config.go | 4 -- pkg/factory/factory.go | 4 -- pkg/service/init.go | 8 +-- 20 files changed, 127 insertions(+), 264 deletions(-) delete mode 100644 internal/context/safe_event_channel.go delete mode 100644 internal/context/safe_event_channel_test.go diff --git a/internal/context/amf.go b/internal/context/amf.go index 61b2e7c2..fa9b31bf 100644 --- a/internal/context/amf.go +++ b/internal/context/amf.go @@ -18,9 +18,9 @@ type N3IWFAMF struct { RelativeAMFCapacity *ngapType.RelativeAMFCapacity PLMNSupportList *ngapType.PLMNSupportList AMFTNLAssociationList map[string]*AMFTNLAssociationItem // v4+v6 as key - /* Overload related */ + // Overload related AMFOverloadContent *AMFOverloadContent - /* Relative Context */ + // Relative Context N3iwfRanUeList map[int64]RanUe // ranUeNgapId as key } diff --git a/internal/context/context.go b/internal/context/context.go index 40310865..f55f72f9 100644 --- a/internal/context/context.go +++ b/internal/context/context.go @@ -35,11 +35,11 @@ type n3iwf interface { type N3IWFContext struct { n3iwf - /* ID generator */ + // ID generator RANUENGAPIDGenerator *idgenerator.IDGenerator TEIDGenerator *idgenerator.IDGenerator - /* Pools */ + // Pools AMFPool sync.Map // map[string]*N3IWFAMF, SCTPAddr as key AMFReInitAvailableList sync.Map // map[string]bool, SCTPAddr as key IKESA sync.Map // map[uint64]*IKESecurityAssociation, SPI as key @@ -52,7 +52,7 @@ type N3IWFContext struct { IKESPIToNGAPId sync.Map // map[uint64]RanUeNgapID, SPI as key NGAPIdToIKESPI sync.Map // map[uint64]SPI, RanUeNgapID as key - /* Security data */ + // Security data CertificateAuthority []byte N3IWFCertificate []byte N3IWFPrivateKey *rsa.PrivateKey @@ -60,7 +60,7 @@ type N3IWFContext struct { IPSecInnerIPPool *ippool.IPPool // TODO: [TWIF] TwifUe may has its own IP address pool - /* XFRM interface */ + // XFRM interface XfrmIfaces sync.Map // map[uint32]*netlink.Link, XfrmIfaceId as key XfrmParentIfaceName string // Every UE's first UP IPsec will use default XFRM interface, additoinal UP IPsec will offset its XFRM id diff --git a/internal/context/ikeue.go b/internal/context/ikeue.go index ecdb262d..3768d87c 100644 --- a/internal/context/ikeue.go +++ b/internal/context/ikeue.go @@ -19,23 +19,23 @@ const ( type N3IWFIkeUe struct { N3iwfCtx *N3IWFContext - /* UE identity */ + // UE identity IPSecInnerIP net.IP IPSecInnerIPAddr *net.IPAddr // Used to send UP packets to UE - /* IKE Security Association */ + // IKE Security Association N3IWFIKESecurityAssociation *IKESecurityAssociation N3IWFChildSecurityAssociation map[uint32]*ChildSecurityAssociation // inbound SPI as key - /* Temporary Mapping of two SPIs */ + // Temporary Mapping of two SPIs // Exchange Message ID(including a SPI) and ChildSA(including a SPI) // Mapping of Message ID of exchange in IKE and Child SA when creating new child SA TemporaryExchangeMsgIDChildSAMapping map[uint32]*ChildSecurityAssociation // Message ID as a key - /* Security */ + // Security Kn3iwf []uint8 // 32 bytes (256 bits), value is from NGAP IE "Security Key" - /* NAS IKE Connection */ + // NAS IKE Connection IKEConnection *UDPSocketInfo // Length of PDU Session List diff --git a/internal/context/n3iwf_ue.go b/internal/context/n3iwf_ue.go index 143e55c5..5b4c7cc4 100644 --- a/internal/context/n3iwf_ue.go +++ b/internal/context/n3iwf_ue.go @@ -12,18 +12,18 @@ import ( type N3IWFRanUe struct { RanUeSharedCtx - /* Temporary cached NAS message */ + // Temporary cached NAS message // Used when NAS registration accept arrived before // UE setup NAS TCP connection with N3IWF, and // Forward pduSessionEstablishmentAccept to UE after // UE send CREATE_CHILD_SA response TemporaryCachedNASMessage []byte - /* NAS TCP Connection Established */ + // NAS TCP Connection Established IsNASTCPConnEstablished bool IsNASTCPConnEstablishedComplete bool - /* NAS TCP Connection */ + // NAS TCP Connection TCPConnection net.Conn } @@ -74,7 +74,7 @@ func (n3iwfUe *N3IWFRanUe) DetachAMF() { delete(n3iwfUe.AMF.N3iwfRanUeList, n3iwfUe.RanUeNgapId) } -/* Implement RanUe interface */ +// Implement RanUe interface func (n3iwfUe *N3IWFRanUe) GetUserLocationInformation() *ngapType.UserLocationInformation { userLocationInformation := new(ngapType.UserLocationInformation) diff --git a/internal/context/ranue.go b/internal/context/ranue.go index e7012938..c2851c26 100644 --- a/internal/context/ranue.go +++ b/internal/context/ranue.go @@ -24,15 +24,15 @@ const ( ) type RanUe interface { - /* Get Attributes */ + // Get Attributes GetUserLocationInformation() *ngapType.UserLocationInformation GetSharedCtx() *RanUeSharedCtx - /* User Plane Traffic */ + // User Plane Traffic // ForwardDL(gtpQoSMsg.QoSTPDUPacket) // ForwardUL() - /* Others */ + // Others CreatePDUSession(int64, ngapType.SNSSAI) (*PDUSession, error) DeletePDUSession(int64) FindPDUSession(int64) *PDUSession @@ -40,7 +40,7 @@ type RanUe interface { } type RanUeSharedCtx struct { - /* UE identity */ + // UE identity RanUeNgapId int64 AmfUeNgapId int64 IPAddrv4 string @@ -49,20 +49,20 @@ type RanUeSharedCtx struct { MaskedIMEISV *ngapType.MaskedIMEISV // TS 38.413 9.3.1.54 Guti string - /* Relative Context */ + // Relative Context N3iwfCtx *N3IWFContext AMF *N3IWFAMF - /* Security */ + // Security SecurityCapabilities *ngapType.UESecurityCapabilities // TS 38.413 9.3.1.86 - /* PDU Session */ + // PDU Session PduSessionList map[int64]*PDUSession // pduSessionId as key - /* PDU Session Setup Temporary Data */ + // PDU Session Setup Temporary Data TemporaryPDUSessionSetupData *PDUSessionSetupTemporaryData - /* Others */ + // Others Guami *ngapType.GUAMI IndexToRfsp int64 Ambr *ngapType.UEAggregateMaximumBitRate diff --git a/internal/context/safe_event_channel.go b/internal/context/safe_event_channel.go deleted file mode 100644 index d58380e1..00000000 --- a/internal/context/safe_event_channel.go +++ /dev/null @@ -1,31 +0,0 @@ -package context - -import "fmt" - -type SafeEvtCh[chanType any] struct { - rcvEvtCh chan chanType - stopSigCh chan struct{} -} - -func (safeEvtCh *SafeEvtCh[chanType]) Init(rcvEvtCh chan chanType) { - safeEvtCh.rcvEvtCh = rcvEvtCh - safeEvtCh.stopSigCh = make(chan struct{}) -} - -func (safeEvtCh *SafeEvtCh[chanType]) SendEvt(evt chanType) error { - select { - case <-safeEvtCh.stopSigCh: - return fmt.Errorf("event channel[%T] is closed", safeEvtCh.rcvEvtCh) - default: - } - safeEvtCh.rcvEvtCh <- evt - return nil -} - -func (safeEvtCh *SafeEvtCh[chanType]) RecvEvtCh() chan chanType { - return safeEvtCh.rcvEvtCh -} - -func (safeEvtCh *SafeEvtCh[chanType]) Close() { - close(safeEvtCh.stopSigCh) -} diff --git a/internal/context/safe_event_channel_test.go b/internal/context/safe_event_channel_test.go deleted file mode 100644 index 969fcd48..00000000 --- a/internal/context/safe_event_channel_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package context_test - -import ( - "sync" - "testing" - "time" - - "github.com/stretchr/testify/require" - - n3iwf_context "github.com/free5gc/n3iwf/internal/context" -) - -// Simulate 1 receiver and N(N=2) senders situation -func TestSafeEvtCh(t *testing.T) { - safeEvtCh := new(n3iwf_context.SafeEvtCh[int]) - safeEvtCh.Init(make(chan int, 10)) - wg := sync.WaitGroup{} - - // Two senders - wg.Add(2) - for i := 0; i < 2; i++ { - go func(i int) { - if i == 0 { - // Case: send failed - time.Sleep(1 * time.Second) - err := safeEvtCh.SendEvt(1) - t.Log(err) - require.Error(t, err) - } else { - // Case: send successed - err := safeEvtCh.SendEvt(1) - require.NoError(t, err) - } - wg.Done() - }(i) - } - - // One receiver - <-safeEvtCh.RecvEvtCh() - safeEvtCh.Close() - - wg.Wait() -} diff --git a/internal/ike/handler.go b/internal/ike/handler.go index 621d7aa1..2d4f421a 100644 --- a/internal/ike/handler.go +++ b/internal/ike/handler.go @@ -601,16 +601,12 @@ func (s *Server) HandleIKEAUTH( ranNgapId = 0 } - err := s.SendNgapEvt(n3iwf_context.NewUnmarshalEAP5GDataEvt( + s.SendNgapEvt(n3iwf_context.NewUnmarshalEAP5GDataEvt( ikeSecurityAssociation.LocalSPI, eapExpanded.VendorData, ikeSecurityAssociation.IkeUE != nil, ranNgapId, )) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Unmarshal EAP5G Data] failed: %+v", err) - return - } ikeSecurityAssociation.IKEConnection = &n3iwf_context.UDPSocketInfo{ Conn: udpConn, @@ -860,7 +856,7 @@ func (s *Server) HandleIKEAUTH( ikeLog.Errorf("Applying XFRM rules failed: %v", err) return } - ikeLog.Debugf(childSecurityAssociationContext.String(cfg.GetXfrmIfaceId())) + ikeLog.Debugln(childSecurityAssociationContext.String(cfg.GetXfrmIfaceId())) // Send IKE message to UE err = SendIKEMessageToUE(udpConn, n3iwfAddr, ueAddr, responseIKEMessage, @@ -880,20 +876,12 @@ func (s *Server) HandleIKEAUTH( ikeSecurityAssociation.State++ // After this, N3IWF will forward NAS with Child SA (IPSec SA) - err = s.SendNgapEvt(n3iwf_context.NewStartTCPSignalNASMsgEvt(ranNgapId)) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Start TCP Signal NAS Msg] failed: %+v", err) - return - } + s.SendNgapEvt(n3iwf_context.NewStartTCPSignalNASMsgEvt(ranNgapId)) // Get TempPDUSessionSetupData from NGAP to setup PDU session if needed - err = s.SendNgapEvt(n3iwf_context.NewGetNGAPContextEvt( + s.SendNgapEvt(n3iwf_context.NewGetNGAPContextEvt( ranNgapId, []int64{n3iwf_context.CxtTempPDUSessionSetupData}, )) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Get NGAP Context] failed: %+v", err) - return - } } } @@ -977,11 +965,7 @@ func (s *Server) HandleCREATECHILDSA( ngapCxtReqNumlist := []int64{n3iwf_context.CxtTempPDUSessionSetupData} - err := s.SendNgapEvt(n3iwf_context.NewGetNGAPContextEvt(ranNgapId, ngapCxtReqNumlist)) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Get NGAP Context] failed: %+v", err) - return - } + s.SendNgapEvt(n3iwf_context.NewGetNGAPContextEvt(ranNgapId, ngapCxtReqNumlist)) } func (s *Server) continueCreateChildSA( @@ -1119,11 +1103,7 @@ func (s *Server) continueCreateChildSA( return } // Forward PDU Seesion Establishment Accept to UE - err = s.SendNgapEvt(n3iwf_context.NewSendNASMsgEvt(ranNgapId)) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Send NAS Msg] failed: %+v", err) - return - } + s.SendNgapEvt(n3iwf_context.NewSendNASMsgEvt(ranNgapId)) temporaryPDUSessionSetupData.FailedErrStr = append(temporaryPDUSessionSetupData.FailedErrStr, n3iwf_context.ErrNil) @@ -1233,16 +1213,12 @@ func (s *Server) HandleUnmarshalEAP5GDataResponse(ikeEvt n3iwf_context.IkeEvt) { n3iwfCtx.IkeSpiNgapIdMapping(ikeUe.N3IWFIKESecurityAssociation.LocalSPI, ranUeNgapId) - err := s.SendNgapEvt(n3iwf_context.NewSendInitialUEMessageEvt( + s.SendNgapEvt(n3iwf_context.NewSendInitialUEMessageEvt( ranUeNgapId, ikeSecurityAssociation.IKEConnection.UEAddr.IP.To4().String(), ikeSecurityAssociation.IKEConnection.UEAddr.Port, nasPDU, )) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Send Init UE Message] failed: %+v", err) - return - } } func (s *Server) HandleSendEAP5GFailureMsg(ikeEvt n3iwf_context.IkeEvt) { @@ -1645,10 +1621,7 @@ func (s *Server) CreatePDUSessionChildSA( break } } else { - err := s.SendNgapEvt(n3iwf_context.NewSendPDUSessionResourceSetupResEvt(ranNgapId)) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Send PDU Sess Resource Setup Res] failed: %+v", err) - } + s.SendNgapEvt(n3iwf_context.NewSendPDUSessionResourceSetupResEvt(ranNgapId)) break } } @@ -1697,13 +1670,9 @@ func (s *Server) StartDPD(ikeUe *n3iwf_context.N3IWFIkeUe) { return } - err := s.SendNgapEvt(n3iwf_context.NewSendUEContextReleaseRequestEvt( + s.SendNgapEvt(n3iwf_context.NewSendUEContextReleaseRequestEvt( ranNgapId, n3iwf_context.ErrRadioConnWithUeLost, )) - if err != nil { - ikeLog.Errorf("SendNgapEvt[Send UE Ctx Release Request] failed: %+v", err) - return - } ikeSA.DPDReqRetransTimer = nil timer.Stop() @@ -1838,10 +1807,7 @@ func (s *Server) handleDeletePayload(payload *ike_message.Delete, isResponse boo return nil, errors.Errorf("Get Protocol ID %d in Informational delete payload, "+ "this payload will not be handled by IKE handler", payload.ProtocolID) } - err = s.SendNgapEvt(evt) - if err != nil { - return nil, errors.Wrapf(err, "handleDeletePayload: SendNgapEvt failed") - } + s.SendNgapEvt(evt) return responseIKEPayload, nil } diff --git a/internal/ike/handler_test.go b/internal/ike/handler_test.go index 1c1c6559..f4366ecf 100644 --- a/internal/ike/handler_test.go +++ b/internal/ike/handler_test.go @@ -93,7 +93,8 @@ func TestGenerateNATDetectHash(t *testing.T) { }, } - for _, tt := range tests { + for i := range tests { + tt := tests[i] t.Run(tt.name, func(t *testing.T) { data, err := n3iwf.ikeServer.generateNATDetectHash(tt.initiatorSPI, tt.responderSPI, &tt.Addr) require.NoError(t, err) @@ -278,7 +279,8 @@ func TestHandleNATDetect(t *testing.T) { }, } - for _, tt := range tests { + for i := range tests { + tt := tests[i] t.Run(tt.name, func(t *testing.T) { ueBehindNAT, n3iwfBehindNAT, err := n3iwf.ikeServer.handleNATDetect( tt.initiatorSPI, tt.responderSPI, diff --git a/internal/ike/server.go b/internal/ike/server.go index fd5ee936..fca6d5f0 100644 --- a/internal/ike/server.go +++ b/internal/ike/server.go @@ -19,6 +19,7 @@ import ( n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/logger" "github.com/free5gc/n3iwf/pkg/factory" + "github.com/free5gc/util/safe_channel" ) const ( @@ -34,7 +35,7 @@ type n3iwf interface { Context() *n3iwf_context.N3IWFContext CancelContext() context.Context - SendNgapEvt(n3iwf_context.NgapEvt) error + SendNgapEvt(n3iwf_context.NgapEvt) } type EspHandler func(srcIP, dstIP *net.UDPAddr, espPkt []byte) error @@ -42,10 +43,10 @@ type EspHandler func(srcIP, dstIP *net.UDPAddr, espPkt []byte) error type Server struct { n3iwf - Listener map[int]*net.UDPConn - RcvIkePktCh chan IkeReceivePacket - StopServer chan struct{} - safeRcvEvtCh *n3iwf_context.SafeEvtCh[n3iwf_context.IkeEvt] + Listener map[int]*net.UDPConn + StopServer chan struct{} + rcvPktCh *safe_channel.SafeCh[IkeReceivePacket] + rcvEvtCh *safe_channel.SafeCh[n3iwf_context.IkeEvt] } type IkeReceivePacket struct { @@ -57,13 +58,12 @@ type IkeReceivePacket struct { func NewServer(n3iwf n3iwf) (*Server, error) { s := &Server{ - n3iwf: n3iwf, - Listener: make(map[int]*net.UDPConn), - RcvIkePktCh: make(chan IkeReceivePacket, RECEIVE_IKEPACKET_CHANNEL_LEN), - StopServer: make(chan struct{}), + n3iwf: n3iwf, + Listener: make(map[int]*net.UDPConn), + StopServer: make(chan struct{}), } - s.safeRcvEvtCh = new(n3iwf_context.SafeEvtCh[n3iwf_context.IkeEvt]) - s.safeRcvEvtCh.Init(make(chan n3iwf_context.IkeEvt, RECEIVE_IKEEVENT_CHANNEL_LEN)) + s.rcvPktCh = safe_channel.NewSafeCh[IkeReceivePacket](RECEIVE_IKEPACKET_CHANNEL_LEN) + s.rcvEvtCh = safe_channel.NewSafeCh[n3iwf_context.IkeEvt](RECEIVE_IKEEVENT_CHANNEL_LEN) return s, nil } @@ -112,15 +112,18 @@ func (s *Server) server(wg *sync.WaitGroup) { ikeLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) } ikeLog.Infof("Ike server stopped") - close(s.RcvIkePktCh) - s.safeRcvEvtCh.Close() + s.rcvPktCh.Close() + s.rcvEvtCh.Close() close(s.StopServer) wg.Done() }() + rcvEvtCh := s.rcvEvtCh.GetRcvChan() + rcvPktCh := s.rcvPktCh.GetRcvChan() + for { select { - case rcvPkt := <-s.RcvIkePktCh: + case rcvPkt := <-rcvPktCh: ikeMsg, ikeSA, err := s.checkIKEMessage( rcvPkt.Msg, &rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr) if err != nil { @@ -129,7 +132,7 @@ func (s *Server) server(wg *sync.WaitGroup) { } s.Dispatch(&rcvPkt.Listener, &rcvPkt.LocalAddr, &rcvPkt.RemoteAddr, ikeMsg, rcvPkt.Msg, ikeSA) - case rcvIkeEvent := <-s.safeRcvEvtCh.RecvEvtCh(): + case rcvIkeEvent := <-rcvEvtCh: s.HandleEvent(rcvIkeEvent) case <-s.StopServer: return @@ -194,12 +197,13 @@ func (s *Server) receiver( continue } - s.RcvIkePktCh <- IkeReceivePacket{ + ikePkt := IkeReceivePacket{ RemoteAddr: *remoteAddr, Listener: *listener, LocalAddr: *localAddr, Msg: msgBuf, } + s.rcvPktCh.Send(ikePkt) } } @@ -234,8 +238,8 @@ func handleNattMsg( return msgBuf, nil } -func (s *Server) SendIkeEvt(evt n3iwf_context.IkeEvt) error { - return s.safeRcvEvtCh.SendEvt(evt) +func (s *Server) SendIkeEvt(evt n3iwf_context.IkeEvt) { + s.rcvEvtCh.Send(evt) } func (s *Server) Stop() { diff --git a/internal/ike/server_test.go b/internal/ike/server_test.go index fd34c75a..bd7a267a 100644 --- a/internal/ike/server_test.go +++ b/internal/ike/server_test.go @@ -38,8 +38,8 @@ func (a *n3iwfTestApp) CancelContext() context.Context { return a.ctx } -func (a *n3iwfTestApp) SendNgapEvt(evt n3iwf_context.NgapEvt) error { - return a.ngapServer.SendNgapEvt(evt) +func (a *n3iwfTestApp) SendNgapEvt(evt n3iwf_context.NgapEvt) { + a.ngapServer.SendNgapEvt(evt) } func NewN3iwfTestApp(cfg *factory.Config) (*n3iwfTestApp, error) { diff --git a/internal/ngap/handler.go b/internal/ngap/handler.go index 4cca7c78..208303f1 100644 --- a/internal/ngap/handler.go +++ b/internal/ngap/handler.go @@ -731,12 +731,9 @@ func (s *Server) HandleInitialContextSetupRequest( return } - err := s.SendIkeEvt(n3iwf_context.NewSendEAPSuccessMsgEvt( + s.SendIkeEvt(n3iwf_context.NewSendEAPSuccessMsgEvt( spi, securityKey.Value.Bytes, len(ranUeCtx.PduSessionList), )) - if err != nil { - ngapLog.Errorf("SendIkeEvt[Send EAP Success Msg] failed: %+v", err) - } default: ngapLog.Errorf("Unknown UE type: %T", ue) } @@ -886,10 +883,12 @@ func (s *Server) handlePDUSessionResourceSetupRequestTransfer( upfAddr := upfIPv4 + gtpv1.GTPUPort upfUDPAddr, err := net.ResolveUDPAddr("udp", upfAddr) if err != nil { + var responseTransfer []byte + ngapLog.Errorf("Resolve UPF addr [%s] failed: %v", upfAddr, err) cause := message.BuildCause(ngapType.CausePresentTransport, ngapType.CauseTransportPresentTransportResourceUnavailable) - responseTransfer, err := message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) + responseTransfer, err = message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %v\n", err) } @@ -899,11 +898,13 @@ func (s *Server) handlePDUSessionResourceSetupRequestTransfer( // UE TEID ueTEID := n3iwfCtx.NewTEID(ranUe) if ueTEID == 0 { + var responseTransfer []byte + ngapLog.Error("Invalid TEID (0).") cause := message.BuildCause( ngapType.CausePresentProtocol, ngapType.CauseProtocolPresentUnspecified) - responseTransfer, err := message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) + responseTransfer, err = message.BuildPDUSessionResourceSetupUnsuccessfulTransfer(*cause, nil) if err != nil { ngapLog.Errorf("Build PDUSessionResourceSetupUnsuccessfulTransfer Error: %v\n", err) } @@ -1068,10 +1069,7 @@ func (s *Server) HandleUEContextModificationRequest( return } - err := s.SendIkeEvt(n3iwf_context.NewIKEContextUpdateEvt(spi, securityKey.Value.Bytes)) // Kn3iwf - if err != nil { - ngapLog.Errorf("SendIkeEvt[IKE Ctx Update] failed: %+v", err) - } + s.SendIkeEvt(n3iwf_context.NewIKEContextUpdateEvt(spi, securityKey.Value.Bytes)) // Kn3iwf } func (s *Server) HandleUEContextReleaseCommand( @@ -1172,10 +1170,7 @@ func (s *Server) releaseIkeUeAndRanUe(ranUe n3iwf_context.RanUe) error { localSPI, ok := n3iwfCtx.IkeSpiLoad(ranUeNgapID) if ok { - err := s.SendIkeEvt(n3iwf_context.NewIKEDeleteRequestEvt(localSPI)) - if err != nil { - return errors.Wrapf(err, "SendIkeEvt[IKE Delete Req] failed") - } + s.SendIkeEvt(n3iwf_context.NewIKEDeleteRequestEvt(localSPI)) } if err := ranUe.Remove(); err != nil { @@ -1322,10 +1317,7 @@ func (s *Server) HandleDownlinkNASTransport( } if !ue.IsNASTCPConnEstablished { - err := s.SendIkeEvt(n3iwf_context.NewSendEAPNASMsgEvt(spi, []byte(nasPDU.Value))) - if err != nil { - ngapLog.Errorf("SendIkeEvt[Send EAP NAS Msg] failed: %+v", err) - } + s.SendIkeEvt(n3iwf_context.NewSendEAPNASMsgEvt(spi, []byte(nasPDU.Value))) } else { // Using a "NAS message envelope" to transport a NAS message // over the non-3GPP access between the UE and the N3IWF @@ -1538,14 +1530,10 @@ func (s *Server) HandlePDUSessionResourceSetupRequest( return } - err := s.SendIkeEvt(n3iwf_context.NewCreatePDUSessionEvt(spi, + s.SendIkeEvt(n3iwf_context.NewCreatePDUSessionEvt(spi, len(ue.PduSessionList), ue.TemporaryPDUSessionSetupData), ) - if err != nil { - ngapLog.Errorf("SendIkeEvt[Create PDU Session] failed: %+v", err) - return - } // TS 23.501 4.12.5 Requested PDU Session Establishment via Untrusted non-3GPP Access // After all IPsec Child SAs are established, the N3IWF shall forward to UE via the signalling IPsec SA @@ -2139,11 +2127,7 @@ func (s *Server) HandlePDUSessionResourceReleaseCommand( } ranUe.GetSharedCtx().PduSessResRelState = n3iwf_context.PduSessResRelStateOngoing - err := s.SendIkeEvt(n3iwf_context.NewSendChildSADeleteRequestEvt(localSPI, releaseIdList)) - if err != nil { - ngapLog.Errorf("SendIkeEvt[Send ChildSA Delete Request] failed: %+v", err) - return - } + s.SendIkeEvt(n3iwf_context.NewSendChildSADeleteRequestEvt(localSPI, releaseIdList)) ranUeCtx.PduSessionReleaseList = releaseList // if nASPDU != nil { @@ -2882,11 +2866,7 @@ func (s *Server) HandleGetNGAPContext( return } - err := s.SendIkeEvt(n3iwf_context.NewGetNGAPContextRepEvt(spi, ngapCxtReqNumlist, ngapCxt)) - if err != nil { - ngapLog.Errorf("SendIkeEvt[Get NGAP Context Rep] failed: %+v", err) - return - } + s.SendIkeEvt(n3iwf_context.NewGetNGAPContextRepEvt(spi, ngapCxtReqNumlist, ngapCxt)) } func (s *Server) HandleUnmarshalEAP5GData( @@ -2942,11 +2922,7 @@ func (s *Server) HandleUnmarshalEAP5GData( selectedAMF := n3iwfCtx.AMFSelection(anParameters.GUAMI, anParameters.SelectedPLMNID) if selectedAMF == nil { - err := s.SendIkeEvt(n3iwf_context.NewSendEAP5GFailureMsgEvt(spi, n3iwf_context.ErrAMFSelection)) - if err != nil { - ngapLog.Errorf("SendIkeEvt[Send EAP5G Failure Msg] failed: %+v", err) - return - } + s.SendIkeEvt(n3iwf_context.NewSendEAP5GFailureMsgEvt(spi, n3iwf_context.ErrAMFSelection)) } else { n3iwfUe := n3iwfCtx.NewN3iwfRanUe() n3iwfUe.AMF = selectedAMF @@ -2961,11 +2937,7 @@ func (s *Server) HandleUnmarshalEAP5GData( } } - err := s.SendIkeEvt(n3iwf_context.NewUnmarshalEAP5GDataResponseEvt(spi, n3iwfUe.RanUeNgapId, nasPDU)) - if err != nil { - ngapLog.Errorf("SendIkeEvt[Unmarshal EAP5G Data Response] failed: %+v", err) - return - } + s.SendIkeEvt(n3iwf_context.NewUnmarshalEAP5GDataResponseEvt(spi, n3iwfUe.RanUeNgapId, nasPDU)) } } else { ranUeNgapId := evt.RanUeNgapId diff --git a/internal/ngap/handler_test.go b/internal/ngap/handler_test.go index 75049d15..37ad392a 100644 --- a/internal/ngap/handler_test.go +++ b/internal/ngap/handler_test.go @@ -35,13 +35,14 @@ func TestReleaseIkeUeAndRanUe(t *testing.T) { n3iwfCtx.IKESPIToNGAPId.Store(spi, ranUeNgapId) stopCh := make(chan struct{}) + rcvIkeEvtCh := n3iwf.mockIkeEvtCh.GetRcvChan() go func() { for { select { case <-stopCh: return - case rcvEvt := <-n3iwf.mockIkeEvtCh.RecvEvtCh(): + case rcvEvt := <-rcvIkeEvtCh: if rcvEvt.Type() != n3iwf_context.IKEDeleteRequest { t.Errorf("Receive Wrong Event") } diff --git a/internal/ngap/message/build.go b/internal/ngap/message/build.go index 1e10561c..f51eaf9c 100644 --- a/internal/ngap/message/build.go +++ b/internal/ngap/message/build.go @@ -114,21 +114,21 @@ func BuildNGSetupRequest( nGSetupRequestIEs.List = append(nGSetupRequestIEs.List, ie) /* - * The reason PagingDRX ie was commented is that in TS23.501 - * PagingDRX was mentioned to be used only for 3GPP access. - * However, the question that if the paging function for N3IWF - * is needed requires verification. - - // PagingDRX - ie = ngapType.NGSetupRequestIEs{} - ie.Id.Value = ngapType.ProtocolIEIDDefaultPagingDRX - ie.Criticality.Value = ngapType.CriticalityPresentIgnore - ie.Value.Present = ngapType.NGSetupRequestIEsPresentDefaultPagingDRX - ie.Value.DefaultPagingDRX = new(ngapType.PagingDRX) - - pagingDRX := ie.Value.DefaultPagingDRX - pagingDRX.Value = ngapType.PagingDRXPresentV128 - nGSetupRequestIEs.List = append(nGSetupRequestIEs.List, ie) + // The reason PagingDRX ie was commented is that in TS23.501 + // PagingDRX was mentioned to be used only for 3GPP access. + // However, the question that if the paging function for N3IWF + // is needed requires verification. + + // PagingDRX + ie = ngapType.NGSetupRequestIEs{} + ie.Id.Value = ngapType.ProtocolIEIDDefaultPagingDRX + ie.Criticality.Value = ngapType.CriticalityPresentIgnore + ie.Value.Present = ngapType.NGSetupRequestIEsPresentDefaultPagingDRX + ie.Value.DefaultPagingDRX = new(ngapType.PagingDRX) + + pagingDRX := ie.Value.DefaultPagingDRX + pagingDRX.Value = ngapType.PagingDRXPresentV128 + nGSetupRequestIEs.List = append(nGSetupRequestIEs.List, ie) */ return ngap.Encoder(pdu) diff --git a/internal/ngap/server.go b/internal/ngap/server.go index e515121a..03058395 100644 --- a/internal/ngap/server.go +++ b/internal/ngap/server.go @@ -14,6 +14,7 @@ import ( "github.com/free5gc/n3iwf/pkg/factory" lib_ngap "github.com/free5gc/ngap" "github.com/free5gc/sctp" + "github.com/free5gc/util/safe_channel" ) const ( @@ -26,15 +27,15 @@ type n3iwf interface { Context() *n3iwf_context.N3IWFContext CancelContext() context.Context - SendIkeEvt(n3iwf_context.IkeEvt) error + SendIkeEvt(n3iwf_context.IkeEvt) } type Server struct { n3iwf - conn []*sctp.SCTPConn - rcvNgapPktCh chan ReceiveNGAPPacket - safeRcvEvtCh *n3iwf_context.SafeEvtCh[n3iwf_context.NgapEvt] + conn []*sctp.SCTPConn + rcvPktCh *safe_channel.SafeCh[ReceiveNGAPPacket] + rcvEvtCh *safe_channel.SafeCh[n3iwf_context.NgapEvt] } type ReceiveNGAPPacket struct { @@ -44,11 +45,10 @@ type ReceiveNGAPPacket struct { func NewServer(n3iwf n3iwf) (*Server, error) { s := &Server{ - n3iwf: n3iwf, - rcvNgapPktCh: make(chan ReceiveNGAPPacket, RECEIVE_NGAPPACKET_CHANNEL_LEN), + n3iwf: n3iwf, } - s.safeRcvEvtCh = new(n3iwf_context.SafeEvtCh[n3iwf_context.NgapEvt]) - s.safeRcvEvtCh.Init(make(chan n3iwf_context.NgapEvt, RECEIVE_NGAPEVENT_CHANNEL_LEN)) + s.rcvPktCh = safe_channel.NewSafeCh[ReceiveNGAPPacket](RECEIVE_NGAPPACKET_CHANNEL_LEN) + s.rcvEvtCh = safe_channel.NewSafeCh[n3iwf_context.NgapEvt](RECEIVE_NGAPEVENT_CHANNEL_LEN) return s, nil } @@ -82,19 +82,22 @@ func (s *Server) runNgapEventHandler(wg *sync.WaitGroup) { ngapLog.Fatalf("panic: %v\n%s", p, string(debug.Stack())) } ngapLog.Infof("NGAP server stopped") - s.safeRcvEvtCh.Close() - close(s.rcvNgapPktCh) + s.rcvEvtCh.Close() + s.rcvPktCh.Close() wg.Done() }() + rcvEvtCh := s.rcvEvtCh.GetRcvChan() + rcvPktCh := s.rcvPktCh.GetRcvChan() + for { select { - case rcvPkt := <-s.rcvNgapPktCh: + case rcvPkt := <-rcvPktCh: if len(rcvPkt.Buf) == 0 { // receiver closed return } s.NGAPDispatch(rcvPkt.Conn, rcvPkt.Buf) - case rcvEvt := <-s.safeRcvEvtCh.RecvEvtCh(): + case rcvEvt := <-rcvEvtCh: s.HandleEvent(rcvEvt) } } @@ -190,7 +193,7 @@ func (s *Server) listenAndServe( if errConn != nil { ngapLog.Errorf("conn close error: %+v", errConn) } - s.rcvNgapPktCh <- ReceiveNGAPPacket{} + s.rcvPktCh.Send(ReceiveNGAPPacket{}) return } ngapLog.Errorf("[SCTP] Read from SCTP connection failed: %+v", err) @@ -207,15 +210,16 @@ func (s *Server) listenAndServe( forwardData := make([]byte, n) copy(forwardData, buf[:n]) - s.rcvNgapPktCh <- ReceiveNGAPPacket{ + ngapPkt := ReceiveNGAPPacket{ Conn: conn, Buf: forwardData[:n], } + s.rcvPktCh.Send(ngapPkt) } } -func (s *Server) SendNgapEvt(evt n3iwf_context.NgapEvt) error { - return s.safeRcvEvtCh.SendEvt(evt) +func (s *Server) SendNgapEvt(evt n3iwf_context.NgapEvt) { + s.rcvEvtCh.Send(evt) } func (s *Server) Stop() { diff --git a/internal/ngap/server_test.go b/internal/ngap/server_test.go index 72540f0f..2861999e 100644 --- a/internal/ngap/server_test.go +++ b/internal/ngap/server_test.go @@ -7,6 +7,7 @@ import ( n3iwf_context "github.com/free5gc/n3iwf/internal/context" "github.com/free5gc/n3iwf/internal/ike" "github.com/free5gc/n3iwf/pkg/factory" + "github.com/free5gc/util/safe_channel" ) type n3iwfTestApp struct { @@ -19,7 +20,7 @@ type n3iwfTestApp struct { ngapServer *Server ikeServer *ike.Server - mockIkeEvtCh *n3iwf_context.SafeEvtCh[n3iwf_context.IkeEvt] + mockIkeEvtCh *safe_channel.SafeCh[n3iwf_context.IkeEvt] } func (a *n3iwfTestApp) Config() *factory.Config { @@ -34,12 +35,12 @@ func (a *n3iwfTestApp) CancelContext() context.Context { return a.ctx } -func (a *n3iwfTestApp) SendNgapEvt(evt n3iwf_context.NgapEvt) error { - return a.ngapServer.SendNgapEvt(evt) +func (a *n3iwfTestApp) SendNgapEvt(evt n3iwf_context.NgapEvt) { + a.ngapServer.SendNgapEvt(evt) } -func (a *n3iwfTestApp) SendIkeEvt(evt n3iwf_context.IkeEvt) error { - return a.mockIkeEvtCh.SendEvt(evt) +func (a *n3iwfTestApp) SendIkeEvt(evt n3iwf_context.IkeEvt) { + a.mockIkeEvtCh.Send(evt) } func NewN3iwfTestApp(cfg *factory.Config) (*n3iwfTestApp, error) { @@ -52,9 +53,7 @@ func NewN3iwfTestApp(cfg *factory.Config) (*n3iwfTestApp, error) { cancel: cancel, wg: &sync.WaitGroup{}, } - n3iwfApp.mockIkeEvtCh = new(n3iwf_context.SafeEvtCh[n3iwf_context.IkeEvt]) - n3iwfApp.mockIkeEvtCh.Init(make(chan n3iwf_context.IkeEvt, 10)) - + n3iwfApp.mockIkeEvtCh = safe_channel.NewSafeCh[n3iwf_context.IkeEvt](10) n3iwfApp.n3iwfCtx, err = n3iwf_context.NewTestContext(n3iwfApp) if err != nil { return nil, err diff --git a/internal/nwucp/server.go b/internal/nwucp/server.go index 2609fad5..e50c1053 100644 --- a/internal/nwucp/server.go +++ b/internal/nwucp/server.go @@ -21,7 +21,7 @@ type n3iwf interface { Context() *n3iwf_context.N3IWFContext CancelContext() context.Context - SendNgapEvt(n3iwf_context.NgapEvt) error + SendNgapEvt(n3iwf_context.NgapEvt) } type Server struct { @@ -107,10 +107,7 @@ func (s *Server) listenAndServe(wg *sync.WaitGroup) { // Store connection n3iwfUe.TCPConnection = connection - err = s.SendNgapEvt(n3iwf_context.NewNASTCPConnEstablishedCompleteEvt(n3iwfUe.RanUeNgapId)) - if err != nil { - nwucpLog.Errorf("SendNgapEvt failed: %v", err) - } + s.SendNgapEvt(n3iwf_context.NewNASTCPConnEstablishedCompleteEvt(n3iwfUe.RanUeNgapId)) wg.Add(1) go serveConn(n3iwfUe, connection, wg) diff --git a/pkg/factory/config.go b/pkg/factory/config.go index 0c954460..bbc37eb6 100644 --- a/pkg/factory/config.go +++ b/pkg/factory/config.go @@ -1,7 +1,3 @@ -/* - * N3IWF Configuration Factory - */ - package factory import ( diff --git a/pkg/factory/factory.go b/pkg/factory/factory.go index cb10b749..c21e11c7 100644 --- a/pkg/factory/factory.go +++ b/pkg/factory/factory.go @@ -1,7 +1,3 @@ -/* - * N3IWF Configuration Factory - */ - package factory import ( diff --git a/pkg/service/init.go b/pkg/service/init.go index fae3aea7..fa79750e 100644 --- a/pkg/service/init.go +++ b/pkg/service/init.go @@ -259,10 +259,10 @@ func (a *N3iwfApp) terminateProcedure() { a.ikeServer.Stop() } -func (a *N3iwfApp) SendNgapEvt(evt n3iwf_context.NgapEvt) error { - return a.ngapServer.SendNgapEvt(evt) +func (a *N3iwfApp) SendNgapEvt(evt n3iwf_context.NgapEvt) { + a.ngapServer.SendNgapEvt(evt) } -func (a *N3iwfApp) SendIkeEvt(evt n3iwf_context.IkeEvt) error { - return a.ikeServer.SendIkeEvt(evt) +func (a *N3iwfApp) SendIkeEvt(evt n3iwf_context.IkeEvt) { + a.ikeServer.SendIkeEvt(evt) }