/// <summary> /// Returns the value of the Radius attribute of the given type or /// null if there is no such attribute. /// Also returns sub-attributes. /// @param type attribute type name /// @return value of the attribute as a string or null if there /// is no such attribute /// @throws ArgumentException if the type name is unknown /// @throws NotImplementedException attribute occurs multiple times /// </summary> public String GetAttributeValue(String type) { RadiusAttribute attr = GetAttribute(type); if (attr == null) { return(null); } else { return(attr.Value); } }
/// <summary> /// Removes the last occurence of the attribute of the given /// type from the packet. /// @param type attribute type code /// </summary> public void RemoveLastAttribute(int type) { IList <RadiusAttribute> attrs = GetAttributes(type); if (attrs == null || attrs.Count == 0) { return; } RadiusAttribute lastAttribute = attrs[attrs.Count - 1]; RemoveAttribute(lastAttribute); }
/** * 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> /// Adds a Radius attribute to this packet. Can also be used /// to add Vendor-Specific sub-attributes. If a attribute with /// a vendor code != -1 is passed in, a VendorSpecificAttribute /// is created for the sub-attribute. /// @param attribute RadiusAttribute object /// </summary> public void AddAttribute(RadiusAttribute attribute) { if (attribute == null) { throw new ArgumentNullException("attribute", "attribute is null"); } attribute.Dictionary = Dictionary; if (attribute.VendorId == -1) { _attributes.Add(attribute); } else { var vsa = new VendorSpecificAttribute(attribute.VendorId); vsa.AddSubAttribute(attribute); _attributes.Add(vsa); } }
/// <summary> /// Adds a Radius attribute to this packet. /// Uses AttributeTypes to lookup the type code and converts /// the value. /// Can also be used to add sub-attributes. /// @param typeName name of the attribute, for example "NAS-Ip-Address" /// @param value value of the attribute, for example "127.0.0.1" /// @throws ArgumentException if type name is unknown /// </summary> public void AddAttribute(String typeName, String value) { if (string.IsNullOrEmpty(typeName)) { throw new ArgumentException("type name is empty"); } if (string.IsNullOrEmpty(value)) { throw new ArgumentException("value is empty"); } AttributeType type = Dictionary.GetAttributeTypeByName(typeName); if (type == null) { throw new ArgumentException("unknown attribute type '" + typeName + "'"); } RadiusAttribute attribute = RadiusAttribute.CreateRadiusAttribute(Dictionary, type.VendorId, type.TypeCode); attribute.Value = value; AddAttribute(attribute); }
/// <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); }