示例#1
0
static void debug_packet(RADIUS_PACKET *packet, int direction)
{
	VALUE_PAIR *vp;
	char buffer[1024];
	char const *received, *from;
	fr_ipaddr_t const *ip;
	uint16_t port;

	if (!packet) return;

	if (direction == 0) {
		received = "Received";
		from = "from";	/* what else? */
		ip = &packet->src_ipaddr;
		port = packet->src_port;

	} else {
		received = "Sending";
		from = "to";	/* hah! */
		ip = &packet->dst_ipaddr;
		port = packet->dst_port;
	}

	/*
	 *	Client-specific debugging re-prints the input
	 *	packet into the client log.
	 *
	 *	This really belongs in a utility library
	 */
	if (is_radius_code(packet->code)) {
		printf("%s %s packet %s host %s port %d, id=%d, length=%d\n",
		       received, fr_packet_codes[packet->code], from,
		       inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
		       port, packet->id, (int) packet->data_len);
	} else {
		printf("%s packet %s host %s port %d code=%d, id=%d, length=%d\n",
		       received, from,
		       inet_ntop(ip->af, &ip->ipaddr, buffer, sizeof(buffer)),
		       port,
		       packet->code, packet->id, (int) packet->data_len);
	}

	for (vp = packet->vps; vp != NULL; vp = vp->next) {
		vp_prints(buffer, sizeof(buffer), vp);
		printf("\t%s\n", buffer);
	}
	fflush(stdout);
}
示例#2
0
/*
 *	Receive one packet, maybe.
 */
static int recv_one_packet(int wait_time)
{
	fd_set		set;
	struct timeval  tv;
	rc_request_t	*request;
	RADIUS_PACKET	*reply, **packet_p;
	volatile int max_fd;

	/* And wait for reply, timing out as necessary */
	FD_ZERO(&set);

	max_fd = fr_packet_list_fd_set(pl, &set);
	if (max_fd < 0) exit(1); /* no sockets to listen on! */

	tv.tv_sec = (wait_time <= 0) ? 0 : wait_time;
	tv.tv_usec = 0;

	/*
	 *	No packet was received.
	 */
	if (select(max_fd, &set, NULL, NULL, &tv) <= 0) return 0;

	/*
	 *	Look for the packet.
	 */
	reply = fr_packet_list_recv(pl, &set);
	if (!reply) {
		ERROR("Received bad packet");
#ifdef WITH_TCP
		/*
		 *	If the packet is bad, we close the socket.
		 *	I'm not sure how to do that now, so we just
		 *	die...
		 */
		if (proto) exit(1);
#endif
		return -1;	/* bad packet */
	}

	/*
	 *	We don't use udpfromto.  So if we bind to "*", we want
	 *	to find replies sent to 192.0.2.4.  Therefore, we
	 *	force all replies to have the one address we know
	 *	about, no matter what real address they were sent to.
	 *
	 *	This only works if were not using any of the
	 *	Packet-* attributes, or running with 'auto'.
	 */
	reply->dst_ipaddr = client_ipaddr;
	reply->dst_port = client_port;

#ifdef WITH_TCP

	/*
	 *	TCP sockets don't use recvmsg(), and thus don't get
	 *	the source IP/port.  However, since they're TCP, we
	 *	know what the source IP/port is, because that's where
	 *	we connected to.
	 */
	if (ipproto == IPPROTO_TCP) {
		reply->src_ipaddr = server_ipaddr;
		reply->src_port = server_port;
	}
#endif

	packet_p = fr_packet_list_find_byreply(pl, reply);
	if (!packet_p) {
		ERROR("Received reply to request we did not send. (id=%d socket %d)",
		      reply->id, reply->sockfd);
		rad_free(&reply);
		return -1;	/* got reply to packet we didn't send */
	}
	request = fr_packet2myptr(rc_request_t, packet, packet_p);

	/*
	 *	Fails the signature validation: not a real reply.
	 *	FIXME: Silently drop it and listen for another packet.
	 */
	if (rad_verify(reply, request->packet, secret) < 0) {
		REDEBUG("Reply verification failed");
		stats.lost++;
		goto packet_done; /* shared secret is incorrect */
	}

	if (print_filename) {
		RDEBUG("%s response code %d", request->files->packets, reply->code);
	}

	deallocate_id(request);
	request->reply = reply;
	reply = NULL;

	/*
	 *	If this fails, we're out of memory.
	 */
	if (rad_decode(request->reply, request->packet, secret) != 0) {
		REDEBUG("Reply decode failed");
		stats.lost++;
		goto packet_done;
	}

	fr_packet_header_print(fr_log_fp, request->reply, true);
	if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, request->reply->vps);

	/*
	 *	Increment counters...
	 */
	switch (request->reply->code) {
	case PW_CODE_ACCESS_ACCEPT:
	case PW_CODE_ACCOUNTING_RESPONSE:
	case PW_CODE_COA_ACK:
	case PW_CODE_DISCONNECT_ACK:
		stats.accepted++;
		break;

	case PW_CODE_ACCESS_CHALLENGE:
		break;

	default:
		stats.rejected++;
	}

	/*
	 *	If we had an expected response code, check to see if the
	 *	packet matched that.
	 */
	if (request->reply->code != request->filter_code) {
		if (is_radius_code(request->reply->code)) {
			REDEBUG("%s: Expected %s got %s", request->name, fr_packet_codes[request->filter_code],
				fr_packet_codes[request->reply->code]);
		} else {
			REDEBUG("%s: Expected %u got %i", request->name, request->filter_code,
				request->reply->code);
		}
		stats.failed++;
	/*
	 *	Check if the contents of the packet matched the filter
	 */
	} else if (!request->filter) {
		stats.passed++;
	} else {
		VALUE_PAIR const *failed[2];

		fr_pair_list_sort(&request->reply->vps, fr_pair_cmp_by_da_tag);
		if (fr_pair_validate(failed, request->filter, request->reply->vps)) {
			RDEBUG("%s: Response passed filter", request->name);
			stats.passed++;
		} else {
			fr_pair_validate_debug(request, failed);
			REDEBUG("%s: Response for failed filter", request->name);
			stats.failed++;
		}
	}

	if (request->resend == resend_count) {
		request->done = true;
	}

