/// <summary>
        /// Sends a packet
        /// </summary>
        /// <param name="responsePacket"></param>
        /// <param name="remoteEndpoint"></param>
        /// <param name="dictionary"></param>
        private void SendResponsePacket(IRadiusPacket responsePacket, IPEndPoint remoteEndpoint, IRadiusDictionary dictionary)
        {
            var responseBytes = responsePacket.GetBytes(dictionary);

            _server.Send(responseBytes, responseBytes.Length, remoteEndpoint);   // todo thread safety... although this implementation will be implicitly thread safeish...
            _log.Info($"{responsePacket.Code} sent to {remoteEndpoint} Id={responsePacket.Identifier}");
        }
        /// <summary>
        /// Tries to get a packet from the stream. Returns true if successful
        /// Returns false if no packet could be parsed or stream is empty ie closing
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="packet"></param>
        /// <returns></returns>
        public bool TryParsePacketFromStream(Stream stream, out IRadiusPacket packet, byte[] sharedSecret)
        {
            var packetHeaderBytes = new byte[4];
            var i = stream.Read(packetHeaderBytes, 0, 4);

            if (i != 0)
            {
                try
                {
                    var packetLength       = BitConverter.ToUInt16(packetHeaderBytes.Reverse().ToArray(), 0);
                    var packetContentBytes = new byte[packetLength - 4];
                    stream.Read(packetContentBytes, 0, packetContentBytes.Length);  // todo stream.read should use loop in case everything is not available immediately

                    packet = Parse(packetHeaderBytes.Concat(packetContentBytes).ToArray(), sharedSecret);
                    return(true);
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "Unable to parse packet from stream");
                }
            }

            packet = null;
            return(false);
        }
예제 #3
0
        public IRadiusPacket HandlePacket(IRadiusPacket packet)
        {
            if (packet.Code == PacketCode.AccessRequest)
            {
                if (packet.GetAttribute <String>("User-Password") == "arctangent")
                {
                    var responsepacket = packet.CreateResponsePacket(PacketCode.AccessAccept);
                    responsepacket.AddAttribute("Service-Type", 1);
                    responsepacket.AddAttribute("Login-Service", 0);
                    responsepacket.AddAttribute("Login-IP-Host", IPAddress.Parse("192.168.1.3"));
                    return(responsepacket);
                }
            }

            var sb = new StringBuilder();

            sb.AppendLine($"Packet dump for {packet.Identifier}:");
            foreach (var attribute in packet.Attributes)
            {
                attribute.Value.ForEach(o => sb.AppendLine($"{attribute.Key} : {o} [{o.GetType()}]"));
            }
            Console.WriteLine(sb.ToString());
            //Console.WriteLine(packet.GetAttribute<String>("3GPP-GGSN-MCC-MNC"));
            throw new InvalidOperationException("Couldnt handle request?!");
        }
        private IRadiusPacket Stop(IRadiusPacket packet)
        {
            var user                = UsernameDomain.Parse(packet.GetAttribute <String>("User-Name"));
            var msisdn              = packet.GetAttribute <String>("Calling-Station-Id");
            var acctSessionId       = packet.GetAttribute <String>("Acct-Session-Id");
            var acctStatusType      = "Stop"; // duuh
            var acctInputOctets     = packet.GetAttribute <UInt32>("Acct-Input-Octets");
            var acctOutputOctets    = packet.GetAttribute <UInt32>("Acct-Output-Octets");
            var acctSessionTime     = packet.GetAttribute <UInt32>("Acct-Session-Time");
            var acctTerminateCause  = packet.GetAttribute <UInt32>("Acct-Terminate-Cause"); // oh crap, guess i need values as well...
            var acctInputGigawords  = packet.GetAttribute <UInt32?>("Acct-Input-Gigawords");
            var acctOutputGigawords = packet.GetAttribute <UInt32?>("Acct-Output-Gigawords");

            _log.Debug($"Handling stop packet for {msisdn} with AcctSessionId {acctSessionId}");
            try
            {
                using (var db = _contextFactory.GetContext())
                {
                    db.AccountingStop(user.Username, user.Domain, msisdn, acctStatusType, acctSessionId, acctInputOctets, acctOutputOctets,
                                      (int)acctSessionTime, acctTerminateCause.ToString(), acctInputGigawords, acctOutputGigawords);
                }
            }
            catch (EntityCommandExecutionException ex)
            {
                if (ex.InnerException?.Message.Contains("duplicate") ?? false)
                {
                    _log.Warn($"Duplicate stop packet for AcctSessionId {acctSessionId}");
                }
                else
                {
                    throw;
                }
            }
            return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
        }
        /// <summary>
        /// Sends a packet
        /// </summary>
        private void Send(IRadiusPacket responsePacket, IPEndPoint remoteEndpoint)
        {
            var responseBytes = _radiusPacketParser.GetBytes(responsePacket);

            _server.Send(responseBytes, responseBytes.Length, remoteEndpoint);
            _logger.Debug($"{responsePacket.Code} sent to {remoteEndpoint} Id={responsePacket.Identifier}");
        }
        public IRadiusPacket HandlePacket(IRadiusPacket packet)
        {
            var config    = ConfigurationManager.AppSettings;
            var domain    = config.Get("Domain");
            var groupName = config.Get("AdGroupName");

            _log.Info($"Recived request with packet code {packet.Code}");
            if (packet.Code == PacketCode.AccessRequest)
            {
                var userName     = packet.GetAttribute <String>("User-Name");
                var userPassword = packet.GetAttribute <String>("User-Password");
                var userLogin    = ValidateCredentials(domain, userName, userPassword, userName, userName);
                var userInGroup  = IsUserInAdGroup(domain, userName, groupName, userName, userPassword);
                _log.Info($"User Login result ={userLogin} UserInGroup result = {userInGroup} for user {userName}");
                if (userInGroup && userLogin)
                {
                    var response = packet.CreateResponsePacket(PacketCode.AccessAccept);
                    response.AddAttribute("Acct-Interim-Interval", 60);
                    return(response);
                }

                return(packet.CreateResponsePacket(PacketCode.AccessReject));
            }

            _log.Info($"Cant handle request code {packet.Code}");

            throw new InvalidOperationException($"Can't handle other requests besides AccessRequests with code {PacketCode.AccessRequest}");
        }
