}
+ssize_t rad_recv_header(int sockfd, lrad_ipaddr_t *src_ipaddr, int *src_port,
+ int *code)
+{
+ ssize_t data_len, packet_len;
+ uint8_t header[4];
+ struct sockaddr_storage src;
+ socklen_t sizeof_src = sizeof(src);
+
+ data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK,
+ (struct sockaddr *)&src, &sizeof_src);
+ if (data_len < 0) return -1;
+
+ /*
+ * Too little data is available, discard the packet.
+ */
+ if (data_len < 4) {
+ recvfrom(sockfd, header, sizeof(header), 0,
+ (struct sockaddr *)&src, &sizeof_src);
+ return 1;
+
+ } else { /* we got 4 bytes of data. */
+ /*
+ * See how long the packet says it is.
+ */
+ packet_len = (header[2] * 256) + header[3];
+
+ /*
+ * The length in the packet says it's less than
+ * a RADIUS header length: discard it.
+ */
+ if (packet_len < AUTH_HDR_LEN) {
+ recvfrom(sockfd, header, sizeof(header), 0,
+ (struct sockaddr *)&src, &sizeof_src);
+ return 1;
+
+ /*
+ * Enforce RFC requirements, for sanity.
+ * Anything after 4k will be discarded.
+ */
+ } else if (packet_len > MAX_PACKET_LEN) {
+ recvfrom(sockfd, header, sizeof(header), 0,
+ (struct sockaddr *)&src, &sizeof_src);
+ return 1;
+ }
+ }
+
+ if (src.ss_family == AF_INET) {
+ struct sockaddr_in *s4;
+
+ s4 = (struct sockaddr_in *)&src;
+ src_ipaddr->af = AF_INET;
+ src_ipaddr->ipaddr.ip4addr = s4->sin_addr;
+ *src_port = ntohs(s4->sin_port);
+
+#ifdef HAVE_STRUCT_SOCKADDR_IN6
+ } else if (src.ss_family == AF_INET6) {
+ struct sockaddr_in6 *s6;
+
+ s6 = (struct sockaddr_in6 *)&src;
+ src_ipaddr->af = AF_INET6;
+ src_ipaddr->ipaddr.ip6addr = s6->sin6_addr;
+ *src_port = ntohs(s6->sin6_port);
+
+#endif
+ } else {
+ recvfrom(sockfd, header, sizeof(header), 0,
+ (struct sockaddr *)&src, &sizeof_src);
+ return 1;
+ }
+
+ *code = header[0];
+
+ /*
+ * The packet says it's this long, but the actual UDP
+ * size could still be smaller.
+ */
+ return packet_len;
+}
+
+
/*
- * Wrapper for recvfrom, which handles recvfromto, IPv6, and all
+ * wrapper for recvfrom, which handles recvfromto, IPv6, and all
* possible combinations.
*/
static ssize_t rad_recvfrom(int sockfd, uint8_t **pbuf, int flags,
lrad_MD5Final(digest, &context);
context = old;
- lrad_MD5Update(&context, passwd, AUTH_PASS_LEN);
+ if (pwlen > AUTH_PASS_LEN) lrad_MD5Update(&context, passwd, AUTH_PASS_LEN);
} else {
lrad_MD5Final(digest, &context);
context = old;
- lrad_MD5Update(&context, passwd + n, AUTH_PASS_LEN);
+ if (pwlen > (n + AUTH_PASS_LEN)) lrad_MD5Update(&context, passwd + n, AUTH_PASS_LEN);
}
for (i = 0; i < AUTH_PASS_LEN; i++) {
radius_packet = *radius_packet_ptr;
free(radius_packet->data);
+
pairfree(&radius_packet->vps);
free(radius_packet);
static int auth_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;
char buffer[128];
RADCLIENT *client;
+ lrad_ipaddr_t src_ipaddr;
- packet = rad_recv(listener->fd);
- if (!packet) {
- RAD_SNMP_TYPE_INC(listener, total_requests);
+ rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);
+ if (rcode < 0) return 0;
+
+ RAD_SNMP_TYPE_INC(listener, total_requests);
+
+ if (rcode < 20) { /* AUTH_HDR_LEN */
RAD_SNMP_TYPE_INC(listener, total_malformed_requests);
- radlog(L_ERR, "%s", librad_errstr);
return 0;
}
-
- RAD_SNMP_TYPE_INC(listener, total_requests);
if ((client = client_listener_find(listener,
- &packet->src_ipaddr)) == NULL) {
+ &src_ipaddr)) == NULL) {
RAD_SNMP_TYPE_INC(listener, total_invalid_requests);
- radlog(L_ERR, "Ignoring request from unknown client %s port %d",
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- buffer, sizeof(buffer)),
- packet->src_port);
- rad_free(&packet);
+ /*
+ * This is debugging rather than logging, so that
+ * DoS attacks don't affect us.
+ */
+ DEBUG("Ignoring request from unknown client %s port %d",
+ inet_ntop(src_ipaddr.af, &src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)), src_port);
return 0;
}
/*
* Some sanity checks, based on the packet code.
*/
- switch(packet->code) {
+ switch(code) {
case PW_AUTHENTICATION_REQUEST:
RAD_SNMP_CLIENT_INC(listener, client, requests);
fun = rad_authenticate;
RAD_SNMP_TYPE_INC(listener, total_packets_dropped);
RAD_SNMP_CLIENT_INC(listener, client, packets_dropped);
DEBUG("WARNING: Ignoring Status-Server request due to security configuration");
- rad_free(&packet);
return 0;
}
fun = rad_status_server;
RAD_SNMP_INC(rad_snmp.auth.total_unknown_types);
RAD_SNMP_CLIENT_INC(listener, client, unknown_types);
- radlog(L_ERR, "Invalid packet code %d sent to authentication port from client %s port %d "
- "- ID %d : IGNORED",
- packet->code, client->shortname,
- packet->src_port, packet->id);
- rad_free(&packet);
+ DEBUG("Invalid packet code %d sent to authentication port from client %s port %d : IGNORED",
+ code, client->shortname, src_port);
return 0;
break;
} /* switch over packet types */
+ /*
+ * Now that we've sanity checked everything, receive the
+ * packet.
+ */
+ packet = rad_recv(listener->fd);
+ if (!packet) {
+ RAD_SNMP_TYPE_INC(listener, total_malformed_requests);
+ radlog(L_ERR, "%s", librad_errstr);
+ return 0;
+ }
+
if (!received_request(listener, packet, prequest, client)) {
RAD_SNMP_TYPE_INC(listener, total_packets_dropped);
RAD_SNMP_CLIENT_INC(listener, client, packets_dropped);
* Receive packets from an accounting socket
*/
static int acct_socket_recv(rad_listen_t *listener,
- RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
+ RAD_REQUEST_FUNP *pfun, REQUEST **prequest)
{
+ ssize_t rcode;
+ int code, src_port;
RADIUS_PACKET *packet;
RAD_REQUEST_FUNP fun = NULL;
char buffer[128];
RADCLIENT *client;
+ lrad_ipaddr_t src_ipaddr;
- packet = rad_recv(listener->fd);
- if (!packet) {
- RAD_SNMP_TYPE_INC(listener, total_requests);
+ rcode = rad_recv_header(listener->fd, &src_ipaddr, &src_port, &code);
+ if (rcode < 0) return 0;
+
+ RAD_SNMP_TYPE_INC(listener, total_requests);
+
+ if (rcode < 20) { /* AUTH_HDR_LEN */
RAD_SNMP_TYPE_INC(listener, total_malformed_requests);
- radlog(L_ERR, "%s", librad_errstr);
return 0;
}
-
- RAD_SNMP_TYPE_INC(listener, total_requests);
if ((client = client_listener_find(listener,
- &packet->src_ipaddr)) == NULL) {
+ &src_ipaddr)) == NULL) {
RAD_SNMP_TYPE_INC(listener, total_invalid_requests);
- radlog(L_ERR, "Ignoring request from unknown client %s port %d",
- inet_ntop(packet->src_ipaddr.af,
- &packet->src_ipaddr.ipaddr,
- buffer, sizeof(buffer)),
- packet->src_port);
- rad_free(&packet);
+ /*
+ * This is debugging rather than logging, so that
+ * DoS attacks don't affect us.
+ */
+ DEBUG("Ignoring request from unknown client %s port %d",
+ inet_ntop(src_ipaddr.af, &src_ipaddr.ipaddr,
+ buffer, sizeof(buffer)), src_port);
return 0;
}
+ /*
+ * Some sanity checks, based on the packet code.
+ */
switch(packet->code) {
case PW_ACCOUNTING_REQUEST:
RAD_SNMP_CLIENT_INC(listener, client, requests);
RAD_SNMP_CLIENT_INC(listener, client, unknown_types);
DEBUG("WARNING: Ignoring Status-Server request due to security configuration");
- rad_free(&packet);
return 0;
}
fun = rad_status_server;
RAD_SNMP_TYPE_INC(listener, total_unknown_types);
RAD_SNMP_CLIENT_INC(listener, client, unknown_types);
- radlog(L_ERR, "Invalid packet code %d sent to a accounting port "
- "from client %s port %d - ID %d : IGNORED",
- packet->code, client->shortname,
- packet->src_port, packet->id);
- rad_free(&packet);
+ 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 */
/*
- * FIXME: Accounting duplicates should be handled
- * differently than authentication duplicates.
+ * Now that we've sanity checked everything, receive the
+ * packet.
+ */
+ packet = rad_recv(listener->fd);
+ if (!packet) {
+ RAD_SNMP_TYPE_INC(listener, total_malformed_requests);
+ radlog(L_ERR, "%s", librad_errstr);
+ return 0;
+ }
+
+ /*
+ * There can be no duplicate accounting packets.
*/
if (!received_request(listener, packet, prequest, client)) {
RAD_SNMP_TYPE_INC(listener, total_packets_dropped);