]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
enable the new radius module
authorAlan T. DeKok <aland@freeradius.org>
Mon, 23 Dec 2024 14:32:11 +0000 (09:32 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Mon, 23 Dec 2024 17:40:34 +0000 (12:40 -0500)
15 files changed:
raddb/mods-available/radius
src/modules/rlm_radius/TODO.md [deleted file]
src/modules/rlm_radius/all.mk
src/modules/rlm_radius/bio.c [moved from src/modules/rlm_radius2/bio.c with 100% similarity]
src/modules/rlm_radius/rlm_radius.c
src/modules/rlm_radius/rlm_radius.h
src/modules/rlm_radius/track.c
src/modules/rlm_radius/track.h
src/modules/rlm_radius2/README.md [deleted file]
src/modules/rlm_radius2/all.mk [deleted file]
src/modules/rlm_radius2/rlm_radius.c [deleted file]
src/modules/rlm_radius2/rlm_radius.h [deleted file]
src/modules/rlm_radius2/track.c [deleted file]
src/modules/rlm_radius2/track.h [deleted file]
src/tests/radclient/config/radiusd.conf

index 14875a8f9e338be6d84803f33aa90f5b8a63c0aa..1eb1fc2f5000580621bd6183742006c1219a3141 100644 (file)
@@ -7,23 +7,53 @@
 #
 #  = Radius Module
 #
-#  The `radius` module in v4, can be used to implement proxying and request
-#  fan-out, as well as synchronous and asynchronous `CoA` and `DM`.
+#  The `radius` module in v4 implements RADIUS proxying and
+#  replication.  In v3, RADIUS proxying is a special kind of
+#  configuration, with it's own load-balancing, fail-over etc.  That
+#  configuration is now simpler in v4.  The outbound RADIUS proxying
+#  is done by just another module: the `radius` module.
+#  Load-balancing and redundant fail-over are handled by the
+#  `load-balance` and `redundant` keywords.
 #
-#  ## Configuration Settings
+#  In v4, the `radius` module most clearly maps to a `home_server` in
+#  v4.  The `radius` module typically makes a connection from one
+#  source IP address to a server at one destination IP/port.  It may
+#  open multiple source ports, depending on how many packets are being
+#  proxied.
+#
+#  ## Behavior
+#
+#  The module adds a Proxy-State attribute to all proxied packets.
+#  This `Proxy-State` contains a 32-bit random number, which is unique
+#  to this module.  This unique number helps to detect proxy loops.
+#
+#  The reply from home server is appended to the reply list for the
+#  current packet.
+#
+#  WARNING: For security reasons, the module ensures that all proxied
+#  `Access-Request` packets contain a `Message-Authenticator`
+#  attribute.  This behavior is *NOT* configurable, and *CANNOT* be
+#  changed.  This behavior is part of the BlastRADIUS mitigations.
 #
 #  Any proxied packet (including `Accounting-Request`) can
 #  receive a `Protocol-Error` response packet.  This packet
 #  is an explicit `NAK` that something went wrong processing
 #  the request.
 #
-#  WARNING: For security reasons, the module ensures that all proxied
-#  `Access-Request` packets contain a `Message-Authenticator` attribute.
-#  This behavior is *NOT* configurable, and *CANNOT* be changed.
+#  Unlike v3, the server does not support any "pre-proxy" or
+#  "post-proxy" processing sections.  Similarly, this module does not
+#  support any "proxy" or "proxy-reply" list.  Instead, the current
+#  request is proxied as-is, and the proxied reply is added to the
+#  current reply list.  If you want to modify the proxied request
+#  and/or proxied reply, then you should use a `subrequest` block to
+#  create a child request.  That child request can then be modified
+#  independently of the parent.  Any reply attributes will have to be
+#  copied back manually to the parent request.
 #
-#  The module adds a Proxy-State attribute to all proxied packets.
-#  This `Proxy-State` contains a 32-bit random number, which is unique
-#  to this module.  This unique number helps to detect proxy loops.
+#  ## Configuration Settings
+#
+#  The configuration settings of this module are similar to the
+#  `home_server` settings in v3.
 #
 #  The module has the following return codes:
 #
 #
 radius {
        #
-       #  transport:: Only UDP transport is allowed.
+       #  mode:: What kind of client behavior is being used.
+       #
+       #  proxy - forward packets which are received from a NAS
+       #       - each packet has a Proxy-State attribute added.
+       #       - it looks for, and stops proxy loops
+       #       - retransmissions are sent only when the NAS retransmits
+       #       - the module fails if it does not receive a reply
+       #
+       #  client - originate packet, and do retransmissions ourselves
+       #       - no Proxy-State is added.
+       #       - the module retransmits as needed
+       #       - the module fails if it does not receive a reply
+       #
+       #  replicate - send packets without waiting for a reply.
+       #       - no Proxy-State is added
+       #       - the module does not expect any reply
+       #       - all replies are discarded
+       #       - the module continues with "ok" immediately after
+       #         sending the packet.
+       #
+       #  unconnected-replicate - replicate packets to dynamic destinations
+       #       - For unconnected UDP sockets only.
+       #       - It MUST have `transport = udp`
+       #       - It MUST have `src_ipaddr = *` and no `src_port`
+       #       - You CANNOT use the module "in place" as with normal proxying.
+       #       - It is only supported via the function %replicate.sendto.ipaddr(ipaddr, port, secret)
+       #
+       #  unconnected-proxy - proxy packets to dynamic destinations
+       #       - For unconnected UDP sockets only.
+       #       - It MUST have `transport = udp`
+       #       - It MUST have `src_ipaddr = *` and no `src_port`
+       #       - You CANNOT use the module "in place" as with normal proxying.
+       #       - It is only supported via the function %proxy.sendto.ipaddr(ipaddr, port, secret)
+       #
+       #  The server can still be used to create (i.e. originate)
+       #  packets via this module when `mode = proxy` is set.  The
+       #  module can automatically detect the difference between
+       #  proxied packets and client packets it originates.
+       #  Originated packets are taken from the detail file, or
+       #  result when changing packet type (e.g. Accounting-Request
+       #  to Disconnect-Request), or when the current request is a
+       #  subrequest, and the parent request is from a different
+       #  protocol.
+       #
+       #  Note that there is no `mode = unconnected`, where the
+       #  module then both proxies packets, and replicates them.  The
+       #  need to track replies when proxying means that it's
+       #  difficult to both proxy and replicate at the same time.  As
+       #  a result, there are two "unconnected" modes, one for each
+       #  of "proxy" and "replicate".
+       #
+       mode = proxy
+
+       #
+       #  transport:: Transport protocol.  Can be `udp` or `tcp`.
        #
        transport = udp
 
@@ -58,77 +142,136 @@ radius {
        #
        #  type:: List of allowed packet types.
        #
-       #  There is currently no way to change the packet type in the
-       #  request.  See `unlang` fork for that functionality.
+       #  The module will only send packets types which are listed
+       #  here.  Other types of packets will be ignored.  The main
+       #  purpose of the `type` configuration is to ensure that the
+       #  correct packets are being sent to the home server.  This
+       #  entry serves as a double-check against misconfigurations.
+       #
+       #  In v3, the `home_server` configuration of `auth`, `acct`,
+       #  or `auth+acct` is used to _find_ a home server.  That is,
+       #  when FreeRADIUS has an `Access-Request` packet in v3, it
+       #  proxies it by looking up a matching `home_server`.
+       #
+       #  In v4, proxying is done by listing the `radius` module in a
+       #  processing section, such as `authenticate radius { ... }`,
+       #  or `recv Accounting-Request { ... }`.  So unlike v3, the
+       #  module doesn't have to _find_ a proxy destination for a
+       #  particular kind of packet.  Instead, the administrator
+       #  _configures_ the module to send packets to a destination.
+       #
+       #  As a result, the module doesn't really care about what kind
+       #  of packets it sends.  It has a packet, a destination where
+       #  that packet should be sent, and it sends the packet.
        #
-       #  NOTE: `Status-Server` is reserved for `inter-server` signaling,
+       #  In order to change packet types, see the `subrequest` keyword.
+       #
+       #  NOTE: `Status-Server` is reserved for connection signaling,
        #  and cannot be proxied.
        #
+       #  Unlike v3, all packet types are allocated from the same
+       #  8-bit ID space.  This change does not affect the majority
+       #  of RADIUS proxying, which only sends one type of packet.
+       #  This change does not affect the home server which receives
+       #  these packets, as the home server does not track IDs except
+       #  to correlate requests to replies.
+       #
+       #  The only visible difference, then, between v3 and v4 is
+       #  that in some cases, the new `radius` module will use more
+       #  source ports when proxying.
+       #
+       #  This change simplifies the implementation of the RADIUS
+       #  client.
+       #
        type = Access-Request
        type = Accounting-Request
 
        #
-       #  replicate:: Whether or not we are replicating packets.
-       #
-       #  Replication is "send proxied request, and continue,
-       #  without waiting for a response".  Any response received
-       #  is discarded, and does not affect packet processing.
+       #  require_message_authenticator::Require Message-Authenticator
+       #  in responses.
        #
-#      replicate = no
-
+       #  A server should include Message-Authenticator attribute as
+       #  the first attribute in responses to Access-Request packets.
+       #  This behavior mitigates against the BlastRADIUS attack.
        #
-       #  synchronous::
+       #  However, not all servers follow this security practice.  As
+       #  a result, this module can be configured to either not
+       #  require, or require, Message-Authenticator.
        #
-       #  In many cases, the module should do retransmissions of
-       #  proxied request on its own.  See the various
-       #  configurations for `initial_rtx_time`,
-       #  etc. below.  This means setting `synchronous = no`.
+       #  If value is `auto`, then the module will automatically
+       #  detect the existence of Message-Authenticator in response
+       #  packets.  Once the module sees a Message-Authenticator, it
+       #  will automatically change the configuration internally to
+       #  `yes`.  This change prevents security "down-bidding"
+       #  attacks.
        #
-       #  However, in some cases, it is useful to retransmit only
-       #  when the server receives a retransmission from the NAS.
-       #  This is done by setting `synchronous = yes`
+       #  Allowed values: yes, no, auto
        #
-       #  In general, if the server is receiving packets directly
-       #  from a NAS, you should set `synchronous = no`.  This is
-       #  because the NAS retransmission behavior is horrible,
-       #  inconsistent, and hard to configure.
+       #  The default is `auto`.
        #
-       #  If the server is receiving packets from another proxy
-       #  server, you should set `synchronous = yes`.  This allows
-       #  the other proxy server to do retransmissions correctly.
+       require_message_authenticator = auto
+
        #
-       #  NOTE: The behavior in v3 is the same as `synchronous = yes`
+       #  response_window: If we do not receive any replies within
+       #  this time period, then start `zombie_period`
        #
-#      synchronous = no
+       response_window = 15
 
        #
-       #  originate:: Whether or not we are creating the packet.
+       #  zombie_period:: If the home server does not reply to
+       #  packets within `response_window`, then `zombie_period`
+       #  starts.
        #
-       #  Sometimes we are creating a request that is not for the purpose of
-       #  proxying another request, in which case we do not want to add a
-       #  Proxy-State attribute.
+       #  When `zombie_period` starts, a connection is marked
+       #  `zombie`, and then is not used to send new packets.  If
+       #  there are no responses on this connection within
+       #  `zombie_period`, the module either closes the connection
+       #  (no `status_check` subsection), or starts pinging the home
+       #  server (`status_check.type = Status-Server`).
        #
-       #  In some cases, such as originating a CoA or Disconnect request,
-       #  including Proxy-State may confuse the receiving NAS.
-#      originate = no
+       zombie_period = 10
 
        #
-       #  require_message_authenticator::Require Message-Authenticator
-       #  in responses.
+       #  revive_interval:: If there are no status checks, mark the
+       #  home server alive after `revive_interval` timeout.
        #
-       #  Including a Message-Authenticator attribute first in response
-       #  packet, mitigates against the blastradius prefix attack.
+       #  Some home servers do not support status checks via the
+       #  `Status-Server` packet.  Others may not have a "test" user
+       #  configured that can be used to query the server, to see if
+       #  it is alive.  For those servers, we have NO WAY of knowing
+       #  when it becomes alive again.  Therefore, after the server
+       #  has been marked dead, we wait a period of time, and mark
+       #  it alive again, in the hope that it has come back to
+       #  life.
        #
-       #  If value is auto, then if any packet received from the client
-       #  contains a valid Message-Authenticator attribute, then the server
-       #  will require it from all future packets from that client.
+       #  If it has NOT come back to life, then the module will wait
+       #  for `zombie_period` before marking it dead again.  During
+       #  the `zombie_period`, ALL AUTHENTICATIONS WILL FAIL, because
+       #  the home server is still dead.  There is NOTHING that can
+       #  be done about this, other than to enable the status checks,
+       #  as documented above.
        #
-       #  Allowed values: yes, no, auto
+       #  e.g. if `zombie_period` is 40 seconds, and `revive_interval`
+       #  is 300 seconds, the for 40 seconds out of every 340, or about
+       #  10% of the time, all authentications will fail.
        #
-       #  The default is "no".
+       #  If the `zombie_period` and `revive_interval` configurations
+       #  are set smaller, than it is possible for up to 50% of
+       #  authentications to fail.
        #
-       require_message_authenticator = auto
+       #  As a result, we recommend enabling status checks, and
+       #  we do NOT recommend using `revive_interval`.
+       #
+       #  The `revive_interval` configuration is used ONLY if the
+       #  `status_check` subsection is not used.  Otherwise,
+       #  `revive_interval` is not necessary, and should be deleted.
+       #
+       #  Useful range of values: 10 to 3600
+       #
+       revive_interval = 3600
 
+       #
+       #  ### Check the status of a connection
        #
        #  status_check { ... }:: For "are you alive?" queries.
        #
@@ -141,12 +284,13 @@ radius {
                #  e.g. 'Access-Request', 'Accounting-Request' or
                #  'Status-Server'.
                #
-               #  Status-Server is recommended as other packet types may
-               #  be interpreted incorrectly, or proxied to a remote
-               #  server defeting the purpose of the status check
+               #  Status-Server is recommended as other packet types
+               #  may be interpreted incorrectly, or may ve proxied
+               #  to a remote server, which defeats the purpose of
+               #  the status checks.
                #
                #  If you specify another type of packet, it MUST be listed
-               #  as an allowed `type`, above.
+               #  as an allowed `type` above.
                #
                type = Status-Server
 
@@ -155,8 +299,9 @@ radius {
                #  be edited.
                #
                #  For other packet types, you can set the contents
-               #  here.  The section MUST be set over "&request.<attribute> = value", and
-               #  anything else will cause a parse error.
+               #  here.  The section MUST be set over
+               #  "&request.<attribute> = value", and anything else
+               #  will cause a parse error.
                #
                #  We RECOMMEND that you use packet contents which
                #  lets the other end easily tell that they are not
@@ -184,60 +329,71 @@ radius {
        }
 
        #
-       #  response_window: If we do not receive a reply within this time period, then
-       #  start `zombie_period`
+       #  ## Transport Protocols
        #
-       response_window = 15
-
-       #
-       #  zombie_period:: If the home server does not reply to a packet, the
-       #  `zombie_period` starts.
-       #
-       #  The connection is marked `zombie`, and isn't used to send new packets.
-       #  If there are no responses within `zombie_period`, the server either
-       #  closes the connection (no `status_check` subsection), or starts pinging the
-       #  home server (`status_check.type = Status-Server`).
+       #  The module supports multiple transport protocols.
        #
-       zombie_period = 10
 
        #
-       #  revive_interval:: If there are no status checks, mark the
-       #  home server alive after `revive_interval` timeout.
+       #  ### File Output
        #
-       #  Some home servers do not support status checks via the
-       #  `Status-Server` packet.  Others may not have a "test" user
-       #  configured that can be used to query the server, to see if
-       #  it is alive.  For those servers, we have NO WAY of knowing
-       #  when it becomes alive again.  Therefore, after the server
-       #  has been marked dead, we wait a period of time, and mark
-       #  it alive again, in the hope that it has come back to
-       #  life.
+       #  Write raw RADIUS packets (no IP or UDP header) to a file.
+       #  This transport can only be used for `mode = replicate`
        #
-       #  If it has NOT come back to life, then the module will wait
-       #  for `zombie_period` before marking it dead again.  During
-       #  the `zombie_period`, ALL AUTHENTICATIONS WILL FAIL, because
-       #  the home server is still dead.  There is NOTHING that can
-       #  be done about this, other than to enable the status checks,
-       #  as documented above.
+       file {
+            filename = ${logdir}/packets.bin
+       }
+
        #
-       #  e.g. if `zombie_period` is 40 seconds, and `revive_interval`
-       #  is 300 seconds, the for 40 seconds out of every 340, or about
-       #  10% of the time, all authentications will fail.
+       #  ### UDP Transport
        #
-       #  If the `zombie_period` and `revive_interval` configurations
-       #  are set smaller, than it is possible for up to 50% of
-       #  authentications to fail.
+       #  Much like the v3 `home_server` configuration.
        #
-       #  As a result, we recommend enabling status checks, and
-       #  we do NOT recommend using `revive_interval`.
+       udp {
+               #
+               #  src_ipaddr:: IP we open our socket on.
+               #
+#              src_ipaddr = *
+
+               #
+               #  Destination IP address, port, and secret.
+               #
+               #  Use `ipv4addr = ...` to force IPv4 addresses.
+               #  Use `ipv6addr = ...` to force IPv6 addresses.
+               #
+               ipaddr = 127.0.0.1
+               port = 1812
+               secret = testing123
+
+               #
+               #  interface:: Interface to bind to.
+               #
+#              interface = eth0
+
+               #
+               #  max_packet_size:: Our max packet size. may be different from the parent.
+               #
+#              max_packet_size = 4096
+
+               #
+               #  recv_buff:: How big the kernel's receive buffer should be.
+               #
+#              recv_buff = 1048576
+
+               #
+               #  send_buff:: How big the kernel's send buffer should be.
+               #
+#              send_buff = 1048576
+       }
+
        #
-       #  The `revive_interval` configuration is used ONLY if the
-       #  `status_check` subsection is not used.  Otherwise,
-       #  `revive_interval` is not necessary, and should be deleted.
+       #  ### TCP
        #
-       #  Useful range of values: 10 to 3600
+       #  The TCP configuration is identical to the `udp` configuration.
        #
-       revive_interval = 3600
+#      tcp {
+#              ...
+#      }
 
        #
        #  ## Connection trunking
@@ -389,55 +545,12 @@ radius {
        }
 
        #
-       #  ## Protocols
-       #
-       #  For now, only UDP is supported.
-       #
-       #  udp { ... }:: UDP is configured here.
-       #
-       udp {
-               ipaddr = 127.0.0.1
-               port = 1812
-               secret = testing123
-
-               #
-               #  NOTE: Don't change anything if you are not sure.
-               #
-
-               #
-               #  interface:: Interface to bind to.
-               #
-#              interface = eth0
-
-               #
-               #  max_packet_size:: Our max packet size. may be different from the parent.
-               #
-#              max_packet_size = 4096
-
-               #
-               #  recv_buff:: How big the kernel's receive buffer should be.
-               #
-#              recv_buff = 1048576
-
-               #
-               #  send_buff:: How big the kernel's send buffer should be.
-               #
-#              send_buff = 1048576
-
-               #
-               #  src_ipaddr:: IP we open our socket on.
-               #
-#              src_ipaddr = ""
-       }
-
-       #
-       #  ## Packets
+       #  ## Retransmission timers.
        #
        #  Each packet can have its own retransmission timers.
        #
        #  The sections are named for each packet type. The contents
-       #  are the same for all packet types.  Only the relevant ones
-       #  are parsed (see `type` above).
+       #  are the same for all packet types.
        #
 
        #
@@ -535,3 +648,87 @@ radius {
                max_rtx_duration = 30
        }
 }
+
+#
+#  ## Replication of Packets
+#
+#  The module supports replication of packets to new destinations at
+#  run time.  In this context, replication means "send the packet, and
+#  do not wait for the response".  This functionality is most useful
+#  when copying large amounts of accounting data to multiple
+#  destinations.
+#
+#  The module can then only be used as a dynamic expansion.  That is,
+#  you cannot specify the `replicate` module directly in a processing
+#  section.
+#
+#  ### Usage
+#
+#  This module can only be used as a dynamic expansion.  Since the
+#  module does not wait for any response, the expansion does not
+#  return any value.
+#
+#  The module can be called from any processing section as follows:
+#
+#      %replicate.sendto.ipaddr(127.0.0.1, 1813, 'testing123')
+#
+#  The function takes three arguments:
+#
+#      * IP address where the packet is sent.  It MUST be the same
+#        address family as `src_ipaddr` below.
+#      * port where the packet is sent.
+#      * secret for this packet.
+#
+#  This function allows the module to send packets to _any_
+#  destination, where the destination is chosen dynamically at run
+#  time.  The arguments to the function can be take from other
+#  attributes, database queries, etc.
+#
+radius replicate {
+       #
+       #  Generally you only want to replicate accounting packets.
+       #
+       type = Accounting-Request
+
+       #
+       #  We are not opening a socket from our server to their
+       #  server.  We are replicating packets.
+       #
+       mode = unconnected-replicate
+
+       #
+       #  For replicated packets, only UDP is supported.
+       #
+       transport = udp
+
+       #
+       #  ### UDP Transport
+       #
+       #  For unconnected modes, only UDP is supported.
+       #
+       udp {
+               #
+               #  src_ipaddr:: The source IP address used by the module.
+               #
+               src_ipaddr = *
+
+               #
+               #  `src_port` cannot be used.  If it is used here, the
+               #  module will refuse to start.  Instead, the module
+               #  will open a unique source port per thread.
+               #
+               #  `secret` cannot be used.  If it is used, the value
+               #  will be ignored.
+               #
+       }
+
+       #
+       #  ### Other Configuration
+       #
+       #  No other configuration items are supported when using
+       #  `mode = unconnected-replicate`.
+       #
+       #  The `pool` configuration is ignored, as is `status-check`,
+       #  along with all per-packet timeouts.
+       #
+}
diff --git a/src/modules/rlm_radius/TODO.md b/src/modules/rlm_radius/TODO.md
deleted file mode 100644 (file)
index e3b8440..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# rlm_radius
-
-## 2017-10-11
-
-After refactoring...
-
-* on read(), don't put connection into active state, as it may not be writable?
-  * or, just do it, and hope for the best... with the event loop handling it
-
-
-## RADIUS fixes
-
-* idle out old connections
-
-* limit # of bad / reconnected connections
-
-* move status_u allocation and init to connection alloc
-
-## connection state
-
-* maybe move Status-Server to fixed-time pings, as recommended in RFC 3539?
-  * low priority, and probably not useful
-
-## Limits
-
-We limit the number of connections, but not the number of proxied
-packets.  This is because (for now), each connection can only proxy 256 packets...
-
-## Status Checks
-
-* connection negotiation in Status-Server in proto_radius
-  * some is there (Response-Length)
-  * add more?  Extended ID, etc.
-
-## Core Issues
-
-things to do in the server core.  Tracked here because it's related to
-the work in rlm_radius.
-
-## Cleanup_delay
-
-* need to double-check cleanup_delay
-  * it works, but it's likely set too small?
-  * especially if the client retransmits are 10s?
-  * or maybe it was the dup detection bug (timestamp) where it didn't detect dups...
-
-## sequence / ACK in network / worker
-
-* double-check ENABLE_SKIPS in src/lib/io/channel.c.  It's disabled
-  for now, as it caused problems.  So it ALWAYS signals the other side. :(
-
-We should move to a "must_signal" approach, as with the network side
-The worker should suppress signals if it sees that the ACKs from the
-other end haven't caught up to it's sent packets.  Otherwise, it must
-signal.
-
-this whole thing is wrong... we end up signaling on every damned packet in real life...
-
-OK... fix the damned channel to use queue depth instead of ACKs
-which makes them less general, but better.  The worker can NAK a packet, send a reply, or mark it ask discarded
-
-
-    DATA        N -> W: (packet + queue 1, active)
-    
-    DATA        N <- W (packet + queue is now 0, inactive)
-    
-    DISCARD     N <- W (no packet, queue is now 0, inactive)
-    
-    SLEEPING    N <- W (no packet, queue is 1, inactive)
-
-
-We also need an "must_signal" flag, for if the other end is
-sleeping... the network always sets it, I guess..
-
-### Fork
-
-* fix fork
-
-    fork server.packet-type {
-        &foo += &parent:bar
-    }
-
-* fork is an 'update' section that also runs a new virtual server.  A
-  little weird, but it should work.
-
-* needs helper functions in virtual_server.c to do it.. and to create
-  child request_t async stuff with listen, protocol handler, etc.
-
-* fork also needs to do this sanity check on compile, so that it knows
-  it can dereference sections which exist...
-
-### clean up request_t structure
-
-many fields are essentially unused.  request->proxy is no longer used,
-but is referenced all over the place.
-
-grunt work, but very useful.
-
-### Network and worker fixups
-
-* switch worker selection from recursing / heap to O(N) lookups and "power of 2"
-  * see comments in src/lib/io/network.c
-
-* associate packets with a particular worker across multiple packets
-  * once this is done, we can move to per-thread SSL contexts, and drop contention massively
-  * with the caveat that *all SSL work* has to be done in one thread
-  * hopefully this doesn't affect things like SQL drivers?  need to check...
-
-* do NUMA for high-end systems
-  * associate N network threads with W worker threads
index 2413dc949ffd2b1f16910acb382ed71af409379d..52bd795c0eea0ac0c2ea49ed29b58fcdf5f747ac 100644 (file)
@@ -1,3 +1,7 @@
-ifeq "${WITH_RADIUS2}" ""
-SUBMAKEFILES := rlm_radius.mk rlm_radius_udp.mk
-endif
+TARGETNAME     := rlm_radius
+TARGET         := $(TARGETNAME)$(L)
+
+SOURCES                := rlm_radius.c track.c
+
+TGT_PREREQS    := libfreeradius-radius$(L) libfreeradius-bio-config$(L) libfreeradius-bio$(L)
+LOG_ID_LIB     = 39
index 8cee28ddfed8439fc2efbd485218731dc6119608..2036ae5ec8b3bdcd2974df1d9045eba243103c6a 100644 (file)
@@ -26,11 +26,13 @@ RCSID("$Id$")
 
 #include <freeradius-devel/io/application.h>
 #include <freeradius-devel/server/modpriv.h>
+#include <freeradius-devel/unlang/xlat_func.h>
 #include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/util/dlist.h>
 
 #include "rlm_radius.h"
 
+static int mode_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
 static int type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
 static int status_check_type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
 static int status_check_update_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
@@ -94,24 +96,46 @@ static conf_parser_t disconnect_config[] = {
        CONF_PARSER_TERMINATOR
 };
 
+static conf_parser_t const transport_config[] = {
+       { FR_CONF_OFFSET_FLAGS("secret", CONF_FLAG_REQUIRED, rlm_radius_t, secret) },
+
+       CONF_PARSER_TERMINATOR
+};
+
+/*
+ *     We only parse the pool options if we're connected.
+ */
+static conf_parser_t const connected_config[] = {
+       { FR_CONF_POINTER("status_check", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) status_check_config },
+
+       { FR_CONF_OFFSET_SUBSECTION("pool", 0, rlm_radius_t, trunk_conf, trunk_config ) },
+
+       { FR_CONF_POINTER("udp", 0, CONF_FLAG_SUBSECTION | CONF_FLAG_OPTIONAL, NULL), .subcs = (void const *) transport_config },
+
+       { FR_CONF_POINTER("tcp", 0, CONF_FLAG_SUBSECTION | CONF_FLAG_OPTIONAL, NULL), .subcs = (void const *) transport_config },
+
+       CONF_PARSER_TERMINATOR
+};
 
 /*
  *     A mapping of configuration file names to internal variables.
  */
 static conf_parser_t const module_config[] = {
-       { FR_CONF_OFFSET_TYPE_FLAGS("transport", FR_TYPE_VOID, 0, rlm_radius_t, io_submodule),
-         .func = module_rlm_submodule_parse },
+       { FR_CONF_OFFSET_FLAGS("mode", CONF_FLAG_REQUIRED, rlm_radius_t, mode), .func = mode_parse, .dflt = "proxy" },
+
+       { FR_CONF_OFFSET_REF(rlm_radius_t, fd_config, fr_bio_fd_client_config) },
 
        { FR_CONF_OFFSET_FLAGS("type", CONF_FLAG_NOT_EMPTY | CONF_FLAG_MULTI | CONF_FLAG_REQUIRED, rlm_radius_t, types),
          .func = type_parse },
 
-       { FR_CONF_OFFSET("replicate", rlm_radius_t, replicate) },
+       { FR_CONF_OFFSET_FLAGS("replicate", CONF_FLAG_DEPRECATED, rlm_radius_t, replicate) },
 
-       { FR_CONF_OFFSET("synchronous", rlm_radius_t, synchronous) },
+       { FR_CONF_OFFSET_FLAGS("synchronous", CONF_FLAG_DEPRECATED, rlm_radius_t, synchronous) },
 
-       { FR_CONF_OFFSET("originate", rlm_radius_t, originate) },
+       { FR_CONF_OFFSET_FLAGS("originate", CONF_FLAG_DEPRECATED, rlm_radius_t, originate) },
 
-       { FR_CONF_POINTER("status_check", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) status_check_config },
+       { FR_CONF_OFFSET("max_packet_size", rlm_radius_t, max_packet_size), .dflt = "4096" },
+       { FR_CONF_OFFSET("max_send_coalesce", rlm_radius_t, max_send_coalesce), .dflt = "1024" },
 
        { FR_CONF_OFFSET("max_attributes", rlm_radius_t, max_attributes), .dflt = STRINGIFY(RADIUS_MAX_ATTRIBUTES) },
 
@@ -126,8 +150,6 @@ static conf_parser_t const module_config[] = {
 
        { FR_CONF_OFFSET("revive_interval", rlm_radius_t, revive_interval) },
 
-       { FR_CONF_OFFSET_SUBSECTION("pool", 0, rlm_radius_t, trunk_conf, trunk_config ) },
-
        CONF_PARSER_TERMINATOR
 };
 
@@ -153,15 +175,97 @@ static fr_dict_attr_t const *attr_chap_password;
 static fr_dict_attr_t const *attr_packet_type;
 static fr_dict_attr_t const *attr_proxy_state;
 
+static fr_dict_attr_t const *attr_error_cause;
+static fr_dict_attr_t const *attr_event_timestamp;
+static fr_dict_attr_t const *attr_extended_attribute_1;
+static fr_dict_attr_t const *attr_message_authenticator;
+static fr_dict_attr_t const *attr_eap_message;
+static fr_dict_attr_t const *attr_nas_identifier;
+static fr_dict_attr_t const *attr_original_packet_code;
+static fr_dict_attr_t const *attr_response_length;
+static fr_dict_attr_t const *attr_user_password;
+
 extern fr_dict_attr_autoload_t rlm_radius_dict_attr[];
 fr_dict_attr_autoload_t rlm_radius_dict_attr[] = {
        { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
        { .out = &attr_chap_password, .name = "CHAP-Password", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
        { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
        { .out = &attr_proxy_state, .name = "Proxy-State", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
+
+       { .out = &attr_error_cause, .name = "Error-Cause", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+       { .out = &attr_event_timestamp, .name = "Event-Timestamp", .type = FR_TYPE_DATE, .dict = &dict_radius},
+       { .out = &attr_extended_attribute_1, .name = "Extended-Attribute-1", .type = FR_TYPE_TLV, .dict = &dict_radius},
+       { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
+       { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
+       { .out = &attr_nas_identifier, .name = "NAS-Identifier", .type = FR_TYPE_STRING, .dict = &dict_radius},
+       { .out = &attr_original_packet_code, .name = "Extended-Attribute-1.Original-Packet-Code", .type = FR_TYPE_UINT32, .dict = &dict_radius},
+       { .out = &attr_response_length, .name = "Extended-Attribute-1.Response-Length", .type = FR_TYPE_UINT32, .dict = &dict_radius },
+       { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius},
+
        { NULL }
 };
 
+#include "bio.c"
+
+static fr_table_num_sorted_t mode_names[] = {
+       { L("client"),          RLM_RADIUS_MODE_CLIENT          },
+       { L("proxy"),           RLM_RADIUS_MODE_PROXY           },
+       { L("replicate"),       RLM_RADIUS_MODE_REPLICATE       },
+       { L("unconnected-replicate"),   RLM_RADIUS_MODE_UNCONNECTED_REPLICATE   },
+//     { L("unconnected-proxy"),       RLM_RADIUS_MODE_UNCONNECTED_PROXY       },
+};
+static size_t mode_names_len = NUM_ELEMENTS(mode_names);
+
+
+/** Set the mode of operation
+ *
+ * @param[in] ctx      to allocate data in (instance of rlm_radius).
+ * @param[out] out     Where to write the parsed data.
+ * @param[in] parent   Base structure address.
+ * @param[in] ci       #CONF_PAIR specifying the name of the type module.
+ * @param[in] rule     unused.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+static int mode_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent,
+                     CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
+{
+       char const              *name = cf_pair_value(cf_item_to_pair(ci));
+       rlm_radius_mode_t       mode;
+       rlm_radius_t            *inst = talloc_get_type_abort(parent, rlm_radius_t);
+
+       mode = fr_table_value_by_str(mode_names, name, RLM_RADIUS_MODE_INVALID);
+
+       /*
+        *      Commented out until we upgrade the old configurations.
+        */
+       if (mode == RLM_RADIUS_MODE_INVALID) {
+               cf_log_err(ci, "Invalid mode name \"%s\"", name);
+               return -1;
+       }
+
+       *(rlm_radius_mode_t *) out = mode;
+
+       /*
+        *      Normally we want connected sockets, in which case we push additional configuration for connected sockets.
+        */
+       if ((mode != RLM_RADIUS_MODE_UNCONNECTED_REPLICATE) &&
+           (mode != RLM_RADIUS_MODE_UNCONNECTED_PROXY)) {
+               CONF_SECTION *cs = cf_item_to_section(cf_parent(ci));
+
+               inst->fd_config.type = FR_BIO_FD_CONNECTED;
+
+               if (cf_section_rules_push(cs, connected_config) < 0) return -1;
+
+       } else {
+               inst->fd_config.type = FR_BIO_FD_UNCONNECTED;
+       }
+
+       return 0;
+}
+
+
 /** Set which types of packets we can parse
  *
  * @param[in] ctx      to allocate data in (instance of rlm_radius).
@@ -217,7 +321,7 @@ static int type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
         */
        cf_section_rule_push(cs, &type_interval_config[code]);
 
-       memcpy(out, &code, sizeof(code));
+       *(uint32_t *) out = code;
 
        return 0;
 }
@@ -345,7 +449,7 @@ static void radius_fixups(rlm_radius_t const *inst, request_t *request)
        /*
         *      Check for proxy loops.
         */
-       if (!inst->originate && RDEBUG_ENABLED) {
+       if ((inst->mode == RLM_RADIUS_MODE_PROXY) && RDEBUG_ENABLED) {
                fr_dcursor_t cursor;
 
                for (vp = fr_pair_dcursor_by_da_init(&cursor, &request->request_pairs, attr_proxy_state);
@@ -353,13 +457,19 @@ static void radius_fixups(rlm_radius_t const *inst, request_t *request)
                     vp = fr_dcursor_next(&cursor)) {
                        if (vp->vp_length != 4) continue;
 
-                       if (memcmp(&inst->proxy_state, vp->vp_octets, 4) == 0) {
+                       if (memcmp(&inst->common_ctx.proxy_state, vp->vp_octets, 4) == 0) {
                                RWARN("Possible proxy loop - please check server configuration.");
                                break;
                        }
                }
        }
 
+       /*
+        *      @todo - check for proxy loops for client && replicate, too.
+        *
+        *      This only catches "self loops", but it may be worth doing.
+        */
+
        if (request->packet->code != FR_RADIUS_CODE_ACCESS_REQUEST) return;
 
        if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_password) &&
@@ -395,7 +505,17 @@ static unlang_action_t CC_HINT(nonnull) mod_process(rlm_rcode_t *p_result, modul
 
        if ((request->packet->code >= FR_RADIUS_CODE_MAX) ||
            !fr_time_delta_ispos(inst->retry[request->packet->code].irt)) { /* can't be zero */
-               REDEBUG("Invalid packet code %d", request->packet->code);
+               REDEBUG("Invalid packet code %u", request->packet->code);
+               RETURN_MODULE_FAIL;
+       }
+
+       /*
+        *      Unconnected sockets use %radius.replicate(ip, port, secret),
+        *      or %radius.sendto(ip, port, secret)
+        */
+       if ((inst->mode == RLM_RADIUS_MODE_UNCONNECTED_REPLICATE) ||
+           (inst->mode == RLM_RADIUS_MODE_UNCONNECTED_PROXY)) {
+               REDEBUG("When using 'mode = unconnected-*', this module cannot be used in-place.  Instead, it must be called via a function call");
                RETURN_MODULE_FAIL;
        }
 
@@ -425,26 +545,104 @@ static unlang_action_t CC_HINT(nonnull) mod_process(rlm_rcode_t *p_result, modul
         *      return another code which indicates what happened to
         *      the request...
         */
-       return inst->io->enqueue(&rcode, inst->io_submodule->data,
-                                module_thread(inst->io_submodule)->data, request);
+       return mod_enqueue(&rcode, inst,
+                          module_thread(mctx->mi)->data, request);
 }
 
+
 static int mod_instantiate(module_inst_ctx_t const *mctx)
 {
        size_t i, num_types;
        rlm_radius_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
        CONF_SECTION *conf = mctx->mi->conf;
 
-       inst->io = (rlm_radius_io_t const *)inst->io_submodule->exported;       /* Public symbol exported by the module */
        inst->name = mctx->mi->name;
        inst->received_message_authenticator = talloc_zero(NULL, bool);         /* Allocated outside of inst to default protection */
 
        /*
-        *      These limits are specific to RADIUS, and cannot be over-ridden
+        *      Allow explicit setting of mode.
         */
-       FR_INTEGER_BOUND_CHECK("trunk.per_connection_max", inst->trunk_conf.max_req_per_conn, >=, 2);
-       FR_INTEGER_BOUND_CHECK("trunk.per_connection_max", inst->trunk_conf.max_req_per_conn, <=, 255);
-       FR_INTEGER_BOUND_CHECK("trunk.per_connection_target", inst->trunk_conf.target_req_per_conn, <=, inst->trunk_conf.max_req_per_conn / 2);
+       if (inst->mode != RLM_RADIUS_MODE_INVALID) goto check_others;
+
+       /*
+        *      If not set, try to insinuate it from context.
+        */
+       if (inst->replicate) {
+               if (inst->originate) {
+                       cf_log_err(conf, "Cannot set 'replicate=true' and 'originate=true' at the same time.");
+                       return -1;
+               }
+
+               if (inst->synchronous) {
+                       cf_log_warn(conf, "Ignoring 'synchronous=true' due to 'replicate=true'");
+               }
+
+               inst->mode = RLM_RADIUS_MODE_REPLICATE;
+               goto check_others;
+       }
+
+       /*
+        *      Argubly we should be allowed to do synchronous proxying _and_ originating client packets.
+        *
+        *      However, the previous code didn't really do that consistently.
+        */
+       if (inst->synchronous && inst->originate) {
+               cf_log_err(conf, "Cannot set 'synchronous=true' and 'originate=true'");
+               return -1;
+       }
+
+       if (inst->synchronous) {
+               inst->mode = RLM_RADIUS_MODE_PROXY;
+       } else {
+               inst->mode = RLM_RADIUS_MODE_CLIENT;
+       }
+
+check_others:
+       /*
+        *      Replication is write-only, and append by default.
+        */
+       if (inst->mode == RLM_RADIUS_MODE_REPLICATE) {
+               if (inst->fd_config.filename && (inst->fd_config.flags != O_WRONLY)) {
+                       cf_log_info(conf, "Setting 'flags = write-only' for writing to a file");
+               }
+               inst->fd_config.flags = O_WRONLY | O_APPEND;
+
+       } else if (inst->fd_config.filename) {
+               cf_log_err(conf, "When using an output 'filename', you MUST set 'mode = replicate'");
+               return -1;
+
+       } else {
+               /*
+                *      All other IO is read+write.
+                */
+               inst->fd_config.flags = O_RDWR;
+       }
+
+       if (fr_bio_fd_check_config(&inst->fd_config) < 0) {
+               cf_log_perr(conf, "Invalid configuration");
+               return -1;
+       }
+
+       /*
+        *      Clamp max_packet_size first before checking recv_buff and send_buff
+        */
+       FR_INTEGER_BOUND_CHECK("max_packet_size", inst->max_packet_size, >=, 64);
+       FR_INTEGER_BOUND_CHECK("max_packet_size", inst->max_packet_size, <=, 65535);
+
+       if ((inst->mode != RLM_RADIUS_MODE_UNCONNECTED_REPLICATE) &&
+           (inst->mode != RLM_RADIUS_MODE_UNCONNECTED_PROXY)) {
+               /*
+                *      These limits are specific to RADIUS, and cannot be over-ridden
+                */
+               FR_INTEGER_BOUND_CHECK("trunk.per_connection_max", inst->trunk_conf.max_req_per_conn, >=, 2);
+               FR_INTEGER_BOUND_CHECK("trunk.per_connection_max", inst->trunk_conf.max_req_per_conn, <=, 255);
+               FR_INTEGER_BOUND_CHECK("trunk.per_connection_target", inst->trunk_conf.target_req_per_conn, <=, inst->trunk_conf.max_req_per_conn / 2);
+       } else {
+               if (inst->fd_config.src_port != 0) {
+                       cf_log_err(conf, "Cannot set 'src_port' when using 'mode = unconnected'");
+                       return -1;
+               }
+       }
 
        FR_TIME_DELTA_BOUND_CHECK("response_window", inst->zombie_period, >=, fr_time_delta_from_sec(1));
        FR_TIME_DELTA_BOUND_CHECK("response_window", inst->zombie_period, <=, fr_time_delta_from_sec(120));
@@ -460,6 +658,17 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
        num_types = talloc_array_length(inst->types);
        fr_assert(num_types > 0);
 
+       inst->timeout_retry = (fr_retry_config_t) {
+               .mrc = 1,
+               .mrd = inst->response_window,
+       };
+
+       inst->common_ctx = (fr_radius_ctx_t) {
+               .secret = inst->secret,
+               .secret_length = inst->secret ? talloc_array_length(inst->secret) - 1 : 0,
+               .proxy_state = fr_rand(),
+       };
+
        /*
         *      Allow for O(1) lookup later...
         */
@@ -479,13 +688,20 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
         *      If we're replicating, we don't care if the other end
         *      is alive.
         */
-       if (inst->replicate && inst->status_check) {
-               cf_log_warn(conf, "Ignoring 'status_check = %s' due to 'replicate = true'",
-                           fr_radius_packet_name[inst->status_check]);
-               inst->status_check = 0;
+       if (inst->status_check) {
+               if (inst->mode == RLM_RADIUS_MODE_REPLICATE) {
+                       cf_log_warn(conf, "Ignoring 'status_check = %s' due to 'mode = replicate'",
+                                   fr_radius_packet_name[inst->status_check]);
+                       inst->status_check = false;
+
+               } else if ((inst->mode == RLM_RADIUS_MODE_UNCONNECTED_REPLICATE) ||
+                          (inst->mode == RLM_RADIUS_MODE_UNCONNECTED_PROXY)) {
+                                  cf_log_warn(conf, "Ignoring 'status_check = %s' due to 'mode = unconnected-*'",
+                                   fr_radius_packet_name[inst->status_check]);
+                       inst->status_check = false;
+               }
        }
 
-
        /*
         *      If we have status checks, then do some sanity checks.
         *      Status-Server is always allowed.  Otherwise, the
@@ -507,13 +723,29 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
                 *      section, to be sure that (e.g.) Access-Request
                 *      contains User-Name, etc.
                 */
+
+               if (inst->fd_config.filename) {
+                       cf_log_info(conf, "Disabling status checks for output file %s", inst->fd_config.filename);
+                       inst->status_check = 0;
+               }
+       }
+
+       /*
+        *      Files and unix sockets can just have us call write().
+        */
+       if (inst->fd_config.filename || inst->fd_config.path) {
+               inst->max_send_coalesce = 1;
        }
 
+       inst->trunk_conf.req_pool_headers = 4;  /* One for the request, one for the buffer, one for the tracking binding, one for Proxy-State VP */
+       inst->trunk_conf.req_pool_size = 1024 + sizeof(fr_pair_t) + 20;
+
        /*
-        *      Don't sanity check the async timers if we're doing
-        *      synchronous proxying.
+        *      Only check the async timers when we're acting as a client.
         */
-       if (inst->synchronous) goto setup_io_submodule;
+       if (inst->mode != RLM_RADIUS_MODE_CLIENT) {
+               return 0;
+       }
 
        /*
         *      Set limits on retransmission timers
@@ -596,15 +828,32 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
                FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrd, <=, fr_time_delta_from_sec(30));
        }
 
-setup_io_submodule:
-       /*
-        *      Get random Proxy-State identifier for this module.
-        */
-       inst->proxy_state = fr_rand();
+       return 0;
+}
+
+static int mod_bootstrap(module_inst_ctx_t const *mctx)
+{
+       xlat_t          *xlat;
+       rlm_radius_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
+
+       switch (inst->mode) {
+       case RLM_RADIUS_MODE_UNCONNECTED_REPLICATE:
+               xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "sendto.ipaddr", xlat_radius_replicate, FR_TYPE_VOID);
+               xlat_func_args_set(xlat, xlat_radius_send_args);
+               break;
+
+       case RLM_RADIUS_MODE_UNCONNECTED_PROXY:
+               fr_assert(0);   /* not implemented */
+               break;
+
+       default:
+               break;
+       }
 
        return 0;
 }
 
+
 static int mod_detach(module_detach_ctx_t const *mctx)
 {
        rlm_radius_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
@@ -647,8 +896,13 @@ module_rlm_t rlm_radius = {
                .onload         = mod_load,
                .unload         = mod_unload,
 
+               .bootstrap      = mod_bootstrap,
                .instantiate    = mod_instantiate,
-               .detach         = mod_detach
+               .detach         = mod_detach,
+
+               .thread_inst_size       = sizeof(bio_thread_t),
+               .thread_inst_type       = "bio_thread_t",
+               .thread_instantiate     = mod_thread_instantiate,
        },
        .method_group = {
                .bindings = (module_method_binding_t[]){
index bc14e6e0e793c39097e3fa7c8b260694ac408e1a..13697630e9bf3527a5c7ef5dbee3d114abb3da7c 100644 (file)
@@ -23,6 +23,9 @@
 #include <freeradius-devel/util/retry.h>
 #include <freeradius-devel/unlang/module.h>
 #include <freeradius-devel/radius/radius.h>
+#include <freeradius-devel/radius/bio.h>
+
+#include <freeradius-devel/bio/fd.h>
 
 /*
  * $Id$
  */
 
 typedef struct rlm_radius_s rlm_radius_t;
-typedef struct rlm_radius_io_s rlm_radius_io_t;
+
+typedef enum {
+       RLM_RADIUS_MODE_INVALID = 0,
+       RLM_RADIUS_MODE_PROXY,
+       RLM_RADIUS_MODE_CLIENT,
+       RLM_RADIUS_MODE_REPLICATE,
+       RLM_RADIUS_MODE_UNCONNECTED_REPLICATE,
+       RLM_RADIUS_MODE_UNCONNECTED_PROXY,
+} rlm_radius_mode_t;
 
 /*
  *     Define a structure for our module configuration.
  */
 struct rlm_radius_s {
+       fr_bio_fd_config_t      fd_config;              //!< for now MUST be at the start!
+
        char const              *name;
-       module_instance_t       *io_submodule;
-       rlm_radius_io_t const   *io;                    //!< Public symbol exported by the submodule.
 
        fr_time_delta_t         response_window;
        fr_time_delta_t         zombie_period;
        fr_time_delta_t         revive_interval;
 
+       char const              *secret;                //!< Shared secret.
+
+       uint32_t                max_packet_size;        //!< Maximum packet size.
+       uint16_t                max_send_coalesce;      //!< Maximum number of packets to coalesce into one mmsg call.
+
+       fr_radius_ctx_t         common_ctx;
+
        bool                    replicate;              //!< Ignore responses.
        bool                    synchronous;            //!< Retransmit when receiving a duplicate request.
-       bool                    originate;              //!< Originating packets, instead of proxying existing ones.
+       bool                    originate;              //!< Originating packets, instead of proxying existing ones.
                                                        ///< Controls whether Proxy-State is added to the outbound
-                                                       ///< request.
+                                                       ///< request
+       rlm_radius_mode_t       mode;                   //!< proxy, client, etc.
 
        uint32_t                max_attributes;         //!< Maximum number of attributes to decode in response.
 
        fr_radius_require_ma_t  require_message_authenticator;  //!< Require Message-Authenticator in responses.
        bool                    *received_message_authenticator;        //!< Received Message-Authenticator in responses.
 
-       uint32_t                proxy_state;            //!< Unique ID (mostly) of this module.
        uint32_t                *types;                 //!< array of allowed packet types
        uint32_t                status_check;           //!< code of status-check type
        map_list_t              status_check_map;       //!< attributes for the status-server checks
@@ -67,21 +85,9 @@ struct rlm_radius_s {
                                                        ///< mark the connection as alive.
 
        bool                    allowed[FR_RADIUS_CODE_MAX];
+
+       fr_retry_config_t       timeout_retry;
        fr_retry_config_t       retry[FR_RADIUS_CODE_MAX];
 
        trunk_conf_t            trunk_conf;             //!< trunk configuration
 };
-
-/** Enqueue a request_t to an IO submodule
- *
- */
-typedef unlang_action_t (*rlm_radius_io_enqueue_t)(rlm_rcode_t *p_result, void *instance, void *thread, request_t *request);
-
-/** Public structure describing an I/O path for an outgoing socket.
- *
- * This structure is exported by client I/O modules e.g. rlm_radius_udp.
- */
-struct rlm_radius_io_s {
-       module_t                common;                 //!< Common fields to all loadable modules.
-       rlm_radius_io_enqueue_t enqueue;                //!< Enqueue a request_t with an IO submodule.
-};
index 80a69d6923beb24d2eb02f2eee7f3813bd8cedf4..b4d71316d4d7c0fb95f076d150c985048c850f39 100644 (file)
@@ -30,7 +30,6 @@ RCSID("$Id$")
 #include <freeradius-devel/util/debug.h>
 
 #include "track.h"
-#include "rlm_radius.h"
 
 /** Create an radius_track_t
  *
@@ -57,25 +56,10 @@ radius_track_t *radius_track_alloc(TALLOC_CTX *ctx)
                fr_dlist_insert_tail(&tt->free_list, &tt->id[i]);
        }
 
-       tt->next_id = fr_rand() & 0xff;
-
        return tt;
 }
 
 
-/** Compare two radius_track_entry_t
- *
- */
-static int8_t te_cmp(void const *one, void const *two)
-{
-       radius_track_entry_t const *a = one;
-       radius_track_entry_t const *b = two;
-       int ret;
-
-       ret = memcmp(a->vector, b->vector, sizeof(a->vector));
-       return CMP(ret, 0);
-}
-
 /** Ensures the entry is released when the ctx passed to radius_track_entry_reserve is freed
  *
  * @param[in] te_p             Entry to release.
@@ -132,7 +116,7 @@ retry:
                 *      don't use it".  Ensure that we only return IDs
                 *      which are in the static array.
                 */
-               if (!tt->use_authenticator && (te != &tt->id[te->id])) {
+               if (te != &tt->id[te->id]) {
                        talloc_free(te);
                        goto retry;
                }
@@ -144,31 +128,8 @@ retry:
         *      There are no free entries, and we can't use the
         *      Request Authenticator.  Oh well...
         */
-       if (!tt->use_authenticator) {
-               fr_strerror_const("No free entries");
-               return -1;
-       }
-
-       /*
-        *      Get a new ID.  It's value doesn't matter at this
-        *      point.
-        */
-       tt->next_id++;
-       tt->next_id &= 0xff;
-
-       /*
-        *      If needed, allocate a subtree.
-        */
-       if (!tt->subtree[tt->next_id]) {
-               MEM(tt->subtree[tt->next_id] = fr_rb_inline_talloc_alloc(tt, radius_track_entry_t, node,
-                                                                        te_cmp, NULL));
-       }
-
-       /*
-        *      Allocate a new one, and insert it into the appropriate subtree.
-        */
-       te = talloc_zero(tt, radius_track_entry_t);
-       te->id = tt->next_id;
+       fr_strerror_const("No free entries");
+       return -1;
 
 done:
        te->tt = tt;
@@ -238,43 +199,8 @@ int radius_track_entry_release(
        /*
         *      We're freeing a static ID, just go do that...
         */
-       if (te == &tt->id[te->id]) {
-               /*
-                *      This entry MAY be in a subtree.  If so, delete
-                *      it.
-                */
-               if (tt->subtree[te->id]) (void) fr_rb_delete(tt->subtree[te->id], te);
+       fr_assert(te == &tt->id[te->id]);
 
-               goto done;
-       }
-
-       /*
-        *      At this point, it MUST be talloc'd.
-        */
-       (void) talloc_get_type_abort(te, radius_track_entry_t);
-
-       /*
-        *      Delete it from the tracking subtree.
-        */
-       fr_assert(tt->subtree[te->id] != NULL);
-       (void) fr_rb_delete(tt->subtree[te->id], te);
-
-       /*
-        *      Try to free memory if the system gets idle.  If the
-        *      system is busy, we will try to keep entries in the
-        *      free list.  If the system becomes completely idle, we
-        *      will clear the free list.
-        */
-       if (fr_dlist_num_elements(&tt->free_list) > tt->num_requests) {
-               talloc_free(te);
-               *te_to_free = NULL;
-               return 0;
-       }
-
-       /*
-        *      Otherwise put it back on the free list.
-        */
-done:
        fr_dlist_insert_tail(&tt->free_list, te);
 
        *te_to_free = NULL;
@@ -292,15 +218,12 @@ done:
  */
 int radius_track_entry_update(radius_track_entry_t *te, uint8_t const *vector)
 {
+#ifndef NDEBUG
        radius_track_t *tt = te->tt;
+#endif
 
        fr_assert(tt);
 
-       /*
-        *      The authentication vector may have changed.
-        */
-       if (tt->subtree[te->id]) (void) fr_rb_delete(tt->subtree[te->id], te);
-
        memcpy(te->vector, vector, sizeof(te->vector));
 
        /*
@@ -309,20 +232,7 @@ int radius_track_entry_update(radius_track_entry_t *te, uint8_t const *vector)
         *
         *      @todo - gracefully handle fallback if the server screws up.
         */
-       if (!tt->use_authenticator) {
-               fr_assert(te == &tt->id[te->id]);
-               return 0;
-       }
-
-       /*
-        *      Insert it into the tree of authenticators
-        *
-        *      We do this even if it was allocated from the static
-        *      array.  That way if the server responds with
-        *      Original-Request-Authenticator, we can easily find it.
-        */
-       if (!fr_rb_insert(tt->subtree[te->id], te)) return -1;
-
+       fr_assert(te == &tt->id[te->id]);
        return 0;
 }
 
@@ -337,81 +247,40 @@ int radius_track_entry_update(radius_track_entry_t *te, uint8_t const *vector)
  */
 radius_track_entry_t *radius_track_entry_find(radius_track_t *tt, uint8_t packet_id, uint8_t const *vector)
 {
-       radius_track_entry_t my_te, *te;
+       radius_track_entry_t *te;
 
        (void) talloc_get_type_abort(tt, radius_track_t);
 
        /*
         *      Just use the static array.
         */
-       if (!tt->use_authenticator || !vector) {
-               te = &tt->id[packet_id];
-
-               /*
-                *      Not in use, die.
-                */
-               if (!te->request) return NULL;
-
-               /*
-                *      Ignore the Request Authenticator, as the
-                *      caller doesn't have it.
-                */
-               return te;
-       }
+       te = &tt->id[packet_id];
 
        /*
-        *      The entry MAY be in the subtree!
+        *      Not in use, die.
         */
-       memcpy(&my_te.vector, vector, sizeof(my_te.vector));
+       if (!te->request) return NULL;
 
-       te = fr_rb_find(tt->subtree[packet_id], &my_te);
+       if (!vector) return te;
 
        /*
-        *      Not found, the packet MAY have been allocated in the
-        *      old-style method prior to negotiation of
-        *      Original-Request-Identifier.
+        *      Protocol-Error and Original-Packet-Vector <sigh>
+        *
+        *      This should arguably have been Original-Packet-Code, but we are stupid.
+        *
+        *      @todo - Allow for multiple ID arrays, one for each packet code.  Or, just switch to using
+        *      src/protocols/radius/id.[ch].
         */
-       if (!te) {
-               te = &tt->id[packet_id];
-
-               /*
-                *      Not in use, die.
-                */
-               if (!te->request) return NULL;
-
-               // @todo - add a "generation" count for packets, so we can skip this after all outstanding packets
-               // are using the new method.  Hmm... probably just a timer "last sent packet with old-style"
-               // and then compare it to te->start
-
-               /*
-                *      We have the vector, so we need to check it.
-                */
-               if (memcmp(te->vector, vector, sizeof(te->vector)) != 0) {
-                       return NULL;
-               }
-
-               return te;
-       }
-
-       (void) talloc_get_type_abort(te, radius_track_entry_t);
-       fr_assert(te->request != NULL);
+       if (memcmp(te->vector, vector, sizeof(te->vector)) != 0) return NULL;
 
+       /*
+        *      Ignore the Request Authenticator, as the
+        *      caller doesn't have it.
+        */
        return te;
 }
 
 
-/** Use Request Authenticator (or not) as an Identifier
- *
- * @param tt           The radius_track_t tracking table
- * @param flag         Whether or not to use it.
- */
-void radius_track_use_authenticator(radius_track_t *tt, bool flag)
-{
-       (void) talloc_get_type_abort(tt, radius_track_t);
-
-       tt->use_authenticator = flag;
-}
-
 #ifndef NDEBUG
 /** Print out the state of every tracking entry
  *
index 0180ad7ce5a599c858b58fd40283babbde9a959c..327361129818344534d2a79e43ea8cd0ce916050 100644 (file)
@@ -42,7 +42,7 @@ struct radius_track_entry_s {
                                                ///< when its parent is freed.  We also zero
                                                ///< out the tracking entry field in the parent.
 
-       request_t               *request;               //!< as always...
+       request_t               *request;       //!< as always...
 
        void            *uctx;                  //!< Result/resumption context.
 
@@ -66,13 +66,8 @@ struct radius_track_s {
 
        fr_dlist_head_t free_list;              //!< so we allocate by least recently used
 
-       bool            use_authenticator;      //!< whether to use the request authenticator as an ID
-       int             next_id;                //!< next ID to allocate
-
        radius_track_entry_t    id[UINT8_MAX + 1];      //!< which ID was used
 
-       fr_rb_tree_t    *subtree[UINT8_MAX + 1];        //!< for Original-Request-Authenticator
-
 #ifndef NDEBUG
        uint64_t        operation;              //!< Incremented each alloc and de-alloc
 #endif
@@ -119,5 +114,3 @@ int                 radius_track_entry_update(radius_track_entry_t *te,
 
 radius_track_entry_t   *radius_track_entry_find(radius_track_t *tt, uint8_t packet_id,
                                                 uint8_t const *vector) CC_HINT(nonnull(1));
-
-void                   radius_track_use_authenticator(radius_track_t *te, bool flag) CC_HINT(nonnull);
diff --git a/src/modules/rlm_radius2/README.md b/src/modules/rlm_radius2/README.md
deleted file mode 100644 (file)
index 944923b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# rlm_radius
-## Metadata
-<dl>
-  <dt>category</dt><dd>io</dd>
-</dl>
-
-## Summary
-Allows Access-Requests, Accounting-Requests, CoA-Requests and Disconnect-Messages to be sent during request processing.
-
-This module can be used to implement proxying and request fan-out, as well as synchronous and asynchronous CoA and DM.
diff --git a/src/modules/rlm_radius2/all.mk b/src/modules/rlm_radius2/all.mk
deleted file mode 100644 (file)
index c8a7b8c..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-#  For now this is tracked in Git, but isn't part of the
-#  normal build.
-#
-ifneq "${WITH_RADIUS2}" ""
-TARGETNAME     := rlm_radius
-TARGET         := $(TARGETNAME)$(L)
-
-SOURCES                := rlm_radius.c track.c
-
-TGT_PREREQS    := libfreeradius-radius$(L) libfreeradius-bio-config$(L) libfreeradius-bio$(L)
-LOG_ID_LIB     = 39
-
-endif
diff --git a/src/modules/rlm_radius2/rlm_radius.c b/src/modules/rlm_radius2/rlm_radius.c
deleted file mode 100644 (file)
index 40d5f4d..0000000
+++ /dev/null
@@ -1,915 +0,0 @@
-/*
- *   This program is is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or (at
- *   your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/**
- * $Id$
- * @file rlm_radius.c
- * @brief A RADIUS client library.
- *
- * @copyright 2016 The FreeRADIUS server project
- * @copyright 2016 Network RADIUS SAS
- */
-RCSID("$Id$")
-
-#include <freeradius-devel/io/application.h>
-#include <freeradius-devel/server/modpriv.h>
-#include <freeradius-devel/unlang/xlat_func.h>
-#include <freeradius-devel/util/debug.h>
-#include <freeradius-devel/util/dlist.h>
-
-#include "rlm_radius.h"
-
-static int mode_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
-static int type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
-static int status_check_type_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
-static int status_check_update_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, conf_parser_t const *rule);
-
-static conf_parser_t const status_check_config[] = {
-       { FR_CONF_OFFSET_TYPE_FLAGS("type", FR_TYPE_VOID, 0, rlm_radius_t, status_check),
-         .func = status_check_type_parse },
-
-       CONF_PARSER_TERMINATOR
-};
-
-static conf_parser_t const status_check_update_config[] = {
-       { FR_CONF_OFFSET_TYPE_FLAGS("update", FR_TYPE_VOID, CONF_FLAG_SUBSECTION | CONF_FLAG_REQUIRED, rlm_radius_t, status_check_map),
-         .name2 = CF_IDENT_ANY,
-         .func = status_check_update_parse },
-       { FR_CONF_OFFSET("num_answers_to_alive", rlm_radius_t, num_answers_to_alive), .dflt = STRINGIFY(3) },
-
-       CONF_PARSER_TERMINATOR
-};
-
-/*
- *     Retransmission intervals for the packets we support.
- */
-static conf_parser_t auth_config[] = {
-       { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_ACCESS_REQUEST].irt), .dflt = STRINGIFY(2) },
-       { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrt), .dflt = STRINGIFY(16) },
-       { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrc), .dflt = STRINGIFY(5) },
-       { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrd), .dflt = STRINGIFY(30) },
-       CONF_PARSER_TERMINATOR
-};
-
-static conf_parser_t acct_config[] = {
-       { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].irt), .dflt = STRINGIFY(2) },
-       { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrt), .dflt = STRINGIFY(5) },
-       { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrc), .dflt = STRINGIFY(1) },
-       { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrd), .dflt = STRINGIFY(30) },
-       CONF_PARSER_TERMINATOR
-};
-
-static conf_parser_t status_config[] = {
-       { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_STATUS_SERVER].irt), .dflt = STRINGIFY(2) },
-       { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_STATUS_SERVER].mrt), .dflt = STRINGIFY(5) },
-       { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_STATUS_SERVER].mrc), .dflt = STRINGIFY(5) },
-       { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_STATUS_SERVER].mrd), .dflt = STRINGIFY(30) },
-       CONF_PARSER_TERMINATOR
-};
-
-static conf_parser_t coa_config[] = {
-       { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_COA_REQUEST].irt), .dflt = STRINGIFY(2) },
-       { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_COA_REQUEST].mrt), .dflt = STRINGIFY(16) },
-       { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_COA_REQUEST].mrc), .dflt = STRINGIFY(5) },
-       { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_COA_REQUEST].mrd), .dflt = STRINGIFY(30) },
-       CONF_PARSER_TERMINATOR
-};
-
-static conf_parser_t disconnect_config[] = {
-       { FR_CONF_OFFSET("initial_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].irt), .dflt = STRINGIFY(2) },
-       { FR_CONF_OFFSET("max_rtx_time", rlm_radius_t, retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrt), .dflt = STRINGIFY(16) },
-       { FR_CONF_OFFSET("max_rtx_count", rlm_radius_t, retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrc), .dflt = STRINGIFY(5) },
-       { FR_CONF_OFFSET("max_rtx_duration", rlm_radius_t, retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrd), .dflt = STRINGIFY(30) },
-       CONF_PARSER_TERMINATOR
-};
-
-static conf_parser_t const transport_config[] = {
-       { FR_CONF_OFFSET_FLAGS("secret", CONF_FLAG_REQUIRED, rlm_radius_t, secret) },
-
-       CONF_PARSER_TERMINATOR
-};
-
-/*
- *     We only parse the pool options if we're connected.
- */
-static conf_parser_t const connected_config[] = {
-       { FR_CONF_POINTER("status_check", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) status_check_config },
-
-       { FR_CONF_OFFSET_SUBSECTION("pool", 0, rlm_radius_t, trunk_conf, trunk_config ) },
-
-       { FR_CONF_POINTER("udp", 0, CONF_FLAG_SUBSECTION | CONF_FLAG_OPTIONAL, NULL), .subcs = (void const *) transport_config },
-
-       { FR_CONF_POINTER("tcp", 0, CONF_FLAG_SUBSECTION | CONF_FLAG_OPTIONAL, NULL), .subcs = (void const *) transport_config },
-
-       CONF_PARSER_TERMINATOR
-};
-
-/*
- *     A mapping of configuration file names to internal variables.
- */
-static conf_parser_t const module_config[] = {
-       { FR_CONF_OFFSET_FLAGS("mode", CONF_FLAG_REQUIRED, rlm_radius_t, mode), .func = mode_parse, .dflt = "proxy" },
-
-       { FR_CONF_OFFSET_REF(rlm_radius_t, fd_config, fr_bio_fd_client_config) },
-
-       { FR_CONF_OFFSET_FLAGS("type", CONF_FLAG_NOT_EMPTY | CONF_FLAG_MULTI | CONF_FLAG_REQUIRED, rlm_radius_t, types),
-         .func = type_parse },
-
-       { FR_CONF_OFFSET_FLAGS("replicate", CONF_FLAG_DEPRECATED, rlm_radius_t, replicate) },
-
-       { FR_CONF_OFFSET_FLAGS("synchronous", CONF_FLAG_DEPRECATED, rlm_radius_t, synchronous) },
-
-       { FR_CONF_OFFSET_FLAGS("originate", CONF_FLAG_DEPRECATED, rlm_radius_t, originate) },
-
-       { FR_CONF_OFFSET("max_packet_size", rlm_radius_t, max_packet_size), .dflt = "4096" },
-       { FR_CONF_OFFSET("max_send_coalesce", rlm_radius_t, max_send_coalesce), .dflt = "1024" },
-
-       { FR_CONF_OFFSET("max_attributes", rlm_radius_t, max_attributes), .dflt = STRINGIFY(RADIUS_MAX_ATTRIBUTES) },
-
-       { FR_CONF_OFFSET("require_message_authenticator", rlm_radius_t, require_message_authenticator),
-         .func = cf_table_parse_int,
-         .uctx = &(cf_table_parse_ctx_t){ .table = fr_radius_require_ma_table, .len = &fr_radius_require_ma_table_len },
-         .dflt = "no" },
-
-       { FR_CONF_OFFSET("response_window", rlm_radius_t, response_window), .dflt = STRINGIFY(20) },
-
-       { FR_CONF_OFFSET("zombie_period", rlm_radius_t, zombie_period), .dflt = STRINGIFY(40) },
-
-       { FR_CONF_OFFSET("revive_interval", rlm_radius_t, revive_interval) },
-
-       CONF_PARSER_TERMINATOR
-};
-
-static conf_parser_t const type_interval_config[FR_RADIUS_CODE_MAX] = {
-       [FR_RADIUS_CODE_ACCESS_REQUEST] = { FR_CONF_POINTER("Access-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) auth_config },
-
-       [FR_RADIUS_CODE_ACCOUNTING_REQUEST] = { FR_CONF_POINTER("Accounting-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) acct_config },
-       [FR_RADIUS_CODE_STATUS_SERVER] = { FR_CONF_POINTER("Status-Server", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) status_config },
-       [FR_RADIUS_CODE_COA_REQUEST] = { FR_CONF_POINTER("CoA-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) coa_config },
-       [FR_RADIUS_CODE_DISCONNECT_REQUEST] = { FR_CONF_POINTER("Disconnect-Request", 0, CONF_FLAG_SUBSECTION, NULL), .subcs = (void const *) disconnect_config },
-};
-
-static fr_dict_t const *dict_radius;
-
-extern fr_dict_autoload_t rlm_radius_dict[];
-fr_dict_autoload_t rlm_radius_dict[] = {
-       { .out = &dict_radius, .proto = "radius" },
-       { NULL }
-};
-
-static fr_dict_attr_t const *attr_chap_challenge;
-static fr_dict_attr_t const *attr_chap_password;
-static fr_dict_attr_t const *attr_packet_type;
-static fr_dict_attr_t const *attr_proxy_state;
-
-static fr_dict_attr_t const *attr_error_cause;
-static fr_dict_attr_t const *attr_event_timestamp;
-static fr_dict_attr_t const *attr_extended_attribute_1;
-static fr_dict_attr_t const *attr_message_authenticator;
-static fr_dict_attr_t const *attr_eap_message;
-static fr_dict_attr_t const *attr_nas_identifier;
-static fr_dict_attr_t const *attr_original_packet_code;
-static fr_dict_attr_t const *attr_response_length;
-static fr_dict_attr_t const *attr_user_password;
-
-extern fr_dict_attr_autoload_t rlm_radius_dict_attr[];
-fr_dict_attr_autoload_t rlm_radius_dict_attr[] = {
-       { .out = &attr_chap_challenge, .name = "CHAP-Challenge", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
-       { .out = &attr_chap_password, .name = "CHAP-Password", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
-       { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
-       { .out = &attr_proxy_state, .name = "Proxy-State", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
-
-       { .out = &attr_error_cause, .name = "Error-Cause", .type = FR_TYPE_UINT32, .dict = &dict_radius },
-       { .out = &attr_event_timestamp, .name = "Event-Timestamp", .type = FR_TYPE_DATE, .dict = &dict_radius},
-       { .out = &attr_extended_attribute_1, .name = "Extended-Attribute-1", .type = FR_TYPE_TLV, .dict = &dict_radius},
-       { .out = &attr_message_authenticator, .name = "Message-Authenticator", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
-       { .out = &attr_eap_message, .name = "EAP-Message", .type = FR_TYPE_OCTETS, .dict = &dict_radius},
-       { .out = &attr_nas_identifier, .name = "NAS-Identifier", .type = FR_TYPE_STRING, .dict = &dict_radius},
-       { .out = &attr_original_packet_code, .name = "Extended-Attribute-1.Original-Packet-Code", .type = FR_TYPE_UINT32, .dict = &dict_radius},
-       { .out = &attr_response_length, .name = "Extended-Attribute-1.Response-Length", .type = FR_TYPE_UINT32, .dict = &dict_radius },
-       { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius},
-
-       { NULL }
-};
-
-#include "bio.c"
-
-static fr_table_num_sorted_t mode_names[] = {
-       { L("client"),          RLM_RADIUS_MODE_CLIENT          },
-       { L("proxy"),           RLM_RADIUS_MODE_PROXY           },
-       { L("replicate"),       RLM_RADIUS_MODE_REPLICATE       },
-       { L("unconnected-replicate"),   RLM_RADIUS_MODE_UNCONNECTED_REPLICATE   },
-//     { L("unconnected-proxy"),       RLM_RADIUS_MODE_UNCONNECTED_PROXY       },
-};
-static size_t mode_names_len = NUM_ELEMENTS(mode_names);
-
-
-/** Set the mode of operation
- *
- * @param[in] ctx      to allocate data in (instance of rlm_radius).
- * @param[out] out     Where to write the parsed data.
- * @param[in] parent   Base structure address.
- * @param[in] ci       #CONF_PAIR specifying the name of the type module.
- * @param[in] rule     unused.
- * @return
- *     - 0 on success.
- *     - -1 on failure.
- */
-static int mode_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent,
-                     CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
-{
-       char const              *name = cf_pair_value(cf_item_to_pair(ci));
-       rlm_radius_mode_t       mode;
-       rlm_radius_t            *inst = talloc_get_type_abort(parent, rlm_radius_t);
-
-       mode = fr_table_value_by_str(mode_names, name, RLM_RADIUS_MODE_INVALID);
-
-#if 0
-       /*
-        *      Commented out until we upgrade the old configurations.
-        */
-       if (mode == RLM_RADIUS_MODE_INVALID) {
-               cf_log_err(ci, "Invalid mode name \"%s\"", name);
-               return -1;
-       }
-#endif
-
-       *(rlm_radius_mode_t *) out = mode;
-
-       /*
-        *      Normally we want connected sockets, in which case we push additional configuration for connected sockets.
-        */
-       if ((mode != RLM_RADIUS_MODE_UNCONNECTED_REPLICATE) &&
-           (mode != RLM_RADIUS_MODE_UNCONNECTED_PROXY)) {
-               CONF_SECTION *cs = cf_item_to_section(cf_parent(ci));
-
-               inst->fd_config.type = FR_BIO_FD_CONNECTED;
-
-               if (cf_section_rules_push(cs, connected_config) < 0) return -1;
-
-       } else {
-               inst->fd_config.type = FR_BIO_FD_UNCONNECTED;
-       }
-
-       return 0;
-}
-
-
-/** Set which types of packets we can parse
- *
- * @param[in] ctx      to allocate data in (instance of rlm_radius).
- * @param[out] out     Where to write the parsed data.
- * @param[in] parent   Base structure address.
- * @param[in] ci       #CONF_PAIR specifying the name of the type module.
- * @param[in] rule     unused.
- * @return
- *     - 0 on success.
- *     - -1 on failure.
- */
-static int type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
-                     CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
-{
-       char const              *type_str = cf_pair_value(cf_item_to_pair(ci));
-       CONF_SECTION            *cs = cf_item_to_section(cf_parent(ci));
-       fr_dict_enum_value_t const      *type_enum;
-       uint32_t                code;
-
-       /*
-        *      Must be the RADIUS module
-        */
-       fr_assert(cs && (strcmp(cf_section_name1(cs), "radius") == 0));
-
-       /*
-        *      Allow the process module to be specified by
-        *      packet type.
-        */
-       type_enum = fr_dict_enum_by_name(attr_packet_type, type_str, -1);
-       if (!type_enum) {
-       invalid_code:
-               cf_log_err(ci, "Unknown or invalid RADIUS packet type '%s'", type_str);
-               return -1;
-       }
-
-       code = type_enum->value->vb_uint32;
-
-       /*
-        *      Status-Server packets cannot be proxied.
-        */
-       if (code == FR_RADIUS_CODE_STATUS_SERVER) {
-               cf_log_err(ci, "Invalid setting of 'type = Status-Server'.  Status-Server packets cannot be proxied.");
-               return -1;
-       }
-
-       if (!code ||
-           (code >= FR_RADIUS_CODE_MAX) ||
-           (!type_interval_config[code].name1)) goto invalid_code;
-
-       /*
-        *      If we're doing async proxying, push the timers for the
-        *      various packet types.
-        */
-       cf_section_rule_push(cs, &type_interval_config[code]);
-
-       *(uint32_t *) out = code;
-
-       return 0;
-}
-
-/** Allow for Status-Server ping checks
- *
- * @param[in] ctx      to allocate data in (instance of proto_radius).
- * @param[out] out     Where to write our parsed data.
- * @param[in] parent   Base structure address.
- * @param[in] ci       #CONF_PAIR specifying the name of the type module.
- * @param[in] rule     unused.
- * @return
- *     - 0 on success.
- *     - -1 on failure.
- */
-static int status_check_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent,
-                                  CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
-{
-       char const              *type_str = cf_pair_value(cf_item_to_pair(ci));
-       CONF_SECTION            *cs = cf_item_to_section(cf_parent(ci));
-       fr_dict_enum_value_t const      *type_enum;
-       uint32_t                code;
-
-       /*
-        *      Allow the process module to be specified by
-        *      packet type.
-        */
-       type_enum = fr_dict_enum_by_name(attr_packet_type, type_str, -1);
-       if (!type_enum) {
-       invalid_code:
-               cf_log_err(ci, "Unknown or invalid RADIUS packet type '%s'", type_str);
-               return -1;
-       }
-
-       code = type_enum->value->vb_uint32;
-
-       /*
-        *      Cheat, and reuse the "type" array for allowed packet
-        *      types.
-        */
-       if (!code ||
-           (code >= FR_RADIUS_CODE_MAX) ||
-           (!type_interval_config[code].name1)) goto invalid_code;
-
-       /*
-        *      Add irt / mrt / mrd / mrc parsing, in the parent
-        *      configuration section.
-        */
-       cf_section_rule_push(cf_item_to_section(cf_parent(cs)), &type_interval_config[code]);
-
-       memcpy(out, &code, sizeof(code));
-
-       /*
-        *      Nothing more to do here, so we stop.
-        */
-       if (code == FR_RADIUS_CODE_STATUS_SERVER) return 0;
-
-       cf_section_rule_push(cs, status_check_update_config);
-
-       return 0;
-}
-
-/** Allow the admin to set packet contents for Status-Server ping checks
- *
- * @param[in] ctx      to allocate data in (instance of proto_radius).
- * @param[out] out     Where to write our parsed data
- * @param[in] parent   Base structure address.
- * @param[in] ci       #CONF_SECTION specifying the things to update
- * @param[in] rule     unused.
- * @return
- *     - 0 on success.
- *     - -1 on failure.
- */
-static int status_check_update_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent,
-                                    CONF_ITEM *ci, UNUSED conf_parser_t const *rule)
-{
-       int                     rcode;
-       CONF_SECTION            *cs;
-       char const              *name2;
-       map_list_t              *head = (map_list_t *)out;
-
-       fr_assert(cf_item_is_section(ci));
-       map_list_init(head);
-
-       cs = cf_item_to_section(ci);
-       name2 = cf_section_name2(cs);
-       if (!name2 || (strcmp(name2, "request") != 0)) {
-               cf_log_err(cs, "You must specify 'request' as the destination list");
-               return -1;
-       }
-
-       /*
-        *      Compile the "update" section.
-        */
-       {
-               tmpl_rules_t    parse_rules = {
-                       .attr = {
-                               .dict_def = dict_radius,
-                       }
-               };
-
-               rcode = map_afrom_cs(ctx, head, cs, &parse_rules, &parse_rules, unlang_fixup_update, NULL, 128);
-               if (rcode < 0) return -1; /* message already printed */
-               if (map_list_empty(head)) {
-                       cf_log_err(cs, "'update' sections cannot be empty");
-                       return -1;
-               }
-       }
-
-       /*
-        *      Rely on "bootstrap" to do sanity checks between 'type
-        *      = Access-Request', and 'update' containing passwords.
-        */
-       return 0;
-}
-
-
-/** Do any RADIUS-layer fixups for proxying.
- *
- */
-static void radius_fixups(rlm_radius_t const *inst, request_t *request)
-{
-       fr_pair_t *vp;
-
-       /*
-        *      Check for proxy loops.
-        */
-       if ((inst->mode == RLM_RADIUS_MODE_PROXY) && RDEBUG_ENABLED) {
-               fr_dcursor_t cursor;
-
-               for (vp = fr_pair_dcursor_by_da_init(&cursor, &request->request_pairs, attr_proxy_state);
-                    vp;
-                    vp = fr_dcursor_next(&cursor)) {
-                       if (vp->vp_length != 4) continue;
-
-                       if (memcmp(&inst->common_ctx.proxy_state, vp->vp_octets, 4) == 0) {
-                               RWARN("Possible proxy loop - please check server configuration.");
-                               break;
-                       }
-               }
-       }
-
-       /*
-        *      @todo - check for proxy loops for client && replicate, too.
-        *
-        *      This only catches "self loops", but it may be worth doing.
-        */
-
-       if (request->packet->code != FR_RADIUS_CODE_ACCESS_REQUEST) return;
-
-       if (fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_password) &&
-           !fr_pair_find_by_da(&request->request_pairs, NULL, attr_chap_challenge)) {
-               MEM(pair_append_request(&vp, attr_chap_challenge) >= 0);
-               fr_pair_value_memdup(vp, request->packet->vector, sizeof(request->packet->vector), true);
-       }
-}
-
-
-/** Send packets outbound.
- *
- */
-static unlang_action_t CC_HINT(nonnull) mod_process(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
-{
-       rlm_radius_t const      *inst = talloc_get_type_abort_const(mctx->mi->data, rlm_radius_t);
-       rlm_rcode_t             rcode;
-       fr_client_t             *client;
-
-       if (!request->packet->code) {
-               REDEBUG("You MUST specify a packet code");
-               RETURN_MODULE_FAIL;
-       }
-
-       /*
-        *      Reserve Status-Server for ourselves, for link-specific
-        *      signaling.
-        */
-       if (request->packet->code == FR_RADIUS_CODE_STATUS_SERVER) {
-               REDEBUG("Cannot proxy Status-Server packets");
-               RETURN_MODULE_FAIL;
-       }
-
-       if ((request->packet->code >= FR_RADIUS_CODE_MAX) ||
-           !fr_time_delta_ispos(inst->retry[request->packet->code].irt)) { /* can't be zero */
-               REDEBUG("Invalid packet code %u", request->packet->code);
-               RETURN_MODULE_FAIL;
-       }
-
-       /*
-        *      Unconnected sockets use %radius.replicate(ip, port, secret),
-        *      or %radius.sendto(ip, port, secret)
-        */
-       if ((inst->mode == RLM_RADIUS_MODE_UNCONNECTED_REPLICATE) ||
-           (inst->mode == RLM_RADIUS_MODE_UNCONNECTED_PROXY)) {
-               REDEBUG("When using 'mode = unconnected-*', this module cannot be used in-place.  Instead, it must be called via a function call");
-               RETURN_MODULE_FAIL;
-       }
-
-       if (!inst->allowed[request->packet->code]) {
-               REDEBUG("Packet code %s is disallowed by the configuration",
-                      fr_radius_packet_name[request->packet->code]);
-               RETURN_MODULE_FAIL;
-       }
-
-       client = client_from_request(request);
-       if (client && client->dynamic && !client->active) {
-               REDEBUG("Cannot proxy packets which define dynamic clients");
-               RETURN_MODULE_FAIL;
-       }
-
-       /*
-        *      Do any necessary RADIUS level fixups
-        *      - check Proxy-State
-        *      - do CHAP-Challenge fixups
-        */
-       radius_fixups(inst, request);
-
-       /*
-        *      Push the request and it's data to the IO submodule.
-        *
-        *      This may return YIELD, for "please yield", or it may
-        *      return another code which indicates what happened to
-        *      the request...
-        */
-       return mod_enqueue(&rcode, inst,
-                          module_thread(mctx->mi)->data, request);
-}
-
-
-static int mod_instantiate(module_inst_ctx_t const *mctx)
-{
-       size_t i, num_types;
-       rlm_radius_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
-       CONF_SECTION *conf = mctx->mi->conf;
-
-       inst->name = mctx->mi->name;
-       inst->received_message_authenticator = talloc_zero(NULL, bool);         /* Allocated outside of inst to default protection */
-
-       /*
-        *      Allow explicit setting of mode.
-        */
-       if (inst->mode != RLM_RADIUS_MODE_INVALID) goto check_others;
-
-       /*
-        *      If not set, try to insinuate it from context.
-        */
-       if (inst->replicate) {
-               if (inst->originate) {
-                       cf_log_err(conf, "Cannot set 'replicate=true' and 'originate=true' at the same time.");
-                       return -1;
-               }
-
-               if (inst->synchronous) {
-                       cf_log_warn(conf, "Ignoring 'synchronous=true' due to 'replicate=true'");
-               }
-
-               inst->mode = RLM_RADIUS_MODE_REPLICATE;
-               goto check_others;
-       }
-
-       /*
-        *      Argubly we should be allowed to do synchronous proxying _and_ originating client packets.
-        *
-        *      However, the previous code didn't really do that consistently.
-        */
-       if (inst->synchronous && inst->originate) {
-               cf_log_err(conf, "Cannot set 'synchronous=true' and 'originate=true'");
-               return -1;
-       }
-
-       if (inst->synchronous) {
-               inst->mode = RLM_RADIUS_MODE_PROXY;
-       } else {
-               inst->mode = RLM_RADIUS_MODE_CLIENT;
-       }
-
-check_others:
-       /*
-        *      Replication is write-only, and append by default.
-        */
-       if (inst->mode == RLM_RADIUS_MODE_REPLICATE) {
-               if (inst->fd_config.filename && (inst->fd_config.flags != O_WRONLY)) {
-                       cf_log_info(conf, "Setting 'flags = write-only' for writing to a file");
-               }
-               inst->fd_config.flags = O_WRONLY | O_APPEND;
-
-       } else if (inst->fd_config.filename) {
-               cf_log_err(conf, "When using an output 'filename', you MUST set 'mode = replicate'");
-               return -1;
-
-       } else {
-               /*
-                *      All other IO is read+write.
-                */
-               inst->fd_config.flags = O_RDWR;
-       }
-
-       if (fr_bio_fd_check_config(&inst->fd_config) < 0) {
-               cf_log_perr(conf, "Invalid configuration");
-               return -1;
-       }
-
-       /*
-        *      Clamp max_packet_size first before checking recv_buff and send_buff
-        */
-       FR_INTEGER_BOUND_CHECK("max_packet_size", inst->max_packet_size, >=, 64);
-       FR_INTEGER_BOUND_CHECK("max_packet_size", inst->max_packet_size, <=, 65535);
-
-       if ((inst->mode != RLM_RADIUS_MODE_UNCONNECTED_REPLICATE) &&
-           (inst->mode != RLM_RADIUS_MODE_UNCONNECTED_PROXY)) {
-               /*
-                *      These limits are specific to RADIUS, and cannot be over-ridden
-                */
-               FR_INTEGER_BOUND_CHECK("trunk.per_connection_max", inst->trunk_conf.max_req_per_conn, >=, 2);
-               FR_INTEGER_BOUND_CHECK("trunk.per_connection_max", inst->trunk_conf.max_req_per_conn, <=, 255);
-               FR_INTEGER_BOUND_CHECK("trunk.per_connection_target", inst->trunk_conf.target_req_per_conn, <=, inst->trunk_conf.max_req_per_conn / 2);
-       } else {
-               if (inst->fd_config.src_port != 0) {
-                       cf_log_err(conf, "Cannot set 'src_port' when using 'mode = unconnected'");
-                       return -1;
-               }
-       }
-
-       FR_TIME_DELTA_BOUND_CHECK("response_window", inst->zombie_period, >=, fr_time_delta_from_sec(1));
-       FR_TIME_DELTA_BOUND_CHECK("response_window", inst->zombie_period, <=, fr_time_delta_from_sec(120));
-
-       FR_TIME_DELTA_BOUND_CHECK("zombie_period", inst->zombie_period, >=, fr_time_delta_from_sec(1));
-       FR_TIME_DELTA_BOUND_CHECK("zombie_period", inst->zombie_period, <=, fr_time_delta_from_sec(120));
-
-       if (!inst->status_check) {
-               FR_TIME_DELTA_BOUND_CHECK("revive_interval", inst->revive_interval, >=, fr_time_delta_from_sec(10));
-               FR_TIME_DELTA_BOUND_CHECK("revive_interval", inst->revive_interval, <=, fr_time_delta_from_sec(3600));
-       }
-
-       num_types = talloc_array_length(inst->types);
-       fr_assert(num_types > 0);
-
-       inst->timeout_retry = (fr_retry_config_t) {
-               .mrc = 1,
-               .mrd = inst->response_window,
-       };
-
-       inst->common_ctx = (fr_radius_ctx_t) {
-               .secret = inst->secret,
-               .secret_length = inst->secret ? talloc_array_length(inst->secret) - 1 : 0,
-               .proxy_state = fr_rand(),
-       };
-
-       /*
-        *      Allow for O(1) lookup later...
-        */
-       for (i = 0; i < num_types; i++) {
-               uint32_t code;
-
-               code = inst->types[i];
-               fr_assert(code > 0);
-               fr_assert(code < FR_RADIUS_CODE_MAX);
-
-               inst->allowed[code] = true;
-       }
-
-       fr_assert(inst->status_check < FR_RADIUS_CODE_MAX);
-
-       /*
-        *      If we're replicating, we don't care if the other end
-        *      is alive.
-        */
-       if (inst->status_check) {
-               if (inst->mode == RLM_RADIUS_MODE_REPLICATE) {
-                       cf_log_warn(conf, "Ignoring 'status_check = %s' due to 'mode = replicate'",
-                                   fr_radius_packet_name[inst->status_check]);
-                       inst->status_check = false;
-
-               } else if ((inst->mode == RLM_RADIUS_MODE_UNCONNECTED_REPLICATE) ||
-                          (inst->mode == RLM_RADIUS_MODE_UNCONNECTED_PROXY)) {
-                                  cf_log_warn(conf, "Ignoring 'status_check = %s' due to 'mode = unconnected-*'",
-                                   fr_radius_packet_name[inst->status_check]);
-                       inst->status_check = false;
-               }
-       }
-
-       /*
-        *      If we have status checks, then do some sanity checks.
-        *      Status-Server is always allowed.  Otherwise, the
-        *      status checks have to match one of the allowed
-        *      packets.
-        */
-       if (inst->status_check) {
-               if (inst->status_check == FR_RADIUS_CODE_STATUS_SERVER) {
-                       inst->allowed[inst->status_check] = true;
-
-               } else if (!inst->allowed[inst->status_check]) {
-                       cf_log_err(conf, "Using 'status_check = %s' requires also 'type = %s'",
-                                  fr_radius_packet_name[inst->status_check], fr_radius_packet_name[inst->status_check]);
-                       return -1;
-               }
-
-               /*
-                *      @todo - check the contents of the "update"
-                *      section, to be sure that (e.g.) Access-Request
-                *      contains User-Name, etc.
-                */
-
-               if (inst->fd_config.filename) {
-                       cf_log_info(conf, "Disabling status checks for output file %s", inst->fd_config.filename);
-                       inst->status_check = 0;
-               }
-       }
-
-       /*
-        *      Files and unix sockets can just have us call write().
-        */
-       if (inst->fd_config.filename || inst->fd_config.path) {
-               inst->max_send_coalesce = 1;
-       }
-
-       inst->trunk_conf.req_pool_headers = 4;  /* One for the request, one for the buffer, one for the tracking binding, one for Proxy-State VP */
-       inst->trunk_conf.req_pool_size = 1024 + sizeof(fr_pair_t) + 20;
-
-       /*
-        *      Only check the async timers when we're acting as a client.
-        */
-       if (inst->mode != RLM_RADIUS_MODE_CLIENT) {
-               return 0;
-       }
-
-       /*
-        *      Set limits on retransmission timers
-        */
-       if (inst->allowed[FR_RADIUS_CODE_ACCESS_REQUEST]) {
-               FR_TIME_DELTA_BOUND_CHECK("Access-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].irt, >=, fr_time_delta_from_sec(1));
-               FR_TIME_DELTA_BOUND_CHECK("Access-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrt, >=, fr_time_delta_from_sec(5));
-               FR_INTEGER_BOUND_CHECK("Access-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrc, >=, 1);
-               FR_TIME_DELTA_BOUND_CHECK("Access-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrd, >=, fr_time_delta_from_sec(5));
-
-               FR_TIME_DELTA_BOUND_CHECK("Access-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].irt, <=, fr_time_delta_from_sec(3));
-               FR_TIME_DELTA_BOUND_CHECK("Access-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrt, <=, fr_time_delta_from_sec(30));
-               FR_INTEGER_BOUND_CHECK("Access-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrc, <=, 10);
-               FR_TIME_DELTA_BOUND_CHECK("Access-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_ACCESS_REQUEST].mrd, <=, fr_time_delta_from_sec(30));
-       }
-
-       /*
-        *      Note that RFC 5080 allows for Accounting-Request to
-        *      have mrt=mrc=mrd = 0, which means "retransmit
-        *      forever".  We allow that, with the restriction that
-        *      the server core will automatically free the request at
-        *      max_request_time.
-        */
-       if (inst->allowed[FR_RADIUS_CODE_ACCOUNTING_REQUEST]) {
-               FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].irt, >=, fr_time_delta_from_sec(1));
-#if 0
-               FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrt, >=, fr_time_delta_from_sec(5));
-               FR_INTEGER_BOUND_CHECK("Accounting-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrc, >=, 0);
-               FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrd, >=, fr_time_delta_from_sec(0));
-#endif
-
-               FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].irt, <=, fr_time_delta_from_sec(3));
-               FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrt, <=, fr_time_delta_from_sec(30));
-               FR_INTEGER_BOUND_CHECK("Accounting-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrc, <=, 10);
-               FR_TIME_DELTA_BOUND_CHECK("Accounting-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_ACCOUNTING_REQUEST].mrd, <=, fr_time_delta_from_sec(30));
-       }
-
-       /*
-        *      Status-Server
-        */
-       if (inst->allowed[FR_RADIUS_CODE_STATUS_SERVER]) {
-               FR_TIME_DELTA_BOUND_CHECK("Status-Server.initial_rtx_time", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].irt, >=, fr_time_delta_from_sec(1));
-               FR_TIME_DELTA_BOUND_CHECK("Status-Server.max_rtx_time", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrt, >=, fr_time_delta_from_sec(5));
-               FR_INTEGER_BOUND_CHECK("Status-Server.max_rtx_count", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrc, >=, 1);
-               FR_TIME_DELTA_BOUND_CHECK("Status-Server.max_rtx_duration", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrd, >=, fr_time_delta_from_sec(5));
-
-               FR_TIME_DELTA_BOUND_CHECK("Status-Server.initial_rtx_time", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].irt, <=, fr_time_delta_from_sec(3));
-               FR_TIME_DELTA_BOUND_CHECK("Status-Server.max_rtx_time", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrt, <=, fr_time_delta_from_sec(30));
-               FR_INTEGER_BOUND_CHECK("Status-Server.max_rtx_count", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrc, <=, 10);
-               FR_TIME_DELTA_BOUND_CHECK("Status-Server.max_rtx_duration", inst->retry[FR_RADIUS_CODE_STATUS_SERVER].mrd, <=, fr_time_delta_from_sec(30));
-       }
-
-       /*
-        *      CoA
-        */
-       if (inst->allowed[FR_RADIUS_CODE_COA_REQUEST]) {
-               FR_TIME_DELTA_BOUND_CHECK("CoA-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_COA_REQUEST].irt, >=, fr_time_delta_from_sec(1));
-               FR_TIME_DELTA_BOUND_CHECK("CoA-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrt, >=, fr_time_delta_from_sec(5));
-               FR_INTEGER_BOUND_CHECK("CoA-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrc, >=, 1);
-               FR_TIME_DELTA_BOUND_CHECK("CoA-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrd, >=, fr_time_delta_from_sec(5));
-
-               FR_TIME_DELTA_BOUND_CHECK("CoA-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_COA_REQUEST].irt, <=, fr_time_delta_from_sec(3));
-               FR_TIME_DELTA_BOUND_CHECK("CoA-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrt, <=, fr_time_delta_from_sec(60));
-               FR_INTEGER_BOUND_CHECK("CoA-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrc, <=, 10);
-               FR_TIME_DELTA_BOUND_CHECK("CoA-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_COA_REQUEST].mrd, <=, fr_time_delta_from_sec(30));
-       }
-
-       /*
-        *      Disconnect
-        */
-       if (inst->allowed[FR_RADIUS_CODE_DISCONNECT_REQUEST]) {
-               FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].irt, >=, fr_time_delta_from_sec(1));
-               FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrt, >=, fr_time_delta_from_sec(5));
-               FR_INTEGER_BOUND_CHECK("Disconnect-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrc, >=, 1);
-               FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrd, >=, fr_time_delta_from_sec(5));
-
-               FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.initial_rtx_time", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].irt, <=, fr_time_delta_from_sec(3));
-               FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.max_rtx_time", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrt, <=, fr_time_delta_from_sec(30));
-               FR_INTEGER_BOUND_CHECK("Disconnect-Request.max_rtx_count", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrc, <=, 10);
-               FR_TIME_DELTA_BOUND_CHECK("Disconnect-Request.max_rtx_duration", inst->retry[FR_RADIUS_CODE_DISCONNECT_REQUEST].mrd, <=, fr_time_delta_from_sec(30));
-       }
-
-       return 0;
-}
-
-static int mod_bootstrap(module_inst_ctx_t const *mctx)
-{
-       xlat_t          *xlat;
-       rlm_radius_t const *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
-
-       switch (inst->mode) {
-       case RLM_RADIUS_MODE_UNCONNECTED_REPLICATE:
-               xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "sendto.ipaddr", xlat_radius_replicate, FR_TYPE_VOID);
-               xlat_func_args_set(xlat, xlat_radius_send_args);
-               break;
-
-       case RLM_RADIUS_MODE_UNCONNECTED_PROXY:
-               fr_assert(0);   /* not implemented */
-               break;
-
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-
-static int mod_detach(module_detach_ctx_t const *mctx)
-{
-       rlm_radius_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_radius_t);
-
-       talloc_free(inst->received_message_authenticator);
-       return 0;
-}
-
-static int mod_load(void)
-{
-       if (fr_radius_global_init() < 0) {
-               PERROR("Failed initialising protocol library");
-               return -1;
-       }
-       return 0;
-}
-
-static void mod_unload(void)
-{
-       fr_radius_global_free();
-}
-
-/*
- *     The module name should be the only globally exported symbol.
- *     That is, everything else should be 'static'.
- *
- *     If the module needs to temporarily modify it's instantiation
- *     data, the type should be changed to MODULE_TYPE_THREAD_UNSAFE.
- *     The server will then take care of ensuring that the module
- *     is single-threaded.
- */
-extern module_rlm_t rlm_radius;
-module_rlm_t rlm_radius = {
-       .common = {
-               .magic          = MODULE_MAGIC_INIT,
-               .name           = "radius",
-               .inst_size      = sizeof(rlm_radius_t),
-               .config         = module_config,
-
-               .onload         = mod_load,
-               .unload         = mod_unload,
-
-               .bootstrap      = mod_bootstrap,
-               .instantiate    = mod_instantiate,
-               .detach         = mod_detach,
-
-               .thread_inst_size       = sizeof(bio_thread_t),
-               .thread_inst_type       = "bio_thread_t",
-               .thread_instantiate     = mod_thread_instantiate,
-       },
-       .method_group = {
-               .bindings = (module_method_binding_t[]){
-                       { .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_process },
-                       MODULE_BINDING_TERMINATOR
-               },
-       }
-};
diff --git a/src/modules/rlm_radius2/rlm_radius.h b/src/modules/rlm_radius2/rlm_radius.h
deleted file mode 100644 (file)
index 1369763..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#pragma once
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-#include <freeradius-devel/io/atomic_queue.h>
-#include <freeradius-devel/server/base.h>
-#include <freeradius-devel/server/map.h>
-#include <freeradius-devel/server/module_rlm.h>
-#include <freeradius-devel/server/trunk.h>
-#include <freeradius-devel/util/dlist.h>
-#include <freeradius-devel/util/retry.h>
-#include <freeradius-devel/unlang/module.h>
-#include <freeradius-devel/radius/radius.h>
-#include <freeradius-devel/radius/bio.h>
-
-#include <freeradius-devel/bio/fd.h>
-
-/*
- * $Id$
- *
- * @file rlm_radius.h
- * @brief Structures for the RADIUS client packets
- *
- * @copyright 2017 Alan DeKok (aland@freeradius.org)
- */
-
-typedef struct rlm_radius_s rlm_radius_t;
-
-typedef enum {
-       RLM_RADIUS_MODE_INVALID = 0,
-       RLM_RADIUS_MODE_PROXY,
-       RLM_RADIUS_MODE_CLIENT,
-       RLM_RADIUS_MODE_REPLICATE,
-       RLM_RADIUS_MODE_UNCONNECTED_REPLICATE,
-       RLM_RADIUS_MODE_UNCONNECTED_PROXY,
-} rlm_radius_mode_t;
-
-/*
- *     Define a structure for our module configuration.
- */
-struct rlm_radius_s {
-       fr_bio_fd_config_t      fd_config;              //!< for now MUST be at the start!
-
-       char const              *name;
-
-       fr_time_delta_t         response_window;
-       fr_time_delta_t         zombie_period;
-       fr_time_delta_t         revive_interval;
-
-       char const              *secret;                //!< Shared secret.
-
-       uint32_t                max_packet_size;        //!< Maximum packet size.
-       uint16_t                max_send_coalesce;      //!< Maximum number of packets to coalesce into one mmsg call.
-
-       fr_radius_ctx_t         common_ctx;
-
-       bool                    replicate;              //!< Ignore responses.
-       bool                    synchronous;            //!< Retransmit when receiving a duplicate request.
-       bool                    originate;              //!< Originating packets, instead of proxying existing ones.
-                                                       ///< Controls whether Proxy-State is added to the outbound
-                                                       ///< request
-       rlm_radius_mode_t       mode;                   //!< proxy, client, etc.
-
-       uint32_t                max_attributes;         //!< Maximum number of attributes to decode in response.
-
-       fr_radius_require_ma_t  require_message_authenticator;  //!< Require Message-Authenticator in responses.
-       bool                    *received_message_authenticator;        //!< Received Message-Authenticator in responses.
-
-       uint32_t                *types;                 //!< array of allowed packet types
-       uint32_t                status_check;           //!< code of status-check type
-       map_list_t              status_check_map;       //!< attributes for the status-server checks
-       uint32_t                num_answers_to_alive;   //!< How many status check responses we need to
-                                                       ///< mark the connection as alive.
-
-       bool                    allowed[FR_RADIUS_CODE_MAX];
-
-       fr_retry_config_t       timeout_retry;
-       fr_retry_config_t       retry[FR_RADIUS_CODE_MAX];
-
-       trunk_conf_t            trunk_conf;             //!< trunk configuration
-};
diff --git a/src/modules/rlm_radius2/track.c b/src/modules/rlm_radius2/track.c
deleted file mode 100644 (file)
index b79b3a7..0000000
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- *   This program is is free software; you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation; either version 2 of the License, or (at
- *   your option) any later version.
- *
- *   This program is distributed in the hope that it will be useful,
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *   GNU General Public License for more details.
- *
- *   You should have received a copy of the GNU General Public License
- *   along with this program; if not, write to the Free Software
- *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/**
- * $Id$
- * @file rlm_radius/track.c
- * @brief Tracking RADUS client packets
- *
- * @copyright 2017 Network RADIUS SAS
- */
-RCSID("$Id$")
-
-#include <freeradius-devel/server/base.h>
-#include <freeradius-devel/util/rb.h>
-#include <freeradius-devel/io/application.h>
-#include <freeradius-devel/util/dlist.h>
-#include <freeradius-devel/util/debug.h>
-
-#include "track.h"
-
-/** Create an radius_track_t
- *
- * @param ctx the talloc ctx
- * @return
- *     - NULL on error
- *     - radius_track_t on success
- */
-radius_track_t *radius_track_alloc(TALLOC_CTX *ctx)
-{
-       int i;
-       radius_track_t *tt;
-
-       MEM(tt = talloc_zero(ctx, radius_track_t));
-
-       fr_dlist_init(&tt->free_list, radius_track_entry_t, entry);
-
-       for (i = 0; i < 256; i++) {
-               tt->id[i].id = i;
-#ifndef NDEBUG
-               tt->id[i].file = __FILE__;
-               tt->id[i].line = __LINE__;
-#endif
-               fr_dlist_insert_tail(&tt->free_list, &tt->id[i]);
-       }
-
-       return tt;
-}
-
-
-/** Ensures the entry is released when the ctx passed to radius_track_entry_reserve is freed
- *
- * @param[in] te_p             Entry to release.
- * @return 0
- */
-static int _radius_track_entry_release_on_free(radius_track_entry_t ***te_p)
-{
-       radius_track_entry_release(*te_p);
-
-       return 0;
-}
-
-/** Allocate a tracking entry.
- *
- * @param[in] file             The allocation was made in.
- * @param[in] line             The allocation was made on.
- * @param[out] te_out          Where the tracking entry should be written.
- *                             If ctx is not-null, then this pointer must
- *                             remain valid for the lifetime of the ctx.
- * @param[in] ctx              If not-null, the tracking entry release will
- *                             be bound to the lifetime of the talloc chunk.
- * @param[in] tt               The radius_track_t tracking table.
- * @param[in] request          The request which will send the proxied packet.
- * @param[in] code             Of the outbound request.
- * @param[in] uctx             The context to associate with the request
- * @return
- *     - 0 on success.
- *     - -1 on failure.
- */
-#ifndef NDEBUG
-int _radius_track_entry_reserve(char const *file, int line,
-#else
-int radius_track_entry_reserve(
-#endif
-                               radius_track_entry_t **te_out,
-                               TALLOC_CTX *ctx, radius_track_t *tt, request_t *request, uint8_t code, void *uctx)
-{
-       radius_track_entry_t *te;
-
-       if (!fr_cond_assert_msg(!*te_out, "Expected tracking entry to be NULL")) return -1;
-
-retry:
-       te = fr_dlist_head(&tt->free_list);
-       if (te) {
-               fr_assert(te->request == NULL);
-
-               /*
-                *      Mark it as used, and remove it from the free list.
-                */
-               fr_dlist_remove(&tt->free_list, te);
-
-               /*
-                *      We've transitioned from "use it", to "oops,
-                *      don't use it".  Ensure that we only return IDs
-                *      which are in the static array.
-                */
-               if (te != &tt->id[te->id]) {
-                       talloc_free(te);
-                       goto retry;
-               }
-
-               goto done;
-       }
-
-       /*
-        *      There are no free entries, and we can't use the
-        *      Request Authenticator.  Oh well...
-        */
-       fr_strerror_const("No free entries");
-       return -1;
-
-done:
-       te->tt = tt;
-       te->request = request;
-       te->uctx = uctx;
-       te->code = code;
-#ifndef NDEBUG
-       te->operation = te->tt->operation++;
-       te->file = file;
-       te->line = line;
-#endif
-       if (ctx) {
-               te->binding = talloc_zero(ctx, radius_track_entry_t **);
-               talloc_set_destructor(te->binding, _radius_track_entry_release_on_free);
-               *(te->binding) = te_out;
-       }
-
-       /*
-        *      te->id is already allocated
-        */
-       tt->num_requests++;
-
-       *te_out = te;
-
-       return 0;
-}
-
-/** Release a tracking entry
- *
- * @param[in] file                     Allocation was released in.
- * @param[in] line                     Allocation was released on.
- * @param[in,out] te_to_free           The #radius_track_entry_t allocated via #radius_track_entry_reserve.
- * @return
- *     - <0 on error
- *     - 0 on success
- */
-#ifndef NDEBUG
-int _radius_track_entry_release(char const *file, int line,
-#else
-int radius_track_entry_release(
-#endif
-                               radius_track_entry_t **te_to_free)
-{
-       radius_track_entry_t    *te = *te_to_free;
-       radius_track_t          *tt;
-
-       if (!te) return 0;
-
-       tt = talloc_get_type_abort(te->tt, radius_track_t);     /* Make sure table is still valid */
-
-       if (te->binding) {
-               talloc_set_destructor(te->binding, NULL);       /* Disarm the destructor */
-               talloc_free(te->binding);
-       }
-
-#ifndef NDEBUG
-       te->operation = te->tt->operation++;
-       te->file = file;
-       te->line = line;
-#endif
-
-       te->request = NULL;
-
-       fr_assert(tt->num_requests > 0);
-       tt->num_requests--;
-
-       /*
-        *      We're freeing a static ID, just go do that...
-        */
-       fr_assert(te == &tt->id[te->id]);
-
-       fr_dlist_insert_tail(&tt->free_list, te);
-
-       *te_to_free = NULL;
-
-       return 0;
-}
-
-/** Update a tracking entry with the authentication vector
- *
- * @param te           The radius_track_entry_t, via radius_track_entry_reserve()
- * @param vector       The authentication vector for the packet we're sending
- * @return
- *     - <0 on error
- *     - 0 on success
- */
-int radius_track_entry_update(radius_track_entry_t *te, uint8_t const *vector)
-{
-       radius_track_t *tt = te->tt;
-
-       fr_assert(tt);
-
-       memcpy(te->vector, vector, sizeof(te->vector));
-
-       /*
-        *      If we're not using the Request Authenticator, the
-        *      tracking entry must be in the static array.
-        *
-        *      @todo - gracefully handle fallback if the server screws up.
-        */
-       fr_assert(te == &tt->id[te->id]);
-       return 0;
-}
-
-/** Find a tracking entry from a request authenticator
- *
- * @param tt           The radius_track_t tracking table
- * @param packet_id            The ID from the RADIUS header
- * @param vector       The Request Authenticator (may be NULL)
- * @return
- *     - NULL on "not found"
- *     - radius_track_entry_t on success
- */
-radius_track_entry_t *radius_track_entry_find(radius_track_t *tt, uint8_t packet_id, uint8_t const *vector)
-{
-       radius_track_entry_t *te;
-
-       (void) talloc_get_type_abort(tt, radius_track_t);
-
-       /*
-        *      Just use the static array.
-        */
-       te = &tt->id[packet_id];
-
-       /*
-        *      Not in use, die.
-        */
-       if (!te->request) return NULL;
-
-       if (!vector) return te;
-
-       /*
-        *      Protocol-Error and Original-Packet-Vector <sigh>
-        *
-        *      This should arguably have been Original-Packet-Code, but we are stupid.
-        *
-        *      @todo - Allow for multiple ID arrays, one for each packet code.  Or, just switch to using
-        *      src/protocols/radius/id.[ch].
-        */
-       if (memcmp(te->vector, vector, sizeof(te->vector)) != 0) return NULL;
-
-       /*
-        *      Ignore the Request Authenticator, as the
-        *      caller doesn't have it.
-        */
-       return te;
-}
-
-
-#ifndef NDEBUG
-/** Print out the state of every tracking entry
- *
- * @param[in] log      destination.
- * @param[in] log_type Type of log message.
- * @param[in] file     this function was called in.
- * @param[in] line     this function was called on.
- * @param[in] tt       Table to print.
- * @param[in] extra    Callback function for printing extra detail.
- */
-void radius_track_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line,
-                           radius_track_t *tt, radius_track_log_extra_t extra)
-{
-       size_t i;
-
-       for (i = 0; i < NUM_ELEMENTS(tt->id); i++) {
-               radius_track_entry_t    *entry;
-
-               entry = &tt->id[i];
-
-               if (entry->request) {
-                       fr_log(log, log_type, file, line,
-                              "[%zu] %"PRIu64 " - Allocated at %s:%u to request %p (%s), uctx %p",
-                              i, entry->operation,
-                              entry->file, entry->line, entry->request, entry->request->name, entry->uctx);
-               } else {
-                       fr_log(log, log_type, file, line,
-                              "[%zu] %"PRIu64 " - Freed at %s:%u",
-                              i, entry->operation, entry->file, entry->line);
-               }
-
-               if (extra) extra(log, log_type, file, line, entry);
-       }
-}
-#endif
diff --git a/src/modules/rlm_radius2/track.h b/src/modules/rlm_radius2/track.h
deleted file mode 100644 (file)
index 3273611..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-#pragma once
-/*
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-/*
- * $Id$
- *
- * @file track.h
- * @brief RADIUS client packet tracking
- *
- * @copyright 2017 Alan DeKok (aland@freeradius.org)
- */
-
-#include "rlm_radius.h"
-#include <freeradius-devel/util/dlist.h>
-
-typedef struct radius_track_entry_s radius_track_entry_t;
-typedef struct radius_track_s radius_track_t;
-
-/** Track one request to a response
- *
- */
-struct radius_track_entry_s {
-       fr_rb_node_t    node;                   //!< Entry in the tracking tree.
-
-       radius_track_t  *tt;
-
-       radius_track_entry_t ***binding;        //!< Binding chunk we use to release the entry
-                                               ///< when its parent is freed.  We also zero
-                                               ///< out the tracking entry field in the parent.
-
-       request_t               *request;       //!< as always...
-
-       void            *uctx;                  //!< Result/resumption context.
-
-       uint8_t         code;                   //!< packet code (sigh)
-       uint8_t         id;                     //!< our ID
-
-       union {
-               fr_dlist_t      entry;                                  //!< For free list.
-               uint8_t         vector[RADIUS_AUTH_VECTOR_LENGTH];      //!< copy of the request authenticator.
-       };
-
-#ifndef NDEBUG
-       uint64_t        operation;              //!< Used to give an idea of the alloc/free timeline.
-       char const      *file;                  //!< Where the entry was allocated.
-       int             line;                   //!< Where the entry was freed.
-#endif
-};
-
-struct radius_track_s {
-       unsigned int    num_requests;           //!< number of requests in the allocation
-
-       fr_dlist_head_t free_list;              //!< so we allocate by least recently used
-
-       radius_track_entry_t    id[UINT8_MAX + 1];      //!< which ID was used
-
-#ifndef NDEBUG
-       uint64_t        operation;              //!< Incremented each alloc and de-alloc
-#endif
-};
-
-radius_track_t         *radius_track_alloc(TALLOC_CTX *ctx);
-
-/*
- *     Debug functions which track allocations and frees
- */
-#ifndef NDEBUG
-#  define              radius_track_entry_reserve(_te_out, _ctx, _tt, _request, _code, _uctx) \
-                               _radius_track_entry_reserve( __FILE__, __LINE__, _te_out, _ctx, _tt, _request, _code, _uctx)
-int                    _radius_track_entry_reserve(char const *file, int line,
-                                                   radius_track_entry_t **te_out,
-                                                   TALLOC_CTX *ctx, radius_track_t *tt, request_t *request,
-                                                   uint8_t code, void *uctx)
-                                                   CC_HINT(nonnull(3,5,6));
-
-#  define              radius_track_entry_release(_te) \
-                               _radius_track_entry_release( __FILE__, __LINE__, _te)
-int                    _radius_track_entry_release(char const *file, int line, radius_track_entry_t **te)
-                                                   CC_HINT(nonnull);
-
-typedef void (*radius_track_log_extra_t)(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line,
-                                        radius_track_entry_t *te);
-
-void                   radius_track_state_log(fr_log_t const *log, fr_log_type_t log_type, char const *file, int line,
-                                              radius_track_t *tt, radius_track_log_extra_t extra);
-/*
- *     Non-debug functions
- */
-#else
-int                    radius_track_entry_reserve(radius_track_entry_t **te_out,
-                                                  TALLOC_CTX *ctx, radius_track_t *tt, request_t *request,
-                                                  uint8_t code, void *uctx)
-                                                  CC_HINT(nonnull(1,3,4));
-
-int                    radius_track_entry_release(radius_track_entry_t **te) CC_HINT(nonnull);
-#endif
-
-int                    radius_track_entry_update(radius_track_entry_t *te,
-                                                 uint8_t const *vector) CC_HINT(nonnull);
-
-radius_track_entry_t   *radius_track_entry_find(radius_track_t *tt, uint8_t packet_id,
-                                                uint8_t const *vector) CC_HINT(nonnull(1));
index fee3de260882df2d37247b0c7df321ceae55cb58..8b41435bbdf99326512c405b71e7f70642c0d395 100644 (file)
@@ -68,6 +68,8 @@ modules {
        }
 
        radius {
+               mode = proxy
+
                type = Access-Request
                type = Accounting-Request