예제 #7
0
        public IRadiusPacket HandlePacket(IRadiusPacket packet)
        {
            if (packet.Code == PacketCode.AccountingRequest)
            {
                switch (packet.GetAttribute <AcctStatusType>("Acct-Status-Type"))
                {
                case AcctStatusType.Start:
                case AcctStatusType.Stop:
                case AcctStatusType.InterimUpdate:
                    return(packet.CreateResponsePacket(PacketCode.AccountingResponse));

                default:
                    break;
                }
            }
            else if (packet.Code == PacketCode.AccessRequest)
            {
                if (packet.GetAttribute <string>("User-Name") == UserName && packet.GetAttribute <string>("User-Password") == UserPassword)
                {
                    var response = packet.CreateResponsePacket(PacketCode.AccessAccept);
                    response.AddAttribute("Acct-Interim-Interval", 60);
                    return(response);
                }

                return(packet.CreateResponsePacket(PacketCode.AccessReject));
            }

            throw new InvalidOperationException("Couldnt handle request?!");
        }
        private IRadiusPacket Interim(IRadiusPacket packet)
        {
            var user                = UsernameDomain.Parse(packet.GetAttribute <String>("User-Name"));
            var msisdn              = packet.GetAttribute <String>("Calling-Station-Id");
            var acctSessionId       = packet.GetAttribute <String>("Acct-Session-Id");
            var acctStatusType      = "Alive"; // duuh
            var acctInputOctets     = packet.GetAttribute <UInt32>("Acct-Input-Octets");
            var acctOutputOctets    = packet.GetAttribute <UInt32>("Acct-Output-Octets");
            var acctSessionTime     = packet.GetAttribute <UInt32>("Acct-Session-Time");
            var acctInputGigawords  = packet.GetAttribute <UInt32?>("Acct-Input-Gigawords");
            var acctOutputGigawords = packet.GetAttribute <UInt32?>("Acct-Output-Gigawords");
            var nasIpAddress        = packet.GetAttribute <IPAddress>("NAS-IP-Address");
            var mccmnc              = Utils.GetMccMncFrom3GPPLocationInfo(packet.GetAttribute <Byte[]>("3GPP-User-Location-Info")).mccmnc;

            _log.Debug($"Handling interim packet for {msisdn} on {mccmnc} with AcctSessionId {acctSessionId}");
            using (var db = _contextFactory.GetContext())
            {
                db.AccountingInterim(user.Username, user.Domain, msisdn, acctStatusType, acctSessionId, acctInputOctets, acctOutputOctets,
                                     (int)acctSessionTime, acctInputGigawords, acctOutputGigawords);
            }

            Task.Factory.StartNew(() =>
            {
                if (CheckDisconnect(acctSessionId))
                {
                    _disconnector.DisconnectUserByMsisdn(msisdn);
                }
            }, TaskCreationOptions.LongRunning);

            return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
        }
        private IRadiusPacket Start(IRadiusPacket packet)
        {
            var user           = UsernameDomain.Parse(packet.GetAttribute <String>("User-Name"));
            var msisdn         = packet.GetAttribute <String>("Calling-Station-Id");
            var acctSessionId  = packet.GetAttribute <String>("Acct-Session-Id");
            var acctStatusType = "Start";    // duuh
            var locationInfo   = Utils.GetMccMncFrom3GPPLocationInfo(packet.GetAttribute <Byte[]>("3GPP-User-Location-Info"));

            _log.Debug($"Handling start packet for {msisdn} with AcctSessionId {acctSessionId}");

            try
            {
                using (var db = _contextFactory.GetContext())
                {
                    db.AccountingStart(user.Username, user.Domain, msisdn, acctStatusType, acctSessionId, locationInfo.mccmnc);
                }

                Task.Factory.StartNew(() => _welcomeSender.CheckWelcomeSms(msisdn), TaskCreationOptions.LongRunning);
            }
            catch (EntityCommandExecutionException ex)
            {
                if (ex.InnerException?.Message.Contains("duplicate") ?? false)
                {
                    _log.Warn($"Duplicate start packet for AcctSessionId {acctSessionId}");
                }
                else
                {
                    throw;
                }
            }

            return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
        }
