コード例 #1
0
ファイル: frs_proxy.c プロジェクト: Antti/freeradius-server
static int proxy_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
{
	/*
	 *	rad_verify is run in event.c, received_proxy_response()
	 */

	return rad_decode(request->proxy_reply, request->proxy,
			   request->home_server->secret);
}
コード例 #2
0
ファイル: frs_status.c プロジェクト: Antti/freeradius-server
static int status_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
{
	if (rad_verify(request->packet, NULL,
		       request->client->secret) < 0) {
		return -1;
	}

	return rad_decode(request->packet, NULL,
			  request->client->secret);
}
コード例 #3
0
ファイル: radclient.c プロジェクト: peruchi/freeradius-server
/*
 *	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;
}
コード例 #4
0
static void got_packet(UNUSED uint8_t *args, const struct pcap_pkthdr *header, const uint8_t *data)
{

	static int count = 1;			/* Packets seen */
	
	/*
	 *  Define pointers for packet's attributes
	 */
	const struct ip_header *ip;		/* The IP header */
	const struct udp_header *udp;		/* The UDP header */
	const uint8_t *payload;			/* Packet payload */
	
	/*
	 *  And define the size of the structures we're using
	 */
	int size_ethernet = sizeof(struct ethernet_header);
	int size_ip = sizeof(struct ip_header);
	int size_udp = sizeof(struct udp_header);
	
	/*
	 *  For FreeRADIUS
	 */
	RADIUS_PACKET *packet, *original;
	struct timeval elapsed;

	/*
	 * Define our packet's attributes
	 */

	if ((data[0] == 2) && (data[1] == 0) &&
	    (data[2] == 0) && (data[3] == 0)) {
		ip = (const struct ip_header*) (data + 4);

	} else {
		ip = (const struct ip_header*)(data + size_ethernet);
	}
	
	udp = (const struct udp_header*)(((const uint8_t *) ip) + size_ip);
	payload = (const uint8_t *)(((const uint8_t *) udp) + size_udp);

	packet = rad_alloc(NULL, 0);
	if (!packet) {
		fprintf(stderr, "Out of memory\n");
		return;
	}

	packet->src_ipaddr.af = AF_INET;
	packet->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;
	packet->src_port = ntohs(udp->udp_sport);
	packet->dst_ipaddr.af = AF_INET;
	packet->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
	packet->dst_port = ntohs(udp->udp_dport);

	memcpy(&packet->data, &payload, sizeof(packet->data));
	packet->data_len = header->len - (payload - data);

	if (!rad_packet_ok(packet, 0)) {
		DEBUG(log_dst, "Packet: %s\n", fr_strerror());
		
		DEBUG(log_dst, "  From     %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
		DEBUG(log_dst, "  To:      %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
		DEBUG(log_dst, "  Type:    %s\n", fr_packet_codes[packet->code]);

		rad_free(&packet);
		return;
	}
	
	switch (packet->code) {
	case PW_COA_REQUEST:
		/* we need a 16 x 0 byte vector for decrypting encrypted VSAs */
		original = nullpacket;
		break;
	case PW_AUTHENTICATION_ACK:
		/* look for a matching request and use it for decoding */
		original = rbtree_finddata(request_tree, packet);
		break;
	case PW_AUTHENTICATION_REQUEST:
		/* save the request for later matching */
		original = rad_alloc_reply(NULL, packet);
		if (original) { /* just ignore allocation failures */
			rbtree_deletebydata(request_tree, original);
			rbtree_insert(request_tree, original);
		}
		/* fallthrough */
	default:
		/* don't attempt to decode any encrypted attributes */
		original = NULL;
	}

	/*
	 *  Decode the data without bothering to check the signatures.
	 */
	if (rad_decode(packet, original, radius_secret) != 0) {
		rad_free(&packet);
		fr_perror("decode");
		return;
	}

	/*
	 *  We've seen a successfull reply to this, so delete it now
	 */
	if (original)
		rbtree_deletebydata(request_tree, original);

	if (filter_vps && filter_packet(packet)) {
		rad_free(&packet);
		DEBUG(log_dst, "Packet number %d doesn't match\n", count++);
		return;
	}

	if (out) {
		pcap_dump((void *) out, header, data);
		goto check_filter;
	}

	INFO(log_dst, "%s Id %d\t", fr_packet_codes[packet->code], packet->id);

	/*
	 *  Print the RADIUS packet
	 */
	INFO(log_dst, "%s:%d -> ", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
	INFO(log_dst, "%s:%d", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
	
	DEBUG1(log_dst, "\t(%d packets)", count++);
	
	if (!start_pcap.tv_sec) {
		start_pcap = header->ts;
	}

	tv_sub(&header->ts, &start_pcap, &elapsed);

	INFO(log_dst, "\t+%u.%03u", (unsigned int) elapsed.tv_sec,
	       (unsigned int) elapsed.tv_usec / 1000);
	
	if (fr_debug_flag > 1) {
		DEBUG(log_dst, "\n");
		if (packet->vps) {
			if (do_sort) sort(packet);
	
			vp_printlist(log_dst, packet->vps);
			pairfree(&packet->vps);
		}
	}
	
	INFO(log_dst, "\n");
	
	if (!to_stdout && (fr_debug_flag > 4)) {
		rad_print_hex(packet);
	}
	
	fflush(log_dst);

 check_filter:
	/*
	 *  If we're doing filtering, Access-Requests are cached in the
	 *  filter tree.
	 */
	if (!filter_vps ||
	    ((packet->code != PW_AUTHENTICATION_REQUEST) &&
	     (packet->code != PW_ACCOUNTING_REQUEST))) {
		rad_free(&packet);
	}
}
コード例 #5
0
static void rs_process_packet(rs_event_t *event, struct pcap_pkthdr const *header, uint8_t const *data)
{

	static int count = 0;			/* Packets seen */
	rs_stats_t *stats = event->stats;
	decode_fail_t reason;

	/*
	 *	Pointers into the packet data we just received
	 */
	size_t len;
	uint8_t const		*p = data;
	struct ip_header const	*ip = NULL;	/* The IP header */
	struct ip_header6 const	*ip6 = NULL;	/* The IPv6 header */
	struct udp_header const	*udp;		/* The UDP header */
	uint8_t			version;	/* IP header version */
	bool			response = false;	/* Was it a response code */

	RADIUS_PACKET *current, *original;
	struct timeval elapsed;
	struct timeval latency;

	count++;

	if (header->caplen <= 5) {
		INFO("Packet too small, captured %i bytes", header->caplen);
		return;
	}

	/*
	 *	Loopback header
	 */
	if ((p[0] == 2) && (p[1] == 0) && (p[2] == 0) && (p[3] == 0)) {
		p += 4;
	/*
	 *	Ethernet header
	 */
	} else {
		p += sizeof(struct ethernet_header);
	}

	version = (p[0] & 0xf0) >> 4;
	switch (version) {
	case 4:
		ip = (struct ip_header const *)p;
		len = (0x0f & ip->ip_vhl) * 4;	/* ip_hl specifies length in 32bit words */
		p += len;
		break;

	case 6:
		ip6 = (struct ip_header6 const *)p;
		p += sizeof(struct ip_header6);

		break;

	default:
		DEBUG("IP version invalid %i", version);
		return;
	}

	/*
	 *	End of variable length bits, do basic check now to see if packet looks long enough
	 */
	len = (p - data) + sizeof(struct udp_header) + (sizeof(radius_packet_t) - 1);	/* length value */
	if (len > header->caplen) {
		DEBUG("Packet too small, we require at least %zu bytes, captured %i bytes",
		      (size_t) len, header->caplen);
		return;
	}

	udp = (struct udp_header const *)p;
	p += sizeof(struct udp_header);

	/*
	 *	With artificial talloc memory limits there's a good chance we can
	 *	recover once some requests timeout, so make an effort to deal
	 *	with allocation failures gracefully.
	 */
	current = rad_alloc(NULL, 0);
	if (!current) {
		ERROR("Failed allocating memory to hold decoded packet");
		return;
	}
	current->timestamp = header->ts;
	current->data_len = header->caplen - (data - p);
	memcpy(&current->data, &p, sizeof(current->data));

	/*
	 *	Populate IP/UDP fields from PCAP data
	 */
	if (ip) {
		current->src_ipaddr.af = AF_INET;
		current->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;

		current->dst_ipaddr.af = AF_INET;
		current->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
	} else {
		current->src_ipaddr.af = AF_INET6;
		memcpy(&current->src_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_src.s6_addr,
		       sizeof(current->src_ipaddr.ipaddr.ip6addr.s6_addr));

		current->dst_ipaddr.af = AF_INET6;
		memcpy(&current->dst_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_dst.s6_addr,
		       sizeof(current->dst_ipaddr.ipaddr.ip6addr.s6_addr));
	}

	current->src_port = ntohs(udp->udp_sport);
	current->dst_port = ntohs(udp->udp_dport);

	if (!rad_packet_ok(current, 0, &reason)) {
		DEBUG("(%i) ** %s **", count, fr_strerror());

		DEBUG("(%i) %s Id %i %s:%s:%d -> %s:%d\t+%u.%03u", count,
		      fr_packet_codes[current->code], current->id,
		      event->in->name,
		      fr_inet_ntop(current->src_ipaddr.af, &current->src_ipaddr.ipaddr), current->src_port,
		      fr_inet_ntop(current->dst_ipaddr.af, &current->dst_ipaddr.ipaddr), current->dst_port,
		      (unsigned int) elapsed.tv_sec, ((unsigned int) elapsed.tv_usec / 1000));

		rad_free(&current);
		return;
	}

	switch (current->code) {
	case PW_CODE_COA_REQUEST:
		/* we need a 16 x 0 byte vector for decrypting encrypted VSAs */
		original = nullpacket;
		break;
	case PW_CODE_ACCOUNTING_RESPONSE:
	case PW_CODE_AUTHENTICATION_REJECT:
	case PW_CODE_AUTHENTICATION_ACK:
		response = true;
		/* look for a matching request and use it for decoding */
		original = rbtree_finddata(request_tree, current);
		break;
	case PW_CODE_ACCOUNTING_REQUEST:
	case PW_CODE_AUTHENTICATION_REQUEST:
		/* save the request for later matching */
		original = rad_alloc_reply(event->conf, current);
		original->timestamp = header->ts;
		if (original) { /* just ignore allocation failures */
			rbtree_deletebydata(request_tree, original);
			rbtree_insert(request_tree, original);
		}
		/* fallthrough */
	default:
		/* don't attempt to decode any encrypted attributes */
		original = NULL;
	}

	/*
	 *  Decode the data without bothering to check the signatures.
	 */
	if (rad_decode(current, original, event->conf->radius_secret) != 0) {
		rad_free(&current);
		fr_perror("decode");
		return;
	}

	if (filter_vps && rs_filter_packet(current)) {
		rad_free(&current);
		DEBUG("Packet number %d doesn't match", count++);
		return;
	}

	if (event->out) {
		pcap_dump((void *) (event->out->dumper), header, data);
		goto check_filter;
	}

	rs_tv_sub(&header->ts, &start_pcap, &elapsed);

	rs_stats_update_count(&stats->gauge, current);
	if (original) {
		rs_tv_sub(&current->timestamp, &original->timestamp, &latency);

		/*
		 *	Update stats for both the request and response types.
		 *
		 *	This isn't useful for things like Access-Requests, but will be useful for
		 *	CoA and Disconnect Messages, as we get the average latency across both
		 *	response types.
		 *
		 *	It also justifies allocating 255 instances rs_latency_t.
		 */
		rs_stats_update_latency(&stats->exchange[current->code], &latency);
		rs_stats_update_latency(&stats->exchange[original->code], &latency);

		/*
		 *	Print info about the response.
		 */
		DEBUG("(%i) %s Id %i %s:%s:%d %s %s:%d\t+%u.%03u\t+%u.%03u", count,
		      fr_packet_codes[current->code], current->id,
		      event->in->name,
		      fr_inet_ntop(current->src_ipaddr.af, &current->src_ipaddr.ipaddr), current->src_port,
		      response ? "<-" : "->",
		      fr_inet_ntop(current->dst_ipaddr.af, &current->dst_ipaddr.ipaddr), current->dst_port,
		      (unsigned int) elapsed.tv_sec, ((unsigned int) elapsed.tv_usec / 1000),
		      (unsigned int) latency.tv_sec, ((unsigned int) latency.tv_usec / 1000));
	/*
	 *	It's the original request
	 */
	} else {
		/*
		 *	Print info about the request
		 */
		DEBUG("(%i) %s Id %i %s:%s:%d %s %s:%d\t+%u.%03u", count,
		      fr_packet_codes[current->code], current->id,
		      event->in->name,
		      fr_inet_ntop(current->src_ipaddr.af, &current->src_ipaddr.ipaddr), current->src_port,
		      response ? "<-" : "->",
		      fr_inet_ntop(current->dst_ipaddr.af, &current->dst_ipaddr.ipaddr), current->dst_port,
		      (unsigned int) elapsed.tv_sec, ((unsigned int) elapsed.tv_usec / 1000));
	}

	if (fr_debug_flag > 1) {
		if (current->vps) {
			if (event->conf->do_sort) {
				pairsort(&current->vps, true);
			}
			vp_printlist(log_dst, current->vps);
			pairfree(&current->vps);
		}
	}

	/*
	 *  We've seen a successful reply to this, so delete it now
	 */
	if (original) {
		rbtree_deletebydata(request_tree, original);
	}

	if (!event->conf->to_stdout && (fr_debug_flag > 4)) {
		rad_print_hex(current);
	}

	fflush(log_dst);

check_filter:
	/*
	 *  If we're doing filtering, Access-Requests are cached in the
	 *  filter tree.
	 */
	if (!filter_vps ||
	    ((current->code != PW_CODE_AUTHENTICATION_REQUEST) && (current->code != PW_CODE_ACCOUNTING_REQUEST))) {
		rad_free(&current);
	}
}
コード例 #6
0
ファイル: radclient.c プロジェクト: rssh/freeradius-server
/*
 *	Receive one packet, maybe.
 */
static int recv_one_packet(int wait_time)
{
	fd_set		set;
	struct timeval  tv;
	radclient_t	*radclient;
	RADIUS_PACKET	*reply, **request_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) {
		fprintf(stderr, "radclient: received bad packet: %s\n",
			fr_strerror());
#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

	if (fr_debug_flag > 2) print_hex(reply);

	request_p = fr_packet_list_find_byreply(pl, reply);
	if (!request_p) {
		fprintf(stderr, "radclient: received response to request we did not send. (id=%d socket %d)\n", reply->id, reply->sockfd);
		rad_free(&reply);
		return -1;	/* got reply to packet we didn't send */
	}
	radclient = fr_packet2myptr(radclient_t, request, request_p);

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

	fr_packet_list_yank(pl, radclient->request);
	if (print_filename) printf("%s:%d %d\n",
				   radclient->filename,
				   radclient->packet_number,
				   reply->code);
	deallocate_id(radclient);
	radclient->reply = reply;
	reply = NULL;

	/*
	 *	If this fails, we're out of memory.
	 */
	if (rad_decode(radclient->reply, radclient->request, secret) != 0) {
		fr_perror("rad_decode");
		totallost++;
		goto packet_done;
	}

	/* libradius debug already prints out the value pairs for us */
	if (!fr_debug_flag && do_output) {
		printf("Received response ID %d, code %d, length = %zd\n",
		       radclient->reply->id, radclient->reply->code,
		       radclient->reply->data_len);
		vp_printlist(stdout, radclient->reply->vps);
	}

	if ((radclient->reply->code == PW_AUTHENTICATION_ACK) ||
	    (radclient->reply->code == PW_ACCOUNTING_RESPONSE) ||
	    (radclient->reply->code == PW_COA_ACK) ||
	    (radclient->reply->code == PW_DISCONNECT_ACK)) {
		success = 1;		/* have a good response */
		totalapp++;
	} else {
		totaldeny++;
	}
	
	if (radclient->resend == resend_count) {
		radclient->done = 1;
	}

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

	return 0;
}
コード例 #7
0
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;
}
コード例 #8
0
ファイル: radzap.c プロジェクト: kubuqi/802.1x-supplicant
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;
}
コード例 #9
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;
}
コード例 #10
0
ファイル: radsniff.c プロジェクト: stjaeger/freeradius-server
static void got_packet(uint8_t *args, const struct pcap_pkthdr *header, const uint8_t *data)
{
	/* Just a counter of how many packets we've had */
	static int count = 1;
	/* Define pointers for packet's attributes */
	const struct ethernet_header *ethernet;  /* The ethernet header */
	const struct ip_header *ip;              /* The IP header */
	const struct udp_header *udp;            /* The UDP header */
	const uint8_t *payload;                     /* Packet payload */
	/* And define the size of the structures we're using */
	int size_ethernet = sizeof(struct ethernet_header);
	int size_ip = sizeof(struct ip_header);
	int size_udp = sizeof(struct udp_header);
	/* For FreeRADIUS */
	RADIUS_PACKET *packet;

	args = args;		/* -Wunused */

	/* Define our packet's attributes */
	ethernet = (const struct ethernet_header*)(data);
	ip = (const struct ip_header*)(ethernet + size_ethernet);
	udp = (const struct udp_header*)(data + size_ethernet + size_ip);
	payload = (const uint8_t *)(data + size_ethernet + size_ip + size_udp);

	packet = malloc(sizeof(*packet));
	if (!packet) {
		fprintf(stderr, "Out of memory\n");
		return;
	}

	memset(packet, 0, sizeof(*packet));
	packet->src_ipaddr.af = AF_INET;
	packet->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;
	packet->src_port = ntohs(udp->udp_sport);
	packet->dst_ipaddr.af = AF_INET;
	packet->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
	packet->dst_port = ntohs(udp->udp_dport);

	packet->data = payload;
	packet->data_len = header->len - size_ethernet - size_ip - size_udp;

	if (!rad_packet_ok(packet, 0)) {
		fr_perror("Packet");
		free(packet);
		return;
	}

	/*
	 *	Decode the data without bothering to check the signatures.
	 */
	if (rad_decode(packet, NULL, radius_secret) != 0) {
		free(packet);
		fr_perror("decode");
		return;
	}
	if (filter_vps && filter_packet(packet)) {
		free(packet);
		DEBUG("Packet number %d doesn't match\n", count++);
		return;
	}

	/* Print the RADIUS packet */
	printf("Packet number %d has just been sniffed\n", count++);
	printf("\tFrom:    %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport));
	printf("\tTo:      %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport));
	printf("\tType:    %s\n", packet_codes[packet->code]);
	if (packet->vps != NULL) {
		vp_printlist(stdout, packet->vps);
		pairfree(&packet->vps);
	}
	fflush(stdout);
	free(packet);
}
コード例 #11
0
ファイル: radius-client.c プロジェクト: gnusec/baoleiji
/*
 *	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;
}
コード例 #12
0
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;
}
コード例 #13
0
static void rs_packet_process(uint64_t count, rs_event_t *event, struct pcap_pkthdr const *header, uint8_t const *data)
{
	rs_stats_t		*stats = event->stats;
	struct timeval		elapsed;
	struct timeval		latency;

	/*
	 *	Pointers into the packet data we just received
	 */
	size_t len;
	uint8_t const		*p = data;
	struct ip_header const	*ip = NULL;	/* The IP header */
	struct ip_header6 const	*ip6 = NULL;	/* The IPv6 header */
	struct udp_header const	*udp;		/* The UDP header */
	uint8_t			version;	/* IP header version */
	bool			response;	/* Was it a response code */

	decode_fail_t		reason;		/* Why we failed decoding the packet */
	static uint64_t		captured = 0;

	RADIUS_PACKET *current;			/* Current packet were processing */
	rs_request_t *original;

	if (!start_pcap.tv_sec) {
		start_pcap = header->ts;
	}

	if (header->caplen <= 5) {
		INFO("Packet too small, captured %i bytes", header->caplen);
		return;
	}

	/*
	 *	Loopback header
	 */
	if ((p[0] == 2) && (p[1] == 0) && (p[2] == 0) && (p[3] == 0)) {
		p += 4;
	/*
	 *	Ethernet header
	 */
	} else {
		p += sizeof(struct ethernet_header);
	}

	version = (p[0] & 0xf0) >> 4;
	switch (version) {
	case 4:
		ip = (struct ip_header const *)p;
		len = (0x0f & ip->ip_vhl) * 4;	/* ip_hl specifies length in 32bit words */
		p += len;
		break;

	case 6:
		ip6 = (struct ip_header6 const *)p;
		p += sizeof(struct ip_header6);

		break;

	default:
		DEBUG("IP version invalid %i", version);
		return;
	}

	/*
	 *	End of variable length bits, do basic check now to see if packet looks long enough
	 */
	len = (p - data) + sizeof(struct udp_header) + (sizeof(radius_packet_t) - 1);	/* length value */
	if (len > header->caplen) {
		DEBUG("Packet too small, we require at least %zu bytes, captured %i bytes",
		      (size_t) len, header->caplen);
		return;
	}

	udp = (struct udp_header const *)p;
	p += sizeof(struct udp_header);

	/*
	 *	With artificial talloc memory limits there's a good chance we can
	 *	recover once some requests timeout, so make an effort to deal
	 *	with allocation failures gracefully.
	 */
	current = rad_alloc(conf, 0);
	if (!current) {
		ERROR("Failed allocating memory to hold decoded packet");
		rs_tv_add_ms(&header->ts, conf->stats.timeout, &stats->quiet);
		return;
	}
	current->timestamp = header->ts;
	current->data_len = header->caplen - (p - data);
	memcpy(&current->data, &p, sizeof(current->data));

	/*
	 *	Populate IP/UDP fields from PCAP data
	 */
	if (ip) {
		current->src_ipaddr.af = AF_INET;
		current->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr;

		current->dst_ipaddr.af = AF_INET;
		current->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr;
	} else {
		current->src_ipaddr.af = AF_INET6;
		memcpy(&current->src_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_src.s6_addr,
		       sizeof(current->src_ipaddr.ipaddr.ip6addr.s6_addr));

		current->dst_ipaddr.af = AF_INET6;
		memcpy(&current->dst_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_dst.s6_addr,
		       sizeof(current->dst_ipaddr.ipaddr.ip6addr.s6_addr));
	}

	current->src_port = ntohs(udp->udp_sport);
	current->dst_port = ntohs(udp->udp_dport);

	if (!rad_packet_ok(current, 0, &reason)) {
		RIDEBUG("(%" PRIu64 ") ** %s **", count, fr_strerror());
		RIDEBUG("(%" PRIu64 ") %s Id %i %s:%s:%d -> %s:%d\t+%u.%03u", count,
			fr_packet_codes[current->code], current->id,
			event->in->name,
			fr_inet_ntop(current->src_ipaddr.af, &current->src_ipaddr.ipaddr), current->src_port,
			fr_inet_ntop(current->dst_ipaddr.af, &current->dst_ipaddr.ipaddr), current->dst_port,
			(unsigned int) elapsed.tv_sec, ((unsigned int) elapsed.tv_usec / 1000));

		rad_free(&current);
		return;
	}

	switch (current->code) {
	case PW_CODE_ACCOUNTING_RESPONSE:
	case PW_CODE_AUTHENTICATION_REJECT:
	case PW_CODE_AUTHENTICATION_ACK:
	case PW_CODE_COA_NAK:
	case PW_CODE_COA_ACK:
	case PW_CODE_DISCONNECT_NAK:
	case PW_CODE_DISCONNECT_ACK:
	case PW_CODE_STATUS_CLIENT:
		{
			rs_request_t search;
			struct timeval when;

			rs_tv_add_ms(&header->ts, conf->stats.timeout, &when);

			/* look for a matching request and use it for decoding */
			search.packet = current;
			original = rbtree_finddata(request_tree, &search);

			/*
			 *	Only decode attributes if we want to print them or filter on them
			 *	rad_packet_ok does checks to verify the packet is actually valid.
			 */
			if (filter_vps || conf->print_packet) {
				if (rad_decode(current, original ? original->packet : NULL,
					       conf->radius_secret) != 0) {
					rad_free(&current);
					fr_perror("decode");
					return;
				}
			}

			/*
			 *	Check if we've managed to link it to a request
			 */
			if (original) {
				/*
				 *	Is this a retransmit?
				 */
				if (!original->linked) {
					original->stats_rsp = &stats->exchange[current->code];
				} else {
					RDEBUG("(%" PRIu64 ") ** RETRANSMISSION **", count);
					original->rt_rsp++;

					rad_free(&original->linked);
					fr_event_delete(event->list, &original->event);
				}

				original->linked = talloc_steal(original, current);

				/*
				 *	Some RADIUS servers and proxy servers may not cache
				 *	Accounting-Responses (and possibly other code),
				 *	and may immediately re-use a RADIUS packet src
				 *	port/id combination on receipt of a response.
				 */
				if (conf->dequeue[current->code]) {
					fr_event_delete(event->list, &original->event);
					rbtree_deletebydata(request_tree, original);
				} else {
					if (!fr_event_insert(event->list, rs_packet_cleanup, original, &when,
						    	     &original->event)) {
						ERROR("Failed inserting new event");
						/*
						 *	Delete the original request/event, it's no longer valid
						 *	for statistics.
						 */
						original->forced_cleanup = true;
						fr_event_delete(event->list, &original->event);
						rbtree_deletebydata(request_tree, original);

						return;
					}
				}
			/*
			 *	No request seen, or request was dropped by attribute filter
			 */
			} else {
				/*
				 *	If filter_vps are set assume the original request was dropped,
				 *	the alternative is maintaining another 'filter', but that adds
				 *	complexity, reduces max capture rate, and is generally a PITA.
				 */
				if (filter_vps) {
					rad_free(&current);
					RDEBUG2("(%" PRIu64 ") Dropped by attribute filter", count);
					return;
				}

				RDEBUG("(%" PRIu64 ") ** UNLINKED **", count);
				stats->exchange[current->code].interval.unlinked_total++;
			}

			response = true;
		}
			break;
	case PW_CODE_ACCOUNTING_REQUEST:
	case PW_CODE_AUTHENTICATION_REQUEST:
	case PW_CODE_COA_REQUEST:
	case PW_CODE_DISCONNECT_REQUEST:
	case PW_CODE_STATUS_SERVER:
		{
			rs_request_t search;
			struct timeval when;

			/*
			 *	Only decode attributes if we want to print them or filter on them
			 *	rad_packet_ok does checks to verify the packet is actually valid.
			 */
			if (filter_vps || conf->print_packet) {
				if (rad_decode(current, NULL, conf->radius_secret) != 0) {
					rad_free(&current);
					fr_perror("decode");
					return;
				}
			}

			/*
			 *	Now verify the packet passes the attribute filter
			 */
			if (filter_vps && !pairvalidate_relaxed(filter_vps, current->vps)) {
				rad_free(&current);
				RDEBUG2("(%" PRIu64 ") Dropped by attribute filter", count);
				return;
			}

			/*
			 *	save the request for later matching
			 */
			search.packet = rad_alloc_reply(conf, current);
			if (!search.packet) {
				ERROR("Failed allocating memory to hold expected reply");
				rs_tv_add_ms(&header->ts, conf->stats.timeout, &stats->quiet);
				rad_free(&current);
				return;
			}
			search.packet->code = current->code;

			rs_tv_add_ms(&header->ts, conf->stats.timeout, &when);

			original = rbtree_finddata(request_tree, &search);

			/*
			 *	Upstream device re-used src/dst ip/port id without waiting
			 *	for the timeout period to expire, or a response.
			 */
			if (original && memcmp(original->packet->vector, current->vector,
					       sizeof(original->packet->vector) != 0)) {
				RDEBUG2("(%" PRIu64 ") ** PREMATURE ID RE-USE **", count);
				stats->exchange[current->code].interval.reused_total++;
				original->forced_cleanup = true;

				fr_event_delete(event->list, &original->event);
				rbtree_deletebydata(request_tree, original);
				original = NULL;
			}

			if (original) {
				RDEBUG("(%" PRIu64 ") ** RETRANSMISSION **", count);
				original->rt_req++;

				rad_free(&original->packet);
				original->packet = talloc_steal(original, search.packet);

				/* We may of seen the response, but it may of been lost upstream */
				rad_free(&original->linked);
				fr_event_delete(event->list, &original->event);
			} else {
				original = talloc_zero(conf, rs_request_t);
				talloc_set_destructor(original, _request_free);

				original->id = count;
				original->in = event->in;
				original->stats_req = &stats->exchange[current->code];
				original->packet = talloc_steal(original, search.packet);

				rbtree_insert(request_tree, original);
			}

			/* update the timestamp in either case */
			original->packet->timestamp = header->ts;

			if (!fr_event_insert(event->list, rs_packet_cleanup, original, &when, &original->event)) {
				ERROR("Failed inserting new event");
				rbtree_deletebydata(request_tree, original);

				return;
			}
			response = false;
		}
			break;
		default:
			RDEBUG("** Unsupported code %i **", current->code);
			rad_free(&current);

			return;
	}

	if (event->out) {
		pcap_dump((void *) (event->out->dumper), header, data);
	}

	rs_tv_sub(&header->ts, &start_pcap, &elapsed);

	/*
	 *	Increase received count
	 */
	stats->exchange[current->code].interval.received_total++;

	/*
	 *	It's a linked response
	 */
	if (original && original->linked) {
		rs_tv_sub(&current->timestamp, &original->packet->timestamp, &latency);

		/*
		 *	Update stats for both the request and response types.
		 *
		 *	This isn't useful for things like Access-Requests, but will be useful for
		 *	CoA and Disconnect Messages, as we get the average latency across both
		 *	response types.
		 *
		 *	It also justifies allocating 255 instances rs_latency_t.
		 */
		rs_stats_update_latency(&stats->exchange[current->code], &latency);
		rs_stats_update_latency(&stats->exchange[original->packet->code], &latency);


		/*
		 *	Print info about the request/response.
		 */
		RIDEBUG("(%" PRIu64 ") %s Id %i %s:%s:%d %s %s:%d\t+%u.%03u\t+%u.%03u", count,
			fr_packet_codes[current->code], current->id,
			event->in->name,
			fr_inet_ntop(current->src_ipaddr.af, &current->src_ipaddr.ipaddr), current->src_port,
			response ? "<-" : "->",
			fr_inet_ntop(current->dst_ipaddr.af, &current->dst_ipaddr.ipaddr), current->dst_port,
			(unsigned int) elapsed.tv_sec, ((unsigned int) elapsed.tv_usec / 1000),
			(unsigned int) latency.tv_sec, ((unsigned int) latency.tv_usec / 1000));
	/*
	 *	It's the original request
	 */
	} else {
		/*
		 *	Print info about the request
		 */
		RIDEBUG("(%" PRIu64 ") %s Id %i %s:%s:%d %s %s:%d\t+%u.%03u", count,
			fr_packet_codes[current->code], current->id,
			event->in->name,
			fr_inet_ntop(current->src_ipaddr.af, &current->src_ipaddr.ipaddr), current->src_port,
			response ? "<-" : "->",
			fr_inet_ntop(current->dst_ipaddr.af, &current->dst_ipaddr.ipaddr), current->dst_port,
			(unsigned int) elapsed.tv_sec, ((unsigned int) elapsed.tv_usec / 1000));
	}

	if (conf->print_packet && (fr_debug_flag > 1) && current->vps) {
		pairsort(&current->vps, true);
		vp_printlist(log_dst, current->vps);
		pairfree(&current->vps);
	}

	if (!conf->to_stdout && (fr_debug_flag > 4)) {
		rad_print_hex(current);
	}

	fflush(log_dst);

	/*
	 *	If it's a request, a duplicate of the packet will of already been stored.
	 *	If it's a unlinked response, we need to free it explicitly, as it will
	 *	not be done by the event queue.
	 */
	if (!response || !original) {
		rad_free(&current);
	}

	captured++;
	/*
	 *	We've hit our capture limit, break out of the event loop
	 */
	if ((conf->limit > 0) && (captured >= conf->limit)) {
		INFO("Captured %" PRIu64 " packets, exiting...", captured);
		fr_event_loop_exit(events, 1);
	}
}