#  -*- text -*-
#
#
#  $Id: fe50c8a30733cefbb07efa73e23604e87f5e2e33 $

#######################################################################
#
#  = Radius Module
#
#  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.
#
#  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.
#
#  == Recommendations
#
#  In most cases, the v3 configuration be moved to v4 without too many
#  problems. For each `home_server foo { ... }` in v3, create a v4
#  module `radius foo { ... } `. Copy over the IP address, port, and
#  secret configuration items. When this step is finished, the bulk of
#  the basic work is done.
#
#  Converting a `home_server_pool foo { ... }` can be done by creating
#  a module in `mods-enabled`, either `load-balance foo { ... }`, or
#  `redundant foo { ... }`. i.e. the v3 module configuration does not
#  have any `instantiate` section. You can just list "virtual" modules
#  directly in the `modules` directory!
#
#  The contents of the `load-balance` or `redundant` section will be
#  the list of home servers which will part of that `load-balance` or
#  `redundant` pool.
#
#  Then, anywhere you want to use a home server, just list it's name
#  in an `unlang` processing section. Anywhere you want to list a home
#  server pool, just list it's name in an `unlang` processing section.
#
#  Unlike v3, there is no `Proxy-To-Realm` attribute, or
#  `Home-Server-Pool`, or `Home-Server-Name`. Instead, you just
#  configure a module (`radius`, or `load-balance`), and then use the
#  module anywhere you want to proxy packets.
#
#  In most cases, you can just set something like `Auth-Type :=
#  example.com`, and then have a section `authenticate example.com {
#  ... }`, which contains the `radius` modules which do proxying. See
#  `sites-available/default` for sample configuration which uses this
#  pattern.
#
#  == 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.
#
#  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.
#
#  == Configuration Settings
#
#  The configuration settings of this module are similar to the
#  `home_server` settings in v3.
#
#  The module has the following return codes:
#
#  [options="header,autowidth"]
#  |===
#  | Code        | Description
#  | invalid     | Something went wrong sending the request,
#                  or the reply packet is invalid.
#  | ok          | the module received an `ack` (`Access-Accept`,
#                  `Accounting-Response`, `CoA-ACK`, etc.)
#  | updated     | the module received an `Access-Challenge`
#  | handled     | the module received a `Protocol-Error`
#  | fail        | there was no response to the proxied request
#  | reject      | the module received a `nak` (`Access-Reject`, `CoA-NAK`, etc.)
#  | noop        | the module saw its own `Proxy-State` attribute,
#                  and is will not proxy the request.  This behavior
#                  prevents proxy loops.
#  |===
#
radius {
	#
	#  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)
	#
	#  dynamic-proxy - proxy packets to dynamic destinations
	#	- RFC 7585 dynamic DNS lookups are not supported
	#	- It MUST have `src_ipaddr = *` and no `src_port`
	#	- You CANNOT use the module "in place" as with normal proxying.
	#	- Proxying 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

	#
	#  max_attributes:: Maximum number of attributes to decode in
	#  response.
	#
	#  Default is 255.
	#
#	max_attributes = 255

	#
	#  type:: List of allowed packet types.
	#
	#  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.
	#
	#  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

	#
	#  require_message_authenticator::Require Message-Authenticator in
	#  responses.
	#
	#  A server should include Message-Authenticator attribute as the
	#  first attribute in responses to Access-Request packets. This
	#  behavior mitigates against the BlastRADIUS attack.
	#
	#  However, not all servers follow this security practice. As a
	#  result, this module can be configured to either not require, or
	#  require, Message-Authenticator.
	#
	#  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.
	#
	#  Allowed values: yes, no, auto
	#
	#  The default is `auto`.
	#
	require_message_authenticator = auto

	#
	#  response_window:: If we do not receive any replies within this
	#  time period, then start `zombie_period`
	#
	response_window = 15

	#
	#  zombie_period:: If the home server does not reply to packets
	#  within `response_window`, then `zombie_period` starts.
	#
	#  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`).
	#
	zombie_period = 10

	#
	#  revive_interval:: If there are no status checks, mark the home
	#  server alive after `revive_interval` timeout.
	#
	#  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 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.
	#
	#  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.
	#
	#  If the `zombie_period` and `revive_interval` configurations are
	#  set smaller, than it is possible for up to 50% of authentications
	#  to fail.
	#
	#  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.
	#
	#  If the home server does not respond to proxied packets, the module
	#  starts pinging the home server with these packets.
	#
	#  Disable status checks by deleting this section, or by commenting
	#  it out.
	#
	status_check {
		#
		#  type:: You can specify any type of request packet here, e.g.
		#  'Access-Request', 'Accounting-Request' or 'Status-Server'.
		#
		#  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.
		#
		type = Status-Server

		#
		#  The packet contents can be set here.
		#
		#  We RECOMMEND that you use packet contents which lets the other
		#  end easily tell that they are not "real" packets from a NAS.
		#
		#  The example here is for Status-Server. The contents will vary by
		#  other packet types. The Message-Authenticator attribute will be
		#  added automatically, and does not need to be specified here.
		#
		#  If the Event-Timestamp attribute is added, it will be updated
		#  each time the packet is sent.
		#
		#  WARNING: Do NOT do SQL queries, LDAP queries, dynamic expansions,
		#  etc. in this section. The contents of the packet are created when
		#  a connection is opened, and are not changeable after that.
		#
		update {
			User-Name := "test-user"
			NAS-Identifier := "Status check.  Are you alive?"
			Event-Timestamp = 0
		}
	}

	#
	#  == Transport Protocols
	#
	#  The module supports multiple transport protocols.
	#

	#
	#  === File Output
	#
	#  Write raw RADIUS packets (no IP or UDP header) to a file. This
	#  transport can only be used for `mode = replicate`
	#
	file {
	     filename = ${logdir}/packets.bin
	}

	#
	#  === UDP Transport
	#
	#  Much like the v3 `home_server` configuration.
	#
	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
	}

	#
	#  === TCP
	#
	#  The TCP configuration is identical to the `udp` configuration.
	#
