public void TestMessageAuthenticatorValidationSuccess()
        {
            var request = "0cda00268a54f4686fb394c52866e302185d062350125a665e2e1e8411f3e243822097c84fa3";
            var secret  = "xyzzy5461";

            var dictionary    = GetDictionary();
            var requestPacket = RadiusPacket.Parse(Utils.StringToByteArray(request), dictionary, Encoding.UTF8.GetBytes(secret));
        }
        public void Test3GPPLocationInfoParsing()
        {
            var request = "01d901becff27ef45a6bc4525aa5d65f483876951f103433363838383735303636393736011b32333230313038353030373639373640666c6578696e65747304060af7e0611a1600001fe40120001031352e3020283537393333290606000000020706000000073d06000000121a0e00001fe4003e0008000000011a17000028af01113233323031303835303037363937361a0d000028af080732333230311a09000028af0a03351a09000028af0c03301a0c000028af020605b28a3e1a27000028af052130352d314239333146373339364645464537344142464646463030384530301a0c000028af0d06303830301e0b666c6578696e6574731a0c000028af0606c230840c1a0d000028af120732333230311a0c000028af0706c23084da1a0d000028af090732333230311a09000028af1a03001a09000028af1503011a10000028af160a0132f210426d1bc01a0a000028af170480011a18000028af1412383632383238303231323838323230301a0c000028af0306000000001a0e00001fe4001800080000000405060001272602120ca8378c51ef621ac229c647a85646071a1100000009170b464c4558494e45545321053136382105313736";
            var secret  = "xyzzy5461";

            var requestPacket = RadiusPacket.Parse(Utils.StringToByteArray(request), GetDictionary(), Encoding.UTF8.GetBytes(secret));
            var locationInfo  = requestPacket.GetAttribute <Byte[]>("3GPP-User-Location-Info");

            Assert.AreEqual("23201", Utils.GetMccMncFrom3GPPLocationInfo(locationInfo).mccmnc);
        }
        public void TestMessageAuthenticatorValidationFail()
        {
            var request = "0cda00268a54f4686fb394c52866e302185d062350125a665e2e1e8411f3e243822097c84fa3";
            var secret  = "xyzzy5461durr";

            var dictionary = GetDictionary();

            Assert.That(() => RadiusPacket.Parse(Utils.StringToByteArray(request), dictionary, Encoding.UTF8.GetBytes(secret)),
                        Throws.TypeOf <InvalidOperationException>());
        }
        public void TestAccountingPacketRequestAuthenticatorFail()
        {
            var packetBytes = "0404002711019c27d4e00cbc523b3e2fc834baf401066e656d6f2806000000012c073230303234";
            var secret      = "foo";

            var requestAuthenticator = RadiusPacket.CalculateRequestAuthenticator(Encoding.UTF8.GetBytes(secret), Utils.StringToByteArray(packetBytes));

            Assert.That(() => RadiusPacket.Parse(Utils.StringToByteArray(packetBytes), GetDictionary(), Encoding.UTF8.GetBytes(secret)),
                        Throws.TypeOf <InvalidOperationException>());
        }
        public void TestAccountingPacketRequestAuthenticatorSuccess()
        {
            var packetBytes = "0404002711019c27d4e00cbc523b3e2fc834baf401066e656d6f2806000000012c073230303234";
            var secret      = "xyzzy5461";

            var requestAuthenticator = RadiusPacket.CalculateRequestAuthenticator(Encoding.UTF8.GetBytes(secret), Utils.StringToByteArray(packetBytes));
            var packet = RadiusPacket.Parse(Utils.StringToByteArray(packetBytes), GetDictionary(), Encoding.UTF8.GetBytes(secret));

            Assert.AreEqual(packet.Authenticator.ToHexString(), requestAuthenticator.ToHexString());
        }
        public void TestLTE3GPPLocationInfoParsing()
        {
            var request = "017301cea4571e304078c73bbb4367ca5fcede3e1f103433363838383735303636393736011b32333230313038353030373639373640666c6578696e65747304060af7e0611a1600001fe40120001031352e3020283537393333291e0b666c6578696e6574730606000000020706000000073d06000000121a0e00001fe4003e0008000000021a17000028af01113233323031303835303037363937361a0d000028af080732333230311a09000028af0a03351a0c000028af020605654e411a0c000028af0d06303830301a0c000028af0606c23084e01a0c000028af0706c23084da1a09000028af1503061a18000028af1412383632383238303231323838323230301a15000028af160f8232f210426d32f21000013e021a0d000028af120732333230311a0d000028af090732333230311a09000028af0c03301a0a000028af170480011a1f000028af051930382d34433038303030343933453030303034393345301a0c000028af0306000000001a09000028af1a03001a0e00001fe4001800080000000f050600012d2202121e205a653bc6cad430e70a585ab0271f1a0c0000159f5806000000031a1100000009170b464c4558494e4554532104393521043935210439352105323136";
            var secret  = "xyzzy5461";

            var ltelocationid = Utils.StringToByteArray("8232f210426d32f21000013e02");
            var requestPacket = RadiusPacket.Parse(Utils.StringToByteArray(request), GetDictionary(), Encoding.UTF8.GetBytes(secret));
            var locationInfo  = requestPacket.GetAttribute <Byte[]>("3GPP-User-Location-Info");

            Assert.AreEqual("23201", Utils.GetMccMncFrom3GPPLocationInfo(locationInfo).mccmnc);
        }
        public void TestMessageAuthenticatorNoSideEffect()
        {
            var request  = Utils.StringToByteArray("0cda00268a54f4686fb394c52866e302185d062350125a665e2e1e8411f3e243822097c84fa3");
            var expected = Utils.StringToByteArray("0cda00268a54f4686fb394c52866e302185d062350125a665e2e1e8411f3e243822097c84fa3");
            var secret   = "xyzzy5461";

            var dictionary    = GetDictionary();
            var requestPacket = RadiusPacket.Parse(request, dictionary, Encoding.UTF8.GetBytes(secret));

            Assert.AreEqual(Utils.ToHexString(expected), Utils.ToHexString(request));
        }
        public void TestPacketParserAndAssembler()
        {
            var request  = "0cda00268a54f4686fb394c52866e302185d062350125a665e2e1e8411f3e243822097c84fa3";
            var expected = request;
            var secret   = "xyzzy5461";

            var dictionary    = GetDictionary();
            var requestPacket = RadiusPacket.Parse(Utils.StringToByteArray(request), dictionary, Encoding.UTF8.GetBytes(secret));
            var bytes         = requestPacket.GetBytes(dictionary);

            Assert.AreEqual(expected, bytes.ToHexString());
        }
        public void TestCreateAndParseAccountingRequestPacket()
        {
            var secret     = "xyzzy5461";
            var dictionary = GetDictionary();
            var packet     = new RadiusPacket(PacketCode.AccountingRequest, 0, secret);

            packet.AddAttribute("User-Name", "nemo");
            packet.AddAttribute("Acct-Status-Type", 2);
            packet.AddAttribute("NAS-IP-Address", IPAddress.Parse("192.168.1.16"));
            packet.AddAttribute("NAS-Port", 3);

            var bytes = packet.GetBytes(dictionary);
            var derp  = RadiusPacket.Parse(bytes, dictionary, Encoding.UTF8.GetBytes(secret));
        }
        /// <summary>
        /// Parses a packet and gets a response packet from the handler
        /// </summary>
        /// <param name="packetHandler"></param>
        /// <param name="sharedSecret"></param>
        /// <param name="packetBytes"></param>
        /// <param name="remoteEndpoint"></param>
        /// <returns></returns>
        internal IRadiusPacket GetResponsePacket(IPacketHandler packetHandler, String sharedSecret, Byte[] packetBytes, IPEndPoint remoteEndpoint)
        {
            var requestPacket = RadiusPacket.Parse(packetBytes, _dictionary, Encoding.UTF8.GetBytes(sharedSecret));

            _log.Info($"Received {requestPacket.Code} from {remoteEndpoint} Id={requestPacket.Identifier}");

            if (_log.IsDebugEnabled)
            {
                DumpPacket(requestPacket);
            }
            _log.Debug(packetBytes.ToHexString());

            // Handle status server requests in server outside packet handler
            if (requestPacket.Code == PacketCode.StatusServer)
            {
                var responseCode = _serverType == RadiusServerType.Authentication ? PacketCode.AccessAccept : PacketCode.AccountingResponse;
                _log.Debug($"Sending {responseCode} for StatusServer request from {remoteEndpoint}");
                return(requestPacket.CreateResponsePacket(responseCode));
            }

            _log.Debug($"Handling packet for remote ip {remoteEndpoint.Address} with {packetHandler.GetType()}");

            var sw             = Stopwatch.StartNew();
            var responsePacket = packetHandler.HandlePacket(requestPacket);

            sw.Stop();
            _log.Debug($"{remoteEndpoint} Id={responsePacket.Identifier}, Received {responsePacket.Code} from handler in {sw.ElapsedMilliseconds}ms");
            if (sw.ElapsedMilliseconds >= 5000)
            {
                _log.Warn($"Slow response for Id {responsePacket.Identifier}, check logs");
            }

            if (requestPacket.Attributes.ContainsKey("Proxy-State"))
            {
                responsePacket.Attributes.Add("Proxy-State", requestPacket.Attributes.SingleOrDefault(o => o.Key == "Proxy-State").Value);
            }

            return(responsePacket);
        }
        public void TestCreatingAndParsingPacket()
        {
            var secret = "xyzzy5461";

            var dictionary = GetDictionary();

            var packet = new RadiusPacket(PacketCode.AccessRequest, 1, secret);

            packet.AddAttribute("User-Name", "*****@*****.**");
            packet.AddAttribute("User-Password", "test");
            packet.AddAttribute("NAS-IP-Address", IPAddress.Parse("127.0.0.1"));
            packet.AddAttribute("NAS-Port", 100);
            packet.AddAttribute("3GPP-IMSI-MCC-MNC", "24001");
            packet.AddAttribute("3GPP-CG-Address", IPAddress.Parse("127.0.0.1"));

            var testPacket = RadiusPacket.Parse(packet.GetBytes(dictionary), dictionary, Encoding.UTF8.GetBytes(secret));

            Assert.AreEqual("*****@*****.**", testPacket.GetAttribute <String>("User-Name"));
            Assert.AreEqual("test", testPacket.GetAttribute <String>("User-Password"));
            Assert.AreEqual(IPAddress.Parse("127.0.0.1"), testPacket.GetAttribute <IPAddress>("NAS-IP-Address"));
            Assert.AreEqual(100, testPacket.GetAttribute <UInt32>("NAS-Port"));
            Assert.AreEqual("24001", testPacket.GetAttribute <String>("3GPP-IMSI-MCC-MNC"));
            Assert.AreEqual(IPAddress.Parse("127.0.0.1"), testPacket.GetAttribute <IPAddress>("3GPP-CG-Address"));
        }
        /// <summary>
        /// Used to handle the packets asynchronously
        /// </summary>
        /// <param name="remoteEndpoint"></param>
        /// <param name="packetBytes"></param>
        private void HandlePacket(IPEndPoint remoteEndpoint, Byte[] packetBytes)
        {
            try
            {
                _log.Debug($"Received packet from {remoteEndpoint}, Concurrent handlers count: {Interlocked.Increment(ref _concurrentHandlerCount)}");

                if (_packetHandlerRepository.TryGetHandler(remoteEndpoint.Address, out var handler))
                {
                    var responsePacket = GetResponsePacket(handler.packetHandler, handler.sharedSecret, packetBytes, remoteEndpoint);
                    if (responsePacket != null)
                    {
                        SendResponsePacket(responsePacket, remoteEndpoint, _dictionary);
                    }
                }
                else
                {
                    _log.Error($"No packet handler found for remote ip {remoteEndpoint}");
                    var packet = RadiusPacket.Parse(packetBytes, _dictionary, Encoding.UTF8.GetBytes("wut"));
                    DumpPacket(packet);
                }
            }
            catch (Exception ex) when(ex is ArgumentException || ex is OverflowException)
            {
                _log.Warn($"Ignoring malformed(?) packet received from {remoteEndpoint}", ex);
                _log.Debug(packetBytes.ToHexString());
            }
            catch (Exception ex)
            {
                _log.Error($"Failed to receive packet from {remoteEndpoint}", ex);
                _log.Debug(packetBytes.ToHexString());
            }
            finally
            {
                Interlocked.Decrement(ref _concurrentHandlerCount);
            }
        }