layeh / radius Goto Github PK
View Code? Open in Web Editor NEWa Go (golang) RADIUS client and server implementation
Home Page: https://pkg.go.dev/layeh.com/radius
License: Mozilla Public License 2.0
a Go (golang) RADIUS client and server implementation
Home Page: https://pkg.go.dev/layeh.com/radius
License: Mozilla Public License 2.0
dictionarygen currently generates functions for all but the following Attribute methods:
Attribute values are currently typed as interface{}
. This defers the error of using an incorrect type to when the packet is encoded, rather than when the attribute value is assigned.
Fix this by defining a new interface that all attribute values must implement. Add implementations for RADIUS's text, string, address, integer, and time types.
This is a breaking change.
hi, patch #41 don't consider that Message-Authenticator should be calculated
rfc5997:
If a server supports Status-Server packets, and is configured to respond to them, and receives a packet from a known client, it MUST validate the Message-Authenticator attribute as defined in [RFC3579], Section 3.2. Packets failing that validation MUST be silently discarded.
rfc3579:
When present in an Access-Request packet, Message-Authenticator is an HMAC-MD5 [RFC2104] hash of the entire Access-Request packet, including Type, ID, Length and Authenticator, using the shared secret as the key, as follows. Message-Authenticator = HMAC-MD5 (Type, Identifier, Length, Request Authenticator, Attributes)
thanks,
Hi there
In the readme file client example exist, Is there any radius server example code?
any comment would be appreciate
Hello,
I'm trying to use CHAP to implement an LDAP MFA using Yubikey, but when I perform CHAPPassword_GetString I get some garbled mess.
My knowledge in RADIUS internals is lacking, unfortunately... Likely, I need to decode/decrypt that in some way using the shared secret.
I took a look at the godoc for both the main package and the rfc2865, but I'm not able to figure out how to do that. I also couldn't find RFC 1661 (CHAP) or RFC 2759 (MS-CHAP v2) sub packages to perhaps get some light.
Can someone please provide an example? One using MSCHAPv2 would be even better!
I'm trying to generate a dictionary:
go run main.go -package redback /usr/share/freeradius/dictionary.redback
and get an error:
radius-dict-gen: dictionary: parse error in /usr/share/freeradius/dictionary.redback:278: duplicate attribute "Tunnel-Flow-Control"
exit status 1
How to fix it?
Dictionary is default from FreeRADIUS.
func NewTLV(tlvType byte, tlvValue Attribute) (Attribute, error) {
if len(tlvValue) < 1 || len(tlvValue) > 253 {
return nil, errors.New("invalid value length")
}
a := make(Attribute, 1+1+len(tlvValue))
a[0] = tlvType
a[1] = byte(1 + 1 + len(tlvValue))
copy(a, tlvValue)
return a, nil
}
should copy(a[2:], tlvValue)
function
Line 87 in 451cb37
Pool of []byte? Release after packet is parsed.
It would be nice if the dictionary generator supported byte
type attributes. There are vendor specific attributes (ex. 3gpp) that use this type.
hi,
How to set different clients to use different secret authentication, like freeradius.
How much work would it be to add support for EAP-MD5? I was looking to use this in combination with strongswan via eap-radius.
this function not support CodeAccountingResponse,so may you can modify it as:
func (p *Packet) IsAuthentic(request *Packet) bool {
switch p.Code {
case CodeAccessAccept, CodeAccessReject, CodeAccountingRequest, CodeAccessChallenge, CodeAccountingResponse:
wire, err := p.Encode()
if err != nil {
return false
}
hash := md5.New()
hash.Write(wire[0:4])
if p.Code == CodeAccountingRequest {
var nul [16]byte
hash.Write(nul[:])
} else if p.Code == CodeAccountingResponse {
w2, _ := request.Encode()
hash.Write(w2[4:20])
} else {
hash.Write(request.Authenticator[:])
}
hash.Write(wire[20:])
hash.Write(request.Secret)
var sum [md5.Size]byte
return bytes.Equal(hash.Sum(sum[0:0]), p.Authenticator[:])
}
return false
}
Example:
ATTRIBUTE Context_Name 4 string
ATTRIBUTE Context-Name 4 string
Hi,
I'm trying to use the library to handle L2TP-specific parameters configuted in FreeRADIUS. The configuration file looks as follows:
[email protected] Cleartext-Password := "test"
Tunnel-Type = L2TP,
Tunnel-Medium-Type = IPv4,
Tunnel-Password = "pass123",
Tunnel-Server-Endpoint = 10.10.10.10
Tunnel-Type, Tunnel-Medium-Type and Tunnel-Server-Endpoint are read properly, but when using the below piece of code to get Tunnel-Password I got an error:
_, tunnelPassword, err := rfc2868.TunnelPassword_LookupString(pkt)
if err == nil {
authResp["TunnelPassword"] = tunnelPassword
}
Output logs:
2020/12/02 11:23:40 invalid password length
I'm wondering if you verified the behavior for Tunnel-Password? I'm not sure if the problem is with FreeRADIUS configuration or with the radius
library?
Line 28 in 0f678f0
here shouldn't 253 to be 255? like if length > len(b) || length < 2 || length > 255 {
because length field in radius attribute includes Type and Length fields. quote below from RFC2865:
The Length field is one octet, and indicates the length of this
Attribute including the Type, Length and Value fields.
I hit this bug when parsing a RADIUS access-request packet of EAP-TLS session, there are multiple EAP-Message attributes in the same packet, and most of them has length field value of 255
I generated library from dictionary file present at https://github.com/wireshark/wireshark/blob/master/radius/dictionary.3gpp. But call to _ThreeGPP_SetVendor()
from ThreeGPPGGSNMCCMNC_SetString()
in the generated library is running into infinite loop.
Adding i++
in below generated code fixed this issue for me -
func _ThreeGPP_SetVendor(p *radius.Packet, typ byte, attr radius.Attribute) (err error) {
for i := 0; i < len(p.Attributes); {
avp := p.Attributes[i]
if avp.Type != rfc2865.VendorSpecific_Type {
i++
continue
}
...
It's not possible to send radius responses as: radius.CodeCoAACK, radius.CodeCoANAK, radius.CodeDisconnectACK.
The next code gives an err: "radius: unknown Packet Code:"
err := w.Write(r.Response(radius.CodeCoAACK))
I'm very new to RADIUS and while trying to replicate a request I captured I came across this package. The request that I captured with wireshark looks like this:
So the Vendor-Specific type has it's own type and value, right?
If I use
packet.Set(rfc2865.VendorSpecific_Type, <attr>)
Then I only set the attr
as value which isn't a type,value construct.
I saw that attributes has an encodeTo
method (here) that could be used to encode to []byte, then use attribute.NewBytes()
to turn it into an attribute that can be added to a packet, but encodeTo
is private so that's maybe not the way to do it
My question is, how do I set the VendorSpecific attribute so that it matches the type structure from my capture? As in, how can I set a type,value structure as the value of the Vendor-Specific? (If that's how it works) (There are a bunch of those attributes with different types)
As reported in the issue #38, the -ignore flag is not being applied during the parse phase, so the parser fails when an unknown attribute type is found. (ex. byte)
I need to repeat this request:
User-Name=18:d2:76:a0:60:d8
Acct-Session-Id=FF16033978047B47-5B431ADB
Framed-IP-Address=100.126.2.188
Deactivate-Service-Name:0=balans
I execute it through the radclient - always OK:
~$ radclient -f packet-coa -x 192.168.0.154 coa secret
Sending CoA-Request of id 124 to 192.168.0.154 port 3799
User-Name = "18:d2:76:a0:60:d8"
Acct-Session-Id = "FF16033978047B47-5B431ADB"
Framed-IP-Address = 100.126.2.188
Deactivate-Service-Name:0 = "balans"
rad_recv: CoA-ACK packet from host 192.168.0.154 port 3799, id=124, length=59
Deactivate-Service-Name:1 = "balans"
Service-Error-Cause:1 = 200
Error-Cause = 200
Event-Timestamp = "Jul 9 2018 14:31:32 +05"
I try to do the same thing through the library:
packet := rc.New(rc.CodeCoARequest, []byte(session.BRAS.Secret))
rfc2865.UserName_SetString(packet, session.MAC.Addr)
rfc2865.FramedIPAddress_Set(packet, session.GetIP())
rfc2866.AcctSessionID_SetString(packet, session.SessionID)
redback.DeactivateServiceName_AddString(packet, byte(auth.Number), auth.Name)
response, err := rc.Exchange(context.Background(), packet, session.BRAS.GetCoAString())
Packet sent:
&{Code:CoA-Request Identifier:63 Authenticator:[127 252 31 208 51 69 117 23 16 252 73 167 57 8 109 63] Secret:[115 101 99 114 101 116] Attributes:map[1:[[49 56 58 100 50 58 55 54 58 97 48 58 54 48 58 100 56]] 8:[[100 126 2 188]] 44:[[70 70 49 54 48 51 51 57 55 56 48 52 55 66 52 55 45 53 66 52 51 49 65 68 66]] 26:[[0 0 9 48 194 9 0 98 97 108 97 110 115]]]}
Packet response:
&{Code:CoA-NAK Identifier:63 Authenticator:[47 246 197 213 242 200 169 83 124 165 14 105 173 178 37 34] Secret:[115 101 99 114 101 116] Attributes:map[101:[[0 0 1 148]] 55:[[91 67 39 7]]]}
The request packet seems to be getting right.
Have any idea what I'm doing wrong?
Currently, it is only possible to Salt Enrypt strings, this is as part of the L2TP RFC.
Howevery, in some RADIUS implementations, Salt Encryption is also used for different attributes other than L2TP.
For this it would be beneficial to add Salt Encryption also IP addresses and Integer values. So basically what is specified in this draft:
draft-ietf-radius-saltencrypt-00.txt
Would it be possible to add this to the IP Address and Integer types? I could supply a PR for.
while go get layeh.com/radius/rfc6911
reports error:
Parsing meta tags from https://layeh.com/radius/rfc6911?go-get=1 (status code 404)
package layeh.com/radius/rfc6911: unrecognized import path "layeh.com/radius/rfc6911" (parse https://layeh.com/radius/rfc6911?go-get=1: no go-import meta tags ())
First, thanks for the awesome library.
To get bandwidth consumption data from a PPPoE Server you would usually use Acct-Input-Octets and Acct-Output-Octets. The problem with them is they are only 4 bytes and they do overflow every 2^32 (uint32) which is just less than 4GB. There are two new attributes which are described in RFC2869 which are Acct-Input-Gigawords and Acct-Output-Gigawords which are also 4 bytes and they extend the download and upload counters to 2^64 (uint64).
It would be nice to see support for these two attributes.
The Radius Server example listens the 1812 port.
What is the recommended way to do the Radius Server listen the 1812 (authentication) and 1813 (accounting) ports?
Hi,
while analyzing some radius packets, generated with this radius library, I noticed that some length values are not correct. I compared the packet attributes with packets, generated by one other library and also with the radius standard.
How it should work, according to the standard:
When having a radius attribute that consist of a tag and an integer value, the tag is represented in one of the four bytes, that usually represent the integer value. That means, this integer value (in combination with tags) is allowed to use only 3 bytes.
What actually happens:
The tag gets its own byte, making the length of the attribute 1 byte larger than it is supposed to be.
This becomes evident when looking for example at the Tunnel-Medium-Type attribute in RFC 2868 (https://tools.ietf.org/html/rfc2868). The tag has the size of 1 byte and the value a size of 3 byte. The total length is specified as 6. When adding this attribute to a radius packet using this layeh/radius library, the value of the length field is 7. This is because the value takes 4 bytes.
When looking at the implementation, the radius.NewTag() method seems to be the method that needs to be adjusted.
Greetings
Tobias
Can be simply replaced with "return"
Sorry if I missed it in the code but I can get the Type (as an int) of an attribute. Is there a way to know that, for example, UserName_Type radius.Type = 1
== "User-Name"? (I'd like to dump attribute key/value pairs in a debugging mode)
for example:
attribute: Huawei-Exec-Privilege
value: 3
dictionary.huawei
ATTRIBUTE Huawei-Exec-Privilege 29 integer
i tried like this:
huaweiExecPrivilege, _ := radius.NewString("Huawei-Exec-Privilege")
huaweiExecPrivilegeAttr := make(radius.Attribute, 2+len(huaweiExecPrivilege))
huaweiExecPrivilegeAttr[0] = byte(3)
huaweiExecPrivilegeAttr[1] = byte(len(huaweiExecPrivilegeAttr))
copy(huaweiExecPrivilegeAttr[2:], huaweiExecPrivilege)
vsa, _ := radius.NewVendorSpecific(29, huaweiExecPrivilegeAttr)
r.Packet.Add(VendorSpecific_Type, vsa)
if username == "rh.wang" && password == "viproot" {
log.Println(NASIdentifier_GetString(r.Packet), NASIPAddress_Get(r.Packet), LoginIPHost_Get(r.Packet), username, password, "Accept")
w.Write(r.Response(radius.CodeAccessAccept))
} else {
log.Println(NASIdentifier_GetString(r.Packet), NASIPAddress_Get(r.Packet), LoginIPHost_Get(r.Packet), username, password, "Reject")
w.Write(r.Response(radius.CodeAccessReject))
}
But it does not work, what should i do?
Hi.
(Sorry if this is not a right place to ask this type of question. I'm also not familiarized with radius protocol)
I'm creating an utility that will receive radius packets (via UDP socket) and decode some A/V pairs to a human readable format. With the help of this project I'm currently able to read the packages and retrieve A/V pairs using rfc2865.<attr_GetString(packet)>.
However, I really need to decode a vendor specific attribute, namely 3GPP User-Location-Info. Can someone point me in the right direction how to do that?
Thanks for any help you could provide.
Hi. I need to send status-server
req to freeradius server.
via radclient
xxx@yyy[~]cat rad
Message-Authenticator = 0x00
FreeRADIUS-Statistics-Type = 15
Response-Packet-Type = Access-Accept
xxx@yyy[~]radclient -t 1 -r 1 127.0.0.1:18121 status adminsecret -x -f rad
Sending Status-Server of id 2 to 127.0.0.1 port 18121
Message-Authenticator = 0x00000000000000000000000000000000
FreeRADIUS-Statistics-Type = 15
rad_recv: Access-Accept packet from host 127.0.0.1 port 18121, id=2, length=428
FreeRADIUS-Total-Access-Requests = 7706
FreeRADIUS-Total-Access-Accepts = 7691
FreeRADIUS-Total-Access-Rejects = 9
...
I feel like i am missing something, but I can't figure out how to do this using this library and whether it can be done at all.
Please help 🙏
Radius dictionary like this:
VENDOR 800 Xylan
VENDORATTR 800 Vattribute 103 string
At Client side,i want to construct a radius packet which contain the Vatrribute? How to do it?
i tried like this:
e.g Vatrribute is "hello"
hello, _ := radius.NewString("hello")
helloAttr := radius.NewVendorSpecific(103, hello)
vsa := radius.NewVendorSpecific(800, helloAttr)
packet.Set(rfc.VendorSpecific_Type, vsa)
But it does not work, what should i do?
Currently, the attributes are stored as a map, which means when the attributes are encoded to wire format the order in which they are encoded is random (or at least can't be relied upon). Unfortunately, this means the order in which attributes are added can impact the encoding and thus a hash generated against one encoding can be invalided by another. The specific use case is:
The encoding at 3 and 6 can generate the attributes in different order and thus the hash generated at step 4 is no longer valid (all the time).
(pull request coming soon)
Hi,
I am trying to use radius-dict-gen to generate helper functions for dictionary.freeradius , but for version 4.0.x here https://github.com/FreeRADIUS/freeradius-server/blob/master/share/dictionary.freeradius#L23 . Generator seems to skip such OIDs. I only recently started using FreeRADIUS, but to me it looks like that dict is using extended attributes like in this rfc https://tools.ietf.org/html/rfc6929#section-2.7.2 .
Is there a way I can "manually" add such attributes to packet, I see there is OID type which is a slice of ints but how can be used? I did a exorter for prometheus here https://github.com/bvantagelimited/freeradius_exporter , but I need it also for version 4.0.x.
Thanks,
Milan
Generated _Lookup methods for vendor attributes call _LookupVendor, which only returns the first matching VSA. They should be using _GetsVendor instead, returning the first match.
Hi.
Thank you first.
It is very useful to me.
I have a question. when i use wrong secret, the client is reties over and over again. how can i configure return error?
Hi,
I tried to run radius-dict-get
on the 3GPP dictionary from the FreeRADIUS project and it fails with
radius-dict-gen: dictionary: parse error in /Users/borud/go/src/ghe.telenordigital.com/TelenorDigital/horde/radius/3gpp/dictionary.3gpp:28: unknown attribute type "byte
The file is at: https://github.com/redBorder/freeradius/blob/master/share/dictionary.3gpp
After changing bytes
to octets
I get the following error message:
radius-dict-gen: 99:6: expected 'IDENT', found 'INT' 3 (and 10 more errors)
I'm confused. What am I doing wrong? Is the issue that the vendor starts with a number? Is this a bug? How can I get around this?
Consider the following VALUE definitions:
VALUE DSL-Transmission-System ADSL2 2
VALUE DSL-Transmission-System ADSL2+ 3
The following identifiers will be generated:
DSLTransmissionSystem_Value_ADSL2 DSLTransmissionSystem = 2
DSLTransmissionSystem_Value_ADSL2 DSLTransmissionSystem = 3
Enhancement: currently after RADIUS request is sent (via Client.Exchange()) the response to the requests blocks.
In order to allow the response to timeout, a ReadTimeout can be set on the connection.
The existing SecretSource method is great and follows the RFC, as it should. However, relying on IP source to determine what secret should be used is difficult in very large environments that don't necessarily standardize IP space deployments. In my employer's use case, it would be much simpler to rely on something like Nas-Identifier.
Would you be open to supporting something like that? I'm happy to do a PR and discuss approaches further.
Radius RFC2865 Section 3, states how to handle mismatch between the value in the length field and the actual packet size:
Length
The Length field is two octets. It indicates the length of the
packet including the Code, Identifier, Length, Authenticator and
Attribute fields. Octets outside the range of the Length field
MUST be treated as padding and ignored on reception. If the
packet is shorter than the Length field indicates, it MUST be
silently discarded. The minimum length is 20 and maximum length
is 4096.
Thus, according to this the case where the packet length is greater than the length field value, shouldn't be discarded as the current implementation, but trunced to fit the declared length.
Is that a feature?
Similar problem in this issus #11 , last replied on Mar 27
I noticed a TODO comment for adding a logger in server-packet.go. I'm interested in helping out with this, but wanted to clarify a few things first.
server in linux
client in linux
send PAP packet,but decrypt User-Password fail
example:
pwd: iO`fOgC.8Y¨
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.