diff options
Diffstat (limited to '')
-rw-r--r-- | src/main/process.c | 189 |
1 files changed, 149 insertions, 40 deletions
diff --git a/src/main/process.c b/src/main/process.c index ed77839..9880e34 100644 --- a/src/main/process.c +++ b/src/main/process.c @@ -1006,6 +1006,12 @@ static void request_cleanup_delay_init(REQUEST *request) #ifdef HAVE_PTHREAD_H rad_assert(request->child_pid == NO_SUCH_CHILD_PID); #endif + + /* + * Set the statistics immediately if we can. + */ + request_stats_final(request); + STATE_MACHINE_TIMER(FR_ACTION_TIMER); return; } @@ -1258,6 +1264,9 @@ static void request_cleanup_delay(REQUEST *request, int action) #ifdef DEBUG_STATE_MACHINE if (rad_debug_lvl) printf("(%u) ********\tNEXT-STATE %s -> %s\n", request->number, __FUNCTION__, "request_cleanup_delay"); #endif + + request_stats_final(request); + STATE_MACHINE_TIMER(FR_ACTION_TIMER); return; } /* else it's time to clean up */ @@ -1486,7 +1495,7 @@ static void request_finish(REQUEST *request, int action) /* * Maybe originate a CoA request. */ - if ((action == FR_ACTION_RUN) && !request->proxy && request->coa) { + if ((action == FR_ACTION_RUN) && (!request->proxy || request->proxy->dst_port == 0) && request->coa) { request_coa_originate(request); } #endif @@ -1591,9 +1600,14 @@ static void request_finish(REQUEST *request, int action) #ifdef WITH_PROXY /* * If we timed out a proxy packet, don't delay - * the reject any more. + * the reject any more. Or, if we proxied it to + * a real home server, then don't delay it. + * + * We don't want to have each proxy in a chain + * adding their own reject delay, which would + * result in N*reject_delays being applied. */ - if (request->proxy && !request->proxy_reply) { + if (request->proxy && (!request->proxy_reply || request->proxy->dst_port != 0)) { request->response_delay.tv_sec = 0; request->response_delay.tv_usec = 0; } @@ -2024,6 +2038,10 @@ static REQUEST *request_setup(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PA return NULL; } +#ifdef WITH_RADIUSV11 + request->reply->radiusv11 = packet->radiusv11; +#endif + request->listener = listener; request->client = client; request->packet = talloc_steal(request, packet); @@ -2286,16 +2304,6 @@ static void remove_from_proxy_hash_nl(REQUEST *request, bool yank) if (!request->in_proxy_hash) return; -#ifdef COA_TUNNEL - /* - * Track how many IDs are used. This information - * helps the listen_coa_find() function get a - * listener which has free IDs. - */ - rad_assert(request->proxy_listener->num_ids_used > 0); - request->proxy_listener->num_ids_used--; -#endif - fr_packet_list_id_free(proxy_list, request->proxy, yank); request->in_proxy_hash = false; @@ -2341,6 +2349,18 @@ static void remove_from_proxy_hash_nl(REQUEST *request, bool yank) if (request->proxy_listener) { request->proxy_listener->count--; + +#ifdef WITH_COA_TUNNEL + /* + * Track how many IDs are used. This information + * helps the listen_coa_find() function get a + * listener which has free IDs. + */ + if (request->proxy_listener->send_coa) { + rad_assert(request->proxy_listener->num_ids_used > 0); + request->proxy_listener->num_ids_used--; + } +#endif } request->proxy_listener = NULL; @@ -2361,18 +2381,6 @@ static void remove_from_proxy_hash(REQUEST *request) */ if (!request->in_proxy_hash) return; -#ifdef WITH_TCP - /* - * Status-Server packets aren't removed from the proxy hash. They're reused. - * - * Unless we're tearing down the listener. - */ - if ((request->proxy->proto == IPPROTO_TCP) && (request->proxy->code == PW_CODE_STATUS_SERVER) && - request->proxy_listener && (request->proxy_listener->status < RAD_LISTEN_STATUS_EOL)) { - return; - } -#endif - /* * The "not in hash" flag is definitive. However, if the * flag says that it IS in the hash, there might still be @@ -2493,13 +2501,13 @@ static int insert_into_proxy_hash(REQUEST *request) goto fail; } -#ifdef COA_TUNNEL +#ifdef WITH_COA_TUNNEL /* * Track how many IDs are used. This information * helps the listen_coa_find() function get a * listener which has free IDs. */ - request->proxy_listener->num_ids_used++; + if (request->proxy_listener->send_coa) request->proxy_listener->num_ids_used++; #endif /* @@ -2790,16 +2798,78 @@ int request_proxy_reply(RADIUS_PACKET *packet) * server core, but I guess we can fix that later. */ if (!request->proxy_reply) { + decode_fail_t reason; + + /* + * If the home server configuration requires a Message-Authenticator, then set the flag, + * but only if the proxied packet is Access-Request or Status-Sercer. + * + * The realms.c file already clears require_ma for TLS connections. + */ + bool require_ma = (request->home_server->require_ma == FR_BOOL_TRUE) && (request->proxy->code == PW_CODE_ACCESS_REQUEST); + if (!request->home_server) { proxy_reply_too_late(request); return 0; } + if (!rad_packet_ok(packet, require_ma, &reason)) { + DEBUG("Ignoring invalid packet - %s", fr_strerror()); + return 0; + } + if (rad_verify(packet, request->proxy, request->home_server->secret) != 0) { DEBUG("Ignoring spoofed proxy reply. Signature is invalid"); return 0; } + + /* + * BlastRADIUS checks. We're running in the main + * listener thread, so there's no conflict + * checking or setting these fields. + */ + if ((request->proxy->code == PW_CODE_ACCESS_REQUEST) && +#ifdef WITH_TLS + !request->home_server->tls && +#endif + !packet->eap_message) { + if (request->home_server->require_ma == FR_BOOL_AUTO) { + if (!packet->message_authenticator) { + RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + RERROR("BlastRADIUS check: Received response to Access-Request without Message-Authenticator."); + RERROR("Setting \"require_message_authenticator = false\" for home_server %s", request->home_server->name); + RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + RERROR("UPGRADE THE HOME SERVER AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK."); + RERROR("Once the home_server is upgraded, set \"require_message_authenticator = true\" for home_server %s.", request->home_server->name); + RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + + request->home_server->require_ma = FR_BOOL_FALSE; + } else { + RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + RERROR("BlastRADIUS check: Received response to Access-Request with Message-Authenticator."); + RERROR("Setting \"require_message_authenticator = true\" for home_server %s", request->home_server->name); + RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + RERROR("It looks like the home server has been updated to protect from the BlastRADIUS attack."); + RERROR("Please set \"require_message_authenticator = true\" for home_server %s", request->home_server->name); + RERROR("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + + request->home_server->require_ma = FR_BOOL_TRUE; + } + + } else if (fr_debug_lvl && (request->home_server->require_ma == FR_BOOL_FALSE) && !packet->message_authenticator) { + /* + * If it's "no" AND we don't have a Message-Authenticator, then complain on every packet. + */ + RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + RDEBUG("BlastRADIUS check: Received packet without Message-Authenticator from home_server %s", request->home_server->name); + RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + RDEBUG("The packet does not contain Message-Authenticator, which is a security issue"); + RDEBUG("UPGRADE THE HOME SERVER AS YOUR NETWORK IS VULNERABLE TO THE BLASTRADIUS ATTACK."); + RDEBUG("Once the home server is upgraded, set \"require_message_authenticator = true\" for home_server %s", request->home_server->name); + RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + } + } } /* @@ -2863,6 +2933,18 @@ int request_proxy_reply(RADIUS_PACKET *packet) #ifdef WITH_STATS /* + * The average includes our time to receive packets and + * look them up in the hashes, which should be the same + * for all packets. + * + * We update the response time only for the FIRST packet + * we receive. + */ + if (request->home_server->ema.window > 0) { + radius_stats_ema(&request->home_server->ema, &request->proxy->timestamp, &now); + } + + /* * Update the proxy listener stats here, because only one * thread accesses that at a time. The home_server and * main proxy_*_stats structures are updated once the @@ -3193,6 +3275,14 @@ static int request_will_proxy(REQUEST *request) pool = home_pool_byname(vp->vp_strvalue, pool_type); /* + * If we didn't find an auth only or acct only pool + * fall-back to those which do both. + */ + if (!pool && ((pool_type == HOME_TYPE_AUTH) || (pool_type == HOME_TYPE_ACCT))) { + pool = home_pool_byname(vp->vp_strvalue, HOME_TYPE_AUTH_ACCT); + } + + /* * Send it directly to a home server (i.e. NAS) */ } else if (((vp = fr_pair_find_by_num(request->config, PW_PACKET_DST_IP_ADDRESS, 0, TAG_ANY)) != NULL) || @@ -3292,6 +3382,15 @@ static int request_will_proxy(REQUEST *request) * Find the home server by name. */ home = home_server_byname(vp->vp_strvalue, type); + + /* + * If we didn't find an auth only or acct only home server + * fall-back to those which do both. + */ + if (!home && ((type == HOME_TYPE_AUTH) || (type == HOME_TYPE_ACCT))) { + home = home_server_byname(vp->vp_strvalue, HOME_TYPE_AUTH_ACCT); + } + if (!home) { RWDEBUG("No such home server %s", vp->vp_strvalue); return 0; @@ -3361,7 +3460,7 @@ static int request_will_proxy(REQUEST *request) home = home_server_ldb(realmname, pool, request); if (!home) { - REDEBUG2("Failed to find live home server: Cancelling proxy"); + REDEBUG2("Failed to find live home server for realm %s: Cancelling proxy", realmname); return -1; } @@ -3373,7 +3472,11 @@ do_home: * Once we've decided to proxy a request, we cannot send * a CoA packet. So we free up any CoA packet here. */ - if (request->coa) request_done(request->coa, FR_ACTION_COA_CANCELLED); + if (request->coa) { + RWDEBUG("Cannot proxy and originate CoA packets at the same time. Cancelling CoA request"); + request_done(request->coa, FR_ACTION_COA_CANCELLED); + request->coa = NULL; + } #endif /* @@ -3605,6 +3708,7 @@ static int request_proxy(REQUEST *request) if (request->coa) { RWDEBUG("Cannot proxy and originate CoA packets at the same time. Cancelling CoA request"); request_done(request->coa, FR_ACTION_COA_CANCELLED); + request->coa = NULL; } #endif @@ -3817,6 +3921,7 @@ static void request_ping(REQUEST *request, int action) break; case FR_ACTION_PROXY_REPLY: + default: rad_assert(request->in_proxy_hash); request->home_server->num_received_pings++; @@ -3855,9 +3960,10 @@ static void request_ping(REQUEST *request, int action) mark_home_server_alive(request, home); break; - default: + case FR_ACTION_RUN: + case FR_ACTION_DUP: RDEBUG3("%s: Ignoring action %s", __FUNCTION__, action_codes[action]); - break; + return; } rad_assert(!request->in_request_hash); @@ -4339,10 +4445,10 @@ static void proxy_wait_for_reply(REQUEST *request, int action) * and should be suppressed by the proxy. */ when = request->proxy->timestamp; - when.tv_sec++; + when.tv_sec += main_config.proxy_dedup_window; if (timercmp(&now, &when, <)) { - DEBUG2("Suppressing duplicate proxied request (too fast) to home server %s port %d proto TCP - ID: %d", + DEBUG2("Suppressing duplicate proxied request (too fast) to home server %s port %d - ID: %d", inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr, buffer, sizeof(buffer)), @@ -4543,9 +4649,9 @@ static void request_coa_originate(REQUEST *request) VERIFY_REQUEST(request); rad_assert(request->coa != NULL); - rad_assert(request->proxy == NULL); + rad_assert(request->proxy == NULL || request->proxy->dst_port == 0); rad_assert(!request->in_proxy_hash); - rad_assert(request->proxy_reply == NULL); + rad_assert(request->proxy_reply == NULL || request->proxy_reply->src_port == 0); /* * Check whether we want to originate one, or cancel one. @@ -5018,7 +5124,11 @@ static bool coa_max_time(REQUEST *request) buffer, sizeof(buffer)), request->proxy->dst_port, mrd); - request_done(request, FR_ACTION_DONE); + if (setup_post_proxy_fail(request)) { + request_queue_or_run(request, coa_no_reply); + } else { + request_done(request, FR_ACTION_DONE); + } return true; } @@ -5386,7 +5496,6 @@ static void listener_free_cb(void *ctx) talloc_free(this); } -#ifdef WITH_TCP #ifdef WITH_PROXY static int proxy_eol_cb(void *ctx, void *data) { @@ -5426,7 +5535,6 @@ static int proxy_eol_cb(void *ctx, void *data) return 0; } #endif /* WITH_PROXY */ -#endif /* WITH_TCP */ static void event_new_fd(rad_listen_t *this) { @@ -5602,6 +5710,7 @@ static void event_new_fd(rad_listen_t *this) */ this->print(this, buffer, sizeof(buffer)); ERROR("Failed adding event handler for socket %s: %s", buffer, fr_strerror()); + this->status = RAD_LISTEN_STATUS_EOL; goto listener_is_eol; } /* end of INIT */ @@ -5645,6 +5754,7 @@ static void event_new_fd(rad_listen_t *this) fr_event_fd_delete(el, 0, this->fd); this->status = RAD_LISTEN_STATUS_REMOVE_NOW; } +#endif /* WITH_TCP */ /* * The socket has had a catastrophic error. Close it. @@ -5708,7 +5818,6 @@ static void event_new_fd(rad_listen_t *this) */ this->status = RAD_LISTEN_STATUS_REMOVE_NOW; } /* socket is at EOL */ -#endif /* WITH_TCP */ if (this->dead) goto wait_some_more; @@ -6147,7 +6256,7 @@ static void check_proxy(rad_listen_t *head) if (sock->my_ipaddr.af == AF_INET) has_v4 = true; if (sock->my_ipaddr.af == AF_INET6) has_v6 = true; break; - + default: break; } |