##	tcp {
		#  copy the relevant configuration items here
##	}

	#
	#  == Connection trunking
	#
	#  Each worker thread (see radiusd.conf, num_workers), has it's own
	#  set of connections. These connections are grouped together into a
	#  "pool".
	#
	#  Much of the configuration here is similar to the old connection
	#  "pool" configuration in v3. However, there are more configuration
	#  parameters, and therefore more control over the behavior.
	#
	pool {
		#
		#  start:: Connections to create during module instantiation.
		#
		#  If the server cannot create specified number of connections
		#  during instantiation it will exit.
		#
		#  Set to `0` to allow the server to start without the database
		#  being available.
		#
		start = 0

		#
		#  min:: Minimum number of connections to keep open.
		#
		min = 1

		#
		#  max:: Maximum number of connections.
		#
		#  If these connections are all in use and a new one is requested,
		#  the request will NOT get a connection.
		#
		max = 8

		#
		#  connecting:: Maximum number of sockets to have in the
		#  "connecting" state.
		#
		#  If a home server goes down, the module will close old / broken
		#  connections, and try to open new ones. In order to avoid flooding
		#  the home server with connection attempts, set the `connecting`
		#  value to a small number.
		#
		connecting = 1

		#
		#  uses:: number of packets which will use the connection.
		#
		#  After `uses` packets have been sent the connection will be
		#  closed, and a new one opened. For no limits, set `uses = 0`.
		#
		uses = 0

		#
		#  lifetime:: lifetime of a connection, in seconds.
		#
		#  After `lifetime` seconds have passed, no new packets will be sent
		#  on the connection. When all replies have been received, the
		#  connection will be closed.
		#
		#  For no limits, set `lifetime = 0`.
		#
		#  It is possible to use precise times, such as `lifetime = 1.023`,
		#  or even qualifiers such as `lifetime = 400ms`.
		#
		lifetime = 0

		#
		#  open_delay:: How long (in seconds) a connection must be above
		#  `per_connection_target` before a new connection is opened.
		#
		#  Parsing of this field is the same as for `lifetime`.
		#
		open_delay = 0.2

		#
		#  close_delay:: How long (in seconds) a connection must be below
		#  `per_connection_target` before a connection is closed.
		#
		close_delay = 1.0

		#
		#  manage_interval:: How often (in seconds) the connections are
		#  checked for limits, in order to open / close connections.
		#
		manage_interval = 0.2

		#
		#  connection { ... }:: Per-connection configuration.
		#
		connection {
			#
			#  connect_timeout:: How long to wait before giving up on a
			#  connection which is being opened.
			#
			connect_timeout = 3.0

			#
			#  reconnect_delay:: If opening a connection fails, or an open
			#  connection fails, we wait `reconnect_delay` seconds before
			#  attempting to open another connection.
			#
			reconnect_delay = 5
		}

		#
		#  request { ... }:: Per-request configuration.
		#
		request {
			#
			#  per_connection_max:: The maximum number of requests which are
			#  "live" on a particular connection.
			#
			per_connection_max = 255

			#
			#  per_connection_target:: The target number of requests which are
			#  "live" on a particular connection.
			#
			#  There can be a balance between overloading a connection, and
			#  under-utilizing it. The default is to fill each connection
			#  before opening a new one.
			#
			per_connection_target = 255

			#
			#  free_delay:: How long to wait before freeing internal resources
			#  associated with the connection.
			#
			free_delay = 10
		}

	}

	#
	#  == 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.
	#

	#
	#  === Access Request packets
	#
	Access-Request {
		#
		#  initial_rtx_time:: If there is no response within this time, the
		#  module will retransmit the packet.
		#
		#  Value should be `1..5`.
		#
		initial_rtx_time = 2

		#
		#  max_rtx_time:: The maximum time between retransmissions.
		#
		#  Value should be `5..30`
		#
		max_rtx_time = 16

		#
		#  [NOTE]
		#  ====
		#  * The following are maximums that *all* apply.
		#
		#  i.e. if any one of the limits is hit, the retransmission stops.
		#  ====
		#

		#
		#  max_rtx_count:: How many times the module will send the packet
		#  before giving up.
		#
		#  Value should be `1..20` _(0 == retransmit forever)_
		#
		max_rtx_count = 2

		#
		#  max_rtx_duration:: The total length of time the module will try
		#  to retransmit the packet.
		#
		#  Value should be `5..60`
		#
		max_rtx_duration = 30
	}

	#
	#  === Accounting Packets
	#
	#  i.e. If you want `retransmit forever`, you should set:
	#
	#    max_rtx_time = 0
	#    max_rtx_count = 0
	#
	Accounting-Request {
		initial_rtx_time = 2
		max_rtx_time = 16
		max_rtx_count = 5
		max_rtx_duration = 30
	}

	#
	#  === CoA Packets
	#
	CoA-Request {
		initial_rtx_time = 2
		max_rtx_time = 16
		max_rtx_count = 5
		max_rtx_duration = 30
	}

	#
	#  === Disconnect packets
	#
	Disconnect-Request {
		initial_rtx_time = 2
		max_rtx_time = 16
		max_rtx_count = 5
		max_rtx_duration = 30
	}

	#
	#  === Status-Server packets
	#
	#  The configuration here helps the module determine if a home server
	#  is alive and responding to requests.
	#
	#  WARNING: The `Status-Server` packets CANNOT be proxied.
	#
	Status-Server {
		initial_rtx_time = 2
		max_rtx_time = 5
		max_rtx_count = 5
		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.
	#
}