예제 #10
0
        /// <summary>
        /// Sends a packet
        /// </summary>
        private void Send(IRadiusPacket responsePacket, string user, IPEndPoint remoteEndpoint, IPEndPoint proxyEndpoint, bool debugLog)
        {
            var responseBytes = _radiusPacketParser.GetBytes(responsePacket);

            _server.Send(responseBytes, responseBytes.Length, proxyEndpoint ?? remoteEndpoint);

            if (proxyEndpoint != null)
            {
                if (debugLog)
                {
                    _logger.Debug("{code:l} sent to {host:l}:{port} via {proxyhost:l}:{proxyport} id={id}", responsePacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, proxyEndpoint.Address, proxyEndpoint.Port, responsePacket.Identifier);
                }
                else
                {
                    _logger.Information("{code:l} sent to {host:l}:{port} via {proxyhost:l}:{proxyport} id={id} user='******'", responsePacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, proxyEndpoint.Address, proxyEndpoint.Port, responsePacket.Identifier, user);
                }
            }
            else
            {
                if (debugLog)
                {
                    _logger.Debug("{code:l} sent to {host:l}:{port} id={id}", responsePacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, responsePacket.Identifier);
                }
                else
                {
                    _logger.Information("{code:l} sent to {host:l}:{port} id={id} user='******'", responsePacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, responsePacket.Identifier, user);
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Tries to get a packet from the stream. Returns true if successful
        /// Returns false if no packet could be parsed or stream is empty ie closing
        /// </summary>
        /// <param name="stream"></param>
        /// <param name="packet"></param>
        /// <param name="dictionary"></param>
        /// <returns></returns>
        public static Boolean TryParsePacketFromStream(Stream stream, out IRadiusPacket packet, RadiusDictionary dictionary, Byte[] sharedSecret)
        {
            var packetHeaderBytes = new Byte[4];
            var i = stream.Read(packetHeaderBytes, 0, 4);

            if (i != 0)
            {
                try
                {
                    var packetLength       = BitConverter.ToUInt16(packetHeaderBytes.Reverse().ToArray(), 0);
                    var packetContentBytes = new Byte[packetLength - 4];
                    stream.Read(packetContentBytes, 0, packetContentBytes.Length);

                    packet = Parse(packetHeaderBytes.Concat(packetContentBytes).ToArray(), dictionary, sharedSecret);
                    return(true);
                }
                catch (Exception ex)
                {
                    _log.Warn("Unable to parse packet from stream", ex);
                }
            }

            packet = null;
            return(false);
        }
예제 #12
0
        /// <summary>
        /// Sends a packet
        /// </summary>
        /// <param name="responsePacket"></param>
        /// <param name="remoteEndpoint"></param>
        void SendResponsePacket(IRadiusPacket responsePacket, IPEndPoint remoteEndpoint)
        {
            var responseBytes = RadiusPacketParser.GetBytes(responsePacket);

            Server.Send(responseBytes, responseBytes.Length, remoteEndpoint);

            //TODO log output here
            //$"{responsePacket.Code} sent to {remoteEndpoint} Id={responsePacket.Identifier}"
        }
예제 #13
0
        public IRadiusPacket HandlePacket(IRadiusPacket packet)
        {
            // Simulate lag
            //Thread.Sleep(new Random().Next(100, 3000));


            if (packet.Authenticator != null)
            {
                Console.WriteLine($"Authenticator {packet.Authenticator.ToHexString()}");
            }
            if (packet.SharedSecret != null)
            {
                Console.WriteLine($"SharedSecret {packet.SharedSecret.ToHexString()}");
            }

            foreach (var att in packet.Attributes)
            {
                Console.WriteLine($"ATT : {att.Key} - {att.Value}");
            }

            var userName      = packet.GetAttribute <String>("User-Name");
            var password      = packet.GetAttribute <String>("User-Password");
            var chap_password = packet.GetAttribute <byte[]>("CHAP-Password");

            Console.WriteLine($"userName {userName} password : {password} chap-password : {chap_password?.ToHexString()}");

            if (packet.Code == PacketCode.AccountingRequest)
            {
                var acctStatusType = packet.GetAttribute <AcctStatusType>("Acct-Status-Type");
                if (acctStatusType == AcctStatusType.Start)
                {
                    return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
                }

                if (acctStatusType == AcctStatusType.Stop)
                {
                    return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
                }

                if (acctStatusType == AcctStatusType.InterimUpdate)
                {
                    return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
                }
            }
            else if (packet.Code == PacketCode.AccessRequest)
            {
                if (packet.GetAttribute <String>("User-Name") == "*****@*****.**" && packet.GetAttribute <String>("User-Password") == "1234")
                {
                    var response = packet.CreateResponsePacket(PacketCode.AccessAccept);
                    response.AddAttribute("Acct-Interim-Interval", 60);
                    return(response);
                }
                return(packet.CreateResponsePacket(PacketCode.AccessReject));
            }

            throw new InvalidOperationException("Couldnt handle request?!");
        }
        private IRadiusPacket Authenticate(IRadiusPacket packet)
        {
            var msisdn = packet.GetAttribute <String>("Calling-Station-Id");

            if (!packet.Attributes.ContainsKey("3GPP-User-Location-Info"))
            {
                _log.Warn("Missing 3GPP-User-Location-Info in packet, ignoring");
                return(null);
            }
            var locationInfo = Utils.GetMccMncFrom3GPPLocationInfo(packet.GetAttribute <Byte[]>("3GPP-User-Location-Info"));

            _log.Debug($"Handling authentication packet for {msisdn} on network {locationInfo.locationType}:{locationInfo.mccmnc}");
            using (var db = _contextFactory.GetContext())
            {
                if (locationInfo.mccmnc == "99999")
                {
                    _log.Warn($"No location info for msisdn {msisdn} check m2m portal 3GPP-SGSN-Address: {packet.GetAttribute<IPAddress>("3GPP-SGSN-Address")}");
                    return(packet.CreateResponsePacket(PacketCode.AccessReject));
                }
                var result = db.Authenticate1(msisdn, "flexinets", msisdn, locationInfo.mccmnc).ToList();
                if (result.Count > 0 && result.First() == null)
                {
                    var response = packet.CreateResponsePacket(PacketCode.AccessAccept);
                    response.AddAttribute("Acct-Interim-Interval", 60);
                    return(response);
                }
                else
                {
                    try
                    {
                        var mccmnc  = Convert.ToInt32(locationInfo.mccmnc);
                        var network = db.Networks.SingleOrDefault(o => o.mccmnc == mccmnc);
                        var simcard = db.SimCards.SingleOrDefault(o => o.Msisdn == msisdn);

                        var sb = new StringBuilder();

                        sb.AppendLine($"Authentication failed for {msisdn} on network {mccmnc} ({network?.providername}, {network?.countryname})");
                        if (simcard.user_id == null)
                        {
                            sb.AppendLine("Sim card not mapped to a user");
                        }
                        else
                        {
                            sb.AppendLine($"User: {simcard.UserSetting.user.username}@{simcard.UserSetting.user.realm}, group: {simcard.UserSetting.user.directory.name}");
                        }
                        _log.Warn(sb.ToString().Trim()); // todo needs throttling to reduce unwanted spam
                    }
                    catch (Exception ex)
                    {
                        _log.Error("huh?", ex);
                    }

                    return(packet.CreateResponsePacket(PacketCode.AccessReject));
                }
            }
        }
예제 #15
0
 public IRadiusPacket HandlePacket(IRadiusPacket packet)
 {
     if (packet.Code == PacketCode.AccountingRequest)
     {
         return(HandleAccountingPacket(packet));
     }
     else if (packet.Code == PacketCode.AccessRequest)
     {
         return(HandleAuthenticationPacket(packet));
     }
     return(null);
 }
예제 #16
0
        /// <summary>
        /// Authenticate user through proxy or locally
        /// </summary>
        /// <param name="packet"></param>
        /// <returns></returns>
        private IRadiusPacket AuthenticateUser(IRadiusPacket packet)
        {
            var usernamedomain = packet.GetAttribute <String>("User-Name").ToLowerInvariant();
            var packetPassword = packet.GetAttribute <String>("User-Password");

            var proxyresponse = _authProxy.ProxyAuthentication(usernamedomain, packetPassword);

            if (proxyresponse.HasValue)
            {
                _log.Info($"Got response from proxy for username {usernamedomain}");
                return(packet.CreateResponsePacket(proxyresponse.Value));
            }
            else
            {
                using (var db = _contextFactory.GetContext())
                {
                    var username = UsernameDomain.Parse(usernamedomain);
                    var userid   = _userAuthProvider.AuthenticateAsync(username.Username, username.Domain, packetPassword).Result;
                    if (userid.HasValue)
                    {
                        return(packet.CreateResponsePacket(PacketCode.AccessAccept));
                    }
                    else
                    {
                        var user = db.users.SingleOrDefault(o => o.username == username.Username && o.realm == username.Domain);
                        if (user == null)
                        {
                            _log.Warn($"Username {usernamedomain} not found");
                        }
                        else if (user.status != 1)
                        {
                            _log.Warn($"Username {usernamedomain} is not active, email: {user.email}");
                        }
                        else
                        {
                            _log.Warn($"Bad password for user {usernamedomain}, password is {packetPassword.Length} characters, email: {user.email}");
                        }

                        var location = packet.GetAttribute <String>("Ipass-Location-Description");
                        if (!String.IsNullOrEmpty(location))
                        {
                            _log.Warn($"iPass location description: {location}");
                        }

                        return(packet.CreateResponsePacket(PacketCode.AccessReject));
                    }
                }
            }
        }
예제 #17
0
        /// <summary>
        /// Check is packet was retransmissed (duplicated)
        /// </summary>
        public bool IsRetransmission(IRadiusPacket requestPacket, IPEndPoint remoteEndpoint)
        {
            //unique key is combination of packet code, identifier, client endpoint, user name and request authenticator

            var uniqueKey = requestPacket.CreateUniqueKey(remoteEndpoint);

            if (_cache.TryGetValue(uniqueKey, out _))
            {
                return(true);
            }

            _cache.Set(uniqueKey, "1", DateTimeOffset.UtcNow.AddMinutes(1));

            return(false);
        }
        /// <summary>
        /// Dump the packet attributes to the log
        /// </summary>
        /// <param name="packet"></param>
        private static void DumpPacket(IRadiusPacket packet)
        {
            var sb = new StringBuilder();

            sb.AppendLine($"Packet dump for {packet.Identifier}:");
            foreach (var attribute in packet.Attributes)
            {
                if (attribute.Key == "User-Password")
                {
                    sb.AppendLine($"{attribute.Key} length : {attribute.Value.First().ToString().Length}");
                }
                else
                {
                    attribute.Value.ForEach(o => sb.AppendLine($"{attribute.Key} : {o} [{o.GetType()}]"));
                }
            }
            _log.Debug(sb.ToString());
        }
예제 #19
0
        /// <summary>
        /// Send a packet with specified timeout
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="remoteEndpoint"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public async Task <IRadiusPacket> SendPacketAsync(IRadiusPacket packet, IPEndPoint remoteEndpoint, TimeSpan timeout)
        {
            await _client.ConnectAsync(remoteEndpoint.Address, remoteEndpoint.Port);

            var sslStream = new SslStream(_client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate));
            await sslStream.AuthenticateAsClientAsync("radsecserver", _certs, SslProtocols.Tls12, true);

            var packetBytes = packet.GetBytes(_dictionary);
            await sslStream.WriteAsync(packetBytes, 0, packetBytes.Length);

            if (RadiusPacket.TryParsePacketFromStream(sslStream, out var responsePacket, _dictionary, packet.SharedSecret))
            {
                _client.Close();
                return(responsePacket);
            }

            _client.Close();
            return(null);
        }
        public IRadiusPacket HandlePacket(IRadiusPacket packet)
        {
            if (packet.Code == PacketCode.AccessRequest)
            {
                return(Authenticate(packet));
            }
            else if (packet.Code == PacketCode.AccountingRequest && packet.GetAttribute <AcctStatusType>("Acct-Status-Type") == AcctStatusType.Start)
            {
                return(Start(packet));
            }
            else if (packet.Code == PacketCode.AccountingRequest && packet.GetAttribute <AcctStatusType>("Acct-Status-Type") == AcctStatusType.Stop)
            {
                return(Stop(packet));
            }
            else if (packet.Code == PacketCode.AccountingRequest && packet.GetAttribute <AcctStatusType>("Acct-Status-Type") == AcctStatusType.InterimUpdate)
            {
                return(Interim(packet));
            }

            throw new InvalidOperationException($"Nothing configured for {packet.Code}");
        }
예제 #21
0
        /// <summary>
        /// Authentication
        /// </summary>
        /// <param name="packet"></param>
        /// <returns></returns>
        private IRadiusPacket HandleAuthenticationPacket(IRadiusPacket packet)
        {
            _log.Info($"Handling {packet.Code} packet for {packet.GetAttribute<String>("User-Name")}");
            var usernamedomain = packet.GetAttribute <String>("User-Name").ToLowerInvariant();
            var response       = AuthenticateUser(packet);

            if (response.Code == PacketCode.AccessReject)
            {
                _failures.Add(usernamedomain);
            }
            else if (response.Code == PacketCode.AccessAccept)
            {
                if (_failures.Contains(usernamedomain))
                {
                    _log.Warn($"Username {usernamedomain} authenticated after failures");
                    _failures.Remove(usernamedomain);
                }
            }

            return(response);
        }
        public IRadiusPacket HandlePacket(IRadiusPacket packet)
        {
            // Simulate lag
            //Thread.Sleep(new Random().Next(100, 3000));

            if (packet.Code == PacketCode.AccountingRequest)
            {
                var acctStatusType = packet.GetAttribute <AcctStatusType>("Acct-Status-Type");
                if (acctStatusType == AcctStatusType.Start)
                {
                    return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
                }

                if (acctStatusType == AcctStatusType.Stop)
                {
                    return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
                }

                if (acctStatusType == AcctStatusType.InterimUpdate)
                {
                    return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
                }
            }
            else if (packet.Code == PacketCode.AccessRequest)
            {
                if (packet.GetAttribute <String>("User-Name") == "*****@*****.**" && packet.GetAttribute <String>("User-Password") == "1234")
                {
                    var response = packet.CreateResponsePacket(PacketCode.AccessAccept);
                    response.AddAttribute("Acct-Interim-Interval", 60);
                    return(response);
                }
                return(packet.CreateResponsePacket(PacketCode.AccessReject));
            }

            throw new InvalidOperationException("Couldnt handle request?!");
        }
예제 #23
0
 /// <summary>
 /// Send a packet with default timeout of 3 seconds
 /// </summary>
 /// <param name="packet"></param>
 /// <param name="remoteEndpoint"></param>
 /// <returns></returns>
 public async Task <IRadiusPacket> SendPacketAsync(IRadiusPacket packet, IPEndPoint remoteEndpoint)
 {
     return(await SendPacketAsync(packet, remoteEndpoint, TimeSpan.FromSeconds(3)));
 }
        /// <summary>
        /// Get the raw packet bytes
        /// </summary>
        /// <returns></returns>
        public byte[] GetBytes(IRadiusPacket packet)
        {
            var packetBytes = new List <byte>
            {
                (byte)packet.Code,
                packet.Identifier
            };

            packetBytes.AddRange(new byte[18]); // Placeholder for length and authenticator

            var messageAuthenticatorPosition = 0;

            foreach (var attribute in packet.Attributes)
            {
                // todo add logic to check attribute object type matches type in dictionary?
                foreach (var value in attribute.Value)
                {
                    var contentBytes = GetAttributeValueBytes(value);
                    var headerBytes  = new byte[2];

                    var attributeType = _radiusDictionary.GetAttribute(attribute.Key);
                    switch (attributeType)
                    {
                    case DictionaryVendorAttribute _attributeType:
                        headerBytes    = new byte[8];
                        headerBytes[0] = 26;     // VSA type

                        var vendorId = BitConverter.GetBytes(_attributeType.VendorId);
                        Array.Reverse(vendorId);
                        Buffer.BlockCopy(vendorId, 0, headerBytes, 2, 4);
                        headerBytes[6] = (byte)_attributeType.VendorCode;
                        headerBytes[7] = (byte)(2 + contentBytes.Length);      // length of the vsa part
                        break;

                    case DictionaryAttribute _attributeType:
                        headerBytes[0] = attributeType.Code;

                        // Encrypt password if this is a User-Password attribute
                        if (_attributeType.Code == 2)
                        {
                            contentBytes = RadiusPassword.Encrypt(packet.SharedSecret, packet.Authenticator, contentBytes);
                        }
                        else if (_attributeType.Code == 80)        // Remember the position of the message authenticator, because it has to be added after everything else
                        {
                            messageAuthenticatorPosition = packetBytes.Count;
                        }
                        break;

                    default:
                        throw new InvalidOperationException($"Unknown attribute {attribute.Key}, check spelling or dictionary");
                    }

                    headerBytes[1] = (byte)(headerBytes.Length + contentBytes.Length);
                    packetBytes.AddRange(headerBytes);
                    packetBytes.AddRange(contentBytes);
                }
            }

            // Note the order of the bytes...
            var packetLengthBytes = BitConverter.GetBytes(packetBytes.Count);

            packetBytes[2] = packetLengthBytes[1];
            packetBytes[3] = packetLengthBytes[0];

            var packetBytesArray = packetBytes.ToArray();

            // todo refactor this...
            if (packet.Code == PacketCode.AccountingRequest || packet.Code == PacketCode.DisconnectRequest || packet.Code == PacketCode.CoaRequest)
            {
                if (messageAuthenticatorPosition != 0)
                {
                    var temp = new byte[16];
                    Buffer.BlockCopy(temp, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16);
                    var messageAuthenticatorBytes = CalculateMessageAuthenticator(packetBytesArray, packet.SharedSecret, null);
                    Buffer.BlockCopy(messageAuthenticatorBytes, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16);
                }

                var authenticator = CalculateRequestAuthenticator(packet.SharedSecret, packetBytesArray);
                Buffer.BlockCopy(authenticator, 0, packetBytesArray, 4, 16);
            }
            else if (packet.Code == PacketCode.StatusServer)
            {
                var authenticator = packet.RequestAuthenticator != null?CalculateResponseAuthenticator(packet.SharedSecret, packet.RequestAuthenticator, packetBytesArray) : packet.Authenticator;

                Buffer.BlockCopy(authenticator, 0, packetBytesArray, 4, 16);

                if (messageAuthenticatorPosition != 0)
                {
                    var temp = new byte[16];
                    Buffer.BlockCopy(temp, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16);
                    var messageAuthenticatorBytes = CalculateMessageAuthenticator(packetBytesArray, packet.SharedSecret, packet.RequestAuthenticator);
                    Buffer.BlockCopy(messageAuthenticatorBytes, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16);
                }
            }
            else
            {
                if (messageAuthenticatorPosition != 0)
                {
                    var temp = new byte[16];
                    Buffer.BlockCopy(temp, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16);
                    var messageAuthenticatorBytes = CalculateMessageAuthenticator(packetBytesArray, packet.SharedSecret, packet.RequestAuthenticator);
                    Buffer.BlockCopy(messageAuthenticatorBytes, 0, packetBytesArray, messageAuthenticatorPosition + 2, 16);
                }

                var authenticator = packet.RequestAuthenticator != null?CalculateResponseAuthenticator(packet.SharedSecret, packet.RequestAuthenticator, packetBytesArray) : packet.Authenticator;

                Buffer.BlockCopy(authenticator, 0, packetBytesArray, 4, 16);
            }

            return(packetBytesArray);
        }
예제 #25
0
        /// <summary>
        /// Accounting
        /// </summary>
        /// <param name="packet"></param>
        /// <returns></returns>
        private IRadiusPacket HandleAccountingPacket(IRadiusPacket packet)
        {
            var acctStatusType = packet.GetAttribute <AcctStatusType>("Acct-Status-Type");

            if (acctStatusType == AcctStatusType.Start || acctStatusType == AcctStatusType.Stop)
            {
                var usernamedomain = UsernameDomain.Parse(packet.GetAttribute <String>("User-Name"));
                var nodeid         = GetUserNodeId(usernamedomain.Username, usernamedomain.Domain);
                _log.Info($"Handling {acctStatusType} packet for {usernamedomain}");
                try
                {
                    using (var db = _contextFactory.GetContext())
                    {
                        var entry = new radiatoraccounting
                        {
                            username          = usernamedomain.Username,
                            realm             = usernamedomain.Domain,
                            node_id           = nodeid,
                            ACCTSTATUSTYPE    = (packet.GetAttribute <AcctStatusType>("Acct-Status-Type")).ToString(),
                            ACCTINPUTOCTETS   = Convert.ToUInt32(packet.GetAttribute <UInt32?>("Acct-Input-Octets")),
                            ACCTOUTPUTOCTETS  = Convert.ToUInt32(packet.GetAttribute <UInt32?>("Acct-Output-Octets")),
                            ACCTSESSIONID     = packet.GetAttribute <String>("Acct-Session-Id"),
                            ACCTSESSIONTIME   = Convert.ToInt32(packet.GetAttribute <UInt32?>("Acct-Session-Time")),
                            NASIDENTIFIER     = packet.GetAttribute <String>("NAS-Identifier"),
                            NASPORT           = packet.GetAttribute <UInt32?>("NAS-Port"),
                            NASPORTTYPE       = packet.GetAttribute <UInt32?>("NAS-Port-Type").ToString(),
                            WISPrLocationName = packet.GetAttribute <String>("WISPr-Location-Name"),
                            temp = packet.GetAttribute <String>("Ipass-Location-Description"),
                            timestamp_datetime = packet.Attributes.ContainsKey("Timestamp") ? (DateTime?)DateTimeOffset.FromUnixTimeSeconds(packet.GetAttribute <Int32>("Timestamp")).UtcDateTime : DateTime.UtcNow
                        };
                        db.radiatoraccountings.Add(entry);
                        db.SaveChanges();
                    }
                }
                catch (DbUpdateConcurrencyException)
                {
                    _log.Info($"Duplicate {acctStatusType} request received");
                }
                catch (Exception ex)
                {
                    _log.Error("Something went wrong", ex);
                }

                if (acctStatusType == AcctStatusType.Start)
                {
                    try
                    {
                        using (var db = _contextFactory.GetContext())
                        {
                            db.radiatoronlines.Add(new radiatoronline
                            {
                                username           = usernamedomain.Username,
                                realm              = usernamedomain.Domain,
                                node_id            = nodeid,
                                ACCTSESSIONID      = packet.GetAttribute <String>("Acct-Session-Id"),
                                timestamp_datetime = packet.Attributes.ContainsKey("Timestamp") ? (DateTime?)DateTimeOffset.FromUnixTimeSeconds(packet.GetAttribute <Int32>("Timestamp")).UtcDateTime : DateTime.UtcNow,
                                NASIDENTIFIER      = packet.GetAttribute <String>("NAS-Identifier"),
                                NASPORT            = packet.GetAttribute <UInt32?>("NAS-Port"),
                                NASPORTTYPE        = packet.GetAttribute <UInt32?>("NAS-Port-Type").ToString(),
                                WISPrLocationName  = packet.GetAttribute <String>("Ipass-Location-Description")
                            });
                            db.SaveChanges();
                        }
                    }
                    catch (DbUpdateConcurrencyException)
                    {
                        _log.Info("Cannot insert duplicate in radiatoronline");
                    }
                }
                if (acctStatusType == AcctStatusType.Stop)
                {
                    try
                    {
                        using (var db = _contextFactory.GetContext())
                        {
                            var acctsessionid = packet.GetAttribute <String>("Acct-Session-Id");
                            var online        = db.radiatoronlines.SingleOrDefault(o => o.ACCTSESSIONID == acctsessionid);
                            if (online != null)
                            {
                                db.radiatoronlines.Remove(online);
                                db.SaveChanges();
                            }
                        }
                    }
                    catch (DbUpdateConcurrencyException)
                    {
                        _log.Info("Nothing to remove from online");
                    }
                }
            }
            return(packet.CreateResponsePacket(PacketCode.AccountingResponse));
        }