Ejemplo n.º 1
0
/**
 * Process authentication server (NuAuth) packet answer. Different answers
 * can be:
 *   - Decision answer: packet accepted/rejected
 *   - Connection destroy: ask conntrack to destroy a connection
 *   - Connection update: ask conntrack to set connection timeout to given
 *     value
 *
 *  \return -1 in case of error
 */
static int auth_packet_to_decision(char *dgram, int dgram_size)
{
	if (dgram_size < 2) {
		debug_log_printf(DEBUG_AREA_GW, DEBUG_LEVEL_DEBUG,
				 "NuAuth sent too small message");
		return -1;
	}

	if (dgram[0] != PROTO_NUFW_VERSION) {
		debug_log_printf(DEBUG_AREA_GW, DEBUG_LEVEL_DEBUG,
				 "Wrong protocol version from authentication server answer.");
		return -1;
	}

	switch (dgram[1]) {
	case AUTH_ANSWER:
		return auth_process_answer(dgram, dgram_size);
	case AUTH_CONN_DESTROY:
		log_area_printf(DEBUG_AREA_MAIN | DEBUG_AREA_GW,
				DEBUG_LEVEL_WARNING,
				"Connection destroy message not supported");
		break;
	case AUTH_CONN_UPDATE:
		log_area_printf(DEBUG_AREA_MAIN | DEBUG_AREA_GW,
				DEBUG_LEVEL_WARNING,
				"Connection update message not supported");
		break;
	default:
		log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_DEBUG,
				"NuAuth message type %d not for me",
				dgram[1]);
		break;
	}
	return -1;
}
Ejemplo n.º 2
0
/**
 * \brief Callback called by NetFilter when a packet with target QUEUE is matched.
 *
 * For TCP packet with flags different than SYN, just send it to NuAuth and
 * accept it.
 *
 * For other packet: First of all, fill a structure ::packet_idl (identifier,
 * timestamp, ...). Try to add the new packet to ::packets_list (fails if the
 * list is full). Ask an authentication to NuAuth using auth_request_send(),
 * If the packet can't be sended, remove it from the list.
 *
 * \return If an error occurs, returns 0, else returns 1.
 */
static int treat_packet(struct nfq_handle *qh, struct nfgenmsg *nfmsg,
			struct nfq_data *nfa, void *data)
{
	packet_idl *current;
	struct queued_pckt q_pckt;
	struct nfqnl_msg_packet_hdr *ph;
	struct timeval timestamp;
	int ret;
#ifdef HAVE_NFQ_INDEV_NAME
	struct nlif_handle *nlif_handle = (struct nlif_handle *) data;
#endif

	debug_log_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG,
			 "(*) New packet");

	q_pckt.payload_len = nfq_get_payload(nfa, &(q_pckt.payload));
	if (q_pckt.payload_len == -1) {
		log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_INFO,
				"Unable to get payload");
		return 0;
	}

	q_pckt.mark = nfq_get_nfmark(nfa);

#ifdef HAVE_NFQ_INDEV_NAME
	if (!get_interface_information(nlif_handle, &q_pckt, nfa)) {
		log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_INFO,
				"Can not get interfaces information for message");
		return 0;
	}
#else
	snprintf(q_pckt.indev, sizeof(q_pckt.indev), "*");
	snprintf(q_pckt.physindev, sizeof(q_pckt.physindev), "*");
	snprintf(q_pckt.outdev, sizeof(q_pckt.outdev), "*");
	snprintf(q_pckt.physoutdev, sizeof(q_pckt.physoutdev), "*");
#endif

	ret = nfq_get_timestamp(nfa, &timestamp);
	if (ret == 0) {
		q_pckt.timestamp = timestamp.tv_sec;
	} else {
		q_pckt.timestamp = time(NULL);
	}

	if (look_for_tcp_flags
	    ((unsigned char *) q_pckt.payload, q_pckt.payload_len)) {
		ph = nfq_get_msg_packet_hdr(nfa);
		if (ph) {
			q_pckt.packet_id = ntohl(ph->packet_id);
			auth_request_send(AUTH_CONTROL, &q_pckt);
			IPQ_SET_VERDICT(q_pckt.packet_id, NF_ACCEPT);
			RETURN_NO_LOG 1;
		} else {
			log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG,
					"Can not get the packet headers");
			return 0;
		}
	}
	current = calloc(1, sizeof(packet_idl));
	current->nfmark = q_pckt.mark;
	current->timestamp = q_pckt.timestamp ;
	current->id = 0;
	if (current == NULL) {
		log_area_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_MESSAGE,
				"Can not allocate packet_id");
		return 0;
	}
#ifdef PERF_DISPLAY_ENABLE
	gettimeofday(&(current->arrival_time), NULL);
