Fork me on GitHub

Project Notes

#214 FreeRADIUS Server on macOS

All about running FreeRADIUS Server on macOS, both native build, and with Docker.

Notes

The FreeRADIUS Server is the leading open source (GNU GPLv2) implementation of RADIUS. It claims:

  • high performance
  • scalable - sites ranging from 10 to 10 million+ users
  • highly configurable
  • multi-protocol policy server: RADIUS, DHCPv4 and VMPS
  • can authenticate users on: 802.1x (WiFi), dialup, PPPoE, VPN’s, VoIP, and many others
  • supports back-end databases such as MySQL, PostgreSQL, Oracle, Microsoft Active Directory, Apache Cassandra, Redis, OpenLDAP, and many more

Native Build on macOS

Installing talloc

talloc is a pre-requisite:

  • brew install talloc
  • or install from source - handled by download_and_make

Build and Install

The steps to build and install are in ./download_and_make

Installation drops files in the following locations:

  • /usr/local/bin
  • /usr/local/sbin
  • /usr/local/var/log/radius
  • /usr/local/etc/raddb

Default locations used by the radius server are configured in /usr/local/etc/raddb/radiusd.conf.

The installation transcript for my test install is in installation_transcript.log.

Test Drive

Starting the Server

Start the server in daemon mode:

sudo /usr/local/sbin/radiusd

Or foreground debug mode:

sudo /usr/local/sbin/radiusd -X

radtest is installed in /usr/local/bin and can be used to test the server. Usage:

Usage: radtest [OPTIONS] user passwd radius-server[:port] nas-port-number secret [ppphint] [nasname]

Attempt to authenticate. I haven’t setup this user yet, so it is expected to fail:

radtest test test localhost 0 testing123
  Socket: 5
  Proto:  17
  Src IP: 0.0.0.0
    port: 63378
  Dst IP: 127.0.0.1
    port: 1812
  Code:   (1) Access-Request
  Id:   14
  Length: 74
  Vector: b567e473a0dae669f1dc49359ea4d82b
  Data:   01  06  74 65 73 74
    02  12  d9 57 d0 5f 6d 05 e4 5c a6 9d 04 a8 03 8b f9 7c
    04  06  c0 a8 00 0f
    05  06  00 00 00 00
    50  12  3d bd 55 57 9b 7f dd d1 3e 91 cd 8c 60 4d 4c 70
Sent Access-Request Id 14 from 0.0.0.0:63378 to 127.0.0.1:1812 length 74
  User-Name = "test"
  User-Password = "test"
  NAS-IP-Address = 192.168.0.15
  NAS-Port = 0
  Message-Authenticator = 0x00
  Cleartext-Password = "test"
Received Access-Reject Id 14 from 127.0.0.1:1812 to 0.0.0.0:0 via lo0 length 20
(0) -: Expected Access-Accept got Access-Reject

That’s expected & good. It’s working!

Reviewing the server config

The default server site config is in /usr/local/etc/raddb/sites-enabled/default

A few things to note:

auth_log # uncommented, to enable log of authentication requests

#
#  Read the 'users' file.  In v3, this is located in
#  raddb/mods-config/files/authorize
files

Adding a user /usr/local/etc/raddb/mods-config/files/authorize. Uncomment the bob account:

#
# The canonical testing user which is in most of the
# examples.
#
bob     Cleartext-Password := "hello"
        Reply-Message := "Hello, %{User-Name}"

Restart the server, and test authentication:

$ radtest bob hello localhost 0 testing123
  Socket: 5
  Proto:  17
  Src IP: 0.0.0.0
    port: 60754
  Dst IP: 127.0.0.1
    port: 1812
  Code:   (1) Access-Request
  Id:   23
  Length: 73
  Vector: 64b3d1e258aa051f59457cfe4f5ac633
  Data:   01  05  62 6f 62
    02  12  0f 2a 46 6e ba 04 03 75 40 c6 ea f0 df 88 7a a6
    04  06  c0 a8 00 0f
    05  06  00 00 00 00
    50  12  46 47 e1 f1 00 19 04 16 c7 61 8e b2 56 df 8c 64
