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: de0c92bfd6ce94026406aa0f5c49729a6816d5d8 $
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: de0c92bfd6ce94026406aa0f5c49729a6816d5d8 $")
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 <string.h>
36#include <pthread.h>
37
38#ifdef HAVE_GETOPT_H
39# include <getopt.h>
40#endif
41
42#define MPRINT1 if (debug_lvl) printf
43
44typedef struct {
45 uint8_t vector[16];
47 struct sockaddr_storage src;
48 socklen_t salen;
50
56
57static int debug_lvl = 0;
59static int my_port;
60static char const *secret = "testing123";
62
63static rlm_rcode_t test_process(UNUSED void const *instance, request_t *request, fr_io_action_t action)
64{
65 MPRINT1("\t\tPROCESS --- request %"PRIu64" action %d\n", request->number, action);
67}
68
69static int test_decode(void const *instance, request_t *request, uint8_t *const data, size_t data_len)
70{
71 fr_listen_test_t const *pc = instance;
72
73 request->async->process = test_process;
74
75 if (!debug_lvl) return 0;
76
77 MPRINT1("\t\tDECODE <<< request %"PRIu64" - %p data %p size %zd\n", request->number, pc, data, data_len);
78
79 return 0;
80}
81
82static ssize_t test_encode(void const *instance, request_t *request, uint8_t *buffer, size_t buffer_len)
83{
84 fr_md5_ctx_t *md5_ctx;
85 fr_listen_test_t const *pc = instance;
86
87 MPRINT1("\t\tENCODE >>> request %"PRIu64"- data %p %p room %zd\n", request->number, pc, buffer, buffer_len);
88
90 buffer[1] = tpc.id;
91 buffer[2] = 0;
92 buffer[3] = 20;
93
94 memcpy(buffer + 4, tpc.vector, 16);
95
97 fr_md5_update(md5_ctx, buffer, 20);
98 fr_md5_update(md5_ctx, (uint8_t const *) secret, strlen(secret));
99 fr_md5_final(buffer + 4, md5_ctx);
101
102 return 20;
103}
104
105static 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)
106{
107 MPRINT1("\t\tNAK !!! request %d - data %p %p size %zd\n", packet[1], ctx, packet, packet_len);
108
109 return 10;
110}
111
112static int test_open(void *ctx, UNUSED void const *master_ctx)
113{
114 fr_listen_test_t *io_ctx = talloc_get_type_abort(ctx, fr_listen_test_t);
115
116 io_ctx->sockfd = fr_socket_server_udp(&io_ctx->ipaddr, &io_ctx->port, NULL, true);
117 if (io_ctx->sockfd < 0) {
118 fr_perror("radius_test: Failed creating socket");
119 fr_exit_now(EXIT_FAILURE);
120 }
121
122 if (fr_socket_bind(io_ctx->sockfd, NULL, &io_ctx->ipaddr, &io_ctx->port) < 0) {
123 fr_perror("radius_test: Failed binding to socket");
124 fr_exit_now(EXIT_FAILURE);
125 }
126
127 return 0;
128}
129
131
132static 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)
133{
134 ssize_t data_size;
135 fr_listen_test_t const *io_ctx = talloc_get_type_abort(ctx, fr_listen_test_t);
136
137 tpc.salen = sizeof(tpc.src);
138 *leftover = 0;
139 *is_dup = false;
140
141 data_size = recvfrom(io_ctx->sockfd, buffer, buffer_len, 0, (struct sockaddr *) &tpc.src, &tpc.salen);
142 if (data_size <= 0) return data_size;
143
144 /*
145 * @todo - check if it's RADIUS.
146 */
147 tpc.id = buffer[1];
148 memcpy(tpc.vector, buffer + 4, sizeof(tpc.vector));
149
151 *recv_time = &start_time;
152 *priority = 0;
153
154 return data_size;
155}
156
157
158static ssize_t test_write(void *ctx, UNUSED void *packet_ctx, UNUSED fr_time_t request_time,
159 uint8_t *buffer, size_t buffer_len, UNUSED size_t written)
160{
161 ssize_t data_size;
162 fr_listen_test_t *io_ctx = talloc_get_type_abort(ctx, fr_listen_test_t);
163
164 tpc.salen = sizeof(tpc.src);
165
166 data_size = sendto(io_ctx->sockfd, buffer, buffer_len, 0, (struct sockaddr *)&tpc.src, tpc.salen);
167 if (data_size <= 0) return data_size;
168
169 /*
170 * @todo - post-write cleanups
171 */
172
173 return data_size;
174}
175
176static int test_fd(void const *ctx)
177{
179
180 return io_ctx->sockfd;
181}
182
184 .name = "schedule-test",
185 .default_message_size = 4096,
186 .open = test_open,
187 .read = test_read,
188 .write = test_write,
189 .fd = test_fd,
190 .nak = test_nak,
191 .encode = test_encode,
192 .decode = test_decode
193};
194
195static void entry_point_set(UNUSED void const *ctx, request_t *request)
196{
197 request->async->process = test_process;
198}
199
201 .entry_point_set = entry_point_set,
202};
203
204static NEVER_RETURNS void usage(void)
205{
206 fprintf(stderr, "usage: schedule_test [OPTS]\n");
207 fprintf(stderr, " -n <num> Start num network threads\n");
208 fprintf(stderr, " -i <address>[:port] Set IP address and optional port.\n");
209 fprintf(stderr, " -s <secret> Set shared secret.\n");
210 fprintf(stderr, " -x Debugging mode.\n");
211
212 fr_exit_now(EXIT_FAILURE);
213}
214
215int main(int argc, char *argv[])
216{
217 int c;
218 int num_networks = 1;
219 int num_workers = 2;
220 uint16_t port16 = 0;
221 TALLOC_CTX *autofree = talloc_autofree_context();
222 fr_schedule_t *sched;
223 fr_listen_t listen = { .app_io = &app_io, .app = &test_app };
224 fr_listen_test_t *app_io_inst;
225
226 listen.app_io_instance = app_io_inst = talloc_zero(autofree, fr_listen_test_t);
227
229
231 default_log.colourise = true;
232
233 memset(&my_ipaddr, 0, sizeof(my_ipaddr));
234 my_ipaddr.af = AF_INET;
235 my_ipaddr.prefix = 32;
236 my_ipaddr.addr.v4.s_addr = htonl(INADDR_LOOPBACK);
237 my_port = 1812;
238
239 while ((c = getopt(argc, argv, "i:n:s:w:x")) != -1) switch (c) {
240 case 'i':
241 if (fr_inet_pton_port(&my_ipaddr, &port16, optarg, -1, AF_INET, true, false) < 0) {
242 fr_perror("Failed parsing ipaddr");
243 fr_exit_now(EXIT_FAILURE);
244 }
245 my_port = port16;
246 break;
247
248 case 'n':
249 num_networks = atoi(optarg);
250 if ((num_networks <= 0) || (num_networks > 16)) usage();
251 break;
252
253 case 's':
254 secret = optarg;
255 break;
256
257 case 'w':
258 num_workers = atoi(optarg);
259 if ((num_workers <= 0) || (num_workers > 1024)) usage();
260 break;
261
262 case 'x':
263 debug_lvl++;
264 fr_debug_lvl++;
265 break;
266
267 case 'h':
268 default:
269 usage();
270 }
271
272#if 0
273 argc -= (optind - 1);
274 argv += (optind - 1);
275#endif
276
277 app_io_inst->ipaddr = my_ipaddr;
278 app_io_inst->port = my_port;
279
280 sched = fr_schedule_create(autofree, NULL, &default_log, debug_lvl, num_networks, num_workers, NULL, NULL);
281 if (!sched) {
282 fprintf(stderr, "schedule_test: Failed to create scheduler\n");
283 fr_exit_now(EXIT_FAILURE);
284 }
285
286 if (listen.app_io->open(listen.app_io_instance, listen.app_io_instance) < 0) fr_exit_now(EXIT_FAILURE);
287
288#if 0
289 /*
290 * Set up the KQ filter for reading.
291 */
292 EV_SET(&events[0], sockfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
293 if (kevent(kq_master, events, 1, NULL, 0, NULL) < 0) {
294 fr_perror("Failed setting KQ for EVFILT_READ");
295 fr_exit_now(EXIT_FAILURE);
296 }
297#endif
298
299 (void) fr_fault_setup(autofree, NULL, argv[0]);
300 (void) fr_schedule_listen_add(sched, &listen);
301
302 sleep(10);
303
304 (void) fr_schedule_destroy(&sched);
305
306 fr_exit_now(EXIT_SUCCESS);
307}
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
#define RCSID(id)
Definition build.h:483
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:313
#define UNUSED
Definition build.h:315
static int kq_master
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:1242
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:234
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
Definition defs.h:34
static int sockfd
Definition dhcpclient.c:56
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:937
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition inet.h:69
int af
Address family.
Definition inet.h:64
union fr_ipaddr_t::@130 addr
IPv4/6 prefix.
void const * app_io_instance
I/O path configuration context.
Definition listen.h:32
fr_app_io_t const * app_io
I/O path functions.
Definition listen.h:31
int fr_log_init_legacy(fr_log_t *log, bool daemonize)
Initialise file descriptors based on logging destination.
Definition log.c:907
int fr_debug_lvl
Definition log.c:43
fr_log_t default_log
Definition log.c:291
fr_md5_update_t fr_md5_update
Definition md5.c:442
fr_md5_final_t fr_md5_final
Definition md5.c:443
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
Definition md5.c:522
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
Definition md5.c:477
void fr_md5_ctx_t
Definition md5.h:28
unsigned short uint16_t
unsigned int uint32_t
long int ssize_t
unsigned char uint8_t
static TALLOC_CTX * autofree
static int num_workers
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:59
#define RETURN_MODULE_OK
Definition rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
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:881
fr_schedule_t * fr_schedule_create(TALLOC_CTX *ctx, 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:463
int fr_schedule_destroy(fr_schedule_t **sc_to_free)
Destroy a scheduler, and tell its child threads to exit.
Definition schedule.c:761
The scheduler.
Definition schedule.c:125
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:867
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:229
#define fr_time()
Allow us to arbitrarily manipulate time.
Definition state_test.c:8
bool colourise
Prefix log messages with VT100 escape codes to change text colour.
Definition log.h:101
#define talloc_get_type_abort_const
Definition talloc.h:282
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:51
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:733
static fr_slen_t data
Definition value.h:1265