#endif
	/* Get unique identifier of packet in queue */
	ph = nfq_get_msg_packet_hdr(nfa);
	if (ph) {
		current->id = ntohl(ph->packet_id);
	} else {
		free(current);
		log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_INFO,
				"Can not get id for message");
		return 0;
	}

	/* Try to add the packet to the list */
	ret = padd(current);
	q_pckt.packet_id = current->id;

	if (ret == 0) {
		/* send an auth request packet */
		if (!auth_request_send(AUTH_REQUEST, &q_pckt)) {
			int sandf = 0;
			/* send failure dropping packet */
			IPQ_SET_VERDICT(q_pckt.packet_id, NF_DROP);
			/* we fail to send the packet so we free packet related to current */
			/* search and destroy packet by packet_id */
			sandf = psearch_and_destroy(q_pckt.packet_id,
						&(q_pckt.mark));

			if (!sandf) {
				log_area_printf(DEBUG_AREA_MAIN,
						DEBUG_LEVEL_WARNING,
						"Packet could not be removed: %u",
						q_pckt.packet_id);
			}
		}
	}
	return 1;
}
Ejemplo n.º 3
0
/**
 * Send an authentication request to NuAuth. May restart TLS session
 * and/or open TLS connection (if closed).
 *
 * Create the thread authsrv() when opening a new session.
 *
 * Packet maximum size is 512 bytes,
 * and it's structure is ::nufw_to_nuauth_auth_message_t.
 *
 * \param type Type of request (::AUTH_REQUEST, ::AUTH_CONTROL, ...)
 * \param pckt_data A pointer to a queued_pckt:: holding packet information
 * \return If an error occurs returns 0, else return 1.
 */
int auth_request_send(uint8_t type, struct queued_pckt *pckt_data)
{
	unsigned char data[512];
	nuv4_nufw_to_nuauth_auth_message_t *msg_header =
	    (nuv4_nufw_to_nuauth_auth_message_t *) & data;
	unsigned char *msg_content =
	    data + sizeof(nuv4_nufw_to_nuauth_auth_message_t);
	int msg_length;

	/* Drop non-IPv(4|6) packet */
	if ((((struct iphdr *) (pckt_data->payload))->version != 4)
	    && (((struct iphdr *) (pckt_data->payload))->version != 6)) {
		log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_DEBUG,
				 "Dropping non-IPv4/non-IPv6 packet (version %u)",
				 ((struct iphdr *) (pckt_data->payload))->
				 version);
		return 0;
	}

	/* Truncate packet content if needed */
	if (sizeof(data) <
	    sizeof(nuv4_nufw_to_nuauth_auth_message_t) + pckt_data->payload_len) {
		debug_log_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_DEBUG,
				 "Very long packet: truncating!");
		pckt_data->payload_len =
		    sizeof(data) -
		    sizeof(nuv4_nufw_to_nuauth_auth_message_t);
	}
	msg_length = sizeof(nuv4_nufw_to_nuauth_auth_message_t) + pckt_data->payload_len;

	/* Fill message header */
	msg_header->protocol_version = PROTO_NUFW_VERSION;
	msg_header->msg_type = type;
	msg_header->msg_length = htons(msg_length);
	msg_header->packet_id = htonl(pckt_data->packet_id);
	msg_header->timestamp = htonl(pckt_data->timestamp);

	/* Add info about interfaces */
	msg_header->mark = pckt_data->mark;
	memcpy(msg_header->indev, pckt_data->indev,
	       IFNAMSIZ * sizeof(char));
	memcpy(msg_header->outdev, pckt_data->outdev,
	       IFNAMSIZ * sizeof(char));
	memcpy(msg_header->physindev, pckt_data->physindev,
	       IFNAMSIZ * sizeof(char));
	memcpy(msg_header->physoutdev, pckt_data->physoutdev,
	       IFNAMSIZ * sizeof(char));

	/* Copy (maybe truncated) packet content */
	memcpy(msg_content, pckt_data->payload, pckt_data->payload_len);

	/* Display message */
	log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_DEBUG,
			"Sending request for %lu", (long)pckt_data->packet_id);

	/* negotiate TLS connection if needed */
	if (!tls.session) {
		log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_INFO,
				"Not connected, trying TLS connection");
		tls_connect();

		if (tls.session) {
			int fd;
			char buf[256];
			buf[0] = '\0';
			nussl_session_get_cipher(tls.session, buf, sizeof(buf));
			log_area_printf(DEBUG_AREA_GW,
					DEBUG_LEVEL_WARNING,
					"[+] TLS connection to nuauth restored (%s:%d), cipher is %s",
					authreq_addr, authreq_port,
					(buf[0] != '\0') ? buf : "none" );

			fd = nussl_session_get_fd(tls.session);
			if (fd >= 0) {
				ev_io_init(&tls.ev_io, tls_activity_cb,
						nussl_session_get_fd(tls.session), EV_READ);
				tls.ev_io.data = &nufw_nfq_watcher;
				ev_io_start(nufw_loop, &tls.ev_io);
			}
		} else {
			log_area_printf(DEBUG_AREA_GW,
					DEBUG_LEVEL_WARNING,
					"[!] TLS connection to nuauth can NOT be restored (%s:%d)",
					authreq_addr, authreq_port);
			return 0;
		}
	}

	if (nussl_write(tls.session, (char*)data, msg_length) < 0) {
		debug_log_printf(DEBUG_AREA_MAIN, DEBUG_LEVEL_DEBUG,
				 "Error during nussl_write (auth_request_send).");
		shutdown_tls();
		log_area_printf(DEBUG_AREA_GW,
				DEBUG_LEVEL_WARNING,
				"[!] TLS send failure");
		return 0;
	}
	return 1;
}
Ejemplo n.º 4
0
/**
 * Process NuAuth message of type #AUTH_ANSWER
 */