Sent Access-Request Id 23 from 0.0.0.0:60754 to 127.0.0.1:1812 length 73
  User-Name = "bob"
  User-Password = "hello"
  NAS-IP-Address = 192.168.0.15
  NAS-Port = 0
  Message-Authenticator = 0x00
  Cleartext-Password = "hello"
Received Access-Accept Id 23 from 127.0.0.1:1812 to 0.0.0.0:0 via lo0 length 32
  Reply-Message = "Hello, bob"

Success!

Removing

cd freeradius-server
sudo make uninstall

Removing talloc

If installed with brew:

brew uninstall talloc

If compiled from source

cd talloc-2.1.2
sudo make uninstall

Running with Docker

Pull a FreeRADIUS Image

docker pull freeradius/freeradius-server:latest

Create a local config directory so configs persist:

mkdir -p freeradius-config

Copy default config from container:

docker run --rm freeradius/freeradius-server:latest \
  tar cf - /etc/freeradius \
  | tar xf - -C ./freeradius-config --strip-components=2

Add a test user in freeradius-config/users

testuser Cleartext-Password := "testpass"

Allow local client in freeradius-config/clients.conf

client localhost {
    ipaddr = 127.0.0.1
    secret = testing123
}

Allow client network in freeradius-config/clients.conf

client private-network-1 {
  ipaddr  = 192.168.65.0/24
  secret  = testing123-1
}

Run FreeRADIUS using local config:

$ docker run --rm --name freeradius \
  -p 1812:1812/udp \
  -p 1813:1813/udp \
  -v $(pwd)/freeradius-config:/etc/freeradius \
  freeradius/freeradius-server:latest -X
...
Listening on auth address * port 1812 bound to server default
Listening on acct address * port 1813 bound to server default
Listening on auth address :: port 1812 bound to server default
Listening on acct address :: port 1813 bound to server default
Listening on auth address 127.0.0.1 port 18120 bound to server inner-tunnel
Listening on proxy address * port 32907
Listening on proxy address :: port 42199
Ready to process requests

Test request using radtest within the same container:

$ docker exec -it freeradius \
  radtest testuser testpass 127.0.0.1 0 testing123
Sent Access-Request Id 71 from 0.0.0.0:33717 to 127.0.0.1:1812 length 78
  User-Name = "testuser"
  User-Password = "testpass"
  NAS-IP-Address = 172.17.0.2
  NAS-Port = 0
  Message-Authenticator = 0x00
  Cleartext-Password = "testpass"
Received Access-Accept Id 71 from 127.0.0.1:1812 to 127.0.0.1:33717 length 38
  Message-Authenticator = 0x204dc8e98fb3245d73758653c322b8a1

