Beispiel #1
0
/**
 * proto_conn_create(s, sas, decr, nopfs, requirepfs, nokeepalive, K, timeo,
 *     callback_dead, cookie):
 * Create a connection with one end at ${s} and the other end connecting to
 * the target addresses ${sas}.  If ${decr} is 0, encrypt the outgoing data;
 * if ${decr} is nonzero, decrypt the incoming data.  If ${nopfs} is non-zero,
 * don't use perfect forward secrecy.  If ${requirepfs} is non-zero, drop
 * the connection if the other end tries to disable perfect forward secrecy.
 * Enable transport layer keep-alives (if applicable) on both sockets if and
 * only if ${nokeepalive} is zero.  Drop the connection if the handshake or
 * connecting to the target takes more than ${timeo} seconds.  When the
 * connection is dropped, invoke ${callback_dead}(${cookie}).  Free ${sas}
 * once it is no longer needed.  Return a cookie which can be passed to
 * proto_conn_drop.
 */
void *
proto_conn_create(int s, struct sock_addr ** sas, int decr, int nopfs,
    int requirepfs, int nokeepalive, const struct proto_secret * K,
    double timeo, int (* callback_dead)(void *), void * cookie)
{
	struct conn_state * C;

	/* Bake a cookie for this connection. */
	if ((C = malloc(sizeof(struct conn_state))) == NULL)
		goto err0;
	C->callback_dead = callback_dead;
	C->cookie = cookie;
	C->sas = sas;
	C->decr = decr;
	C->nopfs = nopfs;
	C->requirepfs = requirepfs;
	C->nokeepalive = nokeepalive;
	C->K = K;
	C->timeo = timeo;
	C->s = s;
	C->t = -1;
	C->connect_cookie = NULL;
	C->connect_timeout_cookie = NULL;
	C->handshake_cookie = NULL;
	C->handshake_timeout_cookie = NULL;
	C->k_f = C->k_r = NULL;
	C->pipe_f = C->pipe_r = NULL;
	C->stat_f = C->stat_r = 1;

	/* Start the connect timer. */
	if ((C->connect_timeout_cookie = events_timer_register_double(
	    callback_connect_timeout, C, C->timeo)) == NULL)
		goto err1;

	/* Connect to target. */
	if ((C->connect_cookie =
	    network_connect(C->sas, callback_connect_done, C)) == NULL)
		goto err2;

	/* If we're decrypting, start the handshake. */
	if (C->decr) {
		if (starthandshake(C, C->s, C->decr))
			goto err3;
	}

	/* Success! */
	return (C);

err3:
	network_connect_cancel(C->connect_cookie);
err2:
	events_timer_cancel(C->connect_timeout_cookie);
err1:
	free(C);
err0:
	/* Failure! */
	return (NULL);
}
/* Update the state for one direction. */
static int
pokeone(struct bwlimit * l, double t, int op)
{
	double waketime;

	/* Add tokens to the bucket. */
	l->bucket += l->Bps * t;

	/* Overflow the bucket at 2 seconds of bandwidth. */
	if (l->bucket > 2 * l->Bps)
		l->bucket = 2 * l->Bps;

	/* Do we need to re-enable traffic? */
	if ((l->bucket >= 1460) && (l->suspended != 0)) {
		/* Allow traffic to pass. */
		if (network_register_resume(op))
			goto err0;
		l->suspended = 0;
	}

	/* Do we need to block traffic? */
	if ((l->bucket < 1460) && (l->suspended == 0)) {
		/* Stop traffic from running. */
		if (network_register_suspend(op))
			goto err0;
		l->suspended = 1;
	}

	/* If traffic is running, we don't need a timer. */
	if ((l->suspended == 0) && (l->timer_cookie != NULL)) {
		events_timer_cancel(l->timer_cookie);
		l->timer_cookie = NULL;
	}

	/* If traffic is suspended, we need a timer. */
	if ((l->suspended == 1) && (l->timer_cookie == NULL)) {
		/* Wait 10 ms or for 1460 bytes of quota. */
		waketime = (1460 - l->bucket) / l->Bps;
		if (waketime < 0.01)
			waketime = 0.01;

		/* Register a timer. */
		if ((l->timer_cookie =
		    events_timer_register_double(callback_timer,
		    l, waketime)) == NULL)
			goto err0;
	}

	/* Success! */
	return (0);

err0:
	/* Failure! */
	return (-1);
}
Beispiel #3
0
/* Start a handshake. */
static int
starthandshake(struct conn_state * C, int s, int decr)
{

	/* Start the handshake timer. */
	if ((C->handshake_timeout_cookie = events_timer_register_double(
	    callback_handshake_timeout, C, C->timeo)) == NULL)
		goto err0;

	/* Start the handshake. */
	if ((C->handshake_cookie = proto_handshake(s, decr, C->nofps,
	    C->K, callback_handshake_done, C)) == NULL)
		goto err1;

	/* Success! */
	return (0);

err1:
	events_timer_cancel(C->handshake_timeout_cookie);
	C->handshake_timeout_cookie = NULL;
err0:
	/* Failure! */
	return (-1);
}
Beispiel #4
0
/* Handle an incoming connection. */
static int
callback_gotconn(void * cookie, int s)
{
	struct accept_state * A = cookie;
	struct conn_state * C;

	/* This accept is no longer in progress. */
	A->accept_cookie = NULL;

	/* We have gained a connection. */
	A->nconn += 1;

	/* Bake a cookie for this connection. */
	if ((C = malloc(sizeof(struct conn_state))) == NULL)
		goto err1;
	C->A = A;
	C->s = s;
	C->t = -1;
	C->connect_cookie = NULL;
	C->handshake_cookie = NULL;
	C->connect_timeout_cookie = C->handshake_timeout_cookie = NULL;
	C->k_f = C->k_r = NULL;
	C->pipe_f = C->pipe_r = NULL;
	C->stat_f = C->stat_r = 1;

	/* Start the connect timer. */
	if ((C->connect_timeout_cookie = events_timer_register_double(
	    callback_connect_timeout, C, C->A->timeo)) == NULL)
		goto err2;

	/* Connect to target. */
	if ((C->connect_cookie =
	    network_connect(A->sas, callback_connect_done, C)) == NULL)
		goto err3;

	/* If we're decrypting, start the handshake. */
	if (C->A->decr) {
		if (starthandshake(C, C->s, C->A->decr))
			goto err4;
	}

	/* Accept another connection if we can. */
	if (doaccept(A))
		goto err0;

	/* Success! */
	return (0);

err4:
	network_connect_cancel(C->connect_cookie);
err3:
	events_timer_cancel(C->connect_timeout_cookie);
err2:
	free(C);
err1:
	A->nconn -= 1;
	close(s);
err0:
	/* Failure! */
	return (-1);
}