Esempio n. 1
0
int
kore_connection_accept(struct listener *l, struct connection **out)
{
	socklen_t		len;
	struct connection	*c;

	kore_debug("kore_connection_accept(%p)", l);

	*out = NULL;
	len = sizeof(struct sockaddr_in);

	c = kore_pool_get(&connection_pool);
	if ((c->fd = accept(l->fd, (struct sockaddr *)&(c->sin), &len)) == -1) {
		kore_pool_put(&connection_pool, c);
		kore_debug("accept(): %s", errno_s);
		return (KORE_RESULT_ERROR);
	}

	if (!kore_connection_nonblock(c->fd)) {
		close(c->fd);
		kore_pool_put(&connection_pool, c);
		return (KORE_RESULT_ERROR);
	}

	c->owner = l;
	c->ssl = NULL;
	c->flags = 0;
	c->inflate_started = 0;
	c->deflate_started = 0;
	c->client_stream_id = 0;
	c->proto = CONN_PROTO_UNKNOWN;
	c->state = CONN_STATE_SSL_SHAKE;
	c->wsize_initial = SPDY_INIT_WSIZE;
	c->idle_timer.start = 0;
	c->idle_timer.length = KORE_IDLE_TIMER_MAX;

	TAILQ_INIT(&(c->send_queue));
	TAILQ_INIT(&(c->recv_queue));
	TAILQ_INIT(&(c->spdy_streams));

	kore_worker_connection_add(c);
	kore_connection_start_idletimer(c);

	*out = c;
	return (KORE_RESULT_OK);
}
Esempio n. 2
0
/*
 * Called for every new connection on a certain ip/port. Which one is
 * configured in the TLS proxy its configuration file.
 */
void
client_setup(struct connection *c)
{
	int			i, fd;
	struct connection	*backend;

	/* Paranoia. */
	if (c->ssl->session == NULL ||
	    c->ssl->session->tlsext_hostname == NULL) {
		kore_connection_disconnect(c);
		return;
	}

	/* Figure out what backend to use. */
	for (i = 0; backends[i].name != NULL; i++) {
		if (!strcasecmp(backends[i].name,
		    c->ssl->session->tlsext_hostname))
			break;
	}

	/* If we don't have any backends, we just disconnect the client. */
	if (backends[i].name == NULL) {
		kore_connection_disconnect(c);
		return;
	}

	/* Create new socket for the backend connection. */
	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		kore_log(LOG_ERR, "socket(): %s", errno_s);
		kore_connection_disconnect(c);
		return;
	}

	/* Set it to non blocking as well. */
	if (!kore_connection_nonblock(fd, 1)) {
		close(fd);
		kore_connection_disconnect(c);
		return;
	}

	/* Grab a new connection from Kore to hook backend into. */
	backend = kore_connection_new(NULL);

	/* Prepare our connection. */
	backend->addrtype = AF_INET;
	backend->addr.ipv4.sin_family = AF_INET;
	backend->addr.ipv4.sin_port = htons(backends[i].port);
	backend->addr.ipv4.sin_addr.s_addr = inet_addr(backends[i].ip);

	/* Set the file descriptor for the backend. */
	backend->fd = fd;

	/* Default write/read callbacks for backend. */
	backend->read = net_read;
	backend->write = net_write;

	/* Connection type (unknown to Kore). */
	backend->proto = CONN_PROTO_UNKNOWN;
	backend->state = CONN_STATE_ESTABLISHED;

	/* The backend idle timer is set first to connection timeout. */
	backend->idle_timer.length = PROXY_CONNECT_TIMEOUT;

	/* The client idle timer is set to default idle time. */
	c->idle_timer.length = PROXY_TIMEOUT;

	/* Now link both the client and the backend connection together. */
	c->hdlr_extra = backend;
	backend->hdlr_extra = c;

	/*
	 * The handle function pointer for the backend is set to the
	 * backend_handle_connect() while connecting.
	 */
	c->handle = client_handle;
	backend->handle = backend_handle_connect;

	/* Set the disconnect method for both connections. */
	c->disconnect = disconnect;
	backend->disconnect = disconnect;

	/* Queue write events for the backend connection for now. */
	kore_platform_schedule_write(backend->fd, backend);

	/* Start idle timer for the backend. */
	kore_connection_start_idletimer(backend);

	/* Set our client connection to established. */
	c->state = CONN_STATE_ESTABLISHED;

	/* Insert the backend into the list of Kore connections. */
	TAILQ_INSERT_TAIL(&connections, backend, list);

	/* Kick off connecting. */
	backend->flags |= CONN_WRITE_POSSIBLE;
	backend->handle(backend);
}
Esempio n. 3
0
File: ktunnel.c Progetto: 2ion/kore
/*
 * Connect to our target host:port and attach it to a struct connection that
 * Kore understands. We set the disconnect method so we get a callback
 * whenever either of the connections will go away so we can cleanup the
 * one it is attached to.
 */
