264
228
if (!request->proxy_reply &&
229
request->home_server &&
265
230
request->home_server->currently_outstanding) {
266
231
request->home_server->currently_outstanding--;
235
* Got from YES in hash, to NO, not in hash while we hold
236
* the mutex. This guarantees that when another thread
237
* grans the mutex, the "not in hash" flag is correct.
239
request->in_proxy_hash = FALSE;
269
241
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
271
request->in_proxy_hash = FALSE;
275
static int insert_into_proxy_hash(REQUEST *request)
244
static void ev_request_free(REQUEST **prequest)
248
if (!prequest || !*prequest) return;
255
* Divorce the child from the parent first,
256
* then clean up the child.
258
request->coa->parent = NULL;
259
ev_request_free(&request->coa);
263
* Divorce the parent from the child, and leave the
264
* parent still alive.
266
if (request->parent && (request->parent->coa == request)) {
267
request->parent->coa = NULL;
271
if (request->ev) fr_event_delete(el, &request->ev);
272
if (request->in_proxy_hash) remove_from_proxy_hash(request);
273
if (request->in_request_hash) remove_from_request_hash(request);
275
request_free(prequest);
278
static int proxy_id_alloc(REQUEST *request, RADIUS_PACKET *packet)
281
rad_listen_t *proxy_listener;
283
if (fr_packet_list_id_alloc(proxy_list, packet)) return 1;
286
* Allocate a new proxy fd. This function adds
287
* it to the tail of the list of listeners. With
288
* some care, this can be thread-safe.
290
proxy_listener = proxy_new_listener(&packet->src_ipaddr, FALSE);
291
if (!proxy_listener) {
292
RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
300
proxy = proxy_listener->fd;
301
for (i = 0; i < 32; i++) {
303
* Found a free entry. Save the socket,
304
* and remember where we saved it.
306
if (proxy_fds[(proxy + i) & 0x1f] == -1) {
307
found = (proxy + i) & 0x1f;
308
proxy_fds[found] = proxy;
309
proxy_listeners[found] = proxy_listener;
313
rad_assert(found >= 0);
315
if (!fr_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
316
RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
321
if (!fr_packet_list_id_alloc(proxy_list, packet)) {
322
RDEBUG2("ERROR: Failed to create a new socket for proxying requests.");
327
* Signal the main thread to add the new FD to the list
330
radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
335
static int insert_into_proxy_hash(REQUEST *request, int retransmit)
280
340
rad_assert(request->proxy != NULL);
281
341
rad_assert(proxy_list != NULL);
283
request->proxy->sockfd = -1;
285
343
PTHREAD_MUTEX_LOCK(&proxy_mutex);
287
request->home_server->currently_outstanding++;
288
request->home_server->total_requests_sent++;
291
* On overflow, back up to ~0.
346
* Keep track of maximum outstanding requests to a
347
* particular home server. 'max_outstanding' is
348
* enforced in home_server_ldb(), in realms.c.
293
if (!request->home_server->total_requests_sent) {
294
request->home_server->total_requests_sent--;
297
if (!fr_packet_list_id_alloc(proxy_list, request->proxy)) {
299
rad_listen_t *proxy_listener;
302
* Allocate a new proxy fd. This function adds
303
* it to the tail of the list of listeners. With
304
* some care, this can be thread-safe.
306
proxy_listener = proxy_new_listener();
307
if (!proxy_listener) {
308
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
309
DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
317
proxy = proxy_listener->fd;
318
for (i = 0; i < 32; i++) {
320
* Found a free entry. Save the socket,
321
* and remember where we saved it.
323
if (proxy_fds[(proxy + i) & 0x1f] == -1) {
324
found = (proxy + i) & 0x1f;
325
proxy_fds[found] = proxy;
326
proxy_listeners[found] = proxy_listener;
330
rad_assert(found >= 0);
332
if (!fr_packet_list_socket_add(proxy_list, proxy_listener->fd)) {
333
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
334
DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
339
if (!fr_packet_list_id_alloc(proxy_list, request->proxy)) {
340
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
341
DEBUG2("ERROR: Failed to create a new socket for proxying requests.");
346
* Signal the main thread to add the new FD to the list
349
radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
350
if (request->home_server) {
351
request->home_server->currently_outstanding++;
355
RADIUS_PACKET packet;
357
packet = *request->proxy;
359
if (!proxy_id_alloc(request, &packet)) {
360
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
365
* Yank the request, free the old Id, and
366
* remember the new Id.
368
fr_packet_list_yank(proxy_list, request->proxy);
369
fr_packet_list_id_free(proxy_list, request->proxy);
370
*request->proxy = packet;
372
} else if (!proxy_id_alloc(request, request->proxy)) {
373
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
351
377
rad_assert(request->proxy->sockfd >= 0);
470
504
remove_from_request_hash(request);
472
507
if (request->proxy && request->in_proxy_hash) {
473
508
wait_for_proxy_id_to_expire(request);
477
DEBUG2("Cleaning up request %d ID %d with timestamp +%d",
513
RDEBUG2("Cleaning up request %d ID %d with timestamp +%d",
478
514
request->number, request->packet->id,
479
(unsigned int) (request->timestamp - start_time));
481
fr_event_delete(el, &request->ev);
482
request_free(&request);
515
(unsigned int) (request->timestamp - fr_start_time));
517
ev_request_free(&request);
522
* In daemon mode, AND this request has debug flags set.
524
#define DEBUG_PACKET if (!debug_flag && request->options && request->radlog) debug_packet
526
static void debug_packet(REQUEST *request, RADIUS_PACKET *packet, int direction)
530
const char *received, *from;
531
const fr_ipaddr_t *ip;
536
rad_assert(request->radlog != NULL);
538
if (direction == 0) {
539
received = "Received";
540
from = "from"; /* what else? */
541
ip = &packet->src_ipaddr;
542
port = packet->src_port;
545
received = "Sending";
546
from = "to"; /* hah! */
547
ip = &packet->dst_ipaddr;
548
port = packet->dst_port;
552
* Client-specific debugging re-prints the input
553
* packet into the client log.
555
* This really belongs in a utility library
557
if ((packet->code > 0) && (packet->code < FR_MAX_PACKET_CODE)) {
558
RDEBUG("%s %s packet %s host %s port %d, id=%d, length=%d",
559
received, fr_packet_codes[packet->code], from,
560
inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
561
port, packet->id, packet->data_len);
563
RDEBUG("%s packet %s host %s port %d code=%d, id=%d, length=%d",
565
inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
567
packet->code, packet->id, packet->data_len);
570
for (vp = packet->vps; vp != NULL; vp = vp->next) {
571
vp_prints(buffer, sizeof(buffer), vp);
572
request->radlog(L_DBG, 0, request, "\t%s", buffer);
486
576
static void reject_delay(void *ctx)
533
641
static void received_response_to_ping(REQUEST *request)
535
home_server *home = request->home_server;
536
644
char buffer[128];
646
rad_assert(request->home_server != NULL);
648
home = request->home_server;
538
649
home->num_received_pings++;
540
DEBUG2("Received response to status check %d (%d in current sequence)",
651
RDEBUG2("Received response to status check %d (%d in current sequence)",
541
652
request->number, home->num_received_pings);
655
* Remove the request from any hashes
657
fr_event_delete(el, &request->ev);
658
remove_from_proxy_hash(request);
659
rad_assert(request->in_request_hash == FALSE);
662
* The control socket may have marked the home server as
663
* alive. OR, it may have suddenly started responding to
664
* requests again. If so, don't re-do the "make alive"
667
if (home->state == HOME_STATE_ALIVE) return;
670
* We haven't received enough ping responses to mark it
671
* "alive". Wait a bit.
543
673
if (home->num_received_pings < home->num_pings_to_alive) {
544
wait_for_proxy_id_to_expire(request);
548
DEBUG2("Marking home server %s port %d alive",
549
inet_ntop(request->proxy->dst_ipaddr.af,
550
&request->proxy->dst_ipaddr.ipaddr,
551
buffer, sizeof(buffer)),
552
request->proxy->dst_port);
677
home->state = HOME_STATE_ALIVE;
678
home->currently_outstanding = 0;
679
home->revive_time = now;
554
681
if (!fr_event_delete(el, &home->ev)) {
555
DEBUG2("Hmm... no event for home server, WTF?");
558
if (!fr_event_delete(el, &request->ev)) {
559
DEBUG2("Hmm... no event for request, WTF?");
562
wait_for_proxy_id_to_expire(request);
564
home->state = HOME_STATE_ALIVE;
565
home->currently_outstanding = 0;
682
RDEBUG2("Hmm... no event for home server. Oh well.");
685
radlog(L_INFO, "PROXY: Marking home server %s port %d alive",
686
inet_ntop(request->proxy->dst_ipaddr.af,
687
&request->proxy->dst_ipaddr.ipaddr,
688
buffer, sizeof(buffer)),
689
request->proxy->dst_port);
694
* Called from start of zombie period, OR after control socket
695
* marks the home server dead.
569
697
static void ping_home_server(void *ctx)
982
1249
* mode, with no threads...
984
1251
if (!callback) {
985
DEBUG("WARNING: Internal sanity check failed in event handler for request %d: Discarding the request!", request->number);
986
fr_event_delete(el, &request->ev);
987
remove_from_proxy_hash(request);
988
remove_from_request_hash(request);
989
request_free(&request);
1252
RDEBUG("WARNING: Internal sanity check failed in event handler for request %d: Discarding the request!", request->number);
1253
ev_request_free(&request);
993
1257
INSERT_EVENT(callback, request);
1261
static void no_response_to_coa_request(void *ctx)
1263
REQUEST *request = ctx;
1266
rad_assert(request->magic == REQUEST_MAGIC);
1267
rad_assert(request->child_state == REQUEST_PROXIED);
1268
rad_assert(request->home_server != NULL);
1269
rad_assert(!request->in_request_hash);
1271
radlog(L_ERR, "No response to CoA request sent to %s",
1272
inet_ntop(request->proxy->dst_ipaddr.af,
1273
&request->proxy->dst_ipaddr.ipaddr,
1274
buffer, sizeof(buffer)));
1279
request->packet->code |= (PW_COA_REQUEST << 8);
1280
post_proxy_fail_handler(request);
1284
static int update_event_timestamp(RADIUS_PACKET *packet, time_t when)
1288
vp = pairfind(packet->vps, PW_EVENT_TIMESTAMP);
1295
packet->data = NULL;
1296
packet->data_len = 0;
1299
return 1; /* time stamp updated */
1304
* Called when we haven't received a response to a CoA request.
1306
static void retransmit_coa_request(void *ctx)
1310
REQUEST *request = ctx;
1312
rad_assert(request->magic == REQUEST_MAGIC);
1313
rad_assert(request->child_state == REQUEST_PROXIED);
1314
rad_assert(request->home_server != NULL);
1315
rad_assert(!request->in_request_hash);
1316
rad_assert(request->parent == NULL);
1318
fr_event_now(el, &now);
1321
* Cap count at MRC, if it is non-zero.
1323
if (request->home_server->coa_mrc &&
1324
(request->num_coa_requests >= request->home_server->coa_mrc)) {
1325
no_response_to_coa_request(request);
1330
* RFC 5080 Section 2.2.1
1332
* RT = 2*RTprev + RAND*RTprev
1333
* = 1.9 * RTprev + rand(0,.2) * RTprev
1334
* = 1.9 * RTprev + rand(0,1) * (RTprev / 5)
1337
delay ^= (delay >> 16);
1339
frac = request->delay / 5;
1340
delay = ((frac >> 16) * delay) + (((frac & 0xffff) * delay) >> 16);
1342
delay += (2 * request->delay) - (request->delay / 10);
1345
* Cap delay at MRT, if MRT is non-zero.
1347
if (request->home_server->coa_mrt &&
1348
(delay > (request->home_server->coa_mrt * USEC))) {
1349
int mrt_usec = request->home_server->coa_mrt * USEC;
1352
* delay = MRT + RAND * MRT
1353
* = 0.9 MRT + rand(0,.2) * MRT
1356
delay ^= (delay >> 15);
1358
delay = ((mrt_usec >> 16) * delay) + (((mrt_usec & 0xffff) * delay) >> 16);
1359
delay += mrt_usec - (mrt_usec / 10);
1362
request->delay = delay;
1363
request->when = now;
1364
tv_add(&request->when, request->delay);
1365
mrd = request->proxy_when;
1366
mrd.tv_sec += request->home_server->coa_mrd;
1369
* Cap duration at MRD.
1371
if (timercmp(&mrd, &request->when, <)) {
1372
request->when = mrd;
1373
INSERT_EVENT(no_response_to_coa_request, request);
1376
INSERT_EVENT(retransmit_coa_request, request);
1379
if (update_event_timestamp(request->proxy, now.tv_sec)) {
1380
if (!insert_into_proxy_hash(request, TRUE)) {
1381
DEBUG("ERROR: Failed re-inserting CoA request into proxy hash.");
1385
request->num_proxied_requests = 0;
1386
request->num_proxied_responses = 0;
1389
request->num_proxied_requests++;
1390
request->num_coa_requests++; /* is NOT reset by code 3 lines above! */
1392
request->proxy_listener->send(request->proxy_listener,
1398
* The original request is either DONE, or in CLEANUP_DELAY.
1400
static int originated_coa_request(REQUEST *request)
1402
int delay, rcode, pre_proxy_type = 0;
1408
rad_assert(request->proxy == NULL);
1409
rad_assert(!request->in_proxy_hash);
1410
rad_assert(request->proxy_reply == NULL);
1412
vp = pairfind(request->config_items, PW_SEND_COA_REQUEST);
1413
if (!vp && request->coa) vp = pairfind(request->coa->proxy->vps, PW_SEND_COA_REQUEST);
1415
if (vp->vp_integer == 0) {
1416
ev_request_free(&request->coa);
1417
return 1; /* success */
1420
if (!request->coa) request_alloc_coa(request);
1421
if (!request->coa) return 0;
1427
* src_ipaddr will be set up in proxy_encode.
1429
memset(&ipaddr, 0, sizeof(ipaddr));
1430
vp = pairfind(coa->proxy->vps, PW_PACKET_DST_IP_ADDRESS);
1432
ipaddr.af = AF_INET;
1433
ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
1435
} else if ((vp = pairfind(coa->proxy->vps,
1436
PW_PACKET_DST_IPV6_ADDRESS)) != NULL) {
1437
ipaddr.af = AF_INET6;
1438
ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
1440
} else if ((vp = pairfind(coa->proxy->vps,
1441
PW_HOME_SERVER_POOL)) != NULL) {
1442
coa->home_pool = home_pool_byname(vp->vp_strvalue,
1444
if (!coa->home_pool) {
1445
RDEBUG2("WARNING: No such home_server_pool %s",
1448
ev_request_free(&request->coa);
1455
} else if (request->client->coa_pool) {
1456
coa->home_pool = request->client->coa_pool;
1458
} else if (request->client->coa_server) {
1459
coa->home_server = request->client->coa_server;
1463
* If all else fails, send it to the client that
1464
* originated this request.
1466
memcpy(&ipaddr, &request->packet->src_ipaddr, sizeof(ipaddr));
1470
* Use the pool, if it exists.
1472
if (coa->home_pool) {
1473
coa->home_server = home_server_ldb(NULL, coa->home_pool, coa);
1474
if (!coa->home_server) {
1475
RDEBUG("WARNING: No live home server for home_server_pool %s", vp->vp_strvalue);
1479
} else if (!coa->home_server) {
1480
int port = PW_COA_UDP_PORT;
1482
vp = pairfind(coa->proxy->vps, PW_PACKET_DST_PORT);
1483
if (vp) port = vp->vp_integer;
1485
coa->home_server = home_server_find(&ipaddr, port);
1486
if (!coa->home_server) {
1487
RDEBUG2("WARNING: Unknown destination %s:%d for CoA request.",
1488
inet_ntop(ipaddr.af, &ipaddr.ipaddr,
1489
buffer, sizeof(buffer)), port);
1494
vp = pairfind(coa->proxy->vps, PW_PACKET_TYPE);
1496
switch (vp->vp_integer) {
1497
case PW_COA_REQUEST:
1498
case PW_DISCONNECT_REQUEST:
1499
coa->proxy->code = vp->vp_integer;
1503
DEBUG("Cannot set CoA Packet-Type to code %d",
1509
if (!coa->proxy->code) coa->proxy->code = PW_COA_REQUEST;
1512
* The rest of the server code assumes that
1513
* request->packet && request->reply exist. Copy them
1514
* from the original request.
1516
rad_assert(coa->packet != NULL);
1517
rad_assert(coa->packet->vps == NULL);
1518
memcpy(coa->packet, request->packet, sizeof(*request->packet));
1519
coa->packet->vps = paircopy(request->packet->vps);
1520
coa->packet->data = NULL;
1521
rad_assert(coa->reply != NULL);
1522
rad_assert(coa->reply->vps == NULL);
1523
memcpy(coa->reply, request->reply, sizeof(*request->reply));
1524
coa->reply->vps = paircopy(request->reply->vps);
1525
coa->reply->data = NULL;
1526
coa->config_items = paircopy(request->config_items);
1529
* Call the pre-proxy routines.
1531
vp = pairfind(request->config_items, PW_PRE_PROXY_TYPE);
1533
RDEBUG2(" Found Pre-Proxy-Type %s", vp->vp_strvalue);
1534
pre_proxy_type = vp->vp_integer;
1537
if (coa->home_pool && coa->home_pool->virtual_server) {
1538
const char *old_server = coa->server;
1540
coa->server = coa->home_pool->virtual_server;
1541
RDEBUG2(" server %s {", coa->server);
1542
rcode = module_pre_proxy(pre_proxy_type, coa);
1544
coa->server = old_server;
1546
rcode = module_pre_proxy(pre_proxy_type, coa);
1553
* Only send the CoA packet if the pre-proxy code succeeded.
1555
case RLM_MODULE_NOOP:
1557
case RLM_MODULE_UPDATED:
1562
* Source IP / port is set when the proxy socket
1565
coa->proxy->dst_ipaddr = coa->home_server->ipaddr;
1566
coa->proxy->dst_port = coa->home_server->port;
1568
if (!insert_into_proxy_hash(coa, FALSE)) {
1569
DEBUG("ERROR: Failed inserting CoA request into proxy hash.");
1574
* We CANNOT divorce the CoA request from the parent
1575
* request. This function is running in a child thread,
1576
* and we need access to the main event loop in order to
1577
* to add the timers for the CoA packet. See
1582
* Forget about the original request completely at this
1587
gettimeofday(&request->proxy_when, NULL);
1588
request->received = request->next_when = request->proxy_when;
1589
rad_assert(request->proxy_reply == NULL);
1592
* Implement re-transmit algorithm as per RFC 5080
1595
* We want IRT + RAND*IRT
1596
* or 0.9 IRT + rand(0,.2) IRT
1598
* 2^20 ~ USEC, and we want 2.
1599
* rand(0,0.2) USEC ~ (rand(0,2^21) / 10)
1601
delay = (fr_rand() & ((1 << 22) - 1)) / 10;
1602
request->delay = delay * request->home_server->coa_irt;
1603
delay = request->home_server->coa_irt * USEC;
1604
delay -= delay / 10;
1605
delay += request->delay;
1607
request->delay = delay;
1608
tv_add(&request->next_when, delay);
1609
request->next_callback = retransmit_coa_request;
1612
* Note that we set proxied BEFORE sending the packet.
1614
* Once we send it, the request is tainted, as
1615
* another thread may have picked it up. Don't
1618
request->num_proxied_requests = 1;
1619
request->num_proxied_responses = 0;
1620
request->child_pid = NO_SUCH_CHILD_PID;
1622
update_event_timestamp(request->proxy, request->proxy_when.tv_sec);
1624
request->child_state = REQUEST_PROXIED;
1626
DEBUG_PACKET(request, request->proxy, 1);
1628
request->proxy_listener->send(request->proxy_listener,
1632
#endif /* WITH_COA */
1635
static int process_proxy_reply(REQUEST *request)
1638
int post_proxy_type = 0;
1642
* Delete any reply we had accumulated until now.
1644
pairfree(&request->reply->vps);
1647
* Run the packet through the post-proxy stage,
1648
* BEFORE playing games with the attributes.
1650
vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
1652
RDEBUG2(" Found Post-Proxy-Type %s", vp->vp_strvalue);
1653
post_proxy_type = vp->vp_integer;
1656
if (request->home_pool && request->home_pool->virtual_server) {
1657
const char *old_server = request->server;
1659
request->server = request->home_pool->virtual_server;
1660
RDEBUG2(" server %s {", request->server);
1661
rcode = module_post_proxy(post_proxy_type, request);
1663
request->server = old_server;
1665
rcode = module_post_proxy(post_proxy_type, request);
1669
if (request->packet->code == request->proxy->code)
1671
* Don't run the next bit if we originated a CoA
1672
* packet, after receiving an Access-Request or
1673
* Accounting-Request.
1678
* There may NOT be a proxy reply, as we may be
1679
* running Post-Proxy-Type = Fail.
1681
if (request->proxy_reply) {
1683
* Delete the Proxy-State Attributes from
1684
* the reply. These include Proxy-State
1685
* attributes from us and remote server.
1687
pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);
1690
* Add the attributes left in the proxy
1691
* reply to the reply list.
1693
pairadd(&request->reply->vps, request->proxy_reply->vps);
1694
request->proxy_reply->vps = NULL;
1697
* Free proxy request pairs.
1699
pairfree(&request->proxy->vps);
1703
default: /* Don't do anything */
1705
case RLM_MODULE_FAIL:
1706
/* FIXME: debug print stuff */
1707
request->child_state = REQUEST_DONE;
1710
case RLM_MODULE_HANDLED:
1711
/* FIXME: debug print stuff */
1712
request->child_state = REQUEST_DONE;
997
1720
static int request_pre_handler(REQUEST *request)
1020
1744
* Put the decoded packet into it's proper place.
1022
1746
if (request->proxy_reply != NULL) {
1023
1747
rcode = request->proxy_listener->decode(request->proxy_listener,
1025
} else if (request->packet->vps == NULL) {
1749
DEBUG_PACKET(request, request->proxy_reply, 0);
1752
if (request->packet->vps == NULL) {
1026
1753
rcode = request->listener->decode(request->listener, request);
1755
if (debug_condition) {
1757
const char *my_debug = debug_condition;
1760
* Ignore parse errors.
1762
radius_evaluate_condition(request, RLM_MODULE_OK, 0,
1766
request->options = 2;
1767
request->radlog = radlog_request;
1771
DEBUG_PACKET(request, request->packet, 0);
1032
1776
if (rcode < 0) {
1033
radlog(L_ERR, "%s Dropping packet without response.", librad_errstr);
1777
radlog(L_ERR, "%s Dropping packet without response.", fr_strerror());
1034
1778
request->child_state = REQUEST_DONE;
1038
if (!request->proxy) {
1782
if (!request->username) {
1039
1783
request->username = pairfind(request->packet->vps,
1043
int post_proxy_type = 0;
1047
* Delete any reply we had accumulated until now.
1049
pairfree(&request->reply->vps);
1052
* Run the packet through the post-proxy stage,
1053
* BEFORE playing games with the attributes.
1055
vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
1057
DEBUG2(" Found Post-Proxy-Type %s", vp->vp_strvalue);
1058
post_proxy_type = vp->vp_integer;
1061
rad_assert(request->home_pool != NULL);
1063
if (request->home_pool->virtual_server) {
1064
const char *old_server = request->server;
1066
request->server = request->home_pool->virtual_server;
1067
DEBUG2(" server %s {", request->server);
1068
rcode = module_post_proxy(post_proxy_type, request);
1070
request->server = old_server;
1072
rcode = module_post_proxy(post_proxy_type, request);
1076
* There may NOT be a proxy reply, as we may be
1077
* running Post-Proxy-Type = Fail.
1079
if (request->proxy_reply) {
1081
* Delete the Proxy-State Attributes from
1082
* the reply. These include Proxy-State
1083
* attributes from us and remote server.
1085
pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);
1088
* Add the attributes left in the proxy
1089
* reply to the reply list.
1091
pairadd(&request->reply->vps, request->proxy_reply->vps);
1092
request->proxy_reply->vps = NULL;
1095
* Free proxy request pairs.
1097
pairfree(&request->proxy->vps);
1101
default: /* Don't do anything */
1103
case RLM_MODULE_FAIL:
1104
/* FIXME: debug print stuff */
1105
request->child_state = REQUEST_DONE;
1108
case RLM_MODULE_HANDLED:
1109
/* FIXME: debug print stuff */
1110
request->child_state = REQUEST_DONE;
1788
if (request->proxy) {
1789
return process_proxy_reply(request);
1120
1799
* Do state handling when we proxy a request.
1254
2015
if (request->packet->code == PW_AUTHENTICATION_REQUEST) {
1255
2016
pool = realm->auth_pool;
2018
#ifdef WITH_ACCOUNTING
1257
2019
} else if (request->packet->code == PW_ACCOUNTING_REQUEST) {
1258
2020
pool = realm->acct_pool;
2024
} else if ((request->packet->code == PW_COA_REQUEST) ||
2025
(request->packet->code == PW_DISCONNECT_REQUEST)) {
2026
pool = realm->acct_pool;
1261
2030
rad_panic("Internal sanity check failed");
1265
DEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
2034
RDEBUG2(" WARNING: Cancelling proxy to Realm %s, as the realm is local.",
1270
2040
home = home_server_ldb(realmname, pool, request);
1272
DEBUG2("ERROR: Failed to find live home server for realm %s",
2042
RDEBUG2("ERROR: Failed to find live home server for realm %s",
1276
2046
request->home_pool = pool;
2050
* Once we've decided to proxy a request, we cannot send
2051
* a CoA packet. So we free up any CoA packet here.
2053
ev_request_free(&request->coa);
1279
2056
* Remember that we sent the request to a Realm.
1281
pairadd(&request->packet->vps,
1282
pairmake("Realm", realmname, T_OP_EQ));
1285
* We read the packet from a detail file, AND it came from
1286
* the server we're about to send it to. Don't do that.
1288
if ((request->packet->code == PW_ACCOUNTING_REQUEST) &&
1289
(request->listener->type == RAD_LISTEN_DETAIL) &&
1290
(home->ipaddr.af == AF_INET) &&
1291
(request->packet->src_ipaddr.af == AF_INET) &&
1292
(home->ipaddr.ipaddr.ip4addr.s_addr == request->packet->src_ipaddr.ipaddr.ip4addr.s_addr)) {
1293
DEBUG2(" rlm_realm: Packet came from realm %s, proxy cancelled", realmname);
1298
* Allocate the proxy packet, only if it wasn't already
1299
* allocated by a module. This check is mainly to support
1300
* the proxying of EAP-TTLS and EAP-PEAP tunneled requests.
1302
* In those cases, the EAP module creates a "fake"
1303
* request, and recursively passes it through the
1304
* authentication stage of the server. The module then
1305
* checks if the request was supposed to be proxied, and
1306
* if so, creates a proxy packet from the TUNNELED request,
1307
* and not from the EAP request outside of the tunnel.
1309
* The proxy then works like normal, except that the response
1310
* packet is "eaten" by the EAP module, and encapsulated into
1313
if (!request->proxy) {
1314
if ((request->proxy = rad_alloc(TRUE)) == NULL) {
1315
radlog(L_ERR|L_CONS, "no memory");
1320
* Copy the request, then look up name and
1321
* plain-text password in the copy.
1323
* Note that the User-Name attribute is the
1324
* *original* as sent over by the client. The
1325
* Stripped-User-Name attribute is the one hacked
1326
* through the 'hints' file.
1328
request->proxy->vps = paircopy(request->packet->vps);
2058
if (realmname) pairadd(&request->packet->vps,
2059
pairmake("Realm", realmname, T_OP_EQ));
1332
2062
* Strip the name, if told to.
2110
2958
* ? The home server gave us a new proxy
2111
* reply, which doesn't match the old
2959
* reply which doesn't match the old
2112
2960
* one. Delete it.
2114
DEBUG2("Ignoring conflicting proxy reply");
2962
RDEBUG2("Ignoring conflicting proxy reply");
2117
2965
/* assert that there's an event queued for request? */
2970
* Verify the packet before doing ANYTHING with it. This
2971
* means we're doing more MD5 checks in the server core.
2972
* However, we can fix that by moving to multiple threads
2973
* listening on sockets.
2975
* We do this AFTER looking the request up in the hash,
2976
* and AFTER vhecking if we saw a previous request. This
2977
* helps minimize the DoS effect of people attacking us
2978
* with spoofed packets.
2980
if (rad_verify(packet, request->proxy,
2981
request->home_server->secret) != 0) {
2982
DEBUG("Ignoring spoofed proxy reply. Signature is invalid");
2986
gettimeofday(&now, NULL);
2989
* Maybe move this earlier in the decision process?
2990
* Having it here means that late or duplicate proxy
2991
* replies no longer get the home server marked as
2992
* "alive". This might be good for stability, though.
2994
* FIXME: Do we really want to do this whenever we
2995
* receive a packet? Setting this here means that we
2996
* mark it alive on *any* packet, even if it's lost all
2997
* of the *other* packets in the last 10s.
2999
request->home_server->state = HOME_STATE_ALIVE;
3003
* When originating CoA, the "proxy" reply is the reply
3004
* to the CoA request that we originated. At this point,
3005
* the original request is finished, and it has a reply.
3007
* However, if we haven't separated the two requests, do
3008
* so now. This is done so that cleaning up the original
3009
* request won't cause the CoA request to be free'd. See
3010
* util.c, request_free()
3012
if (request->parent && (request->parent->coa == request)) {
3013
request->parent->coa = NULL;
3014
request->parent = NULL;
3018
* Skip the next set of checks, as the original
3019
* reply is cached. We want to be able to still
3020
* process the CoA reply, AND to reference the
3021
* original request/reply.
3023
* This is getting to be really quite a bit of a
3029
* If there's a reply to the NAS, ignore everything
3030
* related to proxy responses
3032
if (request->reply && request->reply->code != 0) {
3033
RDEBUG2("Ignoring proxy reply that arrived after we sent a reply to the NAS");
3039
* The average includes our time to receive packets and
3040
* look them up in the hashes, which should be the same
3043
* We update the response time only for the FIRST packet
3046
if (request->home_server->ema.window > 0) {
3047
radius_stats_ema(&request->home_server->ema,
3048
&now, &request->proxy_when);
2122
3052
switch (request->child_state) {
2123
3053
case REQUEST_QUEUED:
2124
3054
case REQUEST_RUNNING:
2125
rad_panic("Internal sanity check failed for child state");
3055
radlog(L_ERR, "Internal sanity check failed for child state");
2128
3058
case REQUEST_REJECT_DELAY:
2129
3059
case REQUEST_CLEANUP_DELAY:
3322
typedef struct listen_detail_t {
2379
* This function is called periodically to see if any FD's are
2380
* available for reading.
3327
* This function is called periodically to see if this detail
3328
* file is available for reading.
2382
static void event_poll_fds(UNUSED void *ctx)
3330
static void event_poll_detail(void *ctx)
2385
3333
RAD_REQUEST_FUNP fun;
2386
3334
REQUEST *request;
3335
rad_listen_t *this = ctx;
2388
3336
struct timeval when;
2390
fr_event_now(el, &now);
3337
listen_detail_t *detail = this->data;
3339
rad_assert(this->type == RAD_LISTEN_DETAIL);
3342
* Try to read something.
3344
* FIXME: This does poll AND receive.
3346
rcode = this->recv(this, &fun, &request);
3348
rad_assert(fun != NULL);
3349
rad_assert(request != NULL);
3351
if (!thread_pool_addrequest(request, fun)) {
3352
request->child_state = REQUEST_DONE;
3356
if (!fr_event_now(el, &now)) gettimeofday(&now, NULL);
2394
for (this = mainconfig.listen; this != NULL; this = this->next) {
2395
if (this->fd >= 0) continue;
2398
* Try to read something.
2400
* FIXME: This does poll AND receive.
2402
rcode = this->recv(this, &fun, &request);
2403
if (!rcode) continue;
2405
rad_assert(fun != NULL);
2406
rad_assert(request != NULL);
2408
if (!thread_pool_addrequest(request, fun)) {
2409
request->child_state = REQUEST_DONE;
2413
* We have an FD. Start watching it.
2415
if (this->fd >= 0) {
2417
* ... unless it's a detail file. In
2418
* that case, we rely on the signal to
2419
* self to know when to continue
2420
* processing the detail file.
2422
if (this->type == RAD_LISTEN_DETAIL) continue;
2425
* FIXME: this should be SNMP handler,
2426
* and we should do SOMETHING when the
2429
if (!fr_event_fd_insert(el, 0, this->fd,
2430
event_socket_handler, this)) {
2433
this->print(this, buffer, sizeof(buffer));
2434
rad_panic("Failed creating handler for snmp");
3360
* Backdoor API to get the delay until the next poll
2442
if (!fr_event_insert(el, event_poll_fds, NULL,
3363
delay = this->encode(this, NULL);
3364
tv_add(&when, delay);
3366
if (!fr_event_insert(el, event_poll_detail, this,
3367
&when, &detail->ev)) {
2444
3368
radlog(L_ERR, "Failed creating handler");