Esempio n. 1
0
int csp_route_work(uint32_t timeout) {

	csp_qfifo_t input;
	csp_packet_t * packet;
	csp_conn_t * conn;
	csp_socket_t * socket;

#ifdef CSP_USE_RDP
	/* Check connection timeouts (currently only for RDP) */
	csp_conn_check_timeouts();
#endif

	/* Get next packet to route */
	if (csp_qfifo_read(&input) != CSP_ERR_NONE)
		return -1;

	packet = input.packet;

	csp_log_packet("INP: S %u, D %u, Dp %u, Sp %u, Pr %u, Fl 0x%02X, Sz %"PRIu16" VIA: %s",
			packet->id.src, packet->id.dst, packet->id.dport,
			packet->id.sport, packet->id.pri, packet->id.flags, packet->length, input.interface->name);

	/* Here there be promiscuous mode */
#ifdef CSP_USE_PROMISC
	csp_promisc_add(packet);
#endif

#ifdef CSP_USE_DEDUP
	/* Check for duplicates */
	if (csp_dedup_is_duplicate(packet)) {
		/* Discard packet */
		csp_log_packet("Duplicate packet discarded");
		csp_buffer_free(packet);
		return 0;
	}
#endif

	/* If the message is not to me, route the message to the correct interface */
	if ((packet->id.dst != csp_get_address()) && (packet->id.dst != CSP_BROADCAST_ADDR)) {

		/* Find the destination interface */
		csp_iface_t * dstif = csp_rtable_find_iface(packet->id.dst);

		/* If the message resolves to the input interface, don't loop it back out */
		if ((dstif == NULL) || ((dstif == input.interface) && (input.interface->split_horizon_off == 0))) {
			csp_buffer_free(packet);
			return 0;
		}

		/* Otherwise, actually send the message */
		if (csp_send_direct(packet->id, packet, dstif, 0) != CSP_ERR_NONE) {
			csp_log_warn("Router failed to send");
			csp_buffer_free(packet);
		}

		/* Next message, please */
		return 0;
	}

	/* Discard packets with unsupported options */
	if (csp_route_check_options(input.interface, packet) != CSP_ERR_NONE) {
		csp_buffer_free(packet);
		return 0;
	}

	/* The message is to me, search for incoming socket */
	socket = csp_port_get_socket(packet->id.dport);

	/* If the socket is connection-less, deliver now */
	if (socket && (socket->opts & CSP_SO_CONN_LESS)) {
		if (csp_route_security_check(socket->opts, input.interface, packet) < 0) {
			csp_buffer_free(packet);
			return 0;
		}
		if (csp_queue_enqueue(socket->socket, &packet, 0) != CSP_QUEUE_OK) {
			csp_log_error("Conn-less socket queue full");
			csp_buffer_free(packet);
			return 0;
		}
		return 0;
	}

	/* Search for an existing connection */
	conn = csp_conn_find(packet->id.ext, CSP_ID_CONN_MASK);

	/* If this is an incoming packet on a new connection */
	if (conn == NULL) {

		/* Reject packet if no matching socket is found */
		if (!socket) {
			csp_buffer_free(packet);
			return 0;
		}

		/* Run security check on incoming packet */
		if (csp_route_security_check(socket->opts, input.interface, packet) < 0) {
			csp_buffer_free(packet);
			return 0;
		}

		/* New incoming connection accepted */
		csp_id_t idout;
		idout.pri   = packet->id.pri;
		idout.src   = csp_get_address();

		idout.dst   = packet->id.src;
		idout.dport = packet->id.sport;
		idout.sport = packet->id.dport;
		idout.flags = packet->id.flags;

		/* Create connection */
		conn = csp_conn_new(packet->id, idout);

		if (!conn) {
			csp_log_error("No more connections available");
			csp_buffer_free(packet);
			return 0;
		}

		/* Store the socket queue and options */
		conn->socket = socket->socket;
		conn->opts = socket->opts;

	/* Packet to existing connection */
	} else {

		/* Run security check on incoming packet */
		if (csp_route_security_check(conn->opts, input.interface, packet) < 0) {
			csp_buffer_free(packet);
			return 0;
		}

	}

#ifdef CSP_USE_RDP
	/* Pass packet to RDP module */
	if (packet->id.flags & CSP_FRDP) {
		csp_rdp_new_packet(conn, packet);
		return 0;
	}
#endif

	/* Pass packet to UDP module */
	csp_udp_new_packet(conn, packet);
	return 0;
}
Esempio n. 2
0
csp_conn_t * csp_connect(uint8_t prio, uint8_t dest, uint8_t dport, uint32_t timeout, uint32_t opts) {

    /* Generate identifier */
    csp_id_t incoming_id, outgoing_id;
    incoming_id.pri = prio;
    incoming_id.dst = my_address;
    incoming_id.src = dest;
    incoming_id.sport = dport;
    incoming_id.flags = 0;
    outgoing_id.pri = prio;
    outgoing_id.dst = dest;
    outgoing_id.src = my_address;
    outgoing_id.dport = dport;
    outgoing_id.flags = 0;

    /* Set connection options */
    if (opts & CSP_O_RDP) {
#ifdef CSP_USE_RDP
        incoming_id.flags |= CSP_FRDP;
        outgoing_id.flags |= CSP_FRDP;
#else
        csp_log_error("Attempt to create RDP connection, but CSP was compiled without RDP support\r\n");
        return NULL;
#endif
    }

    if (opts & CSP_O_HMAC) {
#ifdef CSP_USE_HMAC
        outgoing_id.flags |= CSP_FHMAC;
        incoming_id.flags |= CSP_FHMAC;
#else
        csp_log_error("Attempt to create HMAC authenticated connection, but CSP was compiled without HMAC support\r\n");
        return NULL;
#endif
    }

    if (opts & CSP_O_XTEA) {
#ifdef CSP_USE_XTEA
        outgoing_id.flags |= CSP_FXTEA;
        incoming_id.flags |= CSP_FXTEA;
#else
        csp_log_error("Attempt to create XTEA encrypted connection, but CSP was compiled without XTEA support\r\n");
        return NULL;
#endif
    }

    if (opts & CSP_O_CRC32) {
#ifdef CSP_USE_CRC32
        outgoing_id.flags |= CSP_FCRC32;
        incoming_id.flags |= CSP_FCRC32;
#else
        csp_log_error("Attempt to create CRC32 validated connection, but CSP was compiled without CRC32 support\r\n");
        return NULL;
#endif
    }

    /* Find an unused ephemeral port */
    csp_conn_t * conn;

    /* Wait for sport lock */
    if (csp_bin_sem_wait(&sport_lock, 1000) != CSP_SEMAPHORE_OK)
        return NULL;

    uint8_t start = sport;
    while (++sport != start) {
        if (sport > CSP_ID_PORT_MAX)
            sport = CSP_MAX_BIND_PORT + 1;

        outgoing_id.sport = sport;
        incoming_id.dport = sport;

        /* Match on destination port of _incoming_ identifier */
        conn = csp_conn_find(incoming_id.ext, CSP_ID_DPORT_MASK);

        /* Break if we found an unused ephemeral port */
        if (conn == NULL)
            break;
    }

    /* Post sport lock */
    csp_bin_sem_post(&sport_lock);

    /* If no available ephemeral port was found */
    if (sport == start)
        return NULL;

    /* Get storage for new connection */
    conn = csp_conn_new(incoming_id, outgoing_id);
    if (conn == NULL)
        return NULL;

    /* Set connection options */
    conn->opts = opts;

#ifdef CSP_USE_RDP
    /* Call Transport Layer connect */
    if (outgoing_id.flags & CSP_FRDP) {
        /* If the transport layer has failed to connect
         * deallocate connection structure again and return NULL */
        if (csp_rdp_connect(conn, timeout) != CSP_ERR_NONE) {
            csp_close(conn);
            return NULL;
        }
    }
#endif

    /* We have a successful connection */
    return conn;

}