static int
ktunnel_pipe_create(struct connection *c, const char *host, const char *port)
{
	struct sockaddr_in	sin;
	struct connection	*cpipe;
	u_int16_t		nport;
	int			fd, err;

	nport = kore_strtonum(port, 10, 1, SHRT_MAX, &err);
	if (err == KORE_RESULT_ERROR) {
		kore_log(LOG_ERR, "invalid port given %s", port);
		return (KORE_RESULT_ERROR);
	}

	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		kore_log(LOG_ERR, "socket(): %s", errno_s);
		return (KORE_RESULT_ERROR);
	}

	memset(&sin, 0, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_port = htons(nport);
	sin.sin_addr.s_addr = inet_addr(host);

	kore_log(LOG_NOTICE, "Attempting to connect to %s:%s", host, port);

	if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
		close(fd);
		kore_log(LOG_ERR, "connect(): %s", errno_s);
		return (KORE_RESULT_ERROR);
	}

	if (!kore_connection_nonblock(fd)) {
		close(fd);
		return (KORE_RESULT_ERROR);
	}

	cpipe = kore_connection_new(c);
	cpipe->fd = fd;
	cpipe->addr.ipv4 = sin;
	cpipe->read = net_read;
	cpipe->write = net_write;
	cpipe->addrtype = AF_INET;
	cpipe->proto = CONN_PROTO_UNKNOWN;
	cpipe->state = CONN_STATE_ESTABLISHED;

	/* Don't let these connections timeout any time soon. */
	cpipe->idle_timer.length = 10000000000;
	c->idle_timer.length = 10000000000;

	c->hdlr_extra = cpipe;
	cpipe->hdlr_extra = c;
	c->disconnect = ktunnel_pipe_disconnect;
	cpipe->disconnect = ktunnel_pipe_disconnect;

	kore_worker_connection_add(cpipe);
	kore_connection_start_idletimer(cpipe);
	kore_platform_event_all(cpipe->fd, cpipe);

	net_recv_reset(c, NETBUF_SEND_PAYLOAD_MAX, ktunnel_pipe_data);
	net_recv_queue(cpipe, NETBUF_SEND_PAYLOAD_MAX, NETBUF_CALL_CB_ALWAYS,
	    ktunnel_pipe_data);

	printf("connection started to %s (%p -> %p)\n", host, c, cpipe);
	return (KORE_RESULT_OK);
}
Esempio n. 4
0
File: kore.c Progetto: SDAIA/kore
int
main(int argc, char *argv[])
{
	int		ch, flags;

	flags = 0;

#if !defined(KORE_SINGLE_BINARY)
	while ((ch = getopt(argc, argv, "c:dfhnrv")) != -1) {
#else
	while ((ch = getopt(argc, argv, "dfhnrv")) != -1) {
#endif
		flags++;
		switch (ch) {
#if !defined(KORE_SINGLE_BINARY)
		case 'c':
			config_file = optarg;
			break;
#endif
#if defined(KORE_DEBUG)
		case 'd':
			kore_debug = 1;
			break;
#endif
		case 'f':
			foreground = 1;
			break;
		case 'h':
			usage();
			break;
		case 'n':
			skip_chroot = 1;
			break;
		case 'r':
			skip_runas = 1;
			break;
		case 'v':
			version();
			break;
		default:
			usage();
		}
	}

	argc -= optind;
	argv += optind;

	kore_mem_init();

#if !defined(KORE_SINGLE_BINARY)
	if (argc > 0) {
		if (flags)
			fatal("You cannot specify kore flags and a command");
		return (kore_cli_main(argc, argv));
	}
#endif

	kore_pid = getpid();
	nlisteners = 0;
	LIST_INIT(&listeners);

	kore_log_init();
#if !defined(KORE_NO_HTTP)
	kore_auth_init();
	kore_validator_init();
#endif
	kore_domain_init();
	kore_module_init();
	kore_server_sslstart();

#if !defined(KORE_SINGLE_BINARY)
	if (config_file == NULL)
		usage();
#else
	kore_module_load(NULL, NULL);
#endif

	kore_parse_config();
	kore_platform_init();

#if !defined(KORE_NO_HTTP)
	kore_accesslog_init();
	if (http_body_disk_offload > 0) {
		if (mkdir(http_body_disk_path, 0700) == -1 && errno != EEXIST) {
			printf("can't create http_body_disk_path '%s': %s\n",
			    http_body_disk_path, errno_s);
			return (KORE_RESULT_ERROR);
		}
	}
#endif

	sig_recv = 0;
	signal(SIGHUP, kore_signal);
	signal(SIGQUIT, kore_signal);
	signal(SIGTERM, kore_signal);

	if (foreground)
		signal(SIGINT, kore_signal);
	else
		signal(SIGINT, SIG_IGN);

	kore_server_start();

	kore_log(LOG_NOTICE, "server shutting down");
	kore_worker_shutdown();

	if (!foreground)
		unlink(kore_pidfile);

	kore_listener_cleanup();
	kore_log(LOG_NOTICE, "goodbye");

	return (0);
}

#if !defined(KORE_NO_TLS)
int
kore_tls_sni_cb(SSL *ssl, int *ad, void *arg)
{
	struct kore_domain	*dom;
	const char		*sname;

	sname = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
	kore_debug("kore_tls_sni_cb(): received host %s", sname);

	if (sname != NULL && (dom = kore_domain_lookup(sname)) != NULL) {
		kore_debug("kore_ssl_sni_cb(): Using %s CTX", sname);
		SSL_set_SSL_CTX(ssl, dom->ssl_ctx);

		if (dom->cafile != NULL) {
			SSL_set_verify(ssl, SSL_VERIFY_PEER |
			    SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
		} else {
			SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
		}

		return (SSL_TLSEXT_ERR_OK);
	}

	return (SSL_TLSEXT_ERR_NOACK);
}

void
kore_tls_info_callback(const SSL *ssl, int flags, int ret)
{
	struct connection	*c;

	if (flags & SSL_CB_HANDSHAKE_START) {
		if ((c = SSL_get_app_data(ssl)) == NULL)
			fatal("no SSL_get_app_data");
		c->tls_reneg++;
	}
}
#endif

int
kore_server_bind(const char *ip, const char *port, const char *ccb)
{
	struct listener		*l;
	int			on, r;
	struct addrinfo		hints, *results;

	kore_debug("kore_server_bind(%s, %s)", ip, port);

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;
	hints.ai_flags = 0;

	r = getaddrinfo(ip, port, &hints, &results);
	if (r != 0)
		fatal("getaddrinfo(%s): %s", ip, gai_strerror(r));

	l = kore_malloc(sizeof(struct listener));
	l->type = KORE_TYPE_LISTENER;
	l->addrtype = results->ai_family;

	if (l->addrtype != AF_INET && l->addrtype != AF_INET6)
		fatal("getaddrinfo(): unknown address family %d", l->addrtype);

	if ((l->fd = socket(results->ai_family, SOCK_STREAM, 0)) == -1) {
		kore_free(l);
		freeaddrinfo(results);
		kore_debug("socket(): %s", errno_s);
		printf("failed to create socket: %s\n", errno_s);
		return (KORE_RESULT_ERROR);
	}

	if (!kore_connection_nonblock(l->fd, 1)) {
		kore_free(l);
		freeaddrinfo(results);
		printf("failed to make socket non blocking: %s\n", errno_s);
		return (KORE_RESULT_ERROR);
	}

	on = 1;
	if (setsockopt(l->fd, SOL_SOCKET,
	    SO_REUSEADDR, (const char *)&on, sizeof(on)) == -1) {
		close(l->fd);
		kore_free(l);
		freeaddrinfo(results);
		kore_debug("setsockopt(): %s", errno_s);
		printf("failed to set SO_REUSEADDR: %s\n", errno_s);
		return (KORE_RESULT_ERROR);
	}

	if (bind(l->fd, results->ai_addr, results->ai_addrlen) == -1) {
		close(l->fd);
		kore_free(l);
		freeaddrinfo(results);
		kore_debug("bind(): %s", errno_s);
		printf("failed to bind to %s port %s: %s\n", ip, port, errno_s);
		return (KORE_RESULT_ERROR);
	}

	freeaddrinfo(results);

	if (listen(l->fd, kore_socket_backlog) == -1) {
		close(l->fd);
		kore_free(l);
		kore_debug("listen(): %s", errno_s);
		printf("failed to listen on socket: %s\n", errno_s);
		return (KORE_RESULT_ERROR);
	}

	if (ccb != NULL) {
		*(void **)&(l->connect) = kore_module_getsym(ccb);
		if (l->connect == NULL) {
			printf("no such callback: '%s'\n", ccb);
			close(l->fd);
			kore_free(l);
			return (KORE_RESULT_ERROR);
		}
	} else {
		l->connect = NULL;
	}

	nlisteners++;
	LIST_INSERT_HEAD(&listeners, l, list);

	if (foreground) {
#if !defined(KORE_NO_TLS)
		kore_log(LOG_NOTICE, "running on https://%s:%s", ip, port);
#else
		kore_log(LOG_NOTICE, "running on http://%s:%s", ip, port);
#endif
	}

	return (KORE_RESULT_OK);
}

void
kore_listener_cleanup(void)
{
	struct listener		*l;

	while (!LIST_EMPTY(&listeners)) {
		l = LIST_FIRST(&listeners);
		LIST_REMOVE(l, list);
		close(l->fd);
		kore_free(l);
	}
}

void
kore_signal(int sig)
{
	sig_recv = sig;
}

static void
kore_server_sslstart(void)
{
#if !defined(KORE_NO_TLS)
	kore_debug("kore_server_sslstart()");

	SSL_library_init();
	SSL_load_error_strings();
#endif
}