#
#  == Dynamic Proxying
#
#  This module supports dynamic proxying via a run-time function:
#
#	%proxy.sendto.ipaddr(127.0.0.1, 1812, "testing123")
#
#  The first part of the function name (e.g. `proxy`) is taken from
#  the module name. The rest is fixed as `sendto.ipaddr()`
#
#  The arguments to the function are:
#
#  * destination IP address.
#  * destination port
#  * shared secret
#
#  The function will return the type of response packet if it receives
#  as a response, or else the function all will fail.
#
#	if (%proxy.sendto.ipaddr(127.0.0.1, 1812, "testing123") == 'Access-Accept') {
#	  ...
#	}
#
#  The packet name must be a quoted string.
#
#  The proxying is done asynchronously. i.e. the packet is sent, and
#  the server goes on to do other work. At some point in the future, a
#  response is received, the module processes it, and the server
#  continues.
#
#  The timeouts are controlled as described above.
#
radius proxy {
	type = Access-Request

	#
	#  The mode.
	#
	mode = dynamic-proxy

	#
	#  Both UDP and TCP are supported.
	#
	transport = udp

	#
	#  === UDP Transport
	#
	udp {
		#
		#  src_ipaddr:: The source IP address used by the module.
		#
		src_ipaddr = *

		#
		#  src_port_start:: Start of source port range.
		#
		#  The outgoing proxy normally uses random source ports. When all of
		#  the RADIUS IDs are used for one connection, it opens up another
		#  random source port.
		#
		#  However, it is sometimes useful to restrict the range of source
		#  ports to known values. The `src_port_start` and `src_port_end`
		#  configuration flags allow the port range to be controlled. The
		#  module will then restrict the source ports it is using to be
		#  within this range.
		#
		#  When all ports in this range are used, the module will not be
		#  able to open any more outgoing connections.x
		#
		#  These two configuration items can only be used for UDP sockets.
		#
		src_port_start = 10000

		#
		#  src_port_end:: End of source port range.
		#
		src_port_end = 11000

		#
		#  `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.
		#
	}

	#
	#  Dynamic proxying does *not* support the `status_check` section.
	#

	#
	#  home_server_lifetime:: The lifetime of the home server.
	#
	#  When a new dynamic home server is used, the module caches
	#  information about it. So long as the home server is still being
	#  used, it will not expire. But if it has received all expected
	#  responses (or timeouts), _and_ it has reached its expected
	#  lifetime, then the home server will be deleted.
	#
	#  This process allows for the secret to change over time. However,
	#  the secret can only be changed if there are no outstanding
	#  packets. Otherwise, changing the secret would involve having
	#  multiple packets outstanding which have different secrets. That
	#  doesn't work, and can't be fixed through any code changes on the
	#  server.
	#
	#  The solution to that is to switch to using TLS.
	#
	home_server_lifetime = 3600

	#
	#  These are allowed, but are less useful. If the home server doesn't
	#  respond, it will often just hit the home server lifetime, and be
	#  deleted.
	#
	response_window = 15
	zombie_period = 10
	revive_interval = 3600


	#
	#  == Timeouts
	#
	#  Timeouts for proxying are controlled in sections named for the
	#  packet type. See the examples above for full documentation.
	#
	Access-Request {
		initial_rtx_time = 2
		max_rtx_time = 16
		max_rtx_count = 5
		max_rtx_duration = 30
	}

	#
	#  == Connection trunking
	#
	#  See above for documentation on connection trunking.
	#
	pool {
		#
		#  start:: Connections to create during module instantiation.
		#
		#  If the server cannot create specified number of connections
		#  during instantiation it will exit.
		#
		#  Set to `0` to allow the server to start without the database
		#  being available.
		#
		start = 0

		#
		#  min:: Minimum number of connections to keep open.
		#
		min = 1

		#
		#  max:: Maximum number of connections.
		#
		#  If these connections are all in use and a new one is requested,
		#  the request will NOT get a connection.
		#
		max = 8

		#
		#  connecting:: Maximum number of sockets to have in the
		#  "connecting" state.
		#
		#  If a home server goes down, the module will close old / broken
		#  connections, and try to open new ones. In order to avoid flooding
		#  the home server with connection attempts, set the `connecting`
		#  value to a small number.
		#
		connecting = 1

		#
		#  uses:: number of packets which will use the connection.
		#
		#  After `uses` packets have been sent the connection will be
		#  closed, and a new one opened. For no limits, set `uses = 0`.
		#
		uses = 0

		#
		#  lifetime:: lifetime of a connection, in seconds.
		#
		#  After `lifetime` seconds have passed, no new packets will be sent
		#  on the connection. When all replies have been received, the
		#  connection will be closed.
		#
		#  For no limits, set `lifetime = 0`.
		#
		#  It is possible to use precise times, such as `lifetime = 1.023`,
		#  or even qualifiers such as `lifetime = 400ms`.
		#
		lifetime = 0

		#
		#  open_delay:: How long (in seconds) a connection must be above
		#  `per_connection_target` before a new connection is opened.
		#
		#  Parsing of this field is the same as for `lifetime`.
		#
		open_delay = 0.2

		#
		#  close_delay:: How long (in seconds) a connection must be below
		#  `per_connection_target` before a connection is closed.
		#
		close_delay = 1.0

		#
		#  manage_interval:: How often (in seconds) the connections are
		#  checked for limits, in order to open / close connections.
		#
		manage_interval = 0.2

		#
		#  connection { ... }:: Per-connection configuration.
		#
		connection {
			#
			#  connect_timeout:: How long to wait before giving up on a
			#  connection which is being opened.
			#
			connect_timeout = 3.0

			#
			#  reconnect_delay:: If opening a connection fails, or an open
			#  connection fails, we wait `reconnect_delay` seconds before
			#  attempting to open another connection.
			#
			reconnect_delay = 5
		}

		#
		#  request { ... }:: Per-request configuration.
		#
		request {
			#
			#  per_connection_max:: The maximum number of requests which are
			#  "live" on a particular connection.
			#
			per_connection_max = 255

			#
			#  per_connection_target:: The target number of requests which are
			#  "live" on a particular connection.
			#
			#  There can be a balance between overloading a connection, and
			#  under-utilizing it. The default is to fill each connection
			#  before opening a new one.
			#
			per_connection_target = 255

			#
			#  free_delay:: How long to wait before freeing internal resources
			#  associated with the connection.
			#
			free_delay = 10
		}

	}
}


#
#  == Policy Over-rides
#
#  The proxy policy overrides enables functionality similar to the
#  version 3 pre/post-proxy sections.
#

@policy proxy {
	#
	#  Create a subrequest which we can edit. When the subrequest section
	#  is done,
	#
	subrequest {
		#
		#  Initialize the proxied packet from the request.
		#
		#  This is the "pre-proxy" section.
		#
		request := parent.request

		#
		#  Run the "radius proxy" module noted above.
		#
		proxy

		#
		#  Edit the reply from the home server here.
		#
		#  This is the "post-proxy" section.
		#
		#  Note that the Proxy-State attributes have already been deleted
		#  from the reply, so you don't need to do that here. Those
		#  attributes are not needed by anyone for anything, and confuse
		#  things if they're copied to the original request. The `radius`
		#  module therefore deletes them, to make your life easier.
		#

		#
		#  Like v3, remove all pre-existing attributes in the original
		#  reply, and replace them with the reply from the home server.
		#
		#  It is also possible to copy over some, or none of the attributes
		#  in the reply from the home server. The configuration here is just
		#  an example, and can be edited.
		#
		parent.reply := reply
	}
}
