The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
unit_test_bio.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16/**
17 * $Id: 0ede88e8267d5cdd479c4a9d37acb24be94dabbb $
18 *
19 * @file unit_test_bio.c
20 * @brief TLS server test framework, using the TLS bio
21 *
22 * This program loads the "tls" protocol and reads two top-level sections
23 * from unit_test_tls.conf. The "tls" section supplies the TLS server
24 * context, and takes exactly the items that a TLS configuration takes
25 * anywhere else in the server. The "unit_test_tls" section supplies what
26 * steers the test program itself, which is the address of the listening TCP
27 * socket and whether a client certificate is required.
28 *
29 * One connection is accepted, and the TLS handshake for that connection is
30 * run to completion.
31 *
32 * This program is unit_test_tls.c reworked to use the TLS bio in
33 * src/lib/bio/tls.c. The program opens the sockets as fd bios, and the
34 * TLS bio runs everything else for a connection: the connect, the handshake,
35 * the IO, and the policies. The program supplies the request, the
36 * interpreter, and two callbacks, `connected` and `failed`. The section is
37 * still called "unit_test_tls", so the configuration files of unit_test_tls
38 * work here too. Setting `drop_datagram` is an error, as the TLS bio does
39 * not offer a place to drop a datagram.
40 *
41 * The handshake runs on a persistent asynchronous interpreter, the same way
42 * radiusd runs one. A persistent interpreter keeps the handshake state
43 * across the several rounds of a single connection.
44 *
45 * The "virtual_server" item in the "tls" section names a virtual server.
46 * That virtual server supplies the "verify certificate", "load session",
47 * "store session" and "clear session" sections which the handshake calls.
48 *
49 * To run the test, start unit_test_tls with the test configuration, then
50 * connect to the listening socket:
51 *
52 * @code
53 * ./scripts/bin/unit_test_tls -d src/tests/tls -X
54 *
55 * openssl s_client -connect 127.0.0.1:2083 \
56 * -cert raddb/certs/rsa/client.pem \
57 * -key raddb/certs/rsa/client.key -pass pass:whatever \
58 * -CAfile raddb/certs/rsa/ca.pem
59 * @endcode
60 *
61 * src/tests/tls/unit_test_tls.conf documents every configuration item.
62 *
63 * @copyright 2025 The FreeRADIUS server project
64 */
65RCSID("$Id: 0ede88e8267d5cdd479c4a9d37acb24be94dabbb $")
66
67#include <freeradius-devel/server/base.h>
68#include <freeradius-devel/server/module_rlm.h>
69
70#include <freeradius-devel/io/listen.h>
71#include <freeradius-devel/io/thread.h>
72
73#include <freeradius-devel/tls/base.h>
74#include <freeradius-devel/tls/dtls.h>
75#include <freeradius-devel/tls/strerror.h>
76#include <freeradius-devel/tls/version.h>
77#include <freeradius-devel/tls/connection.h>
78#include <freeradius-devel/bio/base.h>
79#include <freeradius-devel/bio/fd.h>
80#include <freeradius-devel/bio/tls.h>
81#include <freeradius-devel/util/misc.h>
82
83#include <freeradius-devel/unlang/base.h>
84#include <freeradius-devel/unlang/function.h>
85#include <freeradius-devel/unlang/interpret.h>
86
87#include <freeradius-devel/util/socket.h>
88
89#include <freeradius-devel/protocol/freeradius/freeradius.internal.h>
90
91#ifdef HAVE_GETOPT_H
92# include <getopt.h>
93#endif
94
95#include <sys/wait.h>
96
97#define EXIT_WITH_FAILURE \
98do { \
99 ret = EXIT_FAILURE; \
100 goto cleanup; \
101} while (0)
102
103char const *radiusd_version = RADIUSD_VERSION_BUILD("unit_test_bio");
104
106static fr_dict_t const *dict_tls;
107
110 { .out = &dict_freeradius, .proto = "freeradius" },
111 { .out = &dict_tls, .proto = "tls" },
113};
114
115/** The "unit_test_tls" section
116 *
117 * The items at the top level steer the test program and do not configure
118 * TLS. The TLS configuration for each role is a subsection.
119 * `fr_tls_server_config` and `fr_tls_client_config` parse the subsections,
120 * so each subsection takes exactly the items that a `tls { ... }` section
121 * takes anywhere else in the server.
122 */
123/** One transport's socket, named by `transport` in the configuration
124 *
125 */
126typedef struct {
127 fr_ipaddr_t ipaddr; //!< Address of the listening socket.
128 uint16_t port; //!< Port of the listening socket.
130
131typedef struct {
132 char const *transport; //!< "tcp" or "udp", naming the subsection below
133 ///< which holds the socket.
134 int socket_type; //!< SOCK_STREAM or SOCK_DGRAM, from `transport`.
135
136 unit_test_bio_socket_t tcp; //!< The `tcp { ... }` subsection.
137 unit_test_bio_socket_t udp; //!< The `udp { ... }` subsection.
138
139 fr_ipaddr_t ipaddr; //!< Address of the listening socket, copied from
140 ///< whichever subsection `transport` named.
141 uint16_t port; //!< Port of the listening socket, and the default
142 ///< port for -s.
143 uint32_t drop_datagram; //!< Drop this datagram rather than sending it,
144 ///< counting from one. Zero drops nothing.
145 bool require_client_certificate; //!< Whether the client has to present a certificate.
146
147 fr_tls_conf_t *server; //!< The `server { ... }` subsection.
148 fr_tls_conf_t *client; //!< The `client { ... }` subsection, used with `-s`.
150
151/** The socket items, parsed once per transport subsection
152 *
153 */
163
165 /*
166 * `transport` names a subsection, the way a listener's
167 * `transport` does, see common_transport_parse() in
168 * src/lib/bio/fd_config.c. The socket items live in that
169 * subsection rather than here, so that a configuration which
170 * names one transport cannot carry another one's settings.
171 */
172 { FR_CONF_OFFSET("transport", unit_test_bio_conf_t, transport), .dflt = "tcp" },
173
178
179 /*
180 * Lose a datagram on purpose, so that a test can see the
181 * retransmission which recovers from it. Zero loses nothing.
182 */
183 { FR_CONF_OFFSET("drop_datagram", unit_test_bio_conf_t, drop_datagram) },
184
185 { FR_CONF_OFFSET("require_client_certificate", unit_test_bio_conf_t, require_client_certificate),
186 .dflt = "no" },
187
188 /*
189 * A test file may hold only the role that the test runs, so
190 * either subsection may be missing.
191 */
192 { FR_CONF_SUBSECTION_ALLOC("server", CONF_FLAG_OK_MISSING, unit_test_bio_conf_t, server, fr_tls_server_config),
193 .subcs_type = "fr_tls_conf_t" },
194 { FR_CONF_SUBSECTION_ALLOC("client", CONF_FLAG_OK_MISSING, unit_test_bio_conf_t, client, fr_tls_client_config),
195 .subcs_type = "fr_tls_conf_t" },
196
198};
199
200/** State of the test program
201 *
202 * The interpreter and the runnable heap live for the whole of the connection.
203 * A TLS handshake takes several rounds, and each round may yield while a
204 * virtual server section runs. The interpreter and the runnable heap
205 * therefore cannot be allocated once per round.
206 */
207typedef struct {
208 fr_event_list_t *el; //!< Event list everything runs on.
209 unlang_interpret_t *intp; //!< Interpreter for the connection.
210 fr_heap_t *runnable; //!< Requests the interpreter has marked runnable.
211 int yielded; //!< How many requests are currently yielded.
212
213 unit_test_bio_conf_t conf; //!< Parsed "unit_test_tls" section.
214 SSL_CTX *ssl_ctx; //!< Context built from the "tls" section.
215
216 fr_bio_t *listen_bio; //!< Listening fd bio.
217 fr_bio_fd_config_t listen_cfg; //!< Config of `listen_bio`. The bio keeps the pointer.
218 fr_bio_t *fd_bio; //!< The fd bio of the connection being run.
219 fr_bio_fd_config_t fd_cfg; //!< Config of `fd_bio`. The bio keeps the pointer.
220 fr_bio_tls_t *bio; //!< The TLS bio of the connection being run.
221 fr_tls_connection_t *conn; //!< The connection of `bio`. The hooks of this
222 ///< program read this connection.
223 request_t *request; //!< The request the connection runs under.
224
225
226 unsigned int count; //!< How many connections to run.
227 bool alert; //!< Reject the peer with a TLS alert, see -A.
228 bool invalid; //!< Mark the session invalid mid-handshake, see -I.
229 bool nonblock; //!< Put the connection socket in non-blocking mode, see -B.
230 bool client; //!< Act as the client and connect to a server,
231 ///< rather than accept a connection. Copied into
232 ///< every connection this program allocates.
233
234 bool app_data; //!< Send one byte of application data once the
235 ///< handshake is done, see -P.
236
237 bool hold; //!< Once connected, send nothing and stay
238 ///< connected, see -H.
239
240 bool reject; //!< Reject the session once the handshake
241 ///< succeeds, see -R.
242 bool network_fail; //!< Fail the session with a network error once
243 ///< the handshake succeeds, see -N.
244 bool abort_pending; //!< Free the connection once the handshake
245 ///< succeeds, while `store session` is still
246 ///< queued, see -Q.
247 unsigned int connections; //!< How many connections have been run so far.
248 fr_ipaddr_t server_ipaddr; //!< Server named by -s.
249 uint16_t server_port; //!< Port from -s, or from the configuration.
250
251 int sockfd; //!< Listening socket.
252 fr_event_fd_t *accept_ef; //!< Read event for sockfd, while waiting in
253 ///< tls_socket_accept().
254 bool accepting; //!< Waiting in tls_socket_accept().
255
256 char const *command; //!< Command to run, see -e.
257 pid_t command_pid; //!< Command started by -e, or 0.
258 fr_event_pid_t const *command_ev; //!< Waits for the command to exit.
259 bool command_exited; //!< The command has exited.
260 bool command_waiting; //!< Waiting in tls_command_wait().
261
262 int fd; //!< Accepted or connected socket.
263
264 uint8_t *first; //!< The datagram which named the peer, read from
265 ///< the listening socket before the connection's
266 ///< socket existed. Handed to the connection once
267 ///< the connection is running.
268 size_t first_len; //!< Length of `first`.
269 unsigned char *alpn; //!< Protocol list built by -L, in the wire format
270 ///< fr_tls_conf_t expects. NULL means no ALPN.
271 bool alpn_required; //!< Set by -l.
272
273 bool connected; //!< The `connected` callback has run.
274 bool done; //!< Set once the connection has a result.
275 int ret; //!< Exit status.
277
278static void usage(main_config_t const *config, int status);
279static void tls_request_failed(unit_test_bio_t *utt);
280
281/*
282 * Interpreter callbacks.
283 *
284 * The callbacks below mirror the set in
285 * src/lib/unlang/interpret_synchronous.c and src/lib/io/coord_pair.c. The
286 * one difference is that a post-event handler drains the runnable heap,
287 * rather than a loop inside the caller, so the event loop decides when
288 * each request runs.
289 */
290
291/** Schedule a request, once
292 *
293 * A request reaches the heap from two directions: the interpreter creating it,
294 * and the interpreter marking it runnable again. Inserting a request which is
295 * already on the heap puts it there twice, and popping it then returns a
296 * request which the heap still holds, which the interpreter refuses to run.
297 */
299{
300 if (fr_heap_entry_inserted(request->runnable)) return;
301
303}
304
305/** An internal request created by the interpreter has to run on ours
306 *
307 * The subrequests created for the "verify certificate" section and for the
308 * session cache sections reach this callback.
309 *
310 * fr_tls_call_push() pushes each of them as a detachable subrequest, which
311 * the parent waits on rather than running inline, so the subrequest has to be
312 * scheduled here or nothing ever runs it.
313 */
314static void _request_init_internal(request_t *request, void *uctx)
315{
316 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
317
318 RDEBUG3("Initialising internal request");
319
321
322 /*
323 * interpret_child_init() calls this, and nothing else schedules
324 * the child, so a subrequest which is not put on the heap here
325 * never runs at all.
326 */
328}
329
331{
332 RDEBUG3("Done external request");
333
334 /*
335 * main() allocated the request, and the request has to survive
336 * until the connection is done with, so this callback does not
337 * free the request.
338 */
339}
340
342{
343 RDEBUG3("Done internal request");
344
345 /* The code which created the internal request frees the request */
346}
347
349{
350 RDEBUG3("Done detached request");
351
352 /*
353 * Nothing else can free a detached request, so this callback
354 * frees the detached request.
355 */
357}
358
359static void _request_detach(request_t *request, UNUSED void *uctx)
360{
361 RDEBUG3("Request detached");
362
363 if (request_detach(request) < 0) RPEDEBUG("Failed detaching request");
364}
365
366static void _request_yield(request_t *request, void *uctx)
367{
368 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
369
370 utt->yielded++;
371
372 RDEBUG3("Request yielded");
373}
374
375static void _request_resume(request_t *request, UNUSED void *uctx)
376{
377 RDEBUG3("Request resumed");
378}
379
380static void _request_runnable(request_t *request, void *uctx)
381{
382 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
383
384 fr_assert(utt->yielded > 0);
385 utt->yielded--;
386
388}
389
390static bool _request_scheduled(request_t const *request, UNUSED void *uctx)
391{
392 return fr_heap_entry_inserted(request->runnable);
393}
394
395/** Stop the event loop, recording why
396 *
397 * The connection carries the result, so the exit status is decided here
398 * rather than by the TLS bio.
399 */
400static void tls_done(unit_test_bio_t *utt)
401{
402 if (utt->done) return;
403
404 utt->done = true;
405 /*
406 * With -H the peer ends a connection which was already up, and the end is
407 * not a failure.
408 */
409 utt->ret = (utt->conn && utt->conn->failed && !(utt->hold && utt->connected)) ? EXIT_FAILURE : EXIT_SUCCESS;
410
411 fr_event_loop_exit(utt->el, 1);
412}
413
414/** The TLS bio says the connection failed, at any point
415 *
416 */
417static void tls_bio_failed(fr_bio_t *bio)
418{
419 unit_test_bio_t *utt = talloc_get_type_abort(bio->uctx, unit_test_bio_t);
420
421 tls_done(utt);
422}
423
424/** Record a failure this program cannot recover from, and stop
425 *
426 * tls_done() reads the result from the connection, so a failure has to reach
427 * the connection before the program stops.
428 */
430{
431 if (utt->conn) utt->conn->failed = TLS_CONNECTION_FAIL_APPLICATION;
432 tls_done(utt);
433}
434
435/** Something happened on a connection which -H holds open
436 *
437 * The TLS bio removed its fd events when the connection connected, so the
438 * program watches the fd itself. Reading the bio is how the program learns
439 * that the peer has gone.
440 */
441static void _tls_hold_read(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
442{
443 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
444 uint8_t buffer[256];
445 ssize_t slen;
446
447 do {
448 slen = fr_bio_read((fr_bio_t *) utt->bio, NULL, buffer, sizeof(buffer));
449 } while (slen > 0);
450
451 if (slen == fr_bio_error(IO_WOULD_BLOCK)) return;
452
453 if ((slen < 0) || fr_bio_fd_info(utt->fd_bio)->eof) {
454 DEBUG2("The peer ended the held connection");
455 tls_done(utt);
456 }
457}
458
459static void _tls_hold_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags,
460 UNUSED int fd_errno, void *uctx)
461{
462 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
463
464 DEBUG2("The held connection failed");
465 tls_done(utt);
466}
467
468/** The connection is up, and can carry application data
469 *
470 * The TLS bio removed its fd events before calling this function. A program
471 * which had data to send would send it with fr_bio_write(), and close when it
472 * was done.
473 */
475{
476 unit_test_bio_t *utt = talloc_get_type_abort(bio->uctx, unit_test_bio_t);
477
478 DEBUG2("Connection is up and can carry application data");
479
480 /*
481 * Send one byte of application data, which tells the peer that
482 * every session ticket we were going to send has already gone.
483 * The connection only reaches TLS_CONNECTION_CONNECTED when every
484 * ticket section has run.
485 */
486 if (utt->app_data && !utt->client) {
487 uint8_t zero = 0x00;
488
489 if (fr_bio_write(bio, NULL, &zero, sizeof(zero)) != (ssize_t) sizeof(zero)) {
490 PERROR("Failed sending the application data");
492 return;
493 }
494
495 DEBUG("Sent one byte of application data");
496 }
497
498 /*
499 * -H holds the connection open with nothing more to say. A
500 * peer which is still owed a session ticket or a byte of
501 * application data then waits for something which never
502 * arrives, which is what the post-handshake timer is for.
503 *
504 * The connection still ends: the peer gives up, closes, and
505 * the TLS bio fails the connection when it sees EOF.
506 */
507 utt->connected = true;
508
509 if (utt->hold) {
510 DEBUG("Holding the connection open, sending nothing");
511
512 if (fr_event_fd_insert(utt, NULL, utt->el, utt->fd, _tls_hold_read, NULL, _tls_hold_error, utt) < 0) {
513 PERROR("Failed watching the held connection");
515 }
516 return;
517 }
518
519 tls_done(utt);
520}
521
522/** Drain the runnable heap once per pass of the event loop
523 *
524 * A handshake round yields whenever the round runs a virtual server section.
525 * When that section finishes, unlang_interpret_mark_runnable() puts the
526 * request on the runnable heap, and this drains the heap again.
527 */
529{
530 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
532
533 /*
534 * Stand in for an application which rejects a peer outright.
535 *
536 * `pending` says a record has arrived and the handshake has not
537 * read it yet. This hook used to live in _tls_connection_read(),
538 * where its position said the same thing, and the comment there
539 * warned that raising the alert before a record arrives sends it
540 * into an empty handshake, where it is lost. The test cannot
541 * tell: removing this test passes six suite runs out of six,
542 * because a server runs no handshake round until a record
543 * arrives. A client runs one straight away, so keep the test.
544 *
545 * Raising the alert later, with the other two hooks below, is
546 * too late. Those run after the round, and the round which
547 * would have carried the alert has gone.
548 */
549 /*
550 * Stand in for a record which FreeRADIUS itself refuses.
551 *
552 * fr_tls_session_msg_cb() marks such a session invalid and
553 * lets the round finish. The round after that refuses to
554 * continue, records FR_ERROR_VALUE_SESSION_INVALID, and sends
555 * the peer a fatal alert. Setting the flag here reaches that
556 * second round without having to feed the handshake a
557 * malformed record.
558 *
559 * `pending` places this before a round, for the same reason
560 * the alert hook below is placed there.
561 */
562 if (utt->invalid && utt->conn->tls_session && utt->conn->pending &&
563 (utt->connections == utt->count)) {
564 utt->invalid = false;
565 utt->conn->tls_session->invalid = true;
566 }
567
568 if (utt->alert && utt->conn->tls_session && utt->conn->pending &&
569 (utt->connections == utt->count)) {
570 utt->alert = false;
571
572 if (fr_tls_session_alert(utt->conn->request, utt->conn->tls_session,
573 SSL3_AL_FATAL, SSL_AD_ACCESS_DENIED) < 0) {
574 ERROR("Failed raising the TLS alert");
576 return;
577 }
578 }
579
580 while (fr_heap_pop((void **)&request, &utt->runnable) == 0) {
581 if (!request) break;
582
584
585 /*
586 * Only the connection's own request advances the
587 * handshake. A subrequest returns the subrequest's
588 * result through the interpreter.
589 *
590 * The connection's own IO is not done here any more.
591 * tls_connection_frame_process() does it, inside
592 * src/lib/tls, at the point the connection is about to
593 * wait for the peer. A real listener has no hook here,
594 * so nothing which a real listener cannot do belongs
595 * here either.
596 */
597 if (request == utt->conn->request) {
598 /*
599 * Stand in for an application which rejects a
600 * session after the handshake succeeded. The
601 * handshake has finished, so OpenSSL has asked
602 * for the session to be cached, and the
603 * connection is about to run its cache
604 * operations. Failing it here makes those
605 * operations a deny and a clear rather than a
606 * store, which is what rlm_eap_tls does when
607 * policy rejects.
608 */
609 if ((utt->reject || utt->network_fail) && (utt->connections == utt->count) &&
610 fr_tls_session_is_init_finished(utt->conn->tls_session)) {
611 INFO("%s the session after a successful handshake",
612 utt->network_fail ? "Failing, with a network error," : "Rejecting");
613
614 /*
615 * Record the reason, and nothing else.
616 * The handshake has finished, so OpenSSL
617 * has asked for the session to be cached,
618 * and the connection frame is about to run
619 * that cache work. The frame reads
620 * `failed` to decide whether the work is a
621 * store or a deny and a clear, which is
622 * what rlm_eap_tls does when policy
623 * rejects.
624 *
625 * fr_tls_connection_failed() would instead
626 * report the connection finished here, and
627 * the queued cache work would never be
628 * drained. src/lib/tls/session.c asserts
629 * on exactly that.
630 */
631 utt->conn->failed = utt->network_fail ? TLS_CONNECTION_FAIL_SYSCALL :
632 TLS_CONNECTION_FAIL_APPLICATION;
633 }
634
635 /*
636 * Free the connection while `store session` is
637 * still queued. The handshake has finished, so
638 * OpenSSL has asked for the session to be cached
639 * and the connection is about to run that work,
640 * but it has not run yet. Closing now frees the
641 * session with the operation still pending, which
642 * is the path session.c used to assert on and now
643 * discards. This is deterministic: it does not
644 * depend on when the peer closes.
645 */
646 if (utt->abort_pending && (utt->connections == utt->count) &&
647 fr_tls_session_is_init_finished(utt->conn->tls_session)) {
648 INFO("Aborting the connection with cache operations still queued");
649 tls_done(utt);
650 return;
651 }
652 }
653
654 if (utt->done) return;
655 }
656}
657
658/** Open the listening socket described by the "unit_test_tls" section
659 *
660 * The listening socket is an fd bio for both transports. fr_bio_fd_accept()
661 * accepts a stream connection, or takes the first datagram of a peer as a
662 * connection, see tls_socket_accept_one().
663 */
665{
666 fr_ipaddr_t ipaddr = utt->conf.ipaddr;
667 uint16_t port = utt->conf.port;
668 bool dgram = (utt->conf.socket_type == SOCK_DGRAM);
669
670 /*
671 * The items are not marked as required, because a client has no
672 * listening socket, and so needs neither of them.
673 */
674 if ((ipaddr.af == AF_UNSPEC) || !port) {
675 ERROR("Both 'ipaddr' and 'port' must be set in the 'unit_test_tls' section "
676 "when listening for a connection");
677 return -1;
678 }
679
682 .socket_type = utt->conf.socket_type,
683 .transport = dgram ? "udp" : "tcp",
684 .transport_type = dgram ? FR_BIO_FD_TRANSPORT_UDP : FR_BIO_FD_TRANSPORT_TCP,
685 .server = true,
686 .src_ipaddr = ipaddr,
687 .src_port = port,
688 .backlog = 8,
689 .backlog_is_set = true,
690 .reuse_port = dgram, /* the connection's socket shares the port */
691 .async = true, /* so that accepting does not block */
692 };
693
694 utt->listen_bio = fr_bio_fd_alloc(utt, &utt->listen_cfg, 0);
695 if (!utt->listen_bio) {
696 PERROR("Failed opening %s socket", utt->conf.transport);
697 return -1;
698 }
699
701
702 INFO("Listening on %pV port %u using %s", fr_box_ipaddr(ipaddr), port, utt->conf.transport);
703 return 0;
704}
705
706/** Accept a connection, if the listening socket has one queued
707 *
708 * @return
709 * - 1 if a connection was accepted.
710 * - 0 if no connection is queued.
711 * - -1 on error.
712 */
714{
715 int fd, rcode;
716
717 /*
718 * A datagram socket is not listening, so there is nothing to
719 * accept. The first ClientHello names the peer, and the
720 * connection runs on a second socket which is connect()ed to
721 * that peer: the kernel then delivers that peer's datagrams to
722 * the connected socket in preference to this one, and read()
723 * and write() work as they do on a stream.
724 *
725 * The connection cannot run on this socket. connect() is a
726 * property of the socket rather than of the descriptor, so
727 * connecting this one, or any descriptor duplicated from it,
728 * would leave the listening socket bound to one peer for the
729 * rest of the program.
730 */
731 if (utt->conf.socket_type == SOCK_DGRAM) {
732 uint8_t buf[FR_TLS_MAX_PACKET_SIZE];
733 ssize_t slen;
734
735 /*
736 * fr_bio_fd_accept() takes the first datagram of a peer as a connection: it opens
737 * a socket which is connect()ed to that peer, and the kernel then delivers that
738 * peer's datagrams to the connected socket in preference to the listening socket.
739 * The datagram which named the peer is no longer in the socket, and the first read
740 * of the new bio returns the datagram. The program reads the datagram now,
741 * because the datagram decides whether there is a connection at all.
742 *
743 * It is given to the connection once the connection is running, see
744 * _tls_connection_start().
745 */
746 for (;;) {
747 int accepted = fr_bio_fd_accept(utt, &utt->fd_bio, utt->listen_bio);
748
749 if (accepted == 0) return 0;
750
751 if (accepted < 0) {
752 PERROR("Failed accepting the first datagram");
753 return -1;
754 }
755
756 slen = fr_bio_read(utt->fd_bio, NULL, buf, sizeof(buf));
757 if (slen < 0) {
758 PERROR("Failed reading the first datagram");
759 TALLOC_FREE(utt->fd_bio);
760 return -1;
761 }
762
763 /*
764 * Filter input packets by ClientHello.
765 *
766 * Even if we connect() sockets, the connected socket could go away. Packets for
767 * that (old) socket are then received by the original accept socket. We don't
768 * know what to do with them, as the DTLS session goes away when the socket goes
769 * away.
770 *
771 * The main accept socket doesn't read its FD while the DTLS session is
772 * running, so packets might pile up here. This is only a problem for
773 * unit_test_bio, as a real server would keep reading the accept socket.
774 *
775 * A server which takes one of those old datagrams as a new connection request
776 * will try to start a connection to a peer which has already gone. The real
777 * peer's handshake stays queued here, and the handshake never completes.
778 *
779 * The solution (hack) is to just discard anything that doesn't look like a
780 * ClientHello.
781 *
782 * A ClientHello is a handshake record in epoch 0 whose first message is a
783 * client_hello. RFC 6347 Section 4.1 gives the record header, which is
784 * DTLS1_RT_HEADER_LENGTH octets of type, version, epoch, sequence number, and
785 * length. Section 4.3.2 gives the handshake message types. A discarded
786 * datagram looks to the peer like a lost datagram, and the peer retransmits, see
787 * Section 4.2.4.
788 */
789 if ((slen > (ssize_t) DTLS1_RT_HEADER_LENGTH) &&
790 (buf[0] == SSL3_RT_HANDSHAKE) &&
791 (buf[3] == 0) && (buf[4] == 0) &&
792 (buf[DTLS1_RT_HEADER_LENGTH] == SSL3_MT_CLIENT_HELLO)) break;
793
794 DEBUG2("Discarding a %zd byte datagram which does not start a connection", slen);
795 TALLOC_FREE(utt->fd_bio);
796 }
797
798 MEM(utt->first = talloc_memdup(utt, buf, (size_t) slen));
799 utt->first_len = (size_t) slen;
800
801 utt->fd = fr_bio_fd_info(utt->fd_bio)->socket.fd;
802
803 return 1;
804 }
805
806 rcode = fr_bio_fd_accept(utt, &utt->fd_bio, utt->listen_bio);
807 if (rcode == 0) return 0;
808
809 if (rcode < 0) {
810 PERROR("Failed accepting connection");
811 return -1;
812 }
813
814 fd = fr_bio_fd_info(utt->fd_bio)->socket.fd;
815
816 /*
817 * Some systems give the accepted socket the O_NONBLOCK flag of
818 * the listening socket, and some don't. Set the flag to what
819 * -B asks for.
820 */
821 if (utt->nonblock ? (fr_nonblock(fd) < 0) : (fr_blocking(fd) < 0)) {
822 PERROR("Failed setting the connection socket mode");
823 TALLOC_FREE(utt->fd_bio);
824 return -1;
825 }
826
827 utt->fd = fd;
828
829 return 1;
830}
831
832/** Accept the connection once the listening socket is readable
833 *
834 */
835static void _tls_socket_accept(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
836{
837 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
838
839 if (tls_socket_accept_one(utt) == 0) return;
840
842}
843
844/** Stop waiting for a connection if the listening socket fails
845 *
846 */
847static void _tls_socket_error(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, UNUSED void *uctx)
848{
849 ERROR("Listening socket failed: %s", fr_syserror(fd_errno));
850
852}
853
854/** Start waiting for a connection, from inside the event loop
855 *
856 * See tls_connection_run() for why this runs from inside the event loop.
857 */
859{
860 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
861
862 /*
863 * The command exited before this connection, so the only
864 * connection which can arrive is one already queued.
865 */
866 if (utt->command_exited) {
867 if (tls_socket_accept_one(utt) == 0) ERROR("The command exited without connecting");
868
870 return;
871 }
872
873 if (fr_event_fd_insert(utt, &utt->accept_ef, el, utt->sockfd,
874 _tls_socket_accept, NULL, _tls_socket_error, utt) < 0) {
875 PERROR("Failed adding the listening socket to the event loop");
877 }
878}
879
880/** Wait for a connection, or for the command started by -e to exit without connecting
881 *
882 * @return
883 * - 0 with utt->fd set to the accepted connection.
884 * - -1 on failure.
885 */
887{
888 fr_event_user_t *ev = NULL;
889
890 INFO("Waiting for a connection");
891
892 if (fr_event_user_insert(utt, utt->el, &ev, true, _tls_socket_accept_start, utt) < 0) {
893 PERROR("Failed scheduling the wait for a connection");
894 return -1;
895 }
896
897 utt->accepting = true;
898 (void) fr_event_loop(utt->el);
899 utt->accepting = false;
900
901 if (utt->accept_ef) {
903 utt->accept_ef = NULL;
904 }
905 TALLOC_FREE(ev);
906
907 return utt->fd_bio ? 0 : -1;
908}
909
910/** Record that the command started by -e has exited
911 *
912 * If the server is waiting for a connection, a command which exits has either
913 * connected already, and the connection is queued, or never will.
914 */
915static void _tls_command_exit(fr_event_list_t *el, pid_t pid, int status, void *uctx)
916{
917 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
918
919 utt->command_exited = true;
920
921 if (WIFEXITED(status)) {
922 INFO("Command (PID %ld) exited with status %d", (long)pid, WEXITSTATUS(status));
923 } else if (WIFSIGNALED(status)) {
924 INFO("Command (PID %ld) was killed by signal %d", (long)pid, WTERMSIG(status));
925 }
926
927 if (utt->accepting) {
928 if (tls_socket_accept_one(utt) == 0) ERROR("The command exited without connecting");
929
931 return;
932 }
933
935}
936
937/** Start the command named by -e
938 *
939 * A server starts the command once it is listening. A command which connects
940 * to the server connects to a socket which is already listening, so it can't
941 * be refused, and the server sees the command exit, so it never waits for a
942 * peer which has gone.
943 *
944 * A client starts the command once its first connection succeeds.
945 */
946static int tls_command_start(unit_test_bio_t *utt, char const *command)
947{
948 pid_t pid;
949 sigset_t set;
950
951 pid = fork();
952 if (pid < 0) {
953 ERROR("Failed forking the command: %s", fr_syserror(errno));
954 return -1;
955 }
956
957 if (pid == 0) {
958 /*
959 * Only async-signal-safe calls between fork() and exec.
960 * The command gets neither of our sockets, so the peer
961 * sees the connection close when we close it, and it
962 * gets an empty signal mask, not ours.
963 *
964 * Only close() the fds. Freeing the listen bio would
965 * shutdown() the listening socket, which is shared
966 * with the parent after fork().
967 */
968 if (utt->sockfd >= 0) close(utt->sockfd);
969 if (utt->fd >= 0) close(utt->fd);
970 sigemptyset(&set);
971 sigprocmask(SIG_SETMASK, &set, NULL);
972 execl("/bin/sh", "sh", "-c", command, (char *)NULL);
973 _exit(127);
974 }
975
976 INFO("Started command (PID %ld): %s", (long)pid, command);
977
978 utt->command_pid = pid;
979
980 if (fr_event_pid_wait(utt, utt->el, &utt->command_ev, pid, _tls_command_exit, utt) < 0) {
981 PERROR("Failed waiting for the command to exit");
982 return -1;
983 }
984
985 return 0;
986}
987
988/** Wait for the command started by -e to exit, so its output is complete
989 *
990 */
992{
993 if (!utt->command_pid || utt->command_exited) return;
994
995 utt->command_waiting = true;
996 (void) fr_event_loop(utt->el);
997 utt->command_waiting = false;
998}
999
1000/** Connect to the server named by -s
1001 *
1002 * With -B the fd bio connects without blocking, and the TLS bio waits for
1003 * the connect in the event loop.
1004 */
1006{
1008
1009 fr_inet_ntop(buffer, sizeof(buffer), &utt->server_ipaddr);
1010
1011 utt->fd_cfg = (fr_bio_fd_config_t) {
1013 .socket_type = utt->conf.socket_type,
1014 .transport = (utt->conf.socket_type == SOCK_DGRAM) ? "udp" : "tcp",
1015 .transport_type = (utt->conf.socket_type == SOCK_DGRAM) ?
1017 .dst_ipaddr = utt->server_ipaddr,
1018 .dst_port = utt->server_port,
1019 .async = utt->nonblock,
1020 };
1021
1022 utt->fd_bio = fr_bio_fd_alloc(utt, &utt->fd_cfg, 0);
1023 if (!utt->fd_bio) {
1024 PERROR("Failed connecting to %s port %u", buffer, utt->server_port);
1025 return -1;
1026 }
1027
1028 utt->fd = fr_bio_fd_info(utt->fd_bio)->socket.fd;
1029
1030 INFO("Opened a connection to %s port %u on fd %d", buffer, utt->server_port, utt->fd);
1031
1032 return 0;
1033}
1034
1035/** Build an internal client.
1036 *
1037 * unit_test_tls accepts packets from anywhere (for now), and doesn't read "client" configuration sections.
1038 *
1039 * The client is built by allocating a CONF_SECTION rather than by filling in #fr_client_t manually, which
1040 * allows fields to be examined by `%request.client()`.
1041 *
1042 * "proto = tls" sets both the protocol and tls_required. It also fixes the
1043 * secret at "radsec", so that is the secret set here.
1044 */
1045static fr_client_t *tls_client_alloc(TALLOC_CTX *ctx, fr_ipaddr_t const *ipaddr)
1046{
1047 CONF_SECTION *cs;
1048 fr_client_t *client;
1050
1051 /*
1052 * Written without a prefix, the way a person would write it in
1053 * a "client" section. The "ipaddr" item is a COMBO_IP_PREFIX,
1054 * so a bare host address parses as a /32 or a /128.
1055 */
1056 fr_inet_ntop(buffer, sizeof(buffer), ipaddr);
1057
1058 MEM(cs = cf_section_alloc(ctx, NULL, "client", "unit_test_tls"));
1060 MEM(cf_pair_alloc(cs, "proto", "tls", T_OP_EQ, T_BARE_WORD, T_BARE_WORD));
1061 MEM(cf_pair_alloc(cs, "secret", "radsec", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING));
1062 MEM(cf_pair_alloc(cs, "shortname", "unit_test_tls", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING));
1063 MEM(cf_pair_alloc(cs, "nas_type", "test", T_OP_EQ, T_BARE_WORD, T_DOUBLE_QUOTED_STRING));
1064
1065 client = client_afrom_cs(ctx, cs, NULL, 0);
1066 if (!client) {
1067 PERROR("Failed creating the client for %s", buffer);
1068 talloc_free(cs);
1069 return NULL;
1070 }
1071
1072 /*
1073 * The client has to outlive the section it was built from,
1074 * because %request.client() reads the section.
1075 */
1076 talloc_steal(client, cs);
1077
1078 return client;
1079}
1080
1081/** Build the request the handshake runs under
1082 *
1083 * The TLS code reads the control list for TLS-Session-Cert-File and
1084 * TLS-Session-Require-Client-Certificate, and writes the negotiated version
1085 * and cipher suite into the session-state list, so a real request is needed.
1086 */
1087static request_t *tls_request_alloc(TALLOC_CTX *ctx, fr_bio_t *fd_bio, int socket_type)
1088{
1089 fr_bio_fd_info_t const *info = fr_bio_fd_info(fd_bio);
1090 int fd = info->socket.fd;
1092 struct sockaddr_storage sa;
1093 socklen_t salen;
1094
1095 static uint64_t number = 0;
1096
1098 if (!request) return NULL;
1099
1100 if (!request->packet) request->packet = fr_packet_alloc(request, false);
1101 if (!request->reply) request->reply = fr_packet_alloc(request, false);
1102
1103 request->packet->timestamp = fr_time();
1104
1105 request->packet->socket.type = socket_type;
1106 request->packet->socket.fd = fd;
1107
1108 /*
1109 * A stream socket which is still connecting has no peer yet, so
1110 * the fd bio gives the address which the socket is connecting to.
1111 */
1112 salen = sizeof(sa);
1113 if (getpeername(fd, (struct sockaddr *) &sa, &salen) == 0) {
1114 (void) fr_ipaddr_from_sockaddr(&request->packet->socket.inet.src_ipaddr,
1115 &request->packet->socket.inet.src_port, &sa, salen);
1116 } else {
1117 request->packet->socket.inet.src_ipaddr = info->socket.inet.dst_ipaddr;
1118 request->packet->socket.inet.src_port = info->socket.inet.dst_port;
1119 }
1120 request->packet->socket.af = request->packet->socket.inet.src_ipaddr.af;
1121
1122 salen = sizeof(sa);
1123 if (getsockname(fd, (struct sockaddr *) &sa, &salen) == 0) {
1124 (void) fr_ipaddr_from_sockaddr(&request->packet->socket.inet.dst_ipaddr,
1125 &request->packet->socket.inet.dst_port, &sa, salen);
1126 }
1127
1128 /*
1129 * The client is the far end of the connection we just accepted.
1130 */
1131 request->client = tls_client_alloc(request, &request->packet->socket.inet.src_ipaddr);
1132 if (!request->client) {
1134 return NULL;
1135 }
1136
1137 request->number = number++;
1138 request->name = talloc_typed_asprintf(request, "%" PRIu64, request->number);
1139 request->master_state = REQUEST_ACTIVE;
1140
1141 request->log.dst = talloc_zero(request, log_dst_t);
1142 request->log.dst->func = vlog_request;
1143 request->log.dst->uctx = &default_log;
1144 request->log.dst->lvl = fr_debug_lvl;
1145
1146 request->log.lvl = fr_debug_lvl;
1147 request->async = talloc_zero(request, fr_async_t);
1148 request->async->request = request;
1149
1150 if (fr_packet_pairs_from_packet(request->request_ctx, &request->request_pairs, request->packet) < 0) {
1151 ERROR("Failed converting connection addresses to attributes");
1153 return NULL;
1154 }
1155
1156 return request;
1157}
1158
1159/** Start the TLS bio, from inside the event loop
1160 *
1161 * See tls_connection_run() for why this runs from inside the event loop.
1162 * The TLS bio adds the fd to the event loop, runs the handshake, and calls
1163 * tls_bio_connected() or tls_bio_failed().
1164 */
1166{
1167 unit_test_bio_t *utt = talloc_get_type_abort(uctx, unit_test_bio_t);
1168
1169 if (fr_bio_tls_connect(utt->bio) < 0) {
1170 PERROR("Failed starting the TLS connection");
1171 tls_request_failed(utt);
1172 return;
1173 }
1174
1175 /*
1176 * A datagram connection starts with a datagram which was read
1177 * from the listening socket, because that is what named the
1178 * peer. The connection's socket never saw it, so hand it over
1179 * now that there is a connection to hand it to.
1180 */
1181 if (utt->first && !utt->done) {
1182 uint8_t *first = utt->first;
1183 size_t first_len = utt->first_len;
1184
1185 utt->first = NULL;
1186 utt->first_len = 0;
1187
1188 DEBUG3("Handing the connection the %zu byte datagram which named the peer", first_len);
1189 fr_tls_connection_recv(utt->conn, first, first_len);
1190 talloc_free(first);
1191 }
1192}
1193
1194/** Run one connection from the first byte to the last
1195 *
1196 * Everything which belongs to a single connection is allocated here and freed
1197 * again at the end, so that the next connection starts clean. What survives
1198 * is what the cache needs: the interpreter, the modules, and so the sessions
1199 * a policy stored.
1200 *
1201 * The program opens the fd bio, allocates the request, and allocates the TLS
1202 * bio from the request. The TLS bio does the rest.
1203 */
1205{
1206 int ret = -1;
1207 fr_event_user_t *ev = NULL;
1208 request_t *stale;
1209
1210 utt->connections++;
1211
1212 utt->done = false;
1213 utt->connected = false;
1214 utt->ret = EXIT_SUCCESS;
1215 utt->fd = -1;
1216
1217 /*
1218 * Get a connection, one way or the other.
1219 */
1220 if (utt->client) {
1221 if (tls_socket_connect(utt) < 0) return -1;
1222
1223 if (utt->command && !utt->command_pid && (tls_command_start(utt, utt->command) < 0)) goto finish;
1224 } else {
1225 if (tls_socket_accept(utt) < 0) return -1;
1226 }
1227
1228 utt->request = tls_request_alloc(utt, utt->fd_bio, utt->conf.socket_type);
1229 if (!utt->request) goto finish;
1230
1231 unlang_interpret_set(utt->request, utt->intp);
1232
1233 utt->bio = fr_bio_tls_alloc(utt->request, utt->fd_bio, utt->ssl_ctx, utt->client,
1235 if (!utt->bio) {
1236 PERROR("Failed creating the TLS bio");
1237 goto finish;
1238 }
1239
1240 utt->conn = fr_bio_tls_conn(utt->bio);
1241
1242 ((fr_bio_t *) utt->bio)->uctx = utt;
1244 .connected = tls_bio_connected,
1245 .failed = tls_bio_failed,
1246 });
1247
1248 /*
1249 * Name the connection for the log. Only the application knows
1250 * what identifies a connection, which is why the library does
1251 * not do this itself.
1252 */
1253 {
1254 fr_socket_t *socket = &utt->request->packet->socket;
1255
1256 utt->conn->name = fr_asprintf(utt->conn, "%s from %pV:%u to %pV:%u",
1257 (socket->type == SOCK_DGRAM) ? "DTLS" : "TLS",
1258 fr_box_ipaddr(socket->inet.src_ipaddr), socket->inet.src_port,
1259 fr_box_ipaddr(socket->inet.dst_ipaddr), socket->inet.dst_port);
1260 if (!utt->conn->name) goto finish;
1261
1262 DEBUG2("Connection is %s", utt->conn->name);
1263 }
1264
1265 if (!utt->client) {
1266 INFO("Accepted connection from %pV on fd %d",
1267 fr_box_ipaddr(utt->request->packet->socket.inet.src_ipaddr), utt->fd);
1268 }
1269
1270 if (fr_event_post_insert(utt->el, _tls_runnable, utt) < 0) {
1271 PERROR("Failed adding the runnable handler to the event loop");
1272 goto finish;
1273 }
1274
1275 /*
1276 * The connection is started from inside the event loop rather
1277 * than here. Ending the previous connection left the loop
1278 * flagged as exiting, and fr_event_fd_insert() refuses to add a
1279 * socket to a loop in that state. fr_event_loop() clears the
1280 * flag as it starts, so a user event which fires immediately is
1281 * the first point at which the TLS bio can add the socket.
1282 */
1283 if (fr_event_user_insert(utt, utt->el, &ev, true, _tls_connection_start, utt) < 0) {
1284 PERROR("Failed scheduling the start of the connection");
1285 goto finish;
1286 }
1287
1288 (void) fr_event_loop(utt->el);
1289
1290 ret = 0;
1291
1292finish:
1293 (void) fr_event_post_delete(utt->el, _tls_runnable, utt);
1294 if (utt->fd >= 0) (void) fr_event_fd_delete(utt->el, utt->fd, FR_EVENT_FILTER_IO);
1295
1296 /*
1297 * The user event is allocated in utt, which outlives the event
1298 * list. The destructor of the user event removes it from the
1299 * event list, so free it while the event list still exists.
1300 */
1301 TALLOC_FREE(ev);
1302
1303 /*
1304 * Freeing the TLS bio cancels the request, which unwinds the
1305 * connection frame, and then frees the connection. The fd bio
1306 * closes the socket.
1307 */
1308 utt->conn = NULL;
1309 TALLOC_FREE(utt->bio);
1310 TALLOC_FREE(utt->fd_bio);
1311
1312 /*
1313 * Empty the heap before the requests on it are freed. Popping
1314 * clears each entry's index, so nothing is left pointing at
1315 * memory the request pool is about to hand out again.
1316 */
1317 while (fr_heap_pop((void **)&stale, &utt->runnable) == 0) {
1318 if (!stale) break;
1319 }
1320 utt->yielded = 0;
1321
1322 TALLOC_FREE(utt->request);
1323 TALLOC_FREE(utt->first);
1324 utt->fd = -1;
1325
1326 return ret;
1327}
1328
1329/** Turn a comma separated list of names into the wire format ALPN uses
1330 *
1331 * Each name becomes one length octet followed by the name. There is no
1332 * terminator, so the caller takes the length from the array itself.
1333 *
1334 * @param[in] ctx to allocate in.
1335 * @param[in] names comma separated, in order of preference.
1336 * @return
1337 * - the list, whose talloc array length is the length of the list.
1338 * - NULL if a name is empty or longer than 255 octets.
1339 */
1340static unsigned char *tls_alpn_build(TALLOC_CTX *ctx, char const *names)
1341{
1342 unsigned char *alpn, *p;
1343 char const *q;
1344 size_t len;
1345
1346 /*
1347 * One length octet per name, and the names themselves. The
1348 * separators become those length octets, and the first name has
1349 * no separator before it, so one more octet than the string.
1350 */
1351 MEM(alpn = talloc_zero_array(ctx, unsigned char, strlen(names) + 1));
1352 p = alpn;
1353
1354 for (q = names; *q != '\0'; q += len) {
1355 len = strcspn(q, ",");
1356 if ((len == 0) || (len > 255)) {
1357 ERROR("Each ALPN protocol name must be between 1 and 255 characters");
1358 talloc_free(alpn);
1359 return NULL;
1360 }
1361
1362 *p++ = (unsigned char) len;
1363 memcpy(p, q, len);
1364 p += len;
1365
1366 if (q[len] == ',') len++; /* step over the separator */
1367 }
1368
1369 /*
1370 * A trailing separator, or a repeated one, leaves the array
1371 * longer than what was written into it. Shrink it so the array
1372 * length is the length of the list.
1373 */
1374 MEM(alpn = talloc_realloc(ctx, alpn, unsigned char, (size_t) (p - alpn)));
1375
1376 return alpn;
1377}
1378
1379int main(int argc, char *argv[])
1380{
1381 int ret = EXIT_SUCCESS;
1382 int c;
1383 char const *receipt_file = NULL;
1384 char const *command = NULL;
1385 char const *server = NULL;
1386 unsigned int count = 1;
1387 bool alert = false;
1388 bool invalid = false;
1389 bool nonblock = false;
1390 bool reject = false;
1391 bool network_fail = false;
1392 bool abort_pending = false;
1393 bool app_data = false;
1394 bool delay_tickets = false;
1395 bool hold = false;
1396 bool client = false;
1397 char const *alpn_names = NULL;
1398 bool alpn_required = false;
1399 unsigned int i;
1400
1401 TALLOC_CTX *autofree;
1402 TALLOC_CTX *thread_ctx;
1403
1404 char *p;
1406
1407 fr_dict_t *dict = NULL;
1408 fr_dict_t const *dict_check;
1409
1410 virtual_server_t const *vs;
1411 CONF_SECTION *utt_cs;
1412
1413 unit_test_bio_t *utt = NULL;
1414 fr_tls_conf_t *conf = NULL;
1415
1416 /*
1417 * Must be called first, so the handler is called last
1418 */
1420
1422 thread_ctx = talloc_new(autofree);
1423
1425 if (!config) {
1426 fr_perror("unit_test_bio");
1427 fr_exit_now(EXIT_FAILURE);
1428 }
1429
1430 p = strrchr(argv[0], FR_DIR_SEP);
1431 if (!p) {
1432 main_config_name_set_default(config, argv[0], false);
1433 } else {
1434 main_config_name_set_default(config, p + 1, false);
1435 }
1436
1438
1439 if (fr_fault_setup(autofree, getenv("PANIC_ACTION"), argv[0], PANIC_ACTION_SIGNALS) < 0) {
1440 fr_perror("%s", config->name);
1441 fr_exit_now(EXIT_FAILURE);
1442 }
1443#ifdef NDEBUG
1445#endif
1446
1447 fr_debug_lvl = 0;
1448 fr_time_start();
1449
1450 /*
1451 * The tests should have only IPs, not host names.
1452 */
1454
1455 /*
1456 * We always log to stdout.
1457 */
1459 default_log.fd = STDOUT_FILENO;
1460 default_log.print_level = true;
1461
1462 /* Process the options. */
1463 while ((c = getopt(argc, argv, "ABc:Cd:D:e:hHIlL:Mn:NPQr:Rs:TxX")) != -1) {
1464 switch (c) {
1465 case 'A':
1466 alert = true;
1467 break;
1468
1469 case 'B':
1470 nonblock = true;
1471 break;
1472
1473 case 'N':
1474 network_fail = true;
1475 break;
1476
1477 case 'R':
1478 reject = true;
1479 break;
1480
1481 case 'Q':
1482 abort_pending = true;
1483 break;
1484
1485 case 'c':
1486 count = (unsigned int) atoi(optarg);
1487 if (!count) {
1488 fprintf(stderr, "Invalid value \"%s\" for -c\n", optarg);
1489 fr_exit_now(EXIT_FAILURE);
1490 }
1491 break;
1492
1493 case 'C':
1494 check_config = true;
1495 break;
1496
1497 case 'd':
1499 break;
1500
1501 case 'D':
1503 break;
1504
1505 case 'h':
1506 usage(config, EXIT_SUCCESS);
1507 break;
1508
1509 case 'I':
1510 invalid = true;
1511 break;
1512
1513 case 'l':
1514 alpn_required = true;
1515 break;
1516
1517 case 'L':
1518 alpn_names = optarg;
1519 break;
1520
1521 case 'M':
1522 talloc_enable_leak_report();
1523 break;
1524
1525 case 'n':
1526 config->name = optarg;
1527 break;
1528
1529 case 'H':
1530 hold = true;
1531 break;
1532
1533 case 'P':
1534 app_data = true;
1535 break;
1536
1537 case 'T':
1538 delay_tickets = true;
1539 break;
1540
1541 case 'e':
1542 command = optarg;
1543 break;
1544
1545 case 'r':
1546 receipt_file = optarg;
1547 break;
1548
1549 case 's':
1550 server = optarg;
1551 break;
1552
1553 case 'X':
1554 fr_debug_lvl += 2;
1555 default_log.print_level = true;
1556 break;
1557
1558 case 'x':
1559 fr_debug_lvl++;
1560 if (fr_debug_lvl > 2) default_log.print_level = true;
1561 break;
1562
1563 default:
1564 usage(config, EXIT_FAILURE);
1565 break;
1566 }
1567 }
1568
1569 if (receipt_file && (fr_unlink(receipt_file) < 0)) {
1570 fr_perror("%s", config->name);
1572 }
1573
1574 /*
1575 * A mismatch between the OpenSSL headers used at build time and the
1576 * linked OpenSSL library makes this program exit now, rather than
1577 * crash later.
1578 */
1580
1581 /*
1582 * fr_openssl_init() must be called before *ANY* OpenSSL functions are
1583 * used, which is why
1584 * fr_openssl_init() is called so early.
1585 */
1586 if (fr_openssl_init() < 0) EXIT_WITH_FAILURE;
1587
1589
1590 /*
1591 * Mismatch between the binary and the libraries it links against
1592 */
1594 fr_perror("%s", config->name);
1596 }
1597
1598 /*
1599 * Initialise the dynamic loader infrastructure, which the config
1600 * file parser uses.
1601 */
1602 modules_init(config->lib_dir);
1603
1604 if (!fr_dict_global_ctx_init(NULL, true, config->dict_dir)) {
1605 fr_perror("%s", config->name);
1607 }
1608
1610 fr_perror("%s", config->name);
1612 }
1613
1614 if (fr_tls_dict_init() < 0) EXIT_WITH_FAILURE;
1615
1616 /*
1617 * Load the custom dictionary
1618 */
1619 if (fr_dict_read(dict, config->confdir, FR_DICTIONARY_FILE) == -1) {
1620 PERROR("Failed to initialize the dictionaries");
1622 }
1623
1625 fr_perror("%s", config->name);
1627 }
1628
1629 if (request_global_init() < 0) {
1630 fr_perror("%s", config->name);
1632 }
1633
1634 /*
1635 * The triggers are run-time expansions, so the triggers need the
1636 * main event loop.
1637 */
1638 if (main_loop_init() < 0) {
1639 PERROR("Failed initialising main event loop");
1641 }
1642
1643 if (unlang_global_init() < 0) {
1644 fr_perror("%s", config->name);
1646 }
1647
1648 if (modules_rlm_init() < 0) {
1649 fr_perror("%s", config->name);
1651 }
1652
1653 if (virtual_servers_init() < 0) {
1654 fr_perror("%s", config->name);
1656 }
1657
1659
1660 /*
1661 * The TLS bio writes a close_notify alert when the bio closes, and the peer may have closed the
1662 * socket already. The write must fail with an error, as it does in radiusd, and must not kill
1663 * the process.
1664 */
1665#ifdef SIGPIPE
1666 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
1667 fr_perror("%s: Failed ignoring SIGPIPE", config->name);
1669 }
1670#endif
1671
1672 MEM(utt = talloc_zero(autofree, unit_test_bio_t));
1673 utt->sockfd = utt->fd = -1;
1674 utt->ret = EXIT_SUCCESS;
1675 utt->count = count;
1676 utt->alert = alert;
1677 utt->invalid = invalid;
1678 utt->nonblock = nonblock;
1679 utt->app_data = app_data;
1680 utt->hold = hold;
1681 utt->reject = reject;
1682 utt->network_fail = network_fail;
1683 utt->abort_pending = abort_pending;
1684
1685
1686 /*
1687 * Bootstrap and instantiate the virtual servers and the modules
1688 * that the virtual servers use. The TLS subsections name a
1689 * virtual server, so server_init() has to run before
1690 * cf_section_parse() reads the `unit_test_tls` section.
1691 */
1692 if (server_init(config->root_cs, config->confdir, dict) < 0) EXIT_WITH_FAILURE;
1693
1694 vs = virtual_server_find("tls");
1695 if (!vs) {
1696 ERROR("Cannot find virtual server 'tls'");
1698 }
1699
1700 dict_check = virtual_server_dict_by_name("tls");
1701 if (!dict_check || !fr_dict_compatible(dict_check, dict_tls)) {
1702 ERROR("Virtual server 'tls' must have 'namespace = tls'");
1704 }
1705
1706 /*
1707 * Parse the settings that steer the test program, with the TLS
1708 * configuration for each role as a subsection. The TLS rows
1709 * resolve the `virtual_server` item through
1710 * virtual_server_cf_parse(), so server_init() had to run first.
1711 * cf_section_parse_pass2() then resolves the expansions in the
1712 * TLS subsections.
1713 */
1714 utt_cs = cf_section_find(config->root_cs, "unit_test_tls", NULL);
1715 if (!utt_cs) {
1716 ERROR("Cannot find a top-level 'unit_test_tls { ... }' section in %s.conf", config->name);
1718 }
1719
1721
1722 if ((cf_section_parse(utt, &utt->conf, utt_cs) < 0) ||
1723 (cf_section_parse_pass2(&utt->conf, utt_cs) < 0)) {
1724 cf_log_perr(utt_cs, "Failed parsing the 'unit_test_tls' section");
1726 }
1727
1728 /*
1729 * Resolve `transport` into the socket it names, and into the
1730 * socket type which the TLS configuration below is given.
1731 */
1732 if (strcmp(utt->conf.transport, "tcp") == 0) {
1733 utt->conf.socket_type = SOCK_STREAM;
1734 utt->conf.ipaddr = utt->conf.tcp.ipaddr;
1735 utt->conf.port = utt->conf.tcp.port;
1736
1737 } else if (strcmp(utt->conf.transport, "udp") == 0) {
1738 utt->conf.socket_type = SOCK_DGRAM;
1739 utt->conf.ipaddr = utt->conf.udp.ipaddr;
1740 utt->conf.port = utt->conf.udp.port;
1741
1742 } else {
1743 cf_log_err(utt_cs, "Invalid transport name \"%s\", expected \"tcp\" or \"udp\"",
1744 utt->conf.transport);
1746 }
1747
1748 /*
1749 * -s turns the program around: instead of listening for a
1750 * connection, it makes one.
1751 */
1752 if (server) {
1753 utt->client = client = true;
1754
1755 if (fr_inet_pton_port(&utt->server_ipaddr, &utt->server_port, server,
1756 -1, AF_UNSPEC, true, false) < 0) {
1757 PERROR("Invalid value \"%s\" for -s", server);
1759 }
1760
1761 /*
1762 * fr_inet_pton_port() clears the port before it starts,
1763 * so a missing port is zero here, and not the default.
1764 */
1765 if (!utt->server_port) utt->server_port = utt->conf.port;
1766
1767 if (!utt->server_port) {
1768 ERROR("No port given in -s, and no 'port' in the 'unit_test_tls' section");
1770 }
1771 }
1772
1773 if (utt->conf.drop_datagram) {
1774 cf_log_err(utt_cs, "'drop_datagram' is not supported by unit_test_bio, use unit_test_tls");
1776 }
1777
1778 conf = client ? utt->conf.client : utt->conf.server;
1779 if (!conf) {
1780 cf_log_err(utt_cs, "Cannot run as %s, the 'unit_test_tls' section has no '%s { ... }' subsection",
1781 client ? "client" : "server", client ? "client" : "server");
1783 }
1784
1785 conf->delayed_tickets = delay_tickets;
1786
1787 /*
1788 * ALPN is not parsed from the configuration file. The library
1789 * leaves the protocol list to the application, so set it here,
1790 * after the TLS configuration is parsed and before the context
1791 * is built from it. See src/lib/tls/alpn.c.
1792 */
1793 if (alpn_names) {
1794 utt->alpn = tls_alpn_build(utt, alpn_names);
1795 if (!utt->alpn) EXIT_WITH_FAILURE;
1796
1797 conf->alpn = utt->alpn;
1798 conf->sizeof_alpn = talloc_array_length(utt->alpn);
1799 }
1800 conf->alpn_required = alpn_required;
1801
1802 /*
1803 * The transport is set by the application for the same reason
1804 * the ALPN strings are: one `tls { ... }` section is parsed by
1805 * the same rules everywhere, and only the application knows
1806 * what it opened the socket as.
1807 */
1808 conf->socket_type = utt->conf.socket_type;
1809
1810 utt->ssl_ctx = fr_tls_ctx_alloc(conf, client);
1811 if (!utt->ssl_ctx) {
1812 cf_log_perr(utt_cs, "Failed creating the TLS context");
1814 }
1815
1816 /*
1817 * The configuration parsed without error, so exit with success.
1818 */
1819 if (check_config) {
1820 DEBUG("Configuration appears to be OK");
1821 goto cleanup;
1822 }
1823
1824 utt->el = main_loop_event_list();
1825 fr_assert(utt->el != NULL);
1826
1827
1829
1830 /*
1831 * Simulate thread-specific instantiation
1832 */
1834 if (fr_thread_instantiate(thread_ctx, utt->el) < 0) {
1835 fr_perror("%s", config->name);
1837 }
1838
1839 if (modules_rlm_coord_attach(utt->el) < 0) {
1840 fr_perror("%s", config->name);
1842 }
1843
1844 if (fr_coord_pre_event_insert(utt->el) < 0) {
1845 fr_strerror_const("Failed adding coordinator pre-check to event list");
1847 }
1848
1849 if (fr_coord_post_event_insert(utt->el) < 0) {
1850 fr_strerror_const("Failed adding coordinator post-check to event list");
1852 }
1853
1854 /*
1855 * Set the panic action (if required)
1856 */
1857 {
1858 char const *panic_action = NULL;
1859
1860 panic_action = getenv("PANIC_ACTION");
1861 if (!panic_action) panic_action = config->panic_action;
1862
1864 fr_perror("%s", config->name);
1866 }
1867 }
1868
1869 setlinebuf(stdout); /* line buffered output */
1870
1871 /*
1872 * One interpreter, one runnable heap and one request for the
1873 * whole connection. The unit_test_bio_t documentation says why.
1874 */
1875 MEM(utt->runnable = fr_heap_talloc_alloc(utt, fr_pointer_cmp, request_t, runnable, 0));
1876
1877 utt->intp = unlang_interpret_init(utt, utt->el,
1879 .init_internal = _request_init_internal,
1880
1881 .done_external = _request_done_external,
1882 .done_internal = _request_done_internal,
1883 .done_detached = _request_done_detached,
1884
1885 .detach = _request_detach,
1886 .yield = _request_yield,
1887 .resume = _request_resume,
1888 .mark_runnable = _request_runnable,
1889 .scheduled = _request_scheduled,
1890 }, utt);
1891 if (!utt->intp) {
1892 fr_perror("%s", config->name);
1894 }
1895
1896 /*
1897 * Subrequests created by the TLS code inherit the thread default,
1898 * so the thread default has to point at the connection's
1899 * interpreter.
1900 */
1902
1903 /*
1904 * A server has one listening socket for every connection it
1905 * accepts, so it is opened once, here.
1906 */
1907 if (!utt->client && (tls_socket_open(utt) < 0)) EXIT_WITH_FAILURE;
1908
1909 /*
1910 * A server starts the command once it is listening. A client
1911 * starts it once the first connection succeeds, see
1912 * tls_connection_run().
1913 */
1914 utt->command = command;
1915 if (!utt->client && command && (tls_command_start(utt, command) < 0)) EXIT_WITH_FAILURE;
1916
1917 for (i = 0; i < utt->count; i++) {
1919
1920 if (utt->ret != EXIT_SUCCESS) break;
1921 }
1922
1923 tls_command_wait(utt);
1924
1925 ret = utt->ret;
1926
1927cleanup:
1928 if (utt) {
1929 /*
1930 * tls_connection_run() cleans up everything which belongs
1931 * to one connection. What is left here is what outlives
1932 * them.
1933 */
1934 if (utt->ssl_ctx) SSL_CTX_free(utt->ssl_ctx);
1935
1936 if (utt->sockfd >= 0) close(utt->sockfd);
1937
1938 /*
1939 * A failure left the client running. The reap below
1940 * signals it if it doesn't exit by itself.
1941 */
1942 if (utt->command_pid && !utt->command_exited) {
1944 (void) fr_event_pid_reap(utt->el, utt->command_pid, NULL, NULL);
1945 }
1946 }
1947
1949
1950 /*
1951 * Detach from coordinators.
1952 */
1953 if (utt && utt->el && (modules_rlm_coord_detach() > 0)) {
1954 if (unlikely(fr_coord_close_event_insert(utt->el) < 0)) {
1955 ERROR("Failed setting up coordinator close events");
1956 }
1957 fr_event_loop(utt->el);
1958 }
1959
1960 /*
1961 * Free thread data
1962 */
1963 talloc_free(thread_ctx);
1964
1966
1968
1969 if (utt && utt->el) fr_event_list_reap_signal(utt->el, fr_time_delta_from_sec(5), SIGKILL);
1970
1972
1974
1975 server_free();
1976
1977 /*
1978 * Virtual servers need to be freed before modules
1979 * as state entries containing data with module-specific
1980 * destructors may exist.
1981 */
1983
1985
1987
1988 fr_tls_dict_free();
1989
1991
1992 if (fr_dict_free(&dict, __FILE__) < 0) {
1993 fr_perror("unit_test_bio - dict");
1994 ret = EXIT_FAILURE;
1995 }
1996
1997 fr_openssl_free();
1998
1999 if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) {
2000 fr_perror("unit_test_bio");
2001 ret = EXIT_FAILURE;
2002 }
2003
2004 if (talloc_free(autofree) < 0) {
2005 fr_perror("unit_test_bio - autofree");
2006 ret = EXIT_FAILURE;
2007 }
2008
2009 /*
2010 * Ensure our atexit handlers run before any other
2011 * atexit handlers registered by third party libraries.
2012 */
2014
2015 return ret;
2016}
2017
2018/*
2019 * Display the syntax for starting this program.
2020 */
2021static NEVER_RETURNS void usage(main_config_t const *config, int status)
2022{
2023 FILE *output = status ? stderr : stdout;
2024
2025 fprintf(output, "Usage: %s [options]\n", config->name);
2026 fprintf(output, "Options:\n");
2027 fprintf(output, " -A Reject the peer with a fatal TLS alert on the last connection,\n");
2028 fprintf(output, " rather than completing the handshake. With -c 2 the first\n");
2029 fprintf(output, " connection fills the session cache, so the alert then has a\n");
2030 fprintf(output, " session to clear. Used to test the alert and clear paths.\n");
2031 fprintf(output, " -B Put the connection socket in non-blocking mode, so that a read()\n");
2032 fprintf(output, " or a write() which would wait returns EAGAIN instead. The event\n");
2033 fprintf(output, " loop already waits for the socket to be readable or writable, so\n");
2034 fprintf(output, " this exercises the EAGAIN paths rather than changing what runs.\n");
2035 fprintf(output, " -I Mark the session invalid part way through the handshake on the\n");
2036 fprintf(output, " last connection, the way fr_tls_session_msg_cb() marks a record\n");
2037 fprintf(output, " FreeRADIUS refuses. The next round then refuses to continue, and\n");
2038 fprintf(output, " sends the peer a fatal alert saying so.\n");
2039 fprintf(output, " -R Reject the session once the handshake has succeeded on the last\n");
2040 fprintf(output, " connection, as policy would. The cached session is then cleared\n");
2041 fprintf(output, " rather than stored. With -c 2 the first connection fills the\n");
2042 fprintf(output, " cache and the second resumes from it before being rejected, so\n");
2043 fprintf(output, " the clear then has a loaded session to remove.\n");
2044 fprintf(output, " -Q Free the connection on the last connection once the handshake\n");
2045 fprintf(output, " has succeeded, while `store session` is still queued, to\n");
2046 fprintf(output, " exercise the path that discards queued cache operations.\n");
2047 fprintf(output, " -N Fail the session with a network error on the last connection,\n");
2048 fprintf(output, " once the handshake succeeds, to simulate the peer closing the\n");
2049 fprintf(output, " connection. With -c 2 the second connection loads a session\n");
2050 fprintf(output, " from the cache. A network error does not clear the loaded\n");
2051 fprintf(output, " session, and the session stays in the cache.\n");
2052 fprintf(output, " -H Once the connection is up, send nothing and hold it open.\n");
2053 fprintf(output, " A peer which is still owed a session ticket or a byte of\n");
2054 fprintf(output, " application data then waits for something which never\n");
2055 fprintf(output, " arrives, which is what exercises the post-handshake timer.\n");
2056 fprintf(output, " -c <count> Run <count> connections, one after another. Session resumption\n");
2057 fprintf(output, " needs two: one to fill the cache, one to resume from it.\n");
2058 fprintf(output, " -C Check configuration and exit.\n");
2059 fprintf(output, " -d <confdir> Configuration file directory. (defaults to " CONFDIR ").\n");
2060 fprintf(output, " -D <dict_dir> Dictionary files are in \"dict_dir/*\".\n");
2061 fprintf(output, " -e <command> Run <command> in a shell. A server runs it once it is\n");
2062 fprintf(output, " listening, so <command> can be what connects to the server,\n");
2063 fprintf(output, " such as openssl s_client. If <command> exits without\n");
2064 fprintf(output, " connecting, the server fails instead of waiting. With -s,\n");
2065 fprintf(output, " it runs once the first connection succeeds. Either way,\n");
2066 fprintf(output, " unit_test_bio waits for <command> to exit before it exits.\n");
2067 fprintf(output, " -h Print this help message.\n");
2068 fprintf(output, " -M Enable talloc leak reporting.\n");
2069 fprintf(output, " -n <name> Read ${confdir}/name.conf instead of ${confdir}/unit_test_bio.conf.\n");
2070 fprintf(output, " -P Server only. Send one byte of application data, 0x00, once the\n");
2071 fprintf(output, " handshake is done. A server sends every session ticket before\n");
2072 fprintf(output, " its first byte of application data, so this tells a client that\n");
2073 fprintf(output, " no ticket is still on its way.\n");
2074 fprintf(output, " -T Delay stateless TLS 1.3 session tickets, as EAP does. The server\n");
2075 fprintf(output, " sends none in the handshake.\n");
2076 fprintf(output, " -r <receipt_file> Create <receipt_file> when the program exits successfully.\n");
2077 fprintf(output, " -s <server[:port]> Connect to <server> as a TLS client, instead of listening\n");
2078 fprintf(output, " for a connection. Reads the 'tls client' section. The port\n");
2079 fprintf(output, " defaults to 'port' from the 'unit_test_tls' section.\n");
2080 fprintf(output, " -X Turn on full debugging.\n");
2081 fprintf(output, " -x Turn on additional debugging. (-xx gives more debugging).\n");
2082
2083 fr_exit_now(status);
2084}
static int const char char buffer[256]
Definition acutest.h:641
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:179
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:310
#define fr_atexit_thread_trigger_all(...)
Definition atexit.h:236
static ssize_t fr_bio_write(fr_bio_t *bio, void *packet_ctx, void const *buffer, size_t size)
Write raw data to a bio.
Definition base.h:184
static ssize_t fr_bio_read(fr_bio_t *bio, void *packet_ctx, void *buffer, size_t size)
Read raw data from a bio.
Definition base.h:161
void * uctx
user ctx, caller can manually set it.
Definition base.h:114
#define fr_bio_error(_x)
Definition base.h:200
fr_tls_connection_t * fr_bio_tls_conn(fr_bio_tls_t *my)
The TLS connection, so the caller can set conn->name
Definition tls.c:1082
int fr_bio_tls_connect(fr_bio_tls_t *my)
Take the connection through every state which comes before application data.
Definition tls.c:1102
fr_bio_tls_t * fr_bio_tls_alloc(request_t *request, fr_bio_t *next, SSL_CTX *ssl_ctx, bool client, bool client_cert)
Allocate a TLS bio.
Definition tls.c:1031
static uint8_t request[4]
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
Definition build.h:203
#define RCSID(id)
Definition build.h:603
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:413
#define unlikely(_x)
Definition build.h:486
#define UNUSED
Definition build.h:415
bool check_config
Definition cf_file.c:61
int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs)
Parse a configuration section into user-supplied variables.
Definition cf_parse.c:1360
int cf_section_parse_pass2(void *base, CONF_SECTION *cs)
Fixup xlat expansions and attributes.
Definition cf_parse.c:1470
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:722
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:280
@ CONF_FLAG_OK_MISSING
OK if it's missing.
Definition cf_parse.h:491
#define FR_CONF_SUBSECTION_ALLOC(_name, _flags, _struct, _field, _subcs)
conf_parser_t which allocates a struct and populates it from a subsection
Definition cf_parse.h:384
#define cf_section_rules_push(_cs, _rule)
Definition cf_parse.h:754
#define FR_CONF_OFFSET_SUBSECTION(_name, _flags, _struct, _field, _subcs)
conf_parser_t which populates a sub-struct using a CONF_SECTION
Definition cf_parse.h:309
#define FR_CONF_OFFSET_TYPE_FLAGS(_name, _type, _flags, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:238
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:649
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, fr_token_t op, fr_token_t lhs_quote, fr_token_t rhs_quote)
Allocate a CONF_PAIR.
Definition cf_util.c:1487
CONF_SECTION * cf_section_find(CONF_SECTION const *cs, char const *name1, char const *name2)
Find a CONF_SECTION with name1 and optionally name2.
Definition cf_util.c:1247
#define cf_log_err(_cf, _fmt,...)
Definition cf_util.h:340
#define cf_log_perr(_cf, _fmt,...)
Definition cf_util.h:347
#define cf_section_alloc(_ctx, _parent, _name1, _name2)
Definition cf_util.h:198
TALLOC_CTX * autofree
Definition common.c:29
fr_dict_t * dict
Definition common.c:31
int fr_coords_create(TALLOC_CTX *ctx, fr_event_list_t *el)
Start coordinators in single threaded mode.
Definition coord.c:619
void fr_coords_destroy(void)
Clean up coordinators in single threaded mode.
Definition coord.c:601
int fr_coord_close_event_insert(fr_event_list_t *el)
Definition coord.c:900
int fr_coord_post_event_insert(fr_event_list_t *el)
Insert instance specific post-event callbacks.
Definition coord.c:856
int fr_coord_pre_event_insert(fr_event_list_t *el)
Insert instance specific pre-event callbacks.
Definition coord.c:831
static char panic_action[512]
The command to execute when panicking.
Definition debug.c:66
void fr_disable_null_tracking_on_free(TALLOC_CTX *ctx)
Disable the null tracking context when a talloc chunk is freed.
Definition debug.c:1031
void fr_talloc_fault_setup(void)
Register talloc fault handlers.
Definition debug.c:1047
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program, unsigned long fault_signals)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1071
#define PANIC_ACTION_SIGNALS
Definition debug.h:133
#define MEM(x)
Definition debug.h:38
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:272
void dependency_version_print(void)
Definition dependency.c:364
#define ERROR(fmt,...)
Definition dhcpclient.c:40
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static NEVER_RETURNS void usage(void)
Definition dhcpclient.c:113
#define fr_dict_autofree(_to_free)
Definition dict.h:942
bool fr_dict_compatible(fr_dict_t const *dict1, fr_dict_t const *dict2)
See if two dictionaries have the same end parent.
Definition dict_util.c:2948
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:329
int fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename))
Read supplementary attribute definitions into an existing dictionary.
int fr_dict_free(fr_dict_t **dict, char const *dependent)
Decrement the reference count on a previously loaded dictionary.
Definition dict_util.c:4466
#define fr_dict_autoload(_to_load)
Definition dict.h:939
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:335
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir))
Initialise the global protocol hashes.
Definition dict_util.c:4850
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:328
int fr_dict_internal_afrom_file(fr_dict_t **out, char const *dict_subdir, char const *dependent)
(Re-)Initialize the special internal dictionary
#define fr_event_fd_insert(...)
Definition event.h:247
#define fr_event_pid_reap(...)
Definition event.h:274
#define fr_event_pid_wait(...)
Definition event.h:268
@ FR_EVENT_FILTER_IO
Combined filter for read/write functions/.
Definition event.h:83
#define fr_event_user_insert(_ctx, _el, _ev_p, _trigger, _callback, _uctx)
Definition event.h:281
fr_bio_t * fr_bio_fd_alloc(TALLOC_CTX *ctx, fr_bio_fd_config_t const *cfg, size_t offset)
Allocate a FD bio.
Definition fd.c:1116
int fr_bio_fd_accept(TALLOC_CTX *ctx, fr_bio_t **out_p, fr_bio_t *bio)
Accept a new connection on a socket.
Definition fd.c:1858
fr_bio_fd_info_t const * fr_bio_fd_info(fr_bio_t *bio)
Returns a pointer to the bio-specific information.
Definition fd.c:1446
fr_socket_t socket
as connected socket
Definition fd.h:145
bool eof
are we at EOF?
Definition fd.h:154
fr_bio_fd_type_t type
accept, connected, unconnected, etc.
Definition fd.h:93
@ FR_BIO_FD_CONNECTED
connected client sockets (UDP or TCP)
Definition fd.h:63
@ FR_BIO_FD_LISTEN
call fr_bio_fd_accept() for each new connection
Definition fd.h:64
@ FR_BIO_FD_TRANSPORT_TCP
TCP over IPv4 or IPv6.
Definition fd.h:79
@ FR_BIO_FD_TRANSPORT_UDP
UDP over IPv4 or IPv6.
Definition fd.h:80
Configuration for sockets.
Definition fd.h:92
Run-time status of the socket.
Definition fd.h:144
int fr_heap_insert(fr_heap_t **hp, void *data)
Insert a new element into the heap.
Definition heap.c:149
int fr_heap_pop(void **out, fr_heap_t **hp)
Remove a node from the heap.
Definition heap.c:359
static bool fr_heap_entry_inserted(fr_heap_index_t heap_idx)
Check if an entry is inserted into a heap.
Definition heap.h:126
#define fr_heap_talloc_alloc(_ctx, _cmp, _talloc_type, _field, _init)
Creates a heap that verifies elements are of a specific talloc type.
Definition heap.h:117
The main heap structure.
Definition heap.h:68
talloc_free(hp)
int fr_ipaddr_from_sockaddr(fr_ipaddr_t *ipaddr, uint16_t *port, struct sockaddr_storage const *sa, socklen_t salen)
Convert sockaddr to our internal ip address representation.
Definition inet.c:1448
bool fr_hostname_lookups
hostname -> IP lookups?
Definition inet.c:52
int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
Definition inet.c:944
char * fr_inet_ntop(char out[static FR_IPADDR_STRLEN], size_t outlen, fr_ipaddr_t const *addr)
Print the address portion of a fr_ipaddr_t.
Definition inet.c:1025
bool fr_reverse_lookups
IP -> hostname lookups?
Definition inet.c:51
#define FR_IPADDR_STRLEN
Like INET6_ADDRSTRLEN but includes space for the textual Zone ID.
Definition inet.h:89
int af
Address family.
Definition inet.h:64
IPv4/6 prefix.
rlm_rcode_t unlang_interpret(request_t *request, bool running)
Run the interpreter for a current request.
Definition interpret.c:1302
void unlang_interpret_set(request_t *request, unlang_interpret_t *intp)
Set a specific interpreter for a request.
Definition interpret.c:2759
void unlang_interpret_set_thread_default(unlang_interpret_t *intp)
Set the default interpreter for this thread.
Definition interpret.c:2790
unlang_interpret_t * unlang_interpret_init(TALLOC_CTX *ctx, fr_event_list_t *el, unlang_request_func_t *funcs, void *uctx)
Initialize a unlang compiler / interpret.
Definition interpret.c:2710
#define UNLANG_REQUEST_RESUME
Definition interpret.h:48
External functions provided by the owner of the interpret.
Definition interpret.h:116
el_self ties the lifetime of the event list to the interpreter
void fr_bio_cb_set(fr_bio_t *bio, fr_bio_cb_funcs_t const *cb)
Definition base.c:260
int server_init(CONF_SECTION *cs, char const *conf_dir, fr_dict_t *dict)
Initialize src/lib/server/.
Definition base.c:42
void server_free(void)
Free src/lib/server/.
Definition base.c:137
Describes a host allowed to send packets to the server.
Definition client.h:80
void vlog_request(fr_log_type_t type, fr_log_lvl_t lvl, request_t *request, char const *file, int line, char const *fmt, va_list ap, void *uctx)
Send a log message to its destination, possibly including fields from the request.
Definition log.c:293
#define PERROR(_fmt,...)
Definition log.h:233
#define DEBUG3(_fmt,...)
Definition log.h:271
#define RDEBUG3(fmt,...)
Definition log.h:360
#define RPEDEBUG(fmt,...)
Definition log.h:393
Definition log.h:70
int fr_packet_pairs_from_packet(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_packet_t const *packet)
Allocate a "Net." struct with src/dst host and port.
Definition packet.c:91
int unlang_global_init(void)
Definition base.c:158
int fr_event_post_delete(fr_event_list_t *el, fr_event_post_cb_t callback, void *uctx)
Delete a post-event callback from the event list.
Definition event.c:2066
#define fr_time()
Definition event.c:58
unsigned int fr_event_list_reap_signal(fr_event_list_t *el, fr_time_delta_t timeout, int signal)
Send a signal to all the processes we have in our reap list, and reap them.
Definition event.c:1719
void fr_event_loop_exit(fr_event_list_t *el, int code)
Signal an event loop exit with the specified code.
Definition event.c:2423
int fr_event_fd_delete(fr_event_list_t *el, int fd, fr_event_filter_t filter)
Remove a file descriptor from the event loop.
Definition event.c:1204
int fr_event_loop(fr_event_list_t *el)
Run an event loop.
Definition event.c:2445
int fr_event_post_insert(fr_event_list_t *el, fr_event_post_cb_t callback, void *uctx)
Add a post-event callback to the event list.
Definition event.c:2043
A file descriptor/filter event.
Definition event.c:258
Stores all information relating to an event list.
Definition event.c:375
Callbacks for kevent() user events.
Definition event.c:339
int fr_unlink(char const *filename)
Remove a regular file from the filesystem.
Definition file.c:366
ssize_t fr_touch(int *fd_out, char const *filename, mode_t mode, bool mkdir, mode_t dir_mode)
Create an empty file.
Definition file.c:322
int fr_debug_lvl
Definition log.c:41
fr_log_t default_log
Definition log.c:308
@ L_DST_STDOUT
Log to stdout.
Definition log.h:75
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition packet.c:38
Minimal data structure to use the new code.
Definition listen.h:79
int main_config_free(main_config_t **config)
main_config_t * main_config_alloc(TALLOC_CTX *ctx)
Allocate a main_config_t struct, setting defaults.
void main_config_name_set_default(main_config_t *config, char const *name, bool overwrite_config)
Set the server name.
int main_config_init(main_config_t *config)
void main_config_confdir_set(main_config_t *config, char const *name)
Set the global radius config directory.
void main_config_dict_dir_set(main_config_t *config, char const *name)
Set the global dictionary directory.
Main server configuration.
Definition main_config.h:59
fr_event_list_t * main_loop_event_list(void)
Return the main loop event list.
Definition main_loop.c:173
int main_loop_init(void)
Initialise the main event loop, setting up signal handlers.
Definition main_loop.c:262
void main_loop_free(void)
Definition main_loop.c:198
static const uint8_t * zero
Definition md4.c:359
unsigned short uint16_t
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
unsigned long int size_t
fr_cmp_ret_t fr_pointer_cmp(void const *a, void const *b)
Compares two pointers.
Definition misc.c:449
int fr_nonblock(UNUSED int fd)
Definition misc.c:293
int fr_blocking(UNUSED int fd)
Definition misc.c:298
int modules_rlm_coord_attach(fr_event_list_t *el)
Runs the coord_attach method of all registered backend modules.
Definition module_rlm.c:992
int modules_rlm_free(void)
Cleanup all global structures.
int modules_rlm_coord_detach(void)
Runs the coord_detach method of all registered backend modules.
Definition module_rlm.c:999
int modules_rlm_init(void)
Initialise the module list structure.
char * fr_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Special version of asprintf which implements custom format specifiers.
Definition print.c:883
static const conf_parser_t config[]
Definition base.c:162
#define fr_assert(_expr)
Definition rad_assert.h:37
#define DEBUG2(fmt,...)
#define INFO(fmt,...)
Definition radict.c:67
#define WIFEXITED(stat_val)
Definition radiusd.c:66
#define WEXITSTATUS(stat_val)
Definition radiusd.c:63
static bool cleanup
Definition radsniff.c:59
static rs_t * conf
Definition radsniff.c:52
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:44
int request_global_init(void)
Definition request.c:614
int request_detach(request_t *child)
Unlink a subrequest from its parent.
Definition request.c:560
#define request_local_alloc_internal(_ctx, _args)
Allocate a new internal request outside of the request pool.
Definition request.h:344
@ REQUEST_ACTIVE
Request is active (running or runnable)
Definition request.h:89
void fr_schedule_worker_id_set(int id)
Explicitly set the worker id for the current thread.
Definition schedule.c:120
fr_client_t * client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, CONF_SECTION *server_cs, size_t extra)
Allocate a new client from a config section.
Definition client.c:735
void modules_init(char const *lib_dir)
Perform global initialisation for modules.
Definition module.c:1981
return count
Definition module.c:155
fr_log_dst_t dst
Log destination.
Definition log.h:94
int fd
File descriptor to write messages to.
Definition log.h:109
bool print_level
sometimes we don't want log levels printed
Definition log.h:103
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
char * talloc_typed_asprintf(TALLOC_CTX *ctx, char const *fmt,...)
Call talloc vasprintf, setting the type on the new chunk correctly.
Definition talloc.c:621
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:55
int fr_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el)
Instantiate thread-specific data for modules, virtual servers, xlats, unlang, and TLS.
Definition thread.c:177
static const char * names[8]
Definition time.c:618
int fr_time_start(void)
Initialize the local time.
Definition time.c:157
static fr_time_delta_t fr_time_delta_from_sec(int64_t sec)
Definition time.h:599
"server local" time.
Definition time.h:69
int fr_openssl_version_consistent(void)
Definition version.c:246
@ T_BARE_WORD
Definition token.h:118
@ T_OP_EQ
Definition token.h:81
@ T_DOUBLE_QUOTED_STRING
Definition token.h:119
static char const * receipt_file
static fr_event_list_t * el
static void _request_yield(request_t *request, void *uctx)
static void _request_done_external(request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
fr_heap_t * runnable
Requests the interpreter has marked runnable.
fr_tls_connection_t * conn
The connection of bio.
fr_ipaddr_t server_ipaddr
Server named by -s.
int main(int argc, char *argv[])
static void _tls_runnable(UNUSED fr_event_list_t *el, UNUSED fr_time_t now, void *uctx)
Drain the runnable heap once per pass of the event loop.
char const * transport
"tcp" or "udp", naming the subsection below which holds the socket.
fr_event_list_t * el
Event list everything runs on.
static void _request_resume(request_t *request, UNUSED void *uctx)
static void tls_runnable_insert(unit_test_bio_t *utt, request_t *request)
Schedule a request, once.
static void _tls_socket_accept_start(fr_event_list_t *el, void *uctx)
Start waiting for a connection, from inside the event loop.
static void _tls_connection_start(UNUSED fr_event_list_t *el, void *uctx)
Start the TLS bio, from inside the event loop.
bool invalid
Mark the session invalid mid-handshake, see -I.
static int tls_connection_run(unit_test_bio_t *utt)
Run one connection from the first byte to the last.
static void _request_runnable(request_t *request, void *uctx)
uint32_t drop_datagram
Drop this datagram rather than sending it, counting from one.
bool alert
Reject the peer with a TLS alert, see -A.
static fr_client_t * tls_client_alloc(TALLOC_CTX *ctx, fr_ipaddr_t const *ipaddr)
Build an internal client.
uint16_t port
Port of the listening socket.
static void _request_done_internal(request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
bool abort_pending
Free the connection once the handshake succeeds, while store session is still queued,...
static bool _request_scheduled(request_t const *request, UNUSED void *uctx)
static fr_dict_t const * dict_freeradius
static const conf_parser_t unit_test_bio_config[]
int yielded
How many requests are currently yielded.
static fr_dict_t const * dict_tls
fr_bio_tls_t * bio
The TLS bio of the connection being run.
unsigned char * alpn
Protocol list built by -L, in the wire format fr_tls_conf_t expects.
static request_t * tls_request_alloc(TALLOC_CTX *ctx, fr_bio_t *fd_bio, int socket_type)
Build the request the handshake runs under.
static int tls_command_start(unit_test_bio_t *utt, char const *command)
Start the command named by -e.
static void _request_detach(request_t *request, UNUSED void *uctx)
fr_tls_conf_t * server
The server { ... } subsection.
static const conf_parser_t unit_test_bio_socket_config[]
The socket items, parsed once per transport subsection.
int socket_type
SOCK_STREAM or SOCK_DGRAM, from transport.
unit_test_bio_socket_t udp
The udp { ... } subsection.
fr_bio_t * fd_bio
The fd bio of the connection being run.
bool app_data
Send one byte of application data once the handshake is done, see -P.
int ret
Exit status.
static int tls_socket_open(unit_test_bio_t *utt)
Open the listening socket described by the "unit_test_tls" section.
static void _tls_hold_read(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Something happened on a connection which -H holds open.
static void tls_done(unit_test_bio_t *utt)
Stop the event loop, recording why.
static void tls_bio_connected(fr_bio_t *bio)
The connection is up, and can carry application data.
bool done
Set once the connection has a result.
fr_tls_conf_t * client
The client { ... } subsection, used with -s.
bool command_exited
The command has exited.
unsigned int connections
How many connections have been run so far.
fr_dict_autoload_t unit_test_bio_dict[]
fr_bio_fd_config_t listen_cfg
Config of listen_bio. The bio keeps the pointer.
static void tls_bio_failed(fr_bio_t *bio)
The TLS bio says the connection failed, at any point.
char const * radiusd_version
bool nonblock
Put the connection socket in non-blocking mode, see -B.
fr_ipaddr_t ipaddr
Address of the listening socket.
int sockfd
Listening socket.
bool hold
Once connected, send nothing and stay connected, see -H.
bool client
Act as the client and connect to a server, rather than accept a connection.
bool network_fail
Fail the session with a network error once the handshake succeeds, see -N.
fr_event_fd_t * accept_ef
Read event for sockfd, while waiting in tls_socket_accept().
SSL_CTX * ssl_ctx
Context built from the "tls" section.
static void tls_request_failed(unit_test_bio_t *utt)
Record a failure this program cannot recover from, and stop.
static void _tls_socket_error(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, int fd_errno, UNUSED void *uctx)
Stop waiting for a connection if the listening socket fails.
bool alpn_required
Set by -l.
fr_ipaddr_t ipaddr
Address of the listening socket, copied from whichever subsection transport named.
request_t * request
The request the connection runs under.
bool require_client_certificate
Whether the client has to present a certificate.
#define EXIT_WITH_FAILURE
static void _tls_command_exit(fr_event_list_t *el, pid_t pid, int status, void *uctx)
Record that the command started by -e has exited.
static int tls_socket_connect(unit_test_bio_t *utt)
Connect to the server named by -s.
static void _tls_socket_accept(fr_event_list_t *el, UNUSED int fd, UNUSED int flags, void *uctx)
Accept the connection once the listening socket is readable.
fr_bio_fd_config_t fd_cfg
Config of fd_bio. The bio keeps the pointer.
pid_t command_pid
Command started by -e, or 0.
static int tls_socket_accept(unit_test_bio_t *utt)
Wait for a connection, or for the command started by -e to exit without connecting.
char const * command
Command to run, see -e.
unit_test_bio_socket_t tcp
The tcp { ... } subsection.
bool command_waiting
Waiting in tls_command_wait().
static int tls_socket_accept_one(unit_test_bio_t *utt)
Accept a connection, if the listening socket has one queued.
int fd
Accepted or connected socket.
fr_bio_t * listen_bio
Listening fd bio.
static void _request_done_detached(request_t *request, UNUSED rlm_rcode_t rcode, UNUSED void *uctx)
static void _tls_hold_error(UNUSED fr_event_list_t *el, UNUSED int fd, UNUSED int flags, UNUSED int fd_errno, void *uctx)
uint16_t server_port
Port from -s, or from the configuration.
unit_test_bio_conf_t conf
Parsed "unit_test_tls" section.
bool reject
Reject the session once the handshake succeeds, see -R.
size_t first_len
Length of first.
uint8_t * first
The datagram which named the peer, read from the listening socket before the connection's socket exis...
unlang_interpret_t * intp
Interpreter for the connection.
static void _request_init_internal(request_t *request, void *uctx)
An internal request created by the interpreter has to run on ours.
fr_event_pid_t const * command_ev
Waits for the command to exit.
bool connected
The connected callback has run.
bool accepting
Waiting in tls_socket_accept().
static void tls_command_wait(unit_test_bio_t *utt)
Wait for the command started by -e to exit, so its output is complete.
static unsigned char * tls_alpn_build(TALLOC_CTX *ctx, char const *names)
Turn a comma separated list of names into the wire format ALPN uses.
uint16_t port
Port of the listening socket, and the default port for -s.
unsigned int count
How many connections to run.
The "unit_test_tls" section.
State of the test program.
#define FR_DICTIONARY_FILE
Definition conf.h:6
#define FR_DICTIONARY_INTERNAL_DIR
Definition conf.h:7
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:83
int fd
File descriptor if this is a live socket.
Definition socket.h:86
int type
SOCK_STREAM, SOCK_DGRAM, etc.
Definition socket.h:84
Holds information necessary for binding or connecting to a socket.
Definition socket.h:60
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:737
#define fr_strerror_const(_msg)
Definition strerror.h:223
int fr_check_lib_magic(uint64_t magic)
Check if the application linking to the library has the correct magic number.
Definition version.c:40
#define RADIUSD_VERSION_BUILD(_x)
Create a version string for a utility in the suite of FreeRADIUS utilities.
Definition version.h:58
#define RADIUSD_MAGIC_NUMBER
Definition version.h:81
#define fr_box_ipaddr(_val)
Definition value.h:348
static fr_sbuff_err_t char size_t * len
Definition value.h:1061
fr_dict_t const * virtual_server_dict_by_name(char const *virtual_server)
Return the namespace for the named virtual server.
virtual_server_t const * virtual_server_find(char const *name)
Return virtual server matching the specified name.
int virtual_servers_init(void)
Performs global initialisation for the virtual server code.
int virtual_servers_free(void)