The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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 
23 RCSID("$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 
44 typedef struct {
45  uint8_t vector[16];
47  struct sockaddr_storage src;
48  socklen_t salen;
50 
51 typedef struct {
52  int sockfd;
56 
57 static int debug_lvl = 0;
59 static int my_port;
60 static char const *secret = "testing123";
62 
63 static 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 
69 static 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 
82 static 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 
96  md5_ctx = fr_md5_ctx_alloc_from_list();
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);
100  fr_md5_ctx_free_from_list(&md5_ctx);
101 
102  return 20;
103 }
104 
105 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)
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 
112 static 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 
132 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)
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 
150  start_time = fr_time();
151  *recv_time = &start_time;
152  *priority = 0;
153 
154  return data_size;
155 }
156 
157 
158 static 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 
176 static int test_fd(void const *ctx)
177 {
179 
180  return io_ctx->sockfd;
181 }
182 
183 static fr_app_io_t app_io = {
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 
195 static void entry_point_set(UNUSED void const *ctx, request_t *request)
196 {
197  request->async->process = test_process;
198 }
199 
200 static fr_app_t test_app = {
201  .entry_point_set = entry_point_set,
202 };
203 
204 static 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 
215 int 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 
228  fr_time_start();
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:574
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:481
#define NEVER_RETURNS
Should be placed before the function return type.
Definition: build.h:311
#define UNUSED
Definition: build.h:313
static int kq_master
Definition: channel_test.c:46
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.
Definition: merged_model.c:272
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
Definition: merged_model.c:31
unsigned int uint32_t
Definition: merged_model.c:33
long int ssize_t
Definition: merged_model.c:24
unsigned char uint8_t
Definition: merged_model.c:30
static TALLOC_CTX * autofree
Definition: radclient-ng.c:107
static int num_workers
Definition: radius1_test.c:70
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_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
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
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