Radcli library 2.0.0
A simple radius library -- new API reference
Loading...
Searching...
No Matches
raddaeserver.c
1/*
2 * Copyright (C) 2026 Nikos Mavrogiannopoulos
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
32
33#include <config.h>
34#include <errno.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <syslog.h>
39#include <poll.h>
40#include <arpa/inet.h>
41#include <radcli/radcli.h>
42#include <radcli/radcli2.h>
43
44static int opt_nak = 0;
45static uint32_t opt_error_cause = 0;
46static int opt_no_reply = 0;
47static int opt_verbose = 0;
48
49static void print_attrs(const radcli_avp_list *attrs)
50{
51 const radcli_avp *a;
53
54 while ((a = radcli_avp_iter_next(&it)) != NULL) {
55 const radcli_attr_def *def = radcli_avp_def(a);
56 const char *name = radcli_attr_def_name(def);
57
58 switch (radcli_attr_def_type(def)) {
60 case RADCLI_TYPE_DATE: {
61 uint32_t v;
62 if (radcli_avp_get_uint32(a, &v) == 0)
63 printf("\t%s = %u\n", name, (unsigned)v);
64 break;
65 }
66 case RADCLI_TYPE_IPADDR: {
67 uint32_t v;
68 if (radcli_avp_get_uint32(a, &v) == 0) {
69 struct in_addr ia;
70 ia.s_addr = htonl(v);
71 printf("\t%s = %s\n", name, inet_ntoa(ia));
72 }
73 break;
74 }
77 struct in6_addr v6;
78 unsigned prefix;
79 char buf[INET6_ADDRSTRLEN];
80 if (radcli_avp_get_ip6(a, &v6, &prefix) == 0 &&
81 inet_ntop(AF_INET6, &v6, buf, sizeof(buf)) != NULL)
82 printf("\t%s = %s\n", name, buf);
83 break;
84 }
86 uint64_t v;
87 if (radcli_avp_get_uint64(a, &v) == 0)
88 printf("\t%s = %llu\n", name, (unsigned long long)v);
89 break;
90 }
92 default: {
93 const void *val;
94 size_t len;
95 if (radcli_avp_get_bytes(a, &val, &len) == 0)
96 printf("\t%s = %.*s\n", name, (int)len, (const char *)val);
97 break;
98 }
99 }
100 }
101}
102
103static void handle_request(radcli_dae_request *req, void *user)
104{
106 const char *sid, *user_name;
107
108 (void)user;
109
110 printf("%s request:\n", code == RADCLI_DISCONNECT_REQUEST ? "Disconnect" : "CoA");
111 print_attrs(radcli_dae_req_attrs(req));
112
113 if (opt_verbose) {
114 sid = radcli_dae_req_session_id(req);
115 user_name = radcli_dae_req_user_name(req);
116 if (sid != NULL)
117 printf(" (session-id: %s)\n", sid);
118 if (user_name != NULL)
119 printf(" (user-name: %s)\n", user_name);
120 }
121
122 if (opt_no_reply) {
123 printf("(not replying)\n");
124 } else if (opt_nak) {
125 printf("(sending NAK, Error-Cause %u)\n", (unsigned)opt_error_cause);
126 radcli_dae_reply_error(req, opt_error_cause);
127 } else {
128 printf("(sending ACK)\n");
129 radcli_dae_reply(req, 1);
130 }
131
133}
134
135static void usage(void)
136{
137 fprintf(stderr,
138 "usage: raddaeserver [-f config_file] [--nak[=error-cause]] [--no-reply] [-v]\n");
139 exit(1);
140}
141
142int main(int argc, char **argv)
143{
144 const char *config_file = RC_CONFIG_FILE;
145 rc_handle *rh;
146 radcli_dae *dae;
147 int i;
148
149 setvbuf(stdout, NULL, _IOLBF, 0); /* so a log-tailing reader sees each request promptly */
150 openlog("raddaeserver", LOG_PID, LOG_DAEMON);
151
152 for (i = 1; i < argc; i++) {
153 if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) {
154 config_file = argv[++i];
155 } else if (strcmp(argv[i], "--no-reply") == 0) {
156 opt_no_reply = 1;
157 } else if (strncmp(argv[i], "--nak", 5) == 0) {
158 opt_nak = 1;
159 if (argv[i][5] == '=')
160 opt_error_cause = (uint32_t)strtoul(argv[i] + 6, NULL, 10);
161 } else if (strcmp(argv[i], "-v") == 0) {
162 opt_verbose = 1;
163 } else {
164 usage();
165 }
166 }
167
168 rh = rc_read_config(config_file);
169 if (rh == NULL) {
170 fprintf(stderr, "raddaeserver: cannot read config %s\n", config_file);
171 return 1;
172 }
173
174 dae = radcli_dae_new(rh, 0);
175 if (dae == NULL) {
176 fprintf(stderr, "raddaeserver: dynamic authorization is not enabled or is "
177 "misconfigured (check dae-accept/dae-server/dae-secret)\n");
178 rc_destroy(rh);
179 return 1;
180 }
181 radcli_dae_set_handler(dae, handle_request, NULL);
182 if (radcli_dae_start(dae) != 0) {
183 fprintf(stderr, "raddaeserver: cannot start the listener\n");
184 radcli_dae_free(dae);
185 rc_destroy(rh);
186 return 1;
187 }
188
189 printf("raddaeserver: listening\n");
190
191 for (;;) {
192 struct pollfd pfds[RADCLI_CTX_MAX_POLLFDS];
193 size_t nfds;
194 int timeout_ms;
195
196 if (radcli_ctx_get_poll(rh, pfds, RADCLI_CTX_MAX_POLLFDS, &nfds, &timeout_ms) != 0)
197 break;
198 if (nfds == 0)
199 break;
200
201 if (poll(pfds, (nfds_t)nfds, timeout_ms) < 0) {
202 if (errno == EINTR)
203 continue;
204 break;
205 }
206
208 }
209
210 radcli_dae_free(dae);
211 rc_destroy(rh);
212 return 0;
213}
void radcli_dae_free(radcli_dae *dae)
Release a listener, closing its socket if radcli_dae_start() opened one.
Definition dae.c:978
const char * radcli_dae_req_session_id(const radcli_dae_request *req)
Return the request's Acct-Session-Id, if it carried one.
Definition dae.c:1621
int radcli_ctx_get_poll(radcli_ctx *ctx, struct pollfd *pfds, size_t max_pfds, size_t *nfds, int *timeout_ms)
Report what to wait for on ctx's behalf, for the caller's own event loop – radcli never calls poll()/...
Definition dae.c:1091
void radcli_dae_set_handler(radcli_dae *dae, radcli_dae_handler cb, void *user)
Register the callback radcli_ctx_dispatch() invokes for each validated request. May be called before ...
Definition dae.c:852
radcli_code radcli_dae_req_code(const radcli_dae_request *req)
Return the received packet's RADIUS code.
Definition dae.c:1593
int radcli_ctx_dispatch(radcli_ctx *ctx)
Read what is ready on ctx's descriptor(s), validate it, and invoke the registered handler for anythin...
Definition dae.c:2324
int radcli_dae_reply(radcli_dae_request *req, int ack)
Answer a request with an ACK or NAK, selecting 41/42 or 44/45 from the request's own code,...
Definition dae.c:1806
struct radcli_dae_st radcli_dae
Definition radcli2.h:678
const char * radcli_dae_req_user_name(const radcli_dae_request *req)
Return the request's User-Name, if it carried one.
Definition dae.c:1634
int radcli_dae_start(radcli_dae *dae)
Start receiving: binds the socket described by dae-listen.
Definition dae.c:896
const radcli_avp_list * radcli_dae_req_attrs(const radcli_dae_request *req)
Return the request's decoded attributes.
Definition dae.c:1608
#define RADCLI_CTX_MAX_POLLFDS
Definition radcli2.h:764
int radcli_dae_reply_error(radcli_dae_request *req, uint32_t error_cause)
Answer a request with a NAK carrying the given Error-Cause.
Definition dae.c:1821
radcli_dae * radcli_dae_new(radcli_ctx *ctx, unsigned flags)
Validate dae-* configuration and build a dynamic-authorization listener. Opens no socket – see radcli...
Definition dae.c:638
struct radcli_dae_request_st radcli_dae_request
Definition radcli2.h:688
void radcli_dae_request_free(radcli_dae_request *req)
Release a request.
Definition dae.c:1890
int radcli_avp_get_uint64(const radcli_avp *a, uint64_t *out)
Read an attribute's value as a 64-bit integer or ifid.
Definition avp.c:742
radcli_avp_iter radcli_avp_list_iter(const radcli_avp_list *list)
Begin iterating list.
Definition avp.c:666
int radcli_avp_get_ip6(const radcli_avp *a, struct in6_addr *out, unsigned *prefix)
Read an attribute's value as an IPv6 address or prefix.
Definition avp.c:769
int radcli_avp_get_uint32(const radcli_avp *a, uint32_t *out)
Read an attribute's value as an integer/IPv4-address/date.
Definition avp.c:716
const radcli_attr_def * radcli_avp_def(const radcli_avp *a)
Return the attribute definition of a.
Definition avp.c:703
const radcli_avp * radcli_avp_iter_next(radcli_avp_iter *it)
Return the current attribute and advance.
Definition avp.c:680
int radcli_avp_get_bytes(const radcli_avp *a, const void **out, size_t *len)
Read an attribute's value as raw bytes.
Definition avp.c:853
const char * radcli_attr_def_name(const radcli_attr_def *def)
Return an attribute definition's canonical name.
Definition dict2.c:615
radcli_attr_type radcli_attr_def_type(const radcli_attr_def *def)
Return an attribute definition's wire type.
Definition dict2.c:624
@ RADCLI_TYPE_IPV6PREFIX
Definition radcli2.h:200
@ RADCLI_TYPE_STRING
Definition radcli2.h:174
@ RADCLI_TYPE_DATE
Definition radcli2.h:190
@ RADCLI_TYPE_INTEGER64
Definition radcli2.h:205
@ RADCLI_TYPE_IPADDR
Definition radcli2.h:183
@ RADCLI_TYPE_IPV6ADDR
Definition radcli2.h:197
@ RADCLI_TYPE_INTEGER
Definition radcli2.h:180
radcli_code
Definition radcli2.h:506