packet_done:
	rad_free(&request->reply);
	rad_free(&reply);	/* may be NULL */

	return 0;
}
示例#3
0
/** Write a single detail entry to file pointer
 *
 * @param[in] out Where to write entry.
 * @param[in] inst Instance of rlm_detail.
 * @param[in] request The current request.
 * @param[in] packet associated with the request (request, reply, proxy-request, proxy-reply...).
 * @param[in] compat Write out entry in compatibility mode.
 */
static int detail_write(FILE *out, detail_instance_t *inst, REQUEST *request, RADIUS_PACKET *packet, bool compat)
{
	VALUE_PAIR *vp;
	char timestamp[256];

	if (radius_xlat(timestamp, sizeof(timestamp), request, inst->header, NULL, NULL) < 0) {
		return -1;
	}

#define WRITE(fmt, ...) do {\
	if (fprintf(out, fmt, ## __VA_ARGS__) < 0) {\
		RERROR("Failed writing to detail file: %s", fr_syserror(errno));\
		return -1;\
	}\
} while(0)

	WRITE("%s\n", timestamp);

	/*
	 *	Write the information to the file.
	 */
	if (!compat) {
		/*
		 *	Print out names, if they're OK.
		 *	Numbers, if not.
		 */
		if (is_radius_code(packet->code)) {
			WRITE("\tPacket-Type = %s\n", fr_packet_codes[packet->code]);
		} else {
			WRITE("\tPacket-Type = %d\n", packet->code);
		}
	}

	if (inst->log_srcdst) {
		VALUE_PAIR src_vp, dst_vp;

		memset(&src_vp, 0, sizeof(src_vp));
		memset(&dst_vp, 0, sizeof(dst_vp));

		switch (packet->src_ipaddr.af) {
		case AF_INET:
			src_vp.da = dict_attrbyvalue(PW_PACKET_SRC_IP_ADDRESS, 0);
			src_vp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr;

			dst_vp.da = dict_attrbyvalue(PW_PACKET_DST_IP_ADDRESS, 0);
			dst_vp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
			break;

		case AF_INET6:
			src_vp.da = dict_attrbyvalue(PW_PACKET_SRC_IPV6_ADDRESS, 0);
			memcpy(&src_vp.vp_ipv6addr, &packet->src_ipaddr.ipaddr.ip6addr,
			       sizeof(packet->src_ipaddr.ipaddr.ip6addr));
			dst_vp.da = dict_attrbyvalue(PW_PACKET_DST_IPV6_ADDRESS, 0);
			memcpy(&dst_vp.vp_ipv6addr, &packet->dst_ipaddr.ipaddr.ip6addr,
			       sizeof(packet->dst_ipaddr.ipaddr.ip6addr));
			break;

		default:
			break;
		}

		detail_vp_print(request, out, &src_vp);
		detail_vp_print(request, out, &dst_vp);

		src_vp.da = dict_attrbyvalue(PW_PACKET_SRC_PORT, 0);
		src_vp.vp_integer = packet->src_port;
		dst_vp.da = dict_attrbyvalue(PW_PACKET_DST_PORT, 0);
		dst_vp.vp_integer = packet->dst_port;

		detail_vp_print(request, out, &src_vp);
		detail_vp_print(request, out, &dst_vp);
	}

	{
		vp_cursor_t cursor;
		/* Write each attribute/value to the log file */
		for (vp = fr_cursor_init(&cursor, &packet->vps);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			FR_TOKEN op;

			if (inst->ht && fr_hash_table_finddata(inst->ht, vp->da)) continue;

			/*
			 *	Don't print passwords in old format...
			 */
			if (compat && !vp->da->vendor && (vp->da->attr == PW_USER_PASSWORD)) continue;

			/*
			 *	Print all of the attributes, operator should always be '='.
			 */
			op = vp->op;
			vp->op = T_OP_EQ;
			vp_print(out, vp);
			vp->op = op;
		}
	}

	/*
	 *	Add non-protocol attributes.
	 */
	if (compat) {
#ifdef WITH_PROXY
		if (request->proxy) {
			char proxy_buffer[128];

			inet_ntop(request->proxy->dst_ipaddr.af, &request->proxy->dst_ipaddr.ipaddr,
				  proxy_buffer, sizeof(proxy_buffer));
			WRITE("\tFreeradius-Proxied-To = %s\n", proxy_buffer);
		}
#endif

		WRITE("\tTimestamp = %ld\n", (unsigned long) request->timestamp);
	}

	WRITE("\n");

	return 0;
}
示例#4
0
static int tls_socket_recv(rad_listen_t *listener)
{
	bool doing_init = false;
	ssize_t rcode;
	RADIUS_PACKET *packet;
	REQUEST *request;
	listen_socket_t *sock = listener->data;
	fr_tls_status_t status;
	RADCLIENT *client = sock->client;

	if (!sock->packet) {
		sock->packet = fr_radius_alloc(sock, false);
		if (!sock->packet) return 0;

		sock->packet->sockfd = listener->fd;
		sock->packet->src_ipaddr = sock->other_ipaddr;
		sock->packet->src_port = sock->other_port;
		sock->packet->dst_ipaddr = sock->my_ipaddr;
		sock->packet->dst_port = sock->my_port;

		if (sock->request) sock->request->packet = talloc_steal(sock->request, sock->packet);
	}

	/*
	 *	Allocate a REQUEST for debugging, and initialize the TLS session.
	 */
	if (!sock->request) {
		sock->request = request = request_alloc(sock);
		if (!sock->request) {
			ERROR("Out of memory");
			return 0;
		}

		rad_assert(request->packet == NULL);
		rad_assert(sock->packet != NULL);
		request->packet = talloc_steal(request, sock->packet);

		request->component = "<tls-connect>";

		request->reply = fr_radius_alloc(request, false);
		if (!request->reply) return 0;

		rad_assert(sock->tls_session == NULL);

		sock->tls_session = tls_session_init_server(sock, listener->tls, sock->request,
					    listener->tls->require_client_cert);
		if (!sock->tls_session) {
			TALLOC_FREE(sock->request);
			sock->packet = NULL;
			return 0;
		}

		SSL_set_ex_data(sock->tls_session->ssl, FR_TLS_EX_INDEX_REQUEST, (void *)request);

		doing_init = true;
	}

	rad_assert(sock->request != NULL);
	rad_assert(sock->request->packet != NULL);
	rad_assert(sock->packet != NULL);
	rad_assert(sock->tls_session != NULL);

	request = sock->request;

	RDEBUG3("Reading from socket %d", request->packet->sockfd);
	PTHREAD_MUTEX_LOCK(&sock->mutex);
	rcode = read(request->packet->sockfd,
		     sock->tls_session->dirty_in.data,
		     sizeof(sock->tls_session->dirty_in.data));
	if ((rcode < 0) && (errno == ECONNRESET)) {
	do_close:
		PTHREAD_MUTEX_UNLOCK(&sock->mutex);
		DEBUG("Closing TLS socket from client port %u", sock->other_port);
		tls_socket_close(listener);
		PTHREAD_MUTEX_UNLOCK(&sock->mutex);
		return 0;
	}

	if (rcode < 0) {
		RDEBUG("Error reading TLS socket: %s", fr_syserror(errno));
		goto do_close;
	}

	/*
	 *	Normal socket close.
	 */
	if (rcode == 0) goto do_close;

	sock->tls_session->dirty_in.used = rcode;

	dump_hex("READ FROM SSL", sock->tls_session->dirty_in.data, sock->tls_session->dirty_in.used);

	/*
	 *	Catch attempts to use non-SSL.
	 */
	if (doing_init && (sock->tls_session->dirty_in.data[0] != handshake)) {
		RDEBUG("Non-TLS data sent to TLS socket: closing");
		goto do_close;
	}

	/*
	 *	If we need to do more initialization, do that here.
	 */
	if (!SSL_is_init_finished(sock->tls_session->ssl)) {
		if (!tls_handshake_recv(request, sock->tls_session)) {
			RDEBUG("FAILED in TLS handshake receive");
			goto do_close;
		}

		/*
		 *	More ACK data to send.  Do so.
		 */
		if (sock->tls_session->dirty_out.used > 0) {
			tls_socket_write(listener, request);
			PTHREAD_MUTEX_UNLOCK(&sock->mutex);
			return 0;
		}

		/*
		 *	FIXME: Run the request through a virtual
		 *	server in order to see if we like the
		 *	certificate presented by the client.
		 */
	}

	/*
	 *	Try to get application data.
	 */
	status = tls_application_data(sock->tls_session, request);
	RDEBUG("Application data status %d", status);

	if (status == FR_TLS_RECORD_FRAGMENT_MORE) {
		PTHREAD_MUTEX_UNLOCK(&sock->mutex);
		return 0;
	}

	if (sock->tls_session->clean_out.used == 0) {
		PTHREAD_MUTEX_UNLOCK(&sock->mutex);
		return 0;
	}

	/*
	 *	We now have a bunch of application data.
	 */
	dump_hex("TUNNELED DATA > ", sock->tls_session->clean_out.data, sock->tls_session->clean_out.used);

	/*
	 *	If the packet is a complete RADIUS packet, return it to
	 *	the caller.  Otherwise...
	 */
	if ((sock->tls_session->clean_out.used < 20) ||
	    (((sock->tls_session->clean_out.data[2] << 8) | sock->tls_session->clean_out.data[3]) != (int) sock->tls_session->clean_out.used)) {
		RDEBUG("Received bad packet: Length %zd contents %d",
		       sock->tls_session->clean_out.used,
		       (sock->tls_session->clean_out.data[2] << 8) | sock->tls_session->clean_out.data[3]);
		goto do_close;
	}

	packet = sock->packet;
	packet->data = talloc_array(packet, uint8_t, sock->tls_session->clean_out.used);
	packet->data_len = sock->tls_session->clean_out.used;
	sock->tls_session->record_to_buff(&sock->tls_session->clean_out, packet->data, packet->data_len);
	packet->vps = NULL;
	PTHREAD_MUTEX_UNLOCK(&sock->mutex);

	if (!fr_radius_ok(packet, 0, NULL)) {
		if (DEBUG_ENABLED) ERROR("Receive - %s", fr_strerror());
		DEBUG("Closing TLS socket from client");
		PTHREAD_MUTEX_LOCK(&sock->mutex);
		tls_socket_close(listener);
		PTHREAD_MUTEX_UNLOCK(&sock->mutex);
		return 0;	/* do_close unlocks the mutex */
	}

	/*
	 *	Copied from src/lib/radius.c, fr_radius_recv();
	 */
	if (fr_debug_lvl) {
		char host_ipaddr[INET6_ADDRSTRLEN];

		if (is_radius_code(packet->code)) {
			RDEBUG("tls_recv: %s packet from host %s port %d, id=%d, length=%d",
			       fr_packet_codes[packet->code],
			       inet_ntop(packet->src_ipaddr.af,
					 &packet->src_ipaddr.ipaddr,
					 host_ipaddr, sizeof(host_ipaddr)),
			       packet->src_port,
			       packet->id, (int) packet->data_len);
		} else {
			RDEBUG("tls_recv: Packet from host %s port %d code=%d, id=%d, length=%d",
			       inet_ntop(packet->src_ipaddr.af,
					 &packet->src_ipaddr.ipaddr,
					 host_ipaddr, sizeof(host_ipaddr)),
			       packet->src_port,
			       packet->code,
			       packet->id, (int) packet->data_len);
		}
	}

	FR_STATS_INC(auth, total_requests);

	return 1;
}
示例#5
0
/*
 *	Receive one packet, maybe.
 */
