/// <summary> /// Encodes this Radius response packet and sends it to the specified output /// stream. /// @param out output stream to use /// @param sharedSecret shared secret to be used to encode this packet /// @param request Radius request packet /// @exception IOException communication error /// </summary> public void EncodeResponsePacket(Stream @out, String sharedSecret, RadiusPacket request) { if (request == null) { throw new ArgumentNullException("request", "request cannot be null"); } EncodePacket(@out, sharedSecret, request); }
/** * Creates a RadiusProxyConnection object. * @param radiusServer server endpoint * @param radiusClient client endpoint * @param port port the proxied packet arrived at originally */ public RadiusProxyConnection(RadiusEndpoint radiusServer, RadiusEndpoint radiusClient, RadiusPacket packet, int port) { RadiusServer = radiusServer; RadiusClient = radiusClient; Packet = packet; Port = port; }
/// <summary> /// Reads a Radius response packet from the given input stream and /// creates an appropiate RadiusPacket descendant object. /// Reads in all attributes and returns the object. /// Checks the packet authenticator. /// @param dictionary dictionary to use for attributes /// @param in InputStream to read packet from /// @param sharedSecret shared secret to be used to decode this packet /// @param request Radius request packet /// @return new RadiusPacket object /// @exception IOException IO error /// @exception RadiusException malformed packet /// </summary> public RadiusPacket DecodeResponsePacket(IWritableDictionary dictionary, Stream @in, String sharedSecret, RadiusPacket request) { if (request == null) { throw new ArgumentNullException("request", "request may not be null"); } return(DecodePacket(dictionary, @in, sharedSecret, request)); }
public override RadiusPacket AccessRequestReceived(AccessRequest accessRequest, IPEndPoint client) { try { string ip = GetIP(accessRequest); string macAddr = GetMacAddress(ip); RadiusPacket answer; if (ServiceCfg.Instance.TinyConfig.ValidateByLdap) { Logger.InfoFormat("尝试通过Ldap检查用户,账户:{0},密码:{1},Mac:{2},IP:{3}", accessRequest.UserName, accessRequest.Password, macAddr, ip); if (ServiceCfg.Instance.TinyConfig.LdapSetting.IsAuthenticated(accessRequest.UserName, accessRequest.Password)) { Logger.InfoFormat("Ldap登录成功,账户:{0},密码:{1},Mac:{2},IP:{3}", accessRequest.UserName, accessRequest.Password, macAddr, ip); Logger.InfoFormat("{0} login by Ldap success.", accessRequest.UserName); answer = new RadiusPacket(RadiusPacket.AccessAccept, accessRequest.Identifier); CopyProxyState(accessRequest, answer); return answer; } Logger.InfoFormat("Ldap登录失败,账户:{0},密码:{1},Mac:{2},IP:{3}", accessRequest.UserName, accessRequest.Password, macAddr, ip); } if (ServiceCfg.Instance.TinyConfig.ValidateByDatabase) { Logger.InfoFormat("通过本地数据库检查Mac地址,账户:{0},密码:{1},Mac:{2},IP:{3}", accessRequest.UserName, accessRequest.Password, macAddr, ip); Logger.Debug("检查Mac地址"); if (!IsMacCorrect(accessRequest.UserName, macAddr)) { Logger.InfoFormat("Mac地址不正确,账户:{0},密码:{1},Mac:{2},IP:{3}", accessRequest.UserName, accessRequest.Password, macAddr, ip); answer = new RadiusPacket(RadiusPacket.AccessReject, accessRequest.Identifier); CopyProxyState(accessRequest, answer); return answer; } return base.AccessRequestReceived(accessRequest, client); } answer = new RadiusPacket(RadiusPacket.AccessReject, accessRequest.Identifier); CopyProxyState(accessRequest, answer); return answer; } catch (Exception ex) { Logger.Error("some error happend.", ex); return new RadiusPacket(RadiusPacket.AccessReject, accessRequest.Identifier); } }
/// <summary> /// Encodes this Radius packet and sends it to the specified output /// stream. /// @param out output stream to use /// @param sharedSecret shared secret to be used to encode this packet /// @param request Radius request packet if this packet to be encoded /// is a response packet, null if this packet is a request packet /// @exception IOException communication error /// @exception NotImplementedException if required packet data has not been set /// </summary> protected void EncodePacket(Stream outputStream, String sharedSecret, RadiusPacket request) { // check shared secret if (string.IsNullOrEmpty(sharedSecret)) { throw new ArgumentNullException("sharedSecret", "no shared secret has been set"); } // check request authenticator if (request != null && request.Authenticator == null) { throw new NotImplementedException("request authenticator not set"); } // request packet authenticator if (request == null) { // first create authenticator, then encode attributes // (User-Password attribute needs the authenticator) Authenticator = CreateRequestAuthenticator(sharedSecret); EncodeRequestAttributes(sharedSecret); } byte[] attributes = GetAttributeBytes(); int packetLength = RadiusHeaderLength + attributes.Length; if (packetLength > MaxPacketLength) { throw new NotImplementedException("packet too long"); } // response packet authenticator Authenticator = request != null ? CreateResponseAuthenticator(sharedSecret, packetLength, attributes, request.Authenticator) : UpdateRequestAuthenticator(sharedSecret, packetLength, attributes); outputStream.WriteByte(Convert.ToByte(Type)); outputStream.WriteByte(Convert.ToByte(Identifier)); byte[] lengthBytes = BitConverter.GetBytes(Convert.ToInt16(packetLength)); Array.Reverse(lengthBytes); outputStream.Write(lengthBytes, 0, lengthBytes.Length); byte[] authen = Authenticator; outputStream.Write(authen, 0, authen.Length); outputStream.Write(attributes, 0, attributes.Length); }
public override RadiusEndpoint GetProxyServer(RadiusPacket packet, RadiusEndpoint client) { // always proxy try { IPAddress address = IPAddress.Parse("127.0. 0. 1 "); int port = 10000; if (typeof (AccountingRequest).IsInstanceOfType(packet)) port = 10001; return new RadiusEndpoint(new IPEndPoint(address, port), "testing123"); } catch { return null; } }
public override RadiusPacket AccessRequestReceived(AccessRequest accessRequest, IPEndPoint client) { /*if (ServiceCfg.Instance.TinyConfig.ValidateByLdap) { string struser = accessRequest.UserName; string strpwd = accessRequest.Password; string path = ServiceCfg.Instance.TinyConfig.LdapSetting.Path; int type = RadiusPacket.AccessReject; var auth = new LdapAuthentication(path); if (auth.IsAuthenticated(ServiceCfg.Instance.TinyConfig.LdapSetting.DomainName, struser, strpwd)) { type = RadiusPacket.AccessAccept; } if (type == RadiusPacket.AccessAccept) { var answer = new RadiusPacket(type, accessRequest.Identifier); CopyProxyState(accessRequest, answer); return answer; } }*/ string struser = accessRequest.UserName; string strpwd = accessRequest.Password; this.Logger.InfoFormat("通过Ldap检查用户,用户{0},密码{1}", struser, strpwd); if (!LdapAuthentication.IsAuthenticated(struser, strpwd)) { this.Logger.InfoFormat("用户(账户{0},密码{1})Ldap登录失败,尝试本地数据库登陆", struser, strpwd); return base.AccessRequestReceived(accessRequest, client); } else { this.Logger.InfoFormat("用户(账户{0},密码{1})Ldap登录成功.", struser, strpwd); const int type = RadiusPacket.AccessAccept; var answer = new RadiusPacket(type, accessRequest.Identifier); CopyProxyState(accessRequest, answer); return answer; } }
/// <summary> /// Creates a RadiusPacket object. Depending on the passed type, the /// appropiate successor is chosen. Sets the type, but does not touch /// the packet identifier. /// @param type packet type /// @return RadiusPacket object /// </summary> public static RadiusPacket CreateRadiusPacket(int type) { RadiusPacket rp; switch (type) { case AccessRequest: rp = new AccessRequest(); break; case AccountingRequest: rp = new AccountingRequest(); break; case AccessAccept: case AccessReject: case AccountingResponse: default: rp = new RadiusPacket(); break; } rp.Type = type; return(rp); }
/// <summary> /// Creates a RadiusPacket object. Depending on the passed type, the /// appropiate successor is chosen. Sets the type, but does not touch /// the packet identifier. /// @param type packet type /// @return RadiusPacket object /// </summary> public static RadiusPacket CreateRadiusPacket(int type) { RadiusPacket rp; switch (type) { case AccessRequest: rp = new AccessRequest(); break; case AccountingRequest: rp = new AccountingRequest(); break; case AccessAccept: case AccessReject: case AccountingResponse: default: rp = new RadiusPacket(); break; } rp.Type = type; return rp; }
/// <summary> /// Reads a Radius response packet from the given input stream and /// creates an appropiate RadiusPacket descendant object. /// Reads in all attributes and returns the object. /// Checks the packet authenticator. /// @param dictionary dictionary to use for attributes /// @param in InputStream to read packet from /// @param sharedSecret shared secret to be used to decode this packet /// @param request Radius request packet /// @return new RadiusPacket object /// @exception IOException IO error /// @exception RadiusException malformed packet /// </summary> public RadiusPacket DecodeResponsePacket(IWritableDictionary dictionary, Stream @in, String sharedSecret, RadiusPacket request) { if (request == null) throw new ArgumentNullException("request", "request may not be null"); return DecodePacket(dictionary, @in, sharedSecret, request); }
/// <summary> /// Reads a Radius response packet from the given input stream and /// creates an appropiate RadiusPacket descendant object. /// Reads in all attributes and returns the object. /// Checks the packet authenticator. /// @param sharedSecret shared secret to be used to decode this packet /// @param request Radius request packet /// @return new RadiusPacket object /// @exception IOException IO error /// @exception RadiusException malformed packet /// </summary> public static RadiusPacket DecodeResponsePacket(Stream @in, String sharedSecret, RadiusPacket request) { if (request == null) throw new ArgumentNullException("request", "request may not be null"); return DecodePacket(DefaultDictionary.GetDefaultDictionary(), @in, sharedSecret, request); }
/// <summary> /// Encodes this Radius response packet and sends it to the specified output /// stream. /// @param out output stream to use /// @param sharedSecret shared secret to be used to encode this packet /// @param request Radius request packet /// @exception IOException communication error /// </summary> public void EncodeResponsePacket(Stream @out, String sharedSecret, RadiusPacket request) { if (request == null) throw new ArgumentNullException("request", "request cannot be null"); EncodePacket(@out, sharedSecret, request); }
/** * Proxies the given packet to the server given in the Proxy connection. * Stores the Proxy connection object in the cache with a key that * is added to the packet in the "Proxy-State" attribute. * @param packet the packet to Proxy * @param proxyCon the RadiusProxyConnection for this packet * @throws IOException */ protected void proxyPacket(RadiusPacket packet, RadiusProxyConnection proxyConnection) { lock (typeof (RadiusProxy)) { // add Proxy-State attribute proxyIndex++; String proxyIndexStr = proxyIndex.ToString(); packet.AddAttribute(new RadiusAttribute(33, Encoding.UTF8.GetBytes(proxyIndexStr))); // store RadiusProxyConnection object proxyConnections.Add(proxyIndexStr, proxyConnection); } // get server address //IPAddress serverAddress = proxyConnection.getRadiusServer().EndpointAddress.Address; //int serverPort = proxyConnection.getRadiusServer().EndpointAddress.Port; String serverSecret = proxyConnection.RadiusServer.SharedSecret; // save request authenticator (will be calculated new) byte[] auth = packet.Authenticator; // encode new packet (with new authenticator) var bos = new MemoryStream(); packet.EncodeRequestPacket(bos, serverSecret); byte[] data = bos.ToArray(); bos.Dispose(); //var datagram = new DatagramPacket(data, data.Length, serverAddress, serverPort); // restore original authenticator packet.Authenticator = auth; // send packet //Socket proxySocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.IP); proxySocket.Send(data, data.Length); //proxySocket.send(datagram); }
/// <summary> /// Constructs an answer for an Access-Request packet. Either this /// method or isUserAuthenticated should be overriden. /// @param accessRequest Radius request packet /// @param client address of Radius client /// @return response packet or null if no packet shall be sent /// @exception RadiusException malformed request packet; if this /// exception is thrown, no answer will be sent /// </summary> public virtual RadiusPacket AccessRequestReceived(AccessRequest accessRequest, IPEndPoint client) { String plaintext = GetUserPassword(accessRequest.UserName); int type = RadiusPacket.AccessReject; if (plaintext != null && accessRequest.VerifyPassword(plaintext)) type = RadiusPacket.AccessAccept; var answer = new RadiusPacket(type, accessRequest.Identifier); CopyProxyState(accessRequest, answer); return answer; }
/// <summary> /// Creates a Radius response datagram packet from a RadiusPacket to be send. /// @param packet RadiusPacket /// @param secret shared secret to encode packet /// @param request request packet /// @return new datagram packet /// @throws IOException /// </summary> protected Byte[] MakeDatagramPacket(RadiusPacket packet, String secret, RadiusPacket request) { var bos = new MemoryStream(); try { packet.EncodeResponsePacket(bos, secret, request); return bos.ToArray(); } finally { bos.Close(); bos.Dispose(); } }
/// <summary> /// Sets the address the server listens on. /// Must be called before start(). /// Defaults to null, meaning listen on every /// local address (wildcard address). /// @param listenAddress listen address or null /// </summary> /// <summary> /// Copies all Proxy-State attributes from the request /// packet to the response packet. /// @param request request packet /// @param answer response packet /// </summary> protected void CopyProxyState(RadiusPacket request, RadiusPacket answer) { IList<RadiusAttribute> proxyStateAttrs = request.GetAttributes(33); foreach (RadiusAttribute proxyStateAttr in proxyStateAttrs) { //RadiusAttribute proxyStateAttr = (RadiusAttribute)i.next(); answer.AddAttribute(proxyStateAttr); } }
/** * Creates a RadiusPacket from a received datagram packet. * @param packet received datagram * @param request Radius request packet * @return RadiusPacket object */ protected RadiusPacket MakeRadiusPacket(byte[] data, RadiusPacket request) { var memoryStream = new MemoryStream(data); try { return RadiusPacket.DecodeResponsePacket(memoryStream, SharedSecret, request); } finally { memoryStream.Dispose(); } }
/** * Returns the socket used for the server communication. It is * bound to an arbitrary free local port number. * @return local socket * @throws SocketException */ /** * Creates a datagram packet from a RadiusPacket to be send. * @param packet RadiusPacket * @param port destination port number * @return new datagram packet * @throws IOException */ protected byte[] MakeDatagramPacket(RadiusPacket packet) { using (var bos = new MemoryStream()) { packet.EncodeRequestPacket(bos, SharedSecret); byte[] data = bos.ToArray(); bos.Close(); bos.Dispose(); return data; } }
/** * Sends the specified packet to the specified Radius server endpoint. * @param remoteServer Radius endpoint consisting of server address, * port number and shared secret * @param request Radius packet to be sent * @return received response packet * @throws RadiusException malformed packet * @throws IOException error while communication */ public static RadiusPacket Communicate(RadiusEndpoint remoteServer, RadiusPacket request) { var rc = new RadiusClient(remoteServer.EndpointAddress.Address, remoteServer.SharedSecret); return rc.Communicate(request, remoteServer.EndpointAddress.Port); }
/** * Sets the retry count for failed transmissions. * @param retryCount retry count, >0 */ /** * Sends a Radius packet to the server and awaits an answer. * @param request packet to be sent * @param port server port number * @return response Radius packet * @exception RadiusException malformed packet * @exception IOException communication error (after getRetryCount() * retries) */ public RadiusPacket Communicate(RadiusPacket request, int port) { var packetIn = new byte[RadiusPacket.MaxPacketLength]; byte[] packetOut = MakeDatagramPacket(request); Socket socket = Socket; for (int i = 1; i <= RetryCount; i++) { try { var endPoint = new IPEndPoint(Ip, port); socket.SendTo(packetOut, endPoint); socket.Receive(packetIn); return MakeRadiusPacket(packetIn, request); } catch (IOException ioex) { if (i == RetryCount) { if (logger.IsErrorEnabled) { logger.Error("communication failure, no more retries", ioex); } throw ioex; } if (logger.IsInfoEnabled) logger.Info("communication failure, retry " + i); // TODO increase Acct-Delay-Time by getSocketTimeout()/1000 // this changes the packet authenticator and requires packetOut to be // calculated again (call makeDatagramPacket) } } return null; }
/// <summary> /// Encodes this Radius packet and sends it to the specified output /// stream. /// @param out output stream to use /// @param sharedSecret shared secret to be used to encode this packet /// @param request Radius request packet if this packet to be encoded /// is a response packet, null if this packet is a request packet /// @exception IOException communication error /// @exception NotImplementedException if required packet data has not been set /// </summary> protected void EncodePacket(Stream outputStream, String sharedSecret, RadiusPacket request) { // check shared secret if (string.IsNullOrEmpty(sharedSecret)) throw new ArgumentNullException("sharedSecret", "no shared secret has been set"); // check request authenticator if (request != null && request.Authenticator == null) throw new NotImplementedException("request authenticator not set"); // request packet authenticator if (request == null) { // first create authenticator, then encode attributes // (User-Password attribute needs the authenticator) Authenticator = CreateRequestAuthenticator(sharedSecret); EncodeRequestAttributes(sharedSecret); } byte[] attributes = GetAttributeBytes(); int packetLength = RadiusHeaderLength + attributes.Length; if (packetLength > MaxPacketLength) throw new NotImplementedException("packet too long"); // response packet authenticator Authenticator = request != null ? CreateResponseAuthenticator(sharedSecret, packetLength, attributes, request.Authenticator) : UpdateRequestAuthenticator(sharedSecret, packetLength, attributes); outputStream.WriteByte(Convert.ToByte(Type)); outputStream.WriteByte(Convert.ToByte(Identifier)); byte[] lengthBytes = BitConverter.GetBytes(Convert.ToInt16(packetLength)); Array.Reverse(lengthBytes); outputStream.Write(lengthBytes, 0, lengthBytes.Length); byte[] authen = Authenticator; outputStream.Write(authen, 0, authen.Length); outputStream.Write(attributes, 0, attributes.Length); }
/// <summary> /// Reads a Radius response packet from the given input stream and /// creates an appropiate RadiusPacket descendant object. /// Reads in all attributes and returns the object. /// Checks the packet authenticator. /// @param sharedSecret shared secret to be used to decode this packet /// @param request Radius request packet /// @return new RadiusPacket object /// @exception IOException IO error /// @exception RadiusException malformed packet /// </summary> public static RadiusPacket DecodeResponsePacket(Stream @in, String sharedSecret, RadiusPacket request) { if (request == null) { throw new ArgumentNullException("request", "request may not be null"); } return(DecodePacket(DefaultDictionary.GetDefaultDictionary(), @in, sharedSecret, request)); }
/// <summary> /// Reads a Radius packet from the given input stream and /// creates an appropiate RadiusPacket descendant object. /// Reads in all attributes and returns the object. /// Decodes the encrypted fields and attributes of the packet. /// @exception IOException if an IO error occurred /// @exception RadiusException if the Radius packet is malformed /// </summary> /// <param name="dictionary">dictionary to use for attributes</param> /// <param name="inputStream"></param> /// <param name="request">Radius request packet if this is a response packet to be /// decoded, null if this is a request packet to be decoded</param> /// <param name="sharedSecret">shared secret to be used to decode this packet</param> /// <returns>RadiusPacket object</returns> protected static RadiusPacket DecodePacket(IWritableDictionary dictionary, Stream inputStream, String sharedSecret, RadiusPacket request) { // check shared secret if (string.IsNullOrEmpty(sharedSecret)) throw new ArgumentNullException("sharedSecret", "no shared secret has been set"); // check request authenticator if (request != null && request.Authenticator == null) throw new ArgumentNullException("request", "request authenticator not set"); // read and check header int type = inputStream.ReadByte() & 0x0ff; int identifier = inputStream.ReadByte() & 0x0ff; int length = (inputStream.ReadByte() & 0x0ff) << 8 | (inputStream.ReadByte() & 0x0ff); if (request != null && request.Identifier != identifier) throw new RadiusException("bad packet: invalid packet identifier (request: " + request.Identifier + ", response: " + identifier); if (length < RadiusHeaderLength) throw new RadiusException("bad packet: packet too short (" + length + " bytes)"); if (length > MaxPacketLength) throw new RadiusException("bad packet: packet too long (" + length + " bytes)"); // read rest of packet var authenticator = new byte[16]; var attributeData = new byte[length - RadiusHeaderLength]; inputStream.Read(authenticator, 0, 16); inputStream.Read(attributeData, 0, attributeData.Length); // check and count attributes int pos = 0; while (pos < attributeData.Length) { if (pos + 1 >= attributeData.Length) throw new RadiusException("bad packet: attribute Length mismatch"); int attributeLength = attributeData[pos + 1] & 0x0ff; if (attributeLength < 2) throw new RadiusException("bad packet: invalid attribute Length"); pos += attributeLength; } if (pos != attributeData.Length) throw new RadiusException("bad packet: attribute Length mismatch"); // create RadiusPacket object; set properties RadiusPacket rp = CreateRadiusPacket(type); rp.Type = type; rp.Identifier = identifier; rp.Authenticator = authenticator; // load attributes pos = 0; while (pos < attributeData.Length) { int attributeType = attributeData[pos] & 0x0ff; int attributeLength = attributeData[pos + 1] & 0x0ff; RadiusAttribute a = RadiusAttribute.CreateRadiusAttribute(dictionary, -1, attributeType); a.ReadAttribute(attributeData, pos, attributeLength); rp.AddAttribute(a); pos += attributeLength; } // request packet? if (request == null) { // decode attributes rp.DecodeRequestAttributes(sharedSecret); rp.CheckRequestAuthenticator(sharedSecret, length, attributeData); } else { // response packet: check authenticator rp.CheckResponseAuthenticator(sharedSecret, length, attributeData, request.Authenticator); } return rp; }
/** * Sends an answer to a proxied packet back to the original host. * Retrieves the RadiusProxyConnection object from the cache employing * the Proxy-State attribute. * @param packet packet to be sent back * @param remote the server the packet arrived from * @throws IOException */ protected void proxyPacketReceived(RadiusPacket packet, IPEndPoint remote) { // retrieve my Proxy-State attribute (the last) IList<RadiusAttribute> proxyStates = packet.GetAttributes(33); if (proxyStates == null || proxyStates.Count == 0) throw new RadiusException("Proxy packet without Proxy-State attribute"); RadiusAttribute proxyState = proxyStates[proxyStates.Count - 1]; // retrieve Proxy connection from cache string state = BitConverter.ToString(proxyState.Data); var proxyConnection = (RadiusProxyConnection) proxyConnections[state]; proxyConnections.Remove(state); if (proxyConnection == null) { logger.Warn("received packet on Proxy port without saved Proxy connection - duplicate?"); return; } // retrieve client RadiusEndpoint client = proxyConnection.RadiusClient; if (logger.IsInfoEnabled) { logger.Info("received Proxy packet: " + packet); logger.Info("forward packet to " + client.EndpointAddress + " with secret " + client.SharedSecret); } // remove only own Proxy-State (last attribute) packet.RemoveLastAttribute(33); // re-encode answer packet with authenticator of the original packet var answer = new RadiusPacket(packet.Type, packet.Identifier, packet.Attributes); byte[] datagram = MakeDatagramPacket(answer, client.SharedSecret, proxyConnection.Packet); // send back using correct socket UdpClient socket = proxyConnection.Port == AuthPort ? GetAuthSocket() : GetAcctSocket(); socket.Send(datagram, datagram.Length, remote); }
/// <summary> /// Constructs an answer for an Accounting-Request packet. This method /// should be overriden if accounting is supported. /// @param accountingRequest Radius request packet /// @param client address of Radius client /// @return response packet or null if no packet shall be sent /// @exception RadiusException malformed request packet; if this /// exception is thrown, no answer will be sent /// </summary> public RadiusPacket AccountingRequestReceived(AccountingRequest accountingRequest, IPEndPoint client) { var answer = new RadiusPacket(RadiusPacket.AccountingResponse, accountingRequest.Identifier); CopyProxyState(accountingRequest, answer); return answer; }
/// <summary> /// Reads a Radius packet from the given input stream and /// creates an appropiate RadiusPacket descendant object. /// Reads in all attributes and returns the object. /// Decodes the encrypted fields and attributes of the packet. /// @exception IOException if an IO error occurred /// @exception RadiusException if the Radius packet is malformed /// </summary> /// <param name="dictionary">dictionary to use for attributes</param> /// <param name="inputStream"></param> /// <param name="request">Radius request packet if this is a response packet to be /// decoded, null if this is a request packet to be decoded</param> /// <param name="sharedSecret">shared secret to be used to decode this packet</param> /// <returns>RadiusPacket object</returns> protected static RadiusPacket DecodePacket(IWritableDictionary dictionary, Stream inputStream, String sharedSecret, RadiusPacket request) { // check shared secret if (string.IsNullOrEmpty(sharedSecret)) { throw new ArgumentNullException("sharedSecret", "no shared secret has been set"); } // check request authenticator if (request != null && request.Authenticator == null) { throw new ArgumentNullException("request", "request authenticator not set"); } // read and check header int type = inputStream.ReadByte() & 0x0ff; int identifier = inputStream.ReadByte() & 0x0ff; int length = (inputStream.ReadByte() & 0x0ff) << 8 | (inputStream.ReadByte() & 0x0ff); if (request != null && request.Identifier != identifier) { throw new RadiusException("bad packet: invalid packet identifier (request: " + request.Identifier + ", response: " + identifier); } if (length < RadiusHeaderLength) { throw new RadiusException("bad packet: packet too short (" + length + " bytes)"); } if (length > MaxPacketLength) { throw new RadiusException("bad packet: packet too long (" + length + " bytes)"); } // read rest of packet var authenticator = new byte[16]; var attributeData = new byte[length - RadiusHeaderLength]; inputStream.Read(authenticator, 0, 16); inputStream.Read(attributeData, 0, attributeData.Length); // check and count attributes int pos = 0; while (pos < attributeData.Length) { if (pos + 1 >= attributeData.Length) { throw new RadiusException("bad packet: attribute Length mismatch"); } int attributeLength = attributeData[pos + 1] & 0x0ff; if (attributeLength < 2) { throw new RadiusException("bad packet: invalid attribute Length"); } pos += attributeLength; } if (pos != attributeData.Length) { throw new RadiusException("bad packet: attribute Length mismatch"); } // create RadiusPacket object; set properties RadiusPacket rp = CreateRadiusPacket(type); rp.Type = type; rp.Identifier = identifier; rp.Authenticator = authenticator; // load attributes pos = 0; while (pos < attributeData.Length) { int attributeType = attributeData[pos] & 0x0ff; int attributeLength = attributeData[pos + 1] & 0x0ff; RadiusAttribute a = RadiusAttribute.CreateRadiusAttribute(dictionary, -1, attributeType); a.ReadAttribute(attributeData, pos, attributeLength); rp.AddAttribute(a); pos += attributeLength; } // request packet? if (request == null) { // decode attributes rp.DecodeRequestAttributes(sharedSecret); rp.CheckRequestAuthenticator(sharedSecret, length, attributeData); } else { // response packet: check authenticator rp.CheckResponseAuthenticator(sharedSecret, length, attributeData, request.Authenticator); } return(rp); }
/// <summary> /// Handles the received Radius packet and constructs a response. /// @param localAddress local address the packet was received on /// @param remoteAddress remote address the packet was sent by /// @param request the packet /// @return response packet or null for no response /// @throws RadiusException /// </summary> protected virtual RadiusPacket HandlePacket(IPEndPoint localAddress, IPEndPoint remoteAddress, RadiusPacket request, String sharedSecret) { RadiusPacket response = null; // check for duplicates if (!IsPacketDuplicate(request, remoteAddress)) { if (localAddress.Port == AuthPort) { // handle packets on auth port if (typeof(AccessRequest).IsInstanceOfType(request)) response = AccessRequestReceived((AccessRequest)request, remoteAddress); else Logger.Error("unknown Radius packet type: " + request.Type); } else if (localAddress.Port == AcctPort) { // handle packets on acct port if (typeof(AccountingRequest).IsInstanceOfType(request)) response = AccountingRequestReceived((AccountingRequest)request, remoteAddress); else Logger.Error("unknown Radius packet type: " + request.Type); } else { // ignore packet on unknown port } } else Logger.Info("ignore duplicate packet"); return response; }
/** * This method must be implemented to return a RadiusEndpoint * if the given packet is to be proxied. The endpoint represents the * Radius server the packet should be proxied to. * @param packet the packet in question * @param client the client endpoint the packet originated from * (containing the address, port number and shared secret) * @return a RadiusEndpoint or null if the packet should not be * proxied */ public abstract RadiusEndpoint GetProxyServer(RadiusPacket packet, RadiusEndpoint client);
/// <summary> /// Checks whether the passed packet is a duplicate. /// A packet is duplicate if another packet with the same identifier /// has been sent from the same host in the last time. /// @param packet packet in question /// @param address client address /// @return true if it is duplicate /// </summary> protected bool IsPacketDuplicate(RadiusPacket packet, IPEndPoint address) { //long now = System.currentTimeMillis(); DateTime now = DateTime.Now; DateTime intervalStart = now - (new TimeSpan(0, 0, 0, 0, DuplicateInterval)); byte[] authenticator = packet.Authenticator; lock (_receivedPackets) { for (int i = _receivedPackets.Count - 1; i >= 0; i--) { ReceivedPacket p = _receivedPackets[i]; if (p.ReceiveTime < intervalStart) { _receivedPackets.RemoveAt(i); } else { if (p.Address.Equals(address) && p.PacketIdentifier == packet.Identifier) { return authenticator == null || p.Authenticator == null || Equals(p.Authenticator, authenticator); } } } } // add packet to receive list var rp = new ReceivedPacket { Address = address, PacketIdentifier = packet.Identifier, ReceiveTime = now, Authenticator = authenticator }; _receivedPackets.Add(rp); return false; }
/** * Handles packets coming in on the Proxy port. Decides whether * packets coming in on Auth/Acct ports should be proxied. */ protected override RadiusPacket HandlePacket(IPEndPoint localAddress, IPEndPoint remoteAddress, RadiusPacket request, String sharedSecret) { // handle incoming Proxy packet if (localAddress.Port == ProxyPort) { proxyPacketReceived(request, remoteAddress); return null; } // handle auth/acct packet var radiusClient = new RadiusEndpoint(remoteAddress, sharedSecret); RadiusEndpoint radiusServer = GetProxyServer(request, radiusClient); if (radiusServer != null) { // Proxy incoming packet to other radius server var proxyConnection = new RadiusProxyConnection(radiusServer, radiusClient, request, localAddress.Port); logger.Info("Proxy packet to " + proxyConnection); proxyPacket(request, proxyConnection); return null; } else // normal processing return base.HandlePacket(localAddress, remoteAddress, request, sharedSecret); }