/* * Round-robins the receivers, without priority. * * FIXME: Add sockfd, if -1, do round-robin, else do sockfd * IF in fdset. */ RADIUS_PACKET *fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set) { int start; RADIUS_PACKET *packet; if (!pl || !set) return NULL; start = pl->last_recv; do { start++; start &= SOCKOFFSET_MASK; if (pl->sockets[start].sockfd == -1) continue; if (!FD_ISSET(pl->sockets[start].sockfd, set)) continue; packet = rad_recv(pl->sockets[start].sockfd, 0); if (!packet) continue; /* * Call fr_packet_list_find_byreply(). If it * doesn't find anything, discard the reply. */ pl->last_recv = start; return packet; } while (start != pl->last_recv); return NULL; }
/* * 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 status_socket_recv(rad_listen_t *listener, RAD_REQUEST_FUNP *pfun, REQUEST **prequest) { ssize_t rcode; int code, src_port; RADIUS_PACKET *packet; RADCLIENT *client; fr_ipaddr_t src_ipaddr; rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code); if (rcode < 0) return 0; RAD_STATS_TYPE_INC(listener, total_requests); if (rcode < 20) { /* AUTH_HDR_LEN */ RAD_STATS_TYPE_INC(listener, total_malformed_requests); return 0; } if ((client = client_listener_find(listener, &src_ipaddr, src_port)) == NULL) { rad_recv_discard(listener->fd); RAD_STATS_TYPE_INC(listener, total_invalid_requests); return 0; } /* * We only understand Status-Server on this socket. */ if (code != PW_STATUS_SERVER) { DEBUG("Ignoring packet code %d sent to Status-Server port", code); rad_recv_discard(listener->fd); RAD_STATS_TYPE_INC(listener, total_unknown_types); RAD_STATS_CLIENT_INC(listener, client, total_unknown_types); return 0; } /* * Now that we've sanity checked everything, receive the * packet. */ packet = rad_recv(listener->fd, 1); /* require message authenticator */ if (!packet) { RAD_STATS_TYPE_INC(listener, total_malformed_requests); DEBUG("%s", fr_strerror()); return 0; } if (!received_request(listener, packet, prequest, client)) { RAD_STATS_TYPE_INC(listener, total_packets_dropped); RAD_STATS_CLIENT_INC(listener, client, total_packets_dropped); rad_free(&packet); return 0; } *pfun = status_process; return 1; }
static int send_packet(RADIUS_PACKET *req, RADIUS_PACKET **rep) { int i; struct timeval tv; if (!req || !rep || !*rep) return -1; for (i = 0; i < retries; i++) { fd_set rdfdesc; debug_packet(req, R_SENT); if (rad_send(req, NULL, secret) < 0) { fr_perror("radeapclient"); exit(1); } /* And wait for reply, timing out as necessary */ FD_ZERO(&rdfdesc); FD_SET(req->sockfd, &rdfdesc); tv.tv_sec = (int)timeout; tv.tv_usec = 1000000 * (timeout - (int) timeout); /* Something's wrong if we don't get exactly one fd. */ if (select(req->sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) { continue; } *rep = rad_recv(req->sockfd, 0); if (*rep != NULL) { /* * If we get a response from a machine * which we did NOT send a request to, * then complain. */ if (((*rep)->src_ipaddr.af != req->dst_ipaddr.af) || (memcmp(&(*rep)->src_ipaddr.ipaddr, &req->dst_ipaddr.ipaddr, ((req->dst_ipaddr.af == AF_INET ? /* AF_INET6? */ sizeof(req->dst_ipaddr.ipaddr.ip4addr) : /* FIXME: AF_INET6 */ sizeof(req->dst_ipaddr.ipaddr.ip6addr)))) != 0) || ((*rep)->src_port != req->dst_port)) { char src[128], dst[128]; ip_ntoh(&(*rep)->src_ipaddr, src, sizeof(src)); ip_ntoh(&req->dst_ipaddr, dst, sizeof(dst)); fprintf(stderr, "radclient: ERROR: Sent request to host %s port %d, got response from host %s port %d\n!", dst, req->dst_port, src, (*rep)->src_port); exit(1); } break; } else { /* NULL: couldn't receive the packet */ fr_perror("radclient"); exit(1); } } /* No response or no data read (?) */ if (i == retries) { fprintf(stderr, "radclient: no response from server\n"); exit(1); } /* * FIXME: Discard the packet & listen for another. * * Hmm... we should really be using eapol_test, which does * a lot more than radeapclient. */ if (rad_verify(*rep, req, secret) != 0) { fr_perror("rad_verify"); exit(1); } if (rad_decode(*rep, req, secret) != 0) { fr_perror("rad_decode"); exit(1); } /* libradius debug already prints out the value pairs for us */ if (!fr_debug_flag && do_output) { debug_packet(*rep, R_RECV); } if((*rep)->code == PW_CODE_AUTHENTICATION_ACK) { totalapp++; } else if ((*rep)->code == PW_CODE_AUTHENTICATION_REJECT) { totaldeny++; } return 0; }
/* * Recieve packets from a proxy socket. */ static int proxy_socket_recv(rad_listen_t *listener, RAD_REQUEST_FUNP *pfun, REQUEST **prequest) { REQUEST *request; RADIUS_PACKET *packet; char buffer[128]; RAD_REQUEST_FUNP fun = NULL; packet = rad_recv(listener->fd, 0); if (!packet) { radlog(L_ERR, "%s", fr_strerror()); return 0; } /* * FIXME: Client MIB updates? */ switch(packet->code) { case PW_AUTHENTICATION_ACK: case PW_ACCESS_CHALLENGE: case PW_AUTHENTICATION_REJECT: #ifdef WITH_ACCOUNTING case PW_ACCOUNTING_RESPONSE: #endif break; #ifdef WITH_COA case PW_DISCONNECT_ACK: case PW_DISCONNECT_NAK: case PW_COA_ACK: case PW_COA_NAK: break; #endif default: /* * FIXME: Update MIB for packet types? */ radlog(L_ERR, "Invalid packet code %d sent to a proxy port " "from home server %s port %d - ID %d : IGNORED", packet->code, ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)), packet->src_port, packet->id); rad_free(&packet); return 0; } request = received_proxy_response(packet); if (!request) { return 0; } rad_assert(request->process != NULL); #ifdef WITH_COA /* * Distinguish proxied CoA requests from ones we * originate. If we've proxied a DIFFERENT packet type * than the original, then it MUST be a CoA packet. In * that case, we process it as a CoA reply packet, rather * than re-running the original method. */ if (request->packet->code != request->proxy->code) { rad_assert((request->proxy->code == PW_COA_REQUEST) || (request->proxy->code == PW_DISCONNECT_REQUEST)); fun = rad_coa_reply; /* run NEW function */ } else #endif *pfun = request->process; /* re-run original function */ *prequest = request; return 1; }
/* * Find a per-socket client. */ RADCLIENT *client_listener_find(const rad_listen_t *listener, const fr_ipaddr_t *ipaddr, int src_port) { #ifdef WITH_DYNAMIC_CLIENTS int rcode; REQUEST *request; RADCLIENT *created; #endif time_t now; RADCLIENT *client; RADCLIENT_LIST *clients; listen_socket_t *sock; rad_assert(listener != NULL); rad_assert(ipaddr != NULL); sock = listener->data; clients = sock->clients; /* * This HAS to have been initialized previously. */ rad_assert(clients != NULL); client = client_find(clients, ipaddr,sock->proto); if (!client) { char name[256], buffer[128]; #ifdef WITH_DYNAMIC_CLIENTS unknown: /* used only for dynamic clients */ #endif /* * DoS attack quenching, but only in daemon mode. * If they're running in debug mode, show them * every packet. */ if (debug_flag == 0) { static time_t last_printed = 0; now = time(NULL); if (last_printed == now) return NULL; last_printed = now; } listener->print(listener, name, sizeof(name)); radlog(L_ERR, "Ignoring request to %s from unknown client %s port %d" #ifdef WITH_TCP " proto %s" #endif , name, inet_ntop(ipaddr->af, &ipaddr->ipaddr, buffer, sizeof(buffer)), src_port #ifdef WITH_TCP , (sock->proto == IPPROTO_UDP) ? "udp" : "tcp" #endif ); return NULL; } #ifndef WITH_DYNAMIC_CLIENTS return client; /* return the found client. */ #else /* * No server defined, and it's not dynamic. Return it. */ if (!client->client_server && !client->dynamic) return client; now = time(NULL); /* * It's a dynamically generated client, check it. */ if (client->dynamic && (src_port != 0)) { /* * Lives forever. Return it. */ if (client->lifetime == 0) return client; /* * Rate-limit the deletion of known clients. * This makes them last a little longer, but * prevents the server from melting down if (say) * 10k clients all expire at once. */ if (now == client->last_new_client) return client; /* * It's not dead yet. Return it. */ if ((client->created + client->lifetime) > now) return client; /* * This really puts them onto a queue for later * deletion. */ client_delete(clients, client); /* * Go find the enclosing network again. */ client = client_find(clients, ipaddr, sock->proto); /* * WTF? */ if (!client) goto unknown; if (!client->client_server) goto unknown; /* * At this point, 'client' is the enclosing * network that configures where dynamic clients * can be defined. */ rad_assert(client->dynamic == 0); } else { /* * The IP is unknown, so we've found an enclosing * network. Enable DoS protection. We only * allow one new client per second. Known * clients aren't subject to this restriction. */ if (now == client->last_new_client) goto unknown; } client->last_new_client = now; request = request_alloc(); if (!request) goto unknown; request->listener = listener; request->client = client; request->packet = rad_recv(listener->fd, 0x02); /* MSG_PEEK */ if (!request->packet) { /* badly formed, etc */ request_free(&request); goto unknown; } request->reply = rad_alloc_reply(request->packet); if (!request->reply) { request_free(&request); goto unknown; } request->packet->timestamp = request->timestamp; request->number = 0; request->priority = listener->type; request->server = client->client_server; request->root = &mainconfig; /* * Run a fake request through the given virtual server. * Look for FreeRADIUS-Client-IP-Address * FreeRADIUS-Client-Secret * ... * * and create the RADCLIENT structure from that. */ DEBUG("server %s {", request->server); rcode = module_authorize(0, request); DEBUG("} # server %s", request->server); if (rcode != RLM_MODULE_OK) { request_free(&request); goto unknown; } /* * If the client was updated by rlm_dynamic_clients, * don't create the client from attribute-value pairs. */ if (request->client == client) { created = client_create(clients, request); } else { created = request->client; /* * This frees the client if it isn't valid. */ if (!client_validate(clients, client, created)) goto unknown; } request_free(&request); if (!created) goto unknown; return created; #endif }
static int do_packet(int allports, uint32_t nasaddr, const struct radutmp *u) { int i, retries=5, timeout=3; struct timeval tv; RADIUS_PACKET *req, *rep = NULL; VALUE_PAIR *vp; const char *secret; if ((req = rad_alloc(1)) == NULL) { librad_perror("radzap"); exit(1); } req->id = getpid() & 0xFF; req->code = PW_ACCOUNTING_REQUEST; req->dst_port = acct_port; if(req->dst_port == 0) req->dst_port = getport("radacct"); if(req->dst_port == 0) req->dst_port = PW_ACCT_UDP_PORT; if (radiusip == INADDR_NONE) { req->dst_ipaddr = ip_getaddr("localhost"); } else { req->dst_ipaddr = radiusip; } if(!req->dst_ipaddr) req->dst_ipaddr = 0x7f000001; req->vps = NULL; secret = getsecret(req->dst_ipaddr); if(allports != 0) { INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_ACCOUNTING_OFF); IPPAIR(PW_NAS_IP_ADDRESS, nasaddr); INTPAIR(PW_ACCT_DELAY_TIME, 0); } else { char login[sizeof u->login+1]; char session_id[sizeof u->session_id+1]; strNcpy(login, u->login, sizeof login); strNcpy(session_id, u->session_id, sizeof session_id); INTPAIR(PW_ACCT_STATUS_TYPE, PW_STATUS_STOP); IPPAIR(PW_NAS_IP_ADDRESS, u->nas_address); INTPAIR(PW_ACCT_DELAY_TIME, 0); STRINGPAIR(PW_USER_NAME, login); INTPAIR(PW_NAS_PORT, u->nas_port); STRINGPAIR(PW_ACCT_SESSION_ID, session_id); if(u->proto=='P') { INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER); INTPAIR(PW_FRAMED_PROTOCOL, PW_PPP); } else if(u->proto=='S') { INTPAIR(PW_SERVICE_TYPE, PW_FRAMED_USER); INTPAIR(PW_FRAMED_PROTOCOL, PW_SLIP); } else { INTPAIR(PW_SERVICE_TYPE, PW_LOGIN_USER); /* A guess, really */ } IPPAIR(PW_FRAMED_IP_ADDRESS, u->framed_address); INTPAIR(PW_ACCT_SESSION_TIME, 0); INTPAIR(PW_ACCT_INPUT_OCTETS, 0); INTPAIR(PW_ACCT_OUTPUT_OCTETS, 0); INTPAIR(PW_ACCT_INPUT_PACKETS, 0); INTPAIR(PW_ACCT_OUTPUT_PACKETS, 0); } if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("radzap: socket: "); exit(1); } for (i = 0; i < retries; i++) { fd_set rdfdesc; rad_send(req, NULL, secret); /* And wait for reply, timing out as necessary */ FD_ZERO(&rdfdesc); FD_SET(req->sockfd, &rdfdesc); tv.tv_sec = (int)timeout; tv.tv_usec = 1000000 * (timeout - (int)timeout); /* Something's wrong if we don't get exactly one fd. */ if (select(req->sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) { continue; } rep = rad_recv(req->sockfd); if (rep != NULL) { break; } else { /* NULL: couldn't receive the packet */ librad_perror("radzap:"); exit(1); } } /* No response or no data read (?) */ if (i == retries) { fprintf(stderr, "%s: no response from server\n", progname); exit(1); } if (rad_decode(rep, req, secret) != 0) { librad_perror("rad_decode"); exit(1); } vp_printlist(stdout, rep->vps); return 0; }
/* * Receive packets from an accounting socket */ static int acct_socket_recv(rad_listen_t *listener, RAD_REQUEST_FUNP *pfun, REQUEST **prequest) { ssize_t rcode; int code, src_port; RADIUS_PACKET *packet; RAD_REQUEST_FUNP fun = NULL; RADCLIENT *client; fr_ipaddr_t src_ipaddr; rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code); if (rcode < 0) return 0; RAD_STATS_TYPE_INC(listener, total_requests); if (rcode < 20) { /* AUTH_HDR_LEN */ RAD_STATS_TYPE_INC(listener, total_malformed_requests); return 0; } if ((client = client_listener_find(listener, &src_ipaddr, src_port)) == NULL) { rad_recv_discard(listener->fd); RAD_STATS_TYPE_INC(listener, total_invalid_requests); return 0; } /* * Some sanity checks, based on the packet code. */ switch(code) { case PW_ACCOUNTING_REQUEST: RAD_STATS_CLIENT_INC(listener, client, total_requests); fun = rad_accounting; break; case PW_STATUS_SERVER: if (!mainconfig.status_server) { rad_recv_discard(listener->fd); RAD_STATS_TYPE_INC(listener, total_packets_dropped); RAD_STATS_CLIENT_INC(listener, client, total_unknown_types); DEBUG("WARNING: Ignoring Status-Server request due to security configuration"); return 0; } fun = acct_status_server; break; default: rad_recv_discard(listener->fd); RAD_STATS_TYPE_INC(listener, total_unknown_types); RAD_STATS_CLIENT_INC(listener, client, total_unknown_types); DEBUG("Invalid packet code %d sent to a accounting port from client %s port %d : IGNORED", code, client->shortname, src_port); return 0; } /* switch over packet types */ /* * Now that we've sanity checked everything, receive the * packet. */ packet = rad_recv(listener->fd, 0); if (!packet) { RAD_STATS_TYPE_INC(listener, total_malformed_requests); radlog(L_ERR, "%s", fr_strerror()); return 0; } /* * There can be no duplicate accounting packets. */ if (!received_request(listener, packet, prequest, client)) { RAD_STATS_TYPE_INC(listener, total_packets_dropped); RAD_STATS_CLIENT_INC(listener, client, total_packets_dropped); rad_free(&packet); return 0; } *pfun = fun; return 1; }
/* * Recieve packets from a proxy socket. */ static int proxy_socket_recv(rad_listen_t *listener, RAD_REQUEST_FUNP *pfun, REQUEST **prequest) { REQUEST *request; RADIUS_PACKET *packet; char buffer[128]; RAD_REQUEST_FUNP fun = NULL; packet = rad_recv(listener->fd, 0); if (!packet) { radlog(L_ERR, "%s", fr_strerror()); return 0; } /* * FIXME: Client MIB updates? */ switch(packet->code) { case PW_AUTHENTICATION_ACK: case PW_ACCESS_CHALLENGE: case PW_AUTHENTICATION_REJECT: #ifdef WITH_ACCOUNTING case PW_ACCOUNTING_RESPONSE: #endif break; #ifdef WITH_COA case PW_DISCONNECT_ACK: case PW_DISCONNECT_NAK: case PW_COA_ACK: case PW_COA_NAK: fun = rad_coa_reply; /* run NEW function */ break; #endif default: /* * FIXME: Update MIB for packet types? */ radlog(L_ERR, "Invalid packet code %d sent to a proxy port " "from home server %s port %d - ID %d : IGNORED", packet->code, ip_ntoh(&packet->src_ipaddr, buffer, sizeof(buffer)), packet->src_port, packet->id); rad_free(&packet); return 0; } request = received_proxy_response(packet); if (!request) { return 0; } rad_assert(request->process != NULL); #ifdef WITH_COA if (!fun) #endif fun = request->process; /* re-run original function */ *pfun = fun; *prequest = request; return 1; }
/* * Receive one packet, maybe. */ static int recv_one_packet(int wait_time) { fd_set set; struct timeval tv; radclient_t myclient, radclient; RADIUS_PACKET myrequest, *reply; /* And wait for reply, timing out as necessary */ FD_ZERO(&set); FD_SET(sockfd, &set); if (wait_time <= 0) { tv.tv_sec = 0; } else { tv.tv_sec = wait_time; } tv.tv_usec = 0; /* * No packet was received. */ if (select(sockfd + 1, &set, NULL, NULL, &tv) != 1) { return 0; } /* * Look for the packet. */ reply = rad_recv(sockfd); if (!reply) { fprintf(stderr, "radclient: received bad packet: %s\n", librad_errstr); return -1; /* bad packet */ } myclient.request = &myrequest; myrequest.id = reply->id; myrequest.dst_ipaddr = reply->src_ipaddr; myrequest.dst_port = reply->src_port; radclient.reply = reply; /* * FIXME: Do stuff to process the reply. */ #if 0 if (rad_verify(reply, radclient->request, secret) != 0) { printf("rad_verify\n"); librad_perror("rad_verify"); totallost++; goto packet_done; /* shared secret is incorrect */ } #endif if (rad_decode(reply, radclient.request, secret) != 0) { librad_perror("rad_decode"); totallost++; goto packet_done; /* shared secret is incorrect */ } /* libradius debug already prints out the value pairs for us */ if (reply->code != PW_AUTHENTICATION_REJECT) { totalapp++; } else { totaldeny++; } packet_done: /* * Once we've sent the packet as many times as requested, * mark it done. */ return reply->code; }
static int send_packet(RADIUS_PACKET *req, RADIUS_PACKET **rep) { int i; struct timeval tv; for (i = 0; i < retries; i++) { fd_set rdfdesc; rad_send(req, NULL, secret); /* And wait for reply, timing out as necessary */ FD_ZERO(&rdfdesc); FD_SET(req->sockfd, &rdfdesc); tv.tv_sec = (int)timeout; tv.tv_usec = 1000000 * (timeout - (int) timeout); /* Something's wrong if we don't get exactly one fd. */ if (select(req->sockfd + 1, &rdfdesc, NULL, NULL, &tv) != 1) { continue; } *rep = rad_recv(req->sockfd); if (*rep != NULL) { /* * If we get a response from a machine * which we did NOT send a request to, * then complain. */ if (((*rep)->src_ipaddr != req->dst_ipaddr) || ((*rep)->src_port != req->dst_port)) { char src[64], dst[64]; ip_ntoa(src, (*rep)->src_ipaddr); ip_ntoa(dst, req->dst_ipaddr); fprintf(stderr, "radclient: ERROR: Sent request to host %s port %d, got response from host %s port %d\n!", dst, req->dst_port, src, (*rep)->src_port); exit(1); } break; } else { /* NULL: couldn't receive the packet */ librad_perror("radclient:"); exit(1); } } /* No response or no data read (?) */ if (i == retries) { fprintf(stderr, "radclient: no response from server\n"); exit(1); } /* * FIXME: Discard the packet & listen for another. * * Hmm... we should really be using eapol_test, which does * a lot more than radeapclient. */ if (rad_verify(*rep, req, secret) != 0) { librad_perror("rad_verify"); exit(1); } if (rad_decode(*rep, req, secret) != 0) { librad_perror("rad_decode"); exit(1); } /* libradius debug already prints out the value pairs for us */ if (!librad_debug && do_output) { printf("Received response ID %d, code %d, length = %d\n", (*rep)->id, (*rep)->code, (*rep)->data_len); vp_printlist(stdout, (*rep)->vps); } if((*rep)->code == PW_AUTHENTICATION_ACK) { totalapp++; } else { totaldeny++; } return 0; }