static int recv_one_packet(int wait_time)
{
	fd_set		set;
	struct timeval  tv;
	rc_request_t	*request;
	RADIUS_PACKET	*reply, **packet_p;
	volatile int max_fd;

	/* And wait for reply, timing out as necessary */
	FD_ZERO(&set);

	max_fd = fr_packet_list_fd_set(pl, &set);
	if (max_fd < 0) exit(1); /* no sockets to listen on! */

	if (wait_time <= 0) {
		tv.tv_sec = 0;
	} else {
		tv.tv_sec = wait_time;
	}
	tv.tv_usec = 0;

	/*
	 *	No packet was received.
	 */
	if (select(max_fd, &set, NULL, NULL, &tv) <= 0) {
		return 0;
	}

	/*
	 *	Look for the packet.
	 */
	reply = fr_packet_list_recv(pl, &set);
	if (!reply) {
		ERROR("Received bad packet");
#ifdef WITH_TCP
		/*
		 *	If the packet is bad, we close the socket.
		 *	I'm not sure how to do that now, so we just
		 *	die...
		 */
		if (proto) exit(1);
#endif
		return -1;	/* bad packet */
	}

	/*
	 *	udpfromto issues.  We may have bound to "*",
	 *	and we want to find the replies that are sent to
	 *	(say) 127.0.0.1.
	 */
	reply->dst_ipaddr = client_ipaddr;
	reply->dst_port = client_port;
#ifdef WITH_TCP
	reply->src_ipaddr = server_ipaddr;
	reply->src_port = server_port;
#endif

	packet_p = fr_packet_list_find_byreply(pl, reply);
	if (!packet_p) {
		ERROR("Received reply to request we did not send. (id=%d socket %d)",
		      reply->id, reply->sockfd);
		rad_free(&reply);
		return -1;	/* got reply to packet we didn't send */
	}
	request = fr_packet2myptr(rc_request_t, packet, packet_p);

	/*
	 *	Fails the signature validation: not a real reply.
	 *	FIXME: Silently drop it and listen for another packet.
	 */
	if (rad_verify(reply, request->packet, secret) < 0) {
		REDEBUG("Reply verification failed");
		stats.lost++;
		goto packet_done; /* shared secret is incorrect */
	}

	if (print_filename) {
		RDEBUG("%s response code %d", request->files->packets, reply->code);
	}

	deallocate_id(request);
	request->reply = reply;
	reply = NULL;

	/*
	 *	If this fails, we're out of memory.
	 */
	if (rad_decode(request->reply, request->packet, secret) != 0) {
		REDEBUG("Reply decode failed");
		stats.lost++;
		goto packet_done;
	}

	/*
	 *	Increment counters...
	 */
	switch (request->reply->code) {
	case PW_CODE_AUTHENTICATION_ACK:
	case PW_CODE_ACCOUNTING_RESPONSE:
	case PW_CODE_COA_ACK:
	case PW_CODE_DISCONNECT_ACK:
		stats.accepted++;
		break;

	case PW_CODE_ACCESS_CHALLENGE:
		break;

	default:
		stats.rejected++;
	}

	/*
	 *	If we had an expected response code, check to see if the
	 *	packet matched that.
	 */
	if (request->reply->code != request->filter_code) {
		if (is_radius_code(request->packet_code)) {
			REDEBUG("Expected %s got %s", fr_packet_codes[request->filter_code],
				fr_packet_codes[request->reply->code]);
		} else {
			REDEBUG("Expected %u got %i", request->filter_code,
				request->reply->code);
		}
		stats.failed++;
	/*
	 *	Check if the contents of the packet matched the filter
	 */
	} else if (!request->filter) {
		stats.passed++;
	} else {
		VALUE_PAIR const *failed[2];

		pairsort(&request->reply->vps, attrtagcmp);
		if (pairvalidate(failed, request->filter, request->reply->vps)) {
			RDEBUG("Response passed filter");
			stats.passed++;
		} else {
			pairvalidate_debug(request, failed);
			REDEBUG("Response failed filter");
			stats.failed++;
		}
	}

	if (request->resend == resend_count) {
		request->done = true;
	}

packet_done:
	rad_free(&request->reply);
	rad_free(&reply);	/* may be NULL */

	return 0;
}
示例#6
0
/*
 *	Receives a packet, assuming that the RADIUS_PACKET structure
 *	has been filled out already.
 *
 *	This ASSUMES that the packet is allocated && fields
 *	initialized.
 *
 *	This ASSUMES that the socket is marked as O_NONBLOCK, which
 *	the function above does set, if your system supports it.
 *
 *	Calling this function MAY change sockfd,
 *	if src_ipaddr.af == AF_UNSPEC.
 */