Server log corresponding to the request:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
BlastRADIUS check: Received packet with Message-Authenticator.
Setting "require_message_authenticator = true" for client localhost
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
It looks like the client has been updated to protect from the BlastRADIUS attack.
Please set "require_message_authenticator = true" for client localhost
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
(0) Received Access-Request Id 71 from 127.0.0.1:33717 to 127.0.0.1:1812 length 78
(0)   Message-Authenticator = 0xd6ef6362a7430744daa9b8f7bcbcb292
(0)   User-Name = "testuser"
(0)   User-Password = "testpass"
(0)   NAS-IP-Address = 172.17.0.2
(0)   NAS-Port = 0
(0) # Executing section authorize from file /etc/freeradius/sites-enabled/default
(0)   authorize {
(0)     policy filter_username {
(0)       if (&User-Name) {
(0)       if (&User-Name)  -> TRUE
(0)       if (&User-Name)  {
(0)         if (&User-Name =~ / /) {
(0)         if (&User-Name =~ / /)  -> FALSE
(0)         if (&User-Name =~ /@[^@]*@/ ) {
(0)         if (&User-Name =~ /@[^@]*@/ )  -> FALSE
(0)         if (&User-Name =~ /\.\./ ) {
(0)         if (&User-Name =~ /\.\./ )  -> FALSE
(0)         if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/))  {
(0)         if ((&User-Name =~ /@/) && (&User-Name !~ /@(.+)\.(.+)$/))   -> FALSE
(0)         if (&User-Name =~ /\.$/)  {
(0)         if (&User-Name =~ /\.$/)   -> FALSE
(0)         if (&User-Name =~ /@\./)  {
(0)         if (&User-Name =~ /@\./)   -> FALSE
(0)       } # if (&User-Name)  = notfound
(0)     } # policy filter_username = notfound
(0)     [preprocess] = ok
(0)     [chap] = noop
(0)     [mschap] = noop
(0)     [digest] = noop
(0) suffix: Checking for suffix after "@"
(0) suffix: No '@' in User-Name = "testuser", looking up realm NULL
(0) suffix: No such realm "NULL"
(0)     [suffix] = noop
(0) eap: No EAP-Message, not doing EAP
(0)     [eap] = noop
(0) files: users: Matched entry testuser at line 43
(0)     [files] = ok
(0)     [expiration] = noop
(0)     [logintime] = noop
(0)     [pap] = updated
(0)   } # authorize = updated
(0) Found Auth-Type = PAP
(0) # Executing group from file /etc/freeradius/sites-enabled/default
(0)   Auth-Type PAP {
(0) pap: Login attempt with password
(0) pap: Comparing with "known good" Cleartext-Password
(0) pap: User authenticated successfully
(0)     [pap] = ok
(0)   } # Auth-Type PAP = ok
(0) # Executing section post-auth from file /etc/freeradius/sites-enabled/default
(0)   post-auth {
(0)     if (session-state:User-Name && reply:User-Name && request:User-Name && (reply:User-Name == request:User-Name)) {
(0)     if (session-state:User-Name && reply:User-Name && request:User-Name && (reply:User-Name == request:User-Name))  -> FALSE
(0)     update {
(0)       No attributes updated for RHS &session-state:
(0)     } # update = noop
(0)     [exec] = noop
(0)     policy remove_reply_message_if_eap {
(0)       if (&reply:EAP-Message && &reply:Reply-Message) {
(0)       if (&reply:EAP-Message && &reply:Reply-Message)  -> FALSE
(0)       else {
(0)         [noop] = noop
(0)       } # else = noop
(0)     } # policy remove_reply_message_if_eap = noop
(0)     if (EAP-Key-Name && &reply:EAP-Session-Id) {
(0)     if (EAP-Key-Name && &reply:EAP-Session-Id)  -> FALSE
(0)   } # post-auth = noop
(0) Sent Access-Accept Id 71 from 127.0.0.1:1812 to 127.0.0.1:33717 length 38
(0) Finished request
Waking up in 4.9 seconds.
(0) Cleaning up request packet ID 71 with timestamp +14 due to cleanup_delay was reached
Ready to process requests

Credits and References

About LCK#214
RADIUSmacOSinfrastructuredocker

This page is a web-friendly rendering of my project notes shared in the LittleCodingKata GitHub repository.

Project Source on GitHub Return to the LittleCodingKata Catalog
About LittleCodingKata

LittleCodingKata is my collection of programming exercises, research and code toys broadly spanning things that relate to programming and software development (languages, frameworks and tools).

These range from the trivial to the complex and serious. Many are inspired by existing work and I'll note credits and references where applicable. The focus is quite scattered, as I variously work on things new and important in the moment, or go back to revisit things from the past.

This is primarily a personal collection for my own edification and learning, but anyone who stumbles by is welcome to borrow, steal or reference the work here. And if you spot errors or issues I'd really appreciate some feedback - create an issue, send me an email or even send a pull-request.

Follow the Blog follow projects and notes as they are published in your favourite feed reader