The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
radius_schedule_test.c
Go to the documentation of this file.
1/*
2 * radius_schedule_test.c Tests for the scheduler and receiving RADIUS packets
3 *
4 * Version: $Id: 6f4540c00b23672d818fe9b1e174c1f55a5b3d52 $
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 * @copyright 2016 Alan DeKok (aland@freeradius.org)
21 */
22
23RCSID("$Id: 6f4540c00b23672d818fe9b1e174c1f55a5b3d52 $")
24
25#include <freeradius-devel/io/listen.h>
26#include <freeradius-devel/io/schedule.h>
27#include <freeradius-devel/radius/defs.h>
28#include <freeradius-devel/util/debug.h>
29#include <freeradius-devel/util/inet.h>
30#include <freeradius-devel/util/md5.h>
31#include <freeradius-devel/util/syserror.h>
32
33#include <sys/event.h>
34#include <stdio.h>
35#include <pthread.h>
36
37#ifdef HAVE_GETOPT_H
38# include <getopt.h>
39#endif
40
41#define MPRINT1 if (debug_lvl) printf
42
43typedef struct {
44 uint8_t vector[16];
46 struct sockaddr_storage src;
47 socklen_t salen;
49
55
56static int debug_lvl = 0;
58static int my_port;
59static char const *secret = "testing123";
61
62static rlm_rcode_t test_process(UNUSED void const *instance, request_t *request, fr_io_action_t action)
63{
64 MPRINT1("\t\tPROCESS --- request %"PRIu64" action %d\n", request->number, action);
66}
67
68static int test_decode(void const *instance, request_t *request, uint8_t *const data, size_t data_len)
69{
70 fr_listen_test_t const *pc = instance;
71
72 request->async->process = test_process;
73
74 if (!debug_lvl) return 0;
75
76 MPRINT1("\t\tDECODE <<< request %"PRIu64" - %p data %p size %zd\n", request->number, pc, data, data_len);
77
78 return 0;
79}
80
81static ssize_t test_encode(void const *instance, request_t *request, uint8_t *buffer, size_t buffer_len)
82{
83 fr_md5_ctx_t *md5_ctx;
84 fr_listen_test_t const *pc = instance;
85
86 MPRINT1("\t\tENCODE >>> request %"PRIu64"- data %p %p room %zd\n", request->number, pc, buffer, buffer_len);
87
89 buffer[1] = tpc.id;
90 buffer[2] = 0;
91 buffer[3] = 20;
92
93 memcpy(buffer + 4, tpc.vector, 16);
94
96 fr_md5_update(md5_ctx, buffer, 20);
97 fr_md5_update(md5_ctx, (uint8_t const *) secret, strlen(secret));
98 fr_md5_final(buffer + 4, md5_ctx);
100
101 return 20;
102}
103
104static size_t test_nak(void const *ctx, UNUSED void *packet_ctx, uint8_t *const packet, size_t packet_len, UNUSED uint8_t *reply, UNUSED size_t reply_len)
105{
106 MPRINT1("\t\tNAK !!! request %d - data %p %p size %zd\n", packet[1], ctx, packet, packet_len);
107
108 return 10;
109}
110
111static int test_open(void *ctx, UNUSED void const *master_ctx)
112{
113 fr_listen_test_t *io_ctx = talloc_get_type_abort(ctx, fr_listen_test_t);
114
115 io_ctx->sockfd = fr_socket_server_udp(&io_ctx->ipaddr, &io_ctx->port, NULL, true);
116 if (io_ctx->sockfd < 0) {
117 fr_perror("radius_test: Failed creating socket");
118 fr_exit_now(EXIT_FAILURE);
119 }
120
121 if (fr_socket_bind(io_ctx->sockfd, NULL, &io_ctx->ipaddr, &io_ctx->port) < 0) {
122 fr_perror("radius_test: Failed binding to socket");
123 fr_exit_now(EXIT_FAILURE);
124 }
125
126 return 0;
127}
128
130
131static ssize_t test_read(void *ctx, UNUSED void **packet_ctx, fr_time_t **recv_time, uint8_t *buffer, size_t buffer_len, size_t *leftover, uint32_t *priority, bool *is_dup)
132{
133 ssize_t data_size;
134 fr_listen_test_t const *io_ctx = talloc_get_type_abort(ctx, fr_listen_test_t);
135
136 tpc.salen = sizeof(tpc.src);
137 *leftover = 0;
138 *is_dup = false;
139
140 data_size = recvfrom(io_ctx->sockfd, buffer, buffer_len, 0, (struct sockaddr *) &tpc.src, &tpc.salen);
141 if (data_size <= 0) return data_size;
142
143 /*
144 * @todo - check if it's RADIUS.
145 */
146 tpc.id = buffer[1];
147 memcpy(tpc.vector, buffer + 4, sizeof(tpc.vector));
148
150 *recv_time = &start_time;
151 *priority = 0;
152
153 return data_size;
154}
155
156
157static ssize_t test_write(void *ctx, UNUSED void *packet_ctx, UNUSED fr_time_t request_time,
158 uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
159{
160 ssize_t data_size;
161 fr_listen_test_t *io_ctx = talloc_get_type_abort(ctx, fr_listen_test_t);
162
163 tpc.salen = sizeof(tpc.src);
164
165 data_size = sendto(io_ctx->sockfd, buffer, buffer_len, 0, (struct sockaddr *)&tpc.src, tpc.salen);
166 if (data_size <= 0) return data_size;
167
168 /*
169 * @todo - post-write cleanups
170 */
171
172 return data_size;
173}
174
175static int test_fd(void const *ctx)
176{
178
179 return io_ctx->sockfd;
180}
181
183 .name = "schedule-test",
184 .default_message_size = 4096,
185 .open = test_open,
186 .read = test_read,
187 .write = test_write,
188 .fd = test_fd,
189 .nak = test_nak,
190 .encode = test_encode,
191 .decode = test_decode
192};
193
194static void entry_point_set(UNUSED void const *ctx, request_t *request)
195{
196 request->async->process = test_process;
197}
198
200 .entry_point_set = entry_point_set,
201};
202
203static NEVER_RETURNS void usage(void)
204{
205 fprintf(stderr, "usage: schedule_test [OPTS]\n");
206 fprintf(stderr, " -n <num> Start num network threads\n");
207 fprintf(stderr, " -i <address>[:port] Set IP address and optional port.\n");
208 fprintf(stderr, " -s <secret> Set shared secret.\n");
209 fprintf(stderr, " -x Debugging mode.\n");
210
211 fr_exit_now(EXIT_FAILURE);
212}
213
214int main(int argc, char *argv[])
215{
216 int c;
217 int num_networks = 1;
218 int num_workers = 2;
219 uint16_t port16 = 0;
220 TALLOC_CTX *autofree = talloc_autofree_context();
221 fr_schedule_t *sched;
222 fr_listen_t listen = { .app_io = &app_io, .app = &test_app };
223 fr_listen_test_t *app_io_inst;
224
225 listen.app_io_instance = app_io_inst = talloc_zero(autofree, fr_listen_test_t);
226
228
230 default_log.colourise = true;
231
232 memset(&my_ipaddr, 0, sizeof(my_ipaddr));
233 my_ipaddr.af = AF_INET;
234 my_ipaddr.prefix = 32;
235 my_ipaddr.addr.v4.s_addr = htonl(INADDR_LOOPBACK);
236 my_port = 1812;
237
238 while ((c = getopt(argc, argv, "i:n:s:w:x")) != -1) switch (c) {
239 case 'i':
240 if (fr_inet_pton_port(&my_ipaddr, &port16, optarg, -1, AF_INET, true, false) < 0) {
241 fr_perror("Failed parsing ipaddr");
242 fr_exit_now(EXIT_FAILURE);
243 }
244 my_port = port16;
245 break;
246
247 case 'n':
248 num_networks = atoi(optarg);
249 if ((num_networks <= 0) || (num_networks > 16)) usage();
250 break;
251
252 case 's':
253 secret = optarg;
254 break;
255
256 case 'w':
257 num_workers = atoi(optarg);
258 if ((num_workers <= 0) || (num_workers > 1024)) usage();
259 break;
260
261 case 'x':
262 debug_lvl++;
263 fr_debug_lvl++;
264 break;
265
266 case 'h':
267 default:
268 usage();
269 }
270
271#if 0
272 argc -= (optind - 1);
273 argv += (optind - 1);
274#endif
275
276 app_io_inst->ipaddr = my_ipaddr;
277 app_io_inst->port = my_port;
278
279 sched = fr_schedule_create(autofree, false, NULL, &default_log, debug_lvl, num_networks, num_workers, NULL, NULL);
280 if (!sched) {
281 fprintf(stderr, "schedule_test: Failed to create scheduler\n");
282 fr_exit_now(EXIT_FAILURE);
283 }
284
285 if (listen.app_io->open(listen.app_io_instance, listen.app_io_instance) < 0) fr_exit_now(EXIT_FAILURE);
286
287#if 0
288 /*
289 * Set up the KQ filter for reading.
290 */
291 EV_SET(&events[0], sockfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
292 if (kevent(kq_master, events, 1, NULL, 0, NULL) < 0) {
293 fr_perror("Failed setting KQ for EVFILT_READ");
294 fr_exit_now(EXIT_FAILURE);
295 }
296#endif
297
298 (void) fr_fault_setup(autofree, NULL, argv[0]);
299 (void) fr_schedule_listen_add(sched, &listen);
300
301 sleep(10);
302
303 (void) fr_schedule_destroy(&sched);
304
305 fr_exit_now(EXIT_SUCCESS);
306}
static int const char char buffer[256]
Definition acutest.h:576
fr_io_open_t open
Open a new socket for listening, or accept/connect a new connection.
Definition app_io.h:43
size_t default_message_size
Usually maximum message size.
Definition app_io.h:39
Public structure describing an I/O path for a protocol.
Definition app_io.h:33
Describes a new application (protocol)
Definition application.h:71
static TALLOC_CTX * autofree
Definition fuzzer.c:44
#define RCSID(id)
Definition build.h:506
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:334
#define UNUSED
Definition build.h:336
static int kq_master
static size_t num_workers
int fr_fault_setup(TALLOC_CTX *ctx, char const *cmd, char const *program)
Registers signal handlers to execute panic_action on fatal signal.
Definition debug.c:1056
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:236
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition defs.h:34
static int sockfd
Definition dhcpclient.c:55
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
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition inet.h:68
int af
Address family.
Definition inet.h:63
union fr_ipaddr_t::@137 addr
IPv4/6 prefix.
void const * app_io_instance
I/O path configuration context.
Definition listen.h:33
fr_app_io_t const * app_io
I/O path functions.
Definition listen.h:32
#define fr_time()
Definition event.c:60
int fr_log_init_legacy(fr_log_t *log, bool daemonize)
Initialise file descriptors based on logging destination.
Definition log.c:901
int fr_debug_lvl
Definition log.c:40
fr_log_t default_log
Definition log.c:288
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Free function for MD5 digest ctx.
Definition md5.c:515
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Allocation function for MD5 digest context.
Definition md5.c:470
#define fr_md5_final(_out, _ctx)
Finalise the ctx, producing the digest.
Definition md5.h:90
void fr_md5_ctx_t
Definition md5.h:25
#define fr_md5_update(_ctx, _in, _inlen)
Ingest plaintext into the digest.
Definition md5.h:83
unsigned short uint16_t
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
int main(int argc, char *argv[])
static fr_app_t test_app
static ssize_t test_encode(void const *instance, request_t *request, uint8_t *buffer, size_t buffer_len)
static rlm_rcode_t test_process(UNUSED void const *instance, request_t *request, fr_io_action_t action)
static void entry_point_set(UNUSED void const *ctx, request_t *request)
static fr_time_t start_time
static ssize_t test_read(void *ctx, UNUSED void **packet_ctx, fr_time_t **recv_time, uint8_t *buffer, size_t buffer_len, size_t *leftover, uint32_t *priority, bool *is_dup)
static fr_test_packet_ctx_t tpc
struct sockaddr_storage src
static int test_open(void *ctx, UNUSED void const *master_ctx)
static char const * secret
static size_t test_nak(void const *ctx, UNUSED void *packet_ctx, uint8_t *const packet, size_t packet_len, UNUSED uint8_t *reply, UNUSED size_t reply_len)
static int test_fd(void const *ctx)
static ssize_t test_write(void *ctx, UNUSED void *packet_ctx, UNUSED fr_time_t request_time, uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
static int my_port
#define MPRINT1
static fr_ipaddr_t my_ipaddr
static int test_decode(void const *instance, request_t *request, uint8_t *const data, size_t data_len)
static fr_app_io_t app_io
static NEVER_RETURNS void usage(void)
static int debug_lvl
static fr_event_list_t * events
Definition radsniff.c:58
#define RETURN_UNLANG_OK
Definition rcode.h:64
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:44
fr_schedule_t * fr_schedule_create(TALLOC_CTX *ctx, bool single_threaded, fr_event_list_t *el, fr_log_t *logger, fr_log_lvl_t lvl, fr_schedule_thread_instantiate_t worker_thread_instantiate, fr_schedule_thread_detach_t worker_thread_detach, fr_schedule_config_t *config)
Create a scheduler and spawn the child threads.
Definition schedule.c:266
fr_network_t * fr_schedule_listen_add(fr_schedule_t *sc, fr_listen_t *li)
Add a fr_listen_t to a scheduler.
Definition schedule.c:703
int fr_schedule_destroy(fr_schedule_t **sc_to_free)
Destroy a scheduler, and tell its child threads to exit.
Definition schedule.c:571
The scheduler.
Definition schedule.c:76
int fr_socket_server_udp(fr_ipaddr_t const *src_ipaddr, uint16_t *src_port, char const *port_name, bool async)
Open an IPv4/IPv6 unconnected UDP socket.
Definition socket.c:846
int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface.
Definition socket.c:200
bool colourise
Prefix log messages with VT100 escape codes to change text colour.
Definition log.h:98
#define talloc_get_type_abort_const
Definition talloc.h:110
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:48
int fr_time_start(void)
Initialize the local time.
Definition time.c:150
"server local" time.
Definition time.h:69
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:732
static fr_slen_t data
Definition value.h:1340