int fr_tcp_read_packet(RADIUS_PACKET *packet, int flags)
{
	ssize_t len;

	/*
	 *	No data allocated.  Read the 4-byte header into
	 *	a temporary buffer.
	 */
	if (!packet->data) {
		int packet_len;

		len = recv(packet->sockfd, packet->vector + packet->data_len,
			   4 - packet->data_len, 0);
		if (len == 0) return -2; /* clean close */

#ifdef ECONNRESET
		if ((len < 0) && (errno == ECONNRESET)) { /* forced */
			return -2;
		}
#endif

		if (len < 0) {
			fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
			return -1;
		}

		packet->data_len += len;
		if (packet->data_len < 4) { /* want more data */
			return 0;
		}

		packet_len = (packet->vector[2] << 8) | packet->vector[3];

		if (packet_len < AUTH_HDR_LEN) {
			fr_strerror_printf("Discarding packet: Smaller than RFC minimum of 20 bytes");
			return -1;
		}

		/*
		 *	If the packet is too big, then the socket is bad.
		 */
		if (packet_len > MAX_PACKET_LEN) {
			fr_strerror_printf("Discarding packet: Larger than RFC limitation of 4096 bytes");
			return -1;
		}

		packet->data = talloc_array(packet, uint8_t, packet_len);
		if (!packet->data) {
			fr_strerror_printf("Out of memory");
			return -1;
		}

		packet->data_len = packet_len;
		packet->partial = 4;
		memcpy(packet->data, packet->vector, 4);
	}

	/*
	 *	Try to read more data.
	 */
	len = recv(packet->sockfd, packet->data + packet->partial,
		   packet->data_len - packet->partial, 0);
	if (len == 0) return -2; /* clean close */

#ifdef ECONNRESET
	if ((len < 0) && (errno == ECONNRESET)) { /* forced */
		return -2;
	}
#endif

	if (len < 0) {
		fr_strerror_printf("Error receiving packet: %s", fr_syserror(errno));
		return -1;
	}

	packet->partial += len;

	if (packet->partial < packet->data_len) {
		return 0;
	}

	/*
	 *	See if it's a well-formed RADIUS packet.
	 */
	if (!rad_packet_ok(packet, flags, NULL)) {
		return -1;
	}

	/*
	 *	Explicitly set the VP list to empty.
	 */
	packet->vps = NULL;

	if (fr_debug_flag) {
		char ip_buf[128], buffer[256];

		if (packet->src_ipaddr.af != AF_UNSPEC) {
			inet_ntop(packet->src_ipaddr.af,
				  &packet->src_ipaddr.ipaddr,
				  ip_buf, sizeof(ip_buf));
			snprintf(buffer, sizeof(buffer), "host %s port %d",
				 ip_buf, packet->src_port);
		} else {
			snprintf(buffer, sizeof(buffer), "socket %d",
				 packet->sockfd);
		}


		if (is_radius_code(packet->code)) {
			DEBUG("Received %s packet from %s",
			      fr_packet_codes[packet->code], buffer);
		} else {
			DEBUG("Received packet from %s code %d",
			      buffer, packet->code);
		}
		DEBUG(", id=%d, length=%zu\n", packet->id, packet->data_len);
	}

	return 1;		/* done reading the packet */
}