📄 event.c
字号:
*/ if (request->reply->code == PW_AUTHENTICATION_REJECT) { pairdelete(&request->config_items, PW_POST_AUTH_TYPE); vp = radius_pairmake(request, &request->config_items, "Post-Auth-Type", "Reject", T_OP_SET); if (vp) rad_postauth(request); /* * If configured, delay Access-Reject packets. * * If request->root->reject_delay = 0, we discover * that we have to send the packet now. */ when = request->received; when.tv_sec += request->root->reject_delay; if (timercmp(&when, &request->next_when, >)) { DEBUG2("Delaying reject of request %d for %d seconds", request->number, request->root->reject_delay); request->next_when = when; request->next_callback = reject_delay; request->child_pid = NO_SUCH_CHILD_PID; request->child_state = REQUEST_REJECT_DELAY; return; } } request->next_when.tv_sec += request->root->cleanup_delay; request->next_callback = cleanup_delay; child_state = REQUEST_CLEANUP_DELAY; break; case PW_ACCOUNTING_REQUEST: request->next_callback = NULL; /* just to be safe */ child_state = REQUEST_DONE; break; /* * FIXME: Status-Server should probably not be * handled here... */ case PW_STATUS_SERVER: request->next_callback = NULL; child_state = REQUEST_DONE; break; default: if ((request->packet->code > 1024) && (request->packet->code < (1024 + 254 + 1))) { request->next_callback = NULL; child_state = REQUEST_DONE; break; } radlog(L_ERR, "Unknown packet type %d", request->packet->code); rad_panic("Unknown packet type"); break; } /* * Suppress "no reply" packets here, unless we're reading * from the "detail" file. In that case, we've got to * tell the detail file handler that the request is dead, * and it should re-send it. * If configured, encode, sign, and send. */ if ((request->reply->code != 0) || (request->listener->type == RAD_LISTEN_DETAIL)) { request->listener->send(request->listener, request); } /* * Clean up. These are no longer needed. */ pairfree(&request->config_items); pairfree(&request->packet->vps); request->username = NULL; request->password = NULL; pairfree(&request->reply->vps); if (request->proxy) { pairfree(&request->proxy->vps); if (request->proxy_reply) { pairfree(&request->proxy_reply->vps); } /* * We're not tracking responses from the home * server, we can therefore free this memory in * the child thread. */ if (!request->in_proxy_hash) { rad_free(&request->proxy); rad_free(&request->proxy_reply); request->home_server = NULL; } } DEBUG2("Finished request %d.", request->number); request->child_state = child_state; /* * Single threaded mode: update timers now. */ if (!have_children) wait_a_bit(request);}static void received_retransmit(REQUEST *request, const RADCLIENT *client){ char buffer[128]; RAD_SNMP_TYPE_INC(request->listener, total_dup_requests); RAD_SNMP_CLIENT_INC(request->listener, client, dup_requests); switch (request->child_state) { case REQUEST_QUEUED: case REQUEST_RUNNING: discard: radlog(L_ERR, "Discarding duplicate request from " "client %s port %d - ID: %d due to unfinished request %d", client->shortname, request->packet->src_port,request->packet->id, request->number); break; case REQUEST_PROXIED: /* * We're not supposed to have duplicate * accounting packets. The other states handle * duplicates fine (discard, or send duplicate * reply). But we do NOT want to retransmit an * accounting request here, because that would * involve updating the Acct-Delay-Time, and * therefore changing the packet Id, etc. * * Instead, we just discard the packet. We may * eventually respond, or the client will send a * new accounting packet. */ if (request->packet->code == PW_ACCOUNTING_REQUEST) { goto discard; } check_for_zombie_home_server(request); /* * If we've just discovered that the home server is * dead, send the packet to another one. */ if ((request->packet->dst_port != 0) && (request->home_server->state == HOME_STATE_IS_DEAD)) { home_server *home; remove_from_proxy_hash(request); home = home_server_ldb(NULL, request->home_pool, request); if (!home) { DEBUG2("Failed to find live home server for request %d", request->number); no_home_servers: /* * Do post-request processing, * and any insertion of necessary * events. */ post_proxy_fail_handler(request); return; } request->proxy->code = request->packet->code; request->proxy->dst_ipaddr = home->ipaddr; request->proxy->dst_port = home->port; request->home_server = home; /* * Free the old packet, to force re-encoding */ free(request->proxy->data); request->proxy->data = NULL; request->proxy->data_len = 0; /* * Try to proxy the request. */ if (!proxy_request(request)) { DEBUG("ERROR: Failed to re-proxy request %d", request->number); goto no_home_servers; } /* * This code executes in the main server * thread, so there's no need for locking. */ rad_assert(request->next_callback != NULL); INSERT_EVENT(request->next_callback, request); request->next_callback = NULL; return; } /* else the home server is still alive */ DEBUG2("Sending duplicate proxied request to home server %s port %d - ID: %d", inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr, buffer, sizeof(buffer)), request->proxy->dst_port, request->proxy->id); request->num_proxied_requests++; request->proxy_listener->send(request->proxy_listener, request); break; case REQUEST_REJECT_DELAY: DEBUG2("Waiting to send Access-Reject " "to client %s port %d - ID: %d", client->shortname, request->packet->src_port, request->packet->id); break; case REQUEST_CLEANUP_DELAY: case REQUEST_DONE: DEBUG2("Sending duplicate reply " "to client %s port %d - ID: %d", client->shortname, request->packet->src_port, request->packet->id); request->listener->send(request->listener, request); break; }}static void received_conflicting_request(REQUEST *request, const RADCLIENT *client){ radlog(L_ERR, "Received conflicting packet from " "client %s port %d - ID: %d due to unfinished request %d. Giving up on old request.", client->shortname, request->packet->src_port, request->packet->id, request->number); /* * Nuke it from the request hash, so we can receive new * packets. */ remove_from_request_hash(request); switch (request->child_state) { /* * It's queued or running. Tell it to stop, and * wait for it to do so. */ case REQUEST_QUEUED: case REQUEST_RUNNING: request->master_state = REQUEST_STOP_PROCESSING; request->delay += request->delay >> 1; tv_add(&request->when, request->delay); INSERT_EVENT(wait_for_child_to_die, request); return; /* * It's in some other state, and therefore also * in the event queue. At some point, the * child will notice, and we can then delete it. */ default: rad_assert(request->ev != NULL); break; }}static int can_handle_new_request(RADIUS_PACKET *packet, RADCLIENT *client, struct main_config_t *root){ /* * Count the total number of requests, to see if * there are too many. If so, return with an * error. */ if (root->max_requests) { int request_count = fr_packet_list_num_elements(pl); /* * This is a new request. Let's see if * it makes us go over our configured * bounds. */ if (request_count > root->max_requests) { radlog(L_ERR, "Dropping request (%d is too many): " "from client %s port %d - ID: %d", request_count, client->shortname, packet->src_port, packet->id); radlog(L_INFO, "WARNING: Please check the configuration file.\n" "\tThe value for 'max_requests' is probably set too low.\n"); return 0; } /* else there were a small number of requests */ } /* else there was no configured limit for requests */ /* * FIXME: Add per-client checks. If one client is sending * too many packets, start discarding them. * * We increment the counters here, and decrement them * when the response is sent... somewhere in this file. */ /* * FUTURE: Add checks for system load. If the system is * busy, start dropping requests... * * We can probably keep some statistics ourselves... if * there are more requests coming in than we can handle, * start dropping some. */ return 1;}int received_request(rad_listen_t *listener, RADIUS_PACKET *packet, REQUEST **prequest, RADCLIENT *client){ RADIUS_PACKET **packet_p; REQUEST *request = NULL; struct main_config_t *root = &mainconfig; packet_p = fr_packet_list_find(pl, packet); if (packet_p) { request = fr_packet2myptr(REQUEST, packet, packet_p); rad_assert(request->in_request_hash); if ((request->packet->data_len == packet->data_len) && (memcmp(request->packet->vector, packet->vector, sizeof(packet->vector)) == 0)) { received_retransmit(request, client); return 0; } /* * The new request is different from the old one, * but maybe the old is finished. If so, delete * the old one. */ switch (request->child_state) { struct timeval when; default: gettimeofday(&when, NULL); when.tv_sec -= 1; /* * If the cached request was received * within the last second, then we * discard the NEW request instead of the * old one. This will happen ONLY when * the client is severely broken, and is * sending conflicting packets very * quickly. */ if (timercmp(&when, &request->received, <)) { radlog(L_ERR, "Discarding conflicting packet from " "client %s port %d - ID: %d due to recent request %d.", client->shortname, packet->src_port, packet->id, request->number); return 0; } received_conflicting_request(request, client); request = NULL; break; case REQUEST_REJECT_DELAY: case REQUEST_CLEANUP_DELAY: request->child_state = REQUEST_DONE; case REQUEST_DONE: cleanup_delay(request); request = NULL; break; } } /* * We may want to quench the new request. */ if ((listener->type != RAD_LISTEN_DETAIL) && !can_handle_new_request(packet, client, root)) { return 0; } /* * Create and initialize the new request. */ request = request_alloc(); /* never fails */ if ((request->reply = rad_alloc(0)) == NULL) { radlog(L_ERR, "No memory"); exit(1); } request->listener = listener; request->client = client; request->packet = packet; request->packet->timestamp = request->timestamp; request->number = request_num_counter++; request->priority = listener->type; /* * Set virtual server identity */ if (client->server) { request->server = client->server; } else if (listener->server) { request->server = listener->server; } else { request->server = NULL; } /* * Remember the request in the list. */ if (!fr_packet_list_insert(pl, &request->packet)) { radlog(L_ERR, "Failed to insert request %d in the list of live requests: discarding", request->number); request_free(&request); return 0; } request->in_request_hash = TRUE; request->root = root; root->refcount++; /* * The request passes many of our sanity checks. * From here on in, if anything goes wrong, we * send a reject message, instead of dropping the * packet. */ /* * Build the reply template from the request. */ request->reply->sockfd = request->packet->sockfd; request->reply->dst_ipaddr = request->packet->src_ipaddr; request->reply->src_ipaddr = request->packet->dst_ipaddr; request->reply->dst_port = request->packet->src_port; request->reply->src_port = request->packet->dst_port; request->reply->id = request->packet->id; request->reply->code = 0; /* UNKNOWN code */ memcpy(request->reply->vector, request->packet->vector, sizeof(request->reply->vector)); request->reply->vps = NULL; request->reply->data = NULL; request->reply->data_len = 0; request->master_state = REQUEST_ACTIVE; request->child_state = REQUEST_QUEUED; request->next_callback = NULL; gettimeofday(&request->received, NULL); request->timestamp = request->received.tv_sec; request->when = request->received; request->delay = USEC; tv_add(&request->when, request->delay); INSERT_EVENT(wait_a_bit, request); *prequest = request; return 1;}REQUEST *received_proxy_response(RADIUS_PACKET *packet){ char buffer[128]; home_server *home; REQUEST *request; if (!home_server_find(&packet->src_ipaddr, packet->src_port)) { radlog(L_ERR, "Ignoring request from unknown home server %s port %d", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, buffer, sizeof(buffer)), packet->src_port); rad_free(&packet); return NULL; } /* * Also removes from the proxy hash if responses == requests */ request = lookup_in_proxy_hash(packet); if (!request) { radlog(L_PROXY, "No outstanding request was found for proxy reply from home server %s port %d - ID %d", inet_ntop(packet->src_ipaddr.af, &packet->src_ipaddr.ipaddr, buffer, sizeof(buffer)), packet->src_port, packet->id); rad_free(&packet); return NULL; } home = request->home_server; gettimeofday(&now, NULL); home->state = HOME_STATE_ALIVE; if (request->reply && request->reply->code != 0) { DEBUG2("We already replied to this request. Discarding response from home server."); rad_free(&packet); return NULL; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -