/* * Check if an incoming request is "ok" * * It takes packets, not requests. It sees if the packet looks * OK. If so, it does a number of sanity checks on it. */ static int vqp_socket_recv(rad_listen_t *listener) { RADIUS_PACKET *packet; RAD_REQUEST_FUNP fun = NULL; RADCLIENT *client; packet = vqp_recv(listener->fd); if (!packet) { ERROR("%s", fr_strerror()); return 0; } if ((client = client_listener_find(listener, &packet->src_ipaddr, packet->src_port)) == NULL) { rad_free(&packet); return 0; } /* * Do new stuff. */ fun = vmps_process; if (!request_receive(NULL, listener, packet, client, fun)) { rad_free(&packet); return 0; } return 1; }
int dual_tls_recv(rad_listen_t *listener) { RADIUS_PACKET *packet; REQUEST *request; RAD_REQUEST_FUNP fun = NULL; listen_socket_t *sock = listener->data; RADCLIENT *client = sock->client; if (!tls_socket_recv(listener)) { return 0; } rad_assert(sock->request != NULL); rad_assert(sock->request->packet != NULL); rad_assert(sock->packet != NULL); rad_assert(sock->ssn != NULL); request = sock->request; packet = sock->packet; /* * Some sanity checks, based on the packet code. */ switch(packet->code) { case PW_AUTHENTICATION_REQUEST: if (listener->type != RAD_LISTEN_AUTH) goto bad_packet; FR_STATS_INC(auth, total_requests); fun = rad_authenticate; break; case PW_ACCOUNTING_REQUEST: if (listener->type != RAD_LISTEN_ACCT) goto bad_packet; FR_STATS_INC(acct, total_requests); fun = rad_accounting; break; case PW_STATUS_SERVER: if (!mainconfig.status_server) { FR_STATS_INC(auth, total_unknown_types); DEBUG("WARNING: Ignoring Status-Server request due to security configuration"); rad_free(&sock->packet); request->packet = NULL; return 0; } fun = rad_status_server; break; default: bad_packet: FR_STATS_INC(auth, total_unknown_types); DEBUG("Invalid packet code %d sent from client %s port %d : IGNORED", packet->code, client->shortname, packet->src_port); rad_free(&sock->packet); request->packet = NULL; return 0; } /* switch over packet types */ if (!request_receive(listener, packet, client, fun)) { FR_STATS_INC(auth, total_packets_dropped); rad_free(&sock->packet); request->packet = NULL; return 0; } sock->packet = NULL; /* we have no need for more partial reads */ request->packet = NULL; return 1; }
static int serviceConnection2( http_server srv, connection conn, http_request request, http_response response, meta_error e) { dynamic_page dp; size_t cbSent; int status, error = 0; size_t max_posted_content = http_server_get_post_limit(srv); while(!http_server_shutting_down(srv)) { if(!data_on_socket(conn)) return set_tcpip_error(e, EAGAIN); /* Were we able to read a valid http request? * If not, what is the cause of the error? If it is a http * protocol error, we try to send a response back to the client * and close the connection. If it is anything else(tcp/ip, os) * we stop processing. */ error = !request_receive(request, conn, max_posted_content, e); /* So far, so good. We have a valid HTTP request. * Now see if we can locate a page handler function for it. * If we do, call it. If not, see if it on disk or if the * http_server has a default page handler. If neither is true, * then the page was not found(404). */ if(error) ; else if( (dp = http_server_lookup(srv, request)) != NULL) { if(!handle_dynamic(srv, dp, request, response, e)) { error = 1; } } else if(http_server_can_read_files(srv)) { if(!send_disk_file(srv, conn, request, response, e)) { error = 1; } } else if(http_server_has_default_page_handler(srv)) { if(!http_server_run_default_page_handler(srv, request, response, e)) { error = 1; } } else { /* We didn't find the page */ response_set_status(response, HTTP_404_NOT_FOUND); response_set_connection(response, "close"); } if(error) { if(is_protocol_error(e)) { status = get_error_code(e); response_set_status(response, status); response_set_connection(response, "close"); cbSent = response_send(response, conn, e); http_server_add_logentry(srv, conn, request, status, cbSent); } return 0; } /* * Some extra stuff for HTTP 1.0 clients. If client is 1.0 * and connection_close() == 1 and connection header field * isn't set, then we set the connection flag to close. * Done so that 1.0 clients (Lynx) can detect closure. */ if(request_get_version(request) != VERSION_11 && !connection_is_persistent(conn) && strlen(response_get_connection(response)) == 0) response_set_connection(response, "close"); cbSent = response_send(response, conn, e); http_server_add_logentry(srv, conn, request, response_get_status(response), cbSent); if(cbSent == 0) return 0; /* Did the user set the Connection header field to "close" */ if(strcmp(response_get_connection(response), "close") == 0) return 1; if(!connection_is_persistent(conn)) return 1; /** * NOTE: Her må/bør vi legge inn ny funksjonalitet: * Disconnect connections som * a) Har kjørt lengst i tid * b) Har overført mest bytes (opp eller ned) * eller c) har dårligst transfer rate * Grunnen er at dersom vi har n worker threads og n * persistent connections, havner alle nye connections i kø. * De får aldri kjøretid. Så disconnect-regelen over gjelder derfor * kun om køen har > 0 entries. */ connection_flush(conn); request_recycle(request); response_recycle(response); } /* Shutdown detected */ return 1; }
/* * thread responsible for receiving data for a client or a server * note when we add client, this client is effectively added in the receive queue * only few second later due to the select timeout of 3 seconds * and there are the same problem for the deleteion of a client */ static void algopr_receive_thread(void *unused) { struct pending_request pending_requests[EXA_MAX_NODES_NUMBER]; exa_select_handle_t *sh = exa_select_new_handle(); int i; int ret; payload_t *payload = NULL; struct nbd_root_list root_list_recv; /* FIXME: handle the case when we have more than 1024 open file (limit of fd_set) */ fd_set fds; exalog_as(EXAMSG_ISCSI_ID); nbd_init_root(EXA_MAX_NODES_NUMBER, sizeof(payload_t), &root_list_recv); for (i = 0; i < EXA_MAX_NODES_NUMBER; i++) request_reset(&pending_requests[i]); while (algopr_run) { int nfds = 0; FD_ZERO(&fds); /* if one node is added or deleted, this deletion or addition are effective after this */ os_thread_mutex_lock(&peers_lock); for (i = 0; i < EXA_MAX_NODES_NUMBER; i++) { int fd_act = __get_peer_socket(i); if (fd_act < 0) { payload_t *temp_payload; temp_payload = request_reset(&pending_requests[i]); if (temp_payload != NULL) { if (pending_requests[i].big_buffer) nbd_list_post(ð.root_list_big_recv.free, temp_payload->buffer, -1); nbd_list_post(&root_list_recv.free, temp_payload, -1); } temp_payload = NULL; continue; } FD_SET(fd_act, &fds); nfds = fd_act > nfds ? fd_act : nfds; } os_thread_mutex_unlock(&peers_lock); ret = exa_select_in(sh, nfds + 1, &fds); if (ret != 0 && ret != -EFAULT) exalog_error("Select upon receive failed: %s (%d)", os_strerror(-ret), ret); os_thread_mutex_lock(&peers_lock); for (i = 0; i < EXA_MAX_NODES_NUMBER; i++) { struct pending_request *req; int fd_act; fd_act = __get_peer_socket(i); if (fd_act < 0 || !FD_ISSET(fd_act, &fds)) continue; req = &pending_requests[i]; /* WARNING payload is kept from an iteration of while loop to * another, so the variable MUST be global. */ /* FIXME Remove the nbdlist which is useless as we already know * that we NEED EXA_MAX_NODES_NUMBER payload_t elements to be able * to receive simultaneously from EXA_MAX_NODES_NUMBER nodes * FIXME the LISTWAIT flag below is WRONG because waiting here * would mean deadlock... hopefully there are enough elements, and * we never wait.... */ if (payload == NULL) { payload = nbd_list_remove(&root_list_recv.free, NULL, LISTWAIT); EXA_ASSERT(payload != NULL); } if (request_init_transfer(payload, req) == 1) payload = NULL; ret = request_receive(fd_act, req); if (ret == DATA_TRANSFER_NEED_BIG_BUFFER) { req->payload->buffer = nbd_list_remove(ð.root_list_big_recv.free, NULL, LISTWAIT); EXA_ASSERT(req->payload->buffer != NULL); req->big_buffer = true; /* here we just continue because it is forbidden to call * request_receive without passing into select (as sockets are * blocking, we may remain blocked on the recv of nothing) */ continue; } if (ret == DATA_TRANSFER_PENDING) continue; if (ret == DATA_TRANSFER_ERROR) { payload_t *temp_payload = request_reset(req); if (req->big_buffer) nbd_list_post(ð.root_list_big_recv.free, temp_payload->buffer, -1); nbd_list_post(&root_list_recv.free, temp_payload, -1); __disconnect_from_peer(i); if (!suspended) exalog_warning("Failed receiving from peer %" PRInodeid " (socket %d): transfer error.", i, fd_act); continue; } if (ret == DATA_TRANSFER_COMPLETE) { payload_t *_payload = request_reset(req); /* update data network checking data */ algopr_new_msg(_payload->payload, _payload->size1, _payload->buffer, _payload->size2); nbd_list_post(&root_list_recv.free, _payload, -1); } } os_thread_mutex_unlock(&peers_lock); } nbd_close_root(&root_list_recv); exa_select_delete_handle(sh); }
int dual_tls_recv(rad_listen_t *listener) { RADIUS_PACKET *packet; RAD_REQUEST_FUNP fun = NULL; listen_socket_t *sock = listener->data; RADCLIENT *client = sock->client; if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0; if (!tls_socket_recv(listener)) { return 0; } rad_assert(sock->packet != NULL); rad_assert(sock->tls_session != NULL); rad_assert(client != NULL); packet = talloc_steal(NULL, sock->packet); sock->packet = NULL; gettimeofday(&packet->timestamp, NULL); /* * Some sanity checks, based on the packet code. * * "auth+acct" are marked as "auth", with the "dual" flag * set. */ switch (packet->code) { case PW_CODE_ACCESS_REQUEST: if (listener->type != RAD_LISTEN_AUTH) goto bad_packet; FR_STATS_INC(auth, total_requests); fun = rad_authenticate; break; #ifdef WITH_ACCOUNTING case PW_CODE_ACCOUNTING_REQUEST: if (listener->type != RAD_LISTEN_ACCT) { /* * Allow auth + dual. Disallow * everything else. */ if (!((listener->type == RAD_LISTEN_AUTH) && (listener->dual))) { goto bad_packet; } } FR_STATS_INC(acct, total_requests); fun = rad_accounting; break; #endif case PW_CODE_STATUS_SERVER: if (!main_config.status_server) { FR_STATS_INC(auth, total_unknown_types); WARN("Ignoring Status-Server request due to security configuration"); fr_radius_free(&packet); return 0; } fun = rad_status_server; break; default: bad_packet: FR_STATS_INC(auth, total_unknown_types); DEBUG("Invalid packet code %d sent from client %s port %d : IGNORED", packet->code, client->shortname, packet->src_port); fr_radius_free(&packet); return 0; } /* switch over packet types */ if (!request_receive(NULL, listener, packet, client, fun)) { FR_STATS_INC(auth, total_packets_dropped); fr_radius_free(&packet); return 0; } return 1; }
int dual_tls_recv(rad_listen_t *listener) { RADIUS_PACKET *packet; RAD_REQUEST_FUNP fun = NULL; listen_socket_t *sock = listener->data; RADCLIENT *client = sock->client; BIO *rbio; if (listener->status != RAD_LISTEN_STATUS_KNOWN) return 0; redo: if (!tls_socket_recv(listener)) { return 0; } rad_assert(sock->packet != NULL); rad_assert(sock->ssn != NULL); rad_assert(client != NULL); packet = talloc_steal(NULL, sock->packet); sock->packet = NULL; /* * Some sanity checks, based on the packet code. * * "auth+acct" are marked as "auth", with the "dual" flag * set. */ switch (packet->code) { case PW_CODE_ACCESS_REQUEST: if (listener->type != RAD_LISTEN_AUTH) goto bad_packet; FR_STATS_INC(auth, total_requests); fun = rad_authenticate; break; #ifdef WITH_ACCOUNTING case PW_CODE_ACCOUNTING_REQUEST: if (listener->type != RAD_LISTEN_ACCT) { /* * Allow auth + dual. Disallow * everything else. */ if (!((listener->type == RAD_LISTEN_AUTH) && (listener->dual))) { goto bad_packet; } } FR_STATS_INC(acct, total_requests); fun = rad_accounting; break; #endif case PW_CODE_STATUS_SERVER: if (!main_config.status_server) { FR_STATS_INC(auth, total_unknown_types); WARN("Ignoring Status-Server request due to security configuration"); rad_free(&packet); return 0; } fun = rad_status_server; break; default: bad_packet: FR_STATS_INC(auth, total_unknown_types); DEBUG("Invalid packet code %d sent from client %s port %d : IGNORED", packet->code, client->shortname, packet->src_port); rad_free(&packet); return 0; } /* switch over packet types */ if (!request_receive(NULL, listener, packet, client, fun)) { FR_STATS_INC(auth, total_packets_dropped); rad_free(&packet); return 0; } /* * Check for more application data. * * If there is pending SSL data, "peek" at the * application data. If we get at least one byte of * application data, go back to tls_socket_recv(). * SSL_peek() will set SSL_pending(), and * tls_socket_recv() will read another packet. */ rbio = SSL_get_rbio(sock->ssn->ssl); if (BIO_ctrl_pending(rbio)) { char buf[1]; int peek = SSL_peek(sock->ssn->ssl, buf, 1); if (peek > 0) { DEBUG("more TLS records after dual_tls_recv"); goto redo; } } return 1; }
/* * Check if an incoming request is "ok" * * It takes packets, not requests. It sees if the packet looks * OK. If so, it does a number of sanity checks on it. */ static int arp_socket_recv(rad_listen_t *listener) { int ret; arp_socket_t *sock = listener->data; pcap_t *handle = sock->lsock.pcap->handle; const uint8_t *data; struct pcap_pkthdr *header; ssize_t link_len; arp_over_ether_t const *arp; RADIUS_PACKET *packet; ret = pcap_next_ex(handle, &header, &data); if (ret == 0) { DEBUG("No packet retrieved from pcap."); return 0; /* no packet */ } if (ret < 0) { ERROR("Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle)); return 0; } link_len = fr_pcap_link_layer_offset(data, header->caplen, sock->lsock.pcap->link_layer); if (link_len < 0) { PERROR("Failed determining link layer header offset"); return 0; } /* * Silently ignore it if it's too small to be ARP. * * This can happen when pcap gets overloaded and starts truncating packets. */ if (header->caplen < (link_len + sizeof(*arp))) { ERROR("Packet too small, we require at least %zu bytes, got %i bytes", link_len + sizeof(*arp), header->caplen); return 0; } data += link_len; arp = (arp_over_ether_t const *) data; if (ntohs(arp->htype) != ARPHRD_ETHER) return 0; if (ntohs(arp->ptype) != 0x0800) return 0; if (arp->hlen != ETHER_ADDR_LEN) return 0; /* FIXME: malformed error */ if (arp->plen != 4) return 0; /* FIXME: malformed packet error */ packet = talloc_zero(NULL, RADIUS_PACKET); if (!packet) return 0; packet->dst_port = 1; /* so it's not a "fake" request */ packet->data_len = header->caplen - link_len; packet->data = talloc_memdup(packet, arp, packet->data_len); talloc_set_type(packet->data, uint8_t); DEBUG("ARP received on interface %s", sock->lsock.interface); if (!request_receive(NULL, listener, packet, &sock->client, arp_process)) { fr_radius_packet_free(&packet); return 0; } return 1; }