int auth_process_answer(char *dgram, int dgram_size)
{
	nuv5_nuauth_decision_response_t *answer;
	uint32_t nfmark;
	int sandf;
	u_int32_t packet_id;
	int payload_len;
	int msg_len;

	/* check packet size */
	if (dgram_size < (int) sizeof(nuv4_nuauth_decision_response_t)) {
		return -1;
	}
	answer = (nuv5_nuauth_decision_response_t *) dgram;

	/* check payload length */
	payload_len = ntohs(answer->payload_len);
	msg_len = payload_len + sizeof(nuv5_nuauth_decision_response_t);
	if (dgram_size < msg_len) {
		log_area_printf(DEBUG_AREA_GW, DEBUG_LEVEL_WARNING,
				"[!] Packet with improper size: payload of %d, received %d (vs %d)",
				payload_len,
				dgram_size,
				(int) (sizeof(nuv5_nuauth_decision_response_t) + payload_len));
		return -1;
	}

	/* get packet id and user id */
	packet_id = ntohl(answer->packet_id);

	/* search and destroy packet by packet_id */
	sandf = psearch_and_destroy(packet_id, &nfmark);
	if (!sandf) {
		log_area_printf(DEBUG_AREA_GW | DEBUG_AREA_GW,
				DEBUG_LEVEL_WARNING,
				"[!] Packet without a known ID: %u",
				packet_id);
		return -1;
	}

	switch (answer->decision) {
	case DECISION_ACCEPT:
		/* accept packet */
		debug_log_printf(DEBUG_AREA_PACKET,
				 DEBUG_LEVEL_VERBOSE_DEBUG,
				 "(*) Accepting packet with id=%u",
				 packet_id);
		if (nufw_set_mark) {
			debug_log_printf(DEBUG_AREA_PACKET,
					 DEBUG_LEVEL_VERBOSE_DEBUG,
					 "(*) Marking packet with %d",
					 ntohl(answer->tcmark));
#if HAVE_NFQ_MARK_EXPTIME
			if (ntohl(answer->expiration) != -1) {
				IPQ_SET_VWMARK_EXPTIME(packet_id, NF_ACCEPT,
					       answer->tcmark,
					       ntohl(answer->expiration));
			} else {
				IPQ_SET_VWMARK(packet_id, NF_ACCEPT,
					       answer->tcmark);
			}
#else
			IPQ_SET_VWMARK(packet_id, NF_ACCEPT,
				       answer->tcmark);
#endif
		} else {
			IPQ_SET_VERDICT(packet_id, NF_ACCEPT);
		}
		pckt_tx++;
		break;

	case DECISION_REJECT:
		/* Packet is rejected, ie. dropped and ICMP signalized */
		log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_VERBOSE_DEBUG,
				"(*) Rejecting %" PRIu32, packet_id);
		IPQ_SET_VERDICT(packet_id, NF_DROP);
		if (send_icmp_unreach(dgram +
				  sizeof(nuv5_nuauth_decision_response_t),
				  payload_len) == -1) {
			log_area_printf(DEBUG_AREA_PACKET, DEBUG_LEVEL_WARNING,
					"(*) Could not sent ICMP reject for %" PRIu32, packet_id);
		}
		break;

	default:
		/* drop packet */
		debug_log_printf(DEBUG_AREA_PACKET,
				 DEBUG_LEVEL_VERBOSE_DEBUG,
				 "(*) Drop packet %u", packet_id);
		IPQ_SET_VERDICT(packet_id, NF_DROP);
	}
	return msg_len;
}