/// <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 = RadiusPacketParser.Parse(packetBytes, Encoding.UTF8.GetBytes(sharedSecret)); //TODO log output here //$"Received {requestPacket.Code} from {remoteEndpoint} Id={requestPacket.Identifier}" //if logger in debug mode //DumpPacket(requestPacket); //TODO log output here //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; //TODO log output here //$"Sending {responseCode} for StatusServer request from {remoteEndpoint}" return(requestPacket.CreateResponsePacket(responseCode)); } //TODO log output here //$"Handling packet for remote ip {remoteEndpoint.Address} with {packetHandler.GetType()}" var sw = Stopwatch.StartNew(); var responsePacket = packetHandler.HandlePacket(requestPacket); sw.Stop(); //TODO log output here //$"{remoteEndpoint} Id={responsePacket.Identifier}, Received {responsePacket.Code} from handler in {sw.ElapsedMilliseconds}ms" //TODO log output here //if (sw.ElapsedMilliseconds >= 5000) //$"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); }
/// <summary> /// Used to handle the packets asynchronously /// </summary> /// <param name="remoteEndpoint"></param> /// <param name="packetBytes"></param> private void HandlePacket(IPEndPoint remoteEndpoint, Byte[] packetBytes) { try { _logger.LogDebug($"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); } } else { _logger.LogError($"No packet handler found for remote ip {remoteEndpoint}"); var packet = _radiusPacketParser.Parse(packetBytes, Encoding.UTF8.GetBytes("wut")); DumpPacket(packet); } } catch (Exception ex) when(ex is ArgumentException || ex is OverflowException) { _logger.LogWarning($"Ignoring malformed(?) packet received from {remoteEndpoint}", ex); _logger.LogDebug(packetBytes.ToHexString()); } catch (Exception ex) { _logger.LogError(ex, $"Failed to receive packet from {remoteEndpoint}"); _logger.LogDebug(packetBytes.ToHexString()); } finally { Interlocked.Decrement(ref _concurrentHandlerCount); } }
/// <summary> /// Parses a packet and gets a response packet from the handler /// </summary> internal void ParseAndProcess(byte[] packetBytes, IPEndPoint remoteEndpoint) { var requestPacket = _radiusPacketParser.Parse(packetBytes, Encoding.UTF8.GetBytes(_configuration.RadiusSharedSecret)); _logger.Debug($"Received {requestPacket.Code} from {remoteEndpoint} Id={requestPacket.Identifier}"); if (_cacheService.IsRetransmission(requestPacket, remoteEndpoint)) { _logger.Debug($"Retransmissed request from {remoteEndpoint} Id={requestPacket.Identifier}, ignoring"); return; } var request = new PendingRequest { RemoteEndpoint = remoteEndpoint, RequestPacket = requestPacket }; Task.Run(() => _router.HandleRequest(request)); }
/// <summary> /// Authenticate request at Remote Radius Server with user-name and password /// </summary> private async Task <PacketCode> ProcessRadiusAuthentication(PendingRequest request, ClientConfiguration clientConfig) { try { //sending request as is to Remote Radius Server using (var client = new RadiusClient(clientConfig.ServiceClientEndpoint, _logger)) { _logger.Debug($"Sending AccessRequest message with id={{id}} to Remote Radius Server {clientConfig.NpsServerEndpoint}", request.RequestPacket.Identifier); var requestBytes = _packetParser.GetBytes(request.RequestPacket); var response = await client.SendPacketAsync(request.RequestPacket.Identifier, requestBytes, clientConfig.NpsServerEndpoint, TimeSpan.FromSeconds(5)); if (response != null) { var responsePacket = _packetParser.Parse(response, request.RequestPacket.SharedSecret, request.RequestPacket.Authenticator); _logger.Debug("Received {code:l} message with id={id} from Remote Radius Server", responsePacket.Code.ToString(), responsePacket.Identifier); if (responsePacket.Code == PacketCode.AccessAccept) { var userName = request.RequestPacket.UserName; _logger.Information($"User '{{user:l}}' credential and status verified successfully at {clientConfig.NpsServerEndpoint}", userName); } request.ResponsePacket = responsePacket; return(responsePacket.Code); //Code received from remote radius } else { _logger.Warning("Remote Radius Server did not respond on message with id={id}", request.RequestPacket.Identifier); return(PacketCode.AccessReject); //reject by default } } } catch (Exception ex) { _logger.Error(ex, "Radius authentication error"); } return(PacketCode.AccessReject); //reject by default }
/// <summary> /// Authenticate request at Network Policy Server with user-name and password /// </summary> private PacketCode ProcessRadiusAuthentication(PendingRequest request) { try { //sending request as is to Network Policy Server using (var client = new RadiusClient(_configuration.ServiceClientEndpoint, _logger)) { _logger.Debug($"Sending Access-Request message with Id={request.RequestPacket.Identifier} to Network Policy Server {_configuration.NpsServerEndpoint}"); var requestBytes = _packetParser.GetBytes(request.RequestPacket); var response = client.SendPacketAsync(request.RequestPacket.Identifier, requestBytes, _configuration.NpsServerEndpoint, TimeSpan.FromSeconds(5)).Result; if (response != null) { var responsePacket = _packetParser.Parse(response, request.RequestPacket.SharedSecret, request.RequestPacket.Authenticator); _logger.Debug($"Received {responsePacket.Code} message with Id={responsePacket.Identifier} from Network Policy Server"); if (responsePacket.Code == PacketCode.AccessAccept) { var userName = request.RequestPacket.UserName; _logger.Information($"User '{userName}' credential and status verified successfully at {_configuration.NpsServerEndpoint}"); } request.ResponsePacket = responsePacket; return(responsePacket.Code); //Code received from NPS } else { _logger.Warning($"Network Policy Server did not respond on message with Id={request.RequestPacket.Identifier}"); return(PacketCode.AccessReject); //reject by default } } } catch (Exception ex) { _logger.Error(ex, "Radius authentication error"); } return(PacketCode.AccessReject); //reject by default }
/// <summary> /// Parses a packet and gets a response packet from the handler /// </summary> internal void ParseAndProcess(byte[] packetBytes, IPEndPoint remoteEndpoint) { IPEndPoint proxyEndpoint = null; if (IsProxyProtocol(packetBytes, out var sourceEndpoint, out var requestWithoutProxyHeader)) { packetBytes = requestWithoutProxyHeader; proxyEndpoint = remoteEndpoint; remoteEndpoint = sourceEndpoint; } ClientConfiguration clientConfiguration = null; if (RadiusPacketNasIdentifierParser.TryParse(packetBytes, out var nasIdentifier)) { clientConfiguration = _serviceConfiguration.GetClient(nasIdentifier); } if (clientConfiguration == null) { clientConfiguration = _serviceConfiguration.GetClient(remoteEndpoint.Address); } if (clientConfiguration == null) { _logger.Warning("Received packet from unknown client {host:l}:{port}, ignoring", remoteEndpoint.Address, remoteEndpoint.Port); return; } var requestPacket = _radiusPacketParser.Parse(packetBytes, Encoding.UTF8.GetBytes(clientConfiguration.RadiusSharedSecret)); var isRetransmission = _cacheService.IsRetransmission(requestPacket, remoteEndpoint); if (isRetransmission) { _logger.Debug("Retransmissed request from {host:l}:{port} id={id} client '{client:l}', ignoring", remoteEndpoint.Address, remoteEndpoint.Port, requestPacket.Identifier, clientConfiguration.Name); return; } if (proxyEndpoint != null) { if (requestPacket.Code == PacketCode.StatusServer) { _logger.Information("Received {code:l} from {host:l}:{port} proxied by {proxyhost:l}:{proxyport} id={id} client '{client:l}'", requestPacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, proxyEndpoint.Address, proxyEndpoint.Port, requestPacket.Identifier, clientConfiguration.Name); } else { _logger.Information("Received {code:l} from {host:l}:{port} proxied by {proxyhost:l}:{proxyport} id={id} user='******' client '{client:l}'", requestPacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, proxyEndpoint.Address, proxyEndpoint.Port, requestPacket.Identifier, requestPacket.UserName, clientConfiguration.Name); } } else { if (requestPacket.Code == PacketCode.StatusServer) { _logger.Debug("Received {code:l} from {host:l}:{port} id={id} client '{client:l}'", requestPacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, requestPacket.Identifier, clientConfiguration.Name); } else { _logger.Information("Received {code:l} from {host:l}:{port} id={id} user='******' client '{client:l}'", requestPacket.Code.ToString(), remoteEndpoint.Address, remoteEndpoint.Port, requestPacket.Identifier, requestPacket.UserName, clientConfiguration.Name); } } var request = new PendingRequest { RemoteEndpoint = remoteEndpoint, ProxyEndpoint = proxyEndpoint, RequestPacket = requestPacket }; Task.Run(async() => await _router.HandleRequest(request, clientConfiguration)); }