remove ktunnel example, its too old.

This commit is contained in:
Joris Vink 2018-11-29 20:45:26 +01:00
parent 91f420d94a
commit b163d849a6
7 changed files with 0 additions and 972 deletions

View File

@ -1,5 +0,0 @@
*.o
.objs
ktunnel.so
assets.h
cert

View File

@ -1,35 +0,0 @@
KTunnel (anything over HTTPS)
This example demonstrates how we can use Kore to create an
anything-over-HTTPS tunnel.
Build:
```
# kodev build
```
Run:
```
# kodev run
```
Test:
```
# openssl s_client -connect 127.0.0.1:8888
Then enter:
GET /connect?host=74.125.232.248&port=80 HTTP/1.1
Host: 127.0.0.1
GET / HTTP/1.1
Host: www.google.se
(And hit enter)
```
You should see Kore connect to the google server given and
return the results back to you.
A client for OSX exists under the **client/** directory. It requires
you to link with -lssl and -lcrypto.

View File

@ -1,16 +0,0 @@
#
# You probably want to change the include and library
# paths before compiling.
#
CFLAGS+=-Wall -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+=-Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+=-Wsign-compare -Iincludes -g
CFLAGS+=-I../../openssl-1.0.1i/include
all:
gcc $(CFLAGS) -c client.c -o client.o
gcc -L../../openssl-1.0.1i/ client.o -o client -lcrypto -lssl
clean:
rm -f client *.o

View File

@ -1,685 +0,0 @@
/*
* Copyright (c) 2014 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <sys/event.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "openssl/err.h"
#include "openssl/ssl.h"
#include <err.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define errno_s strerror(errno)
#define ssl_errno_s ERR_error_string(ERR_get_error(), NULL)
#define KQUEUE_EVENT_COUNT 100
#define NETBUF_RECV_MAX 8192
#define HTTP_REQUEST_FMT \
"GET %s?host=%s&port=%s HTTP/1.1\r\nHost: %s\r\n\r\n"
struct netbuf {
u_int8_t *data;
u_int32_t offset;
u_int32_t length;
TAILQ_ENTRY(netbuf) list;
};
TAILQ_HEAD(netbuf_list, netbuf);
#define PEER_CAN_READ 0x01
#define PEER_CAN_WRITE 0x02
struct peer {
int fd;
int family;
int flags;
char *name;
char *host;
char *port;
int (*write)(struct peer *);
int (*read)(struct peer *, struct peer *);
SSL *ssl;
SSL_CTX *ssl_ctx;
void *connection;
struct peer *opposite;
struct netbuf *recv_buf;
struct netbuf_list write_queue;
};
#define CONNECTION_WILL_DISCONNECT 0x01
struct connection {
int flags;
struct peer local;
struct peer remote;
TAILQ_ENTRY(connection) list;
};
TAILQ_HEAD(, connection) clients;
TAILQ_HEAD(, connection) disconnects;
void usage(void);
void fatal(const char *, ...);
int ktunnel_peer_handle(struct peer *);
void ktunnel_peer_cleanup(struct peer *);
void ktunnel_connection_close(struct connection *);
void ktunnel_connection_cleanup(struct connection *);
void ktunnel_event_schedule(int, int, int, void *);
void ktunnel_set_nonblock(int);
int ktunnel_write_local(struct peer *);
int ktunnel_write_remote(struct peer *);
int ktunnel_read_local(struct peer *, struct peer *);
int ktunnel_read_remote(struct peer *, struct peer *);
void ktunnel_accept(struct peer *);
void ktunnel_bind(struct peer *, struct addrinfo *);
void ktunnel_connect(struct peer *, struct addrinfo *);
void ktunnel_peer_init(struct peer *, const char *,
void (*cb)(struct peer *, struct addrinfo *));
void ktunnel_netbuf_create(struct netbuf **, struct netbuf_list *,
u_int8_t *, u_int32_t);
int kfd = - 1;
u_int32_t nchanges = 0;
struct kevent *events = NULL;
struct kevent *changelist = NULL;
char *target_host = NULL;
char *target_port = NULL;
char *remote_name = NULL;
char *http_hostname = NULL;
char *http_path = "/connect";
void
usage(void)
{
fprintf(stderr,
"Usage: ktunnel-client [-h host] [-p path] "
"local:port remote:port target:port\n");
exit(1);
}
int
main(int argc, char *argv[])
{
int n, i, ch;
struct connection *c, *cnext;
struct peer lpeer, *peer;
while ((ch = getopt(argc, argv, "h:p:")) != -1) {
switch (ch) {
case 'h':
http_hostname = optarg;
break;
case 'p':
http_path = optarg;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 3)
usage();
TAILQ_INIT(&clients);
TAILQ_INIT(&disconnects);
if ((kfd = kqueue()) == -1)
fatal("kqueue(): %s", errno_s);
nchanges = 0;
events = calloc(KQUEUE_EVENT_COUNT, sizeof(struct kevent));
changelist = calloc(KQUEUE_EVENT_COUNT, sizeof(struct kevent));
if (events == NULL || changelist == NULL)
fatal("calloc(): %s", errno_s);
memset(&lpeer, 0, sizeof(lpeer));
ktunnel_peer_init(&lpeer, argv[0], ktunnel_bind);
ktunnel_event_schedule(lpeer.fd, EVFILT_READ, EV_ADD, &lpeer);
remote_name = argv[1];
target_host = argv[2];
if ((target_port = strchr(target_host, ':')) == NULL)
fatal("Target host does not contain a port");
*(target_port)++ = '\0';
if (http_hostname == NULL)
http_hostname = target_host;
for (;;) {
n = kevent(kfd, changelist, nchanges,
events, KQUEUE_EVENT_COUNT, NULL);
if (n == -1) {
if (errno == EINTR)
continue;
fatal("kevent(): %s", errno_s);
}
nchanges = 0;
for (i = 0; i < n; i++) {
if (events[i].udata == NULL)
fatal("events[%d].udata == NULL", i);
peer = (struct peer *)events[i].udata;
if (events[i].flags & EV_EOF ||
events[i].flags & EV_ERROR) {
if (peer->fd == lpeer.fd)
fatal("error on listening socket");
ktunnel_connection_close(peer->connection);
continue;
}
if (peer->fd == lpeer.fd) {
ktunnel_accept(peer);
continue;
}
if (events[i].filter == EVFILT_READ)
peer->flags |= PEER_CAN_READ;
if (events[i].filter == EVFILT_WRITE)
peer->flags |= PEER_CAN_WRITE;
if (ktunnel_peer_handle(peer) == -1) {
ktunnel_connection_close(peer->connection);
} else {
if (!TAILQ_EMPTY(&peer->write_queue)) {
ktunnel_event_schedule(peer->fd,
EVFILT_WRITE,
EV_ADD | EV_ONESHOT, peer);
}
}
}
for (c = TAILQ_FIRST(&disconnects); c != NULL; c = cnext) {
cnext = TAILQ_NEXT(c, list);
TAILQ_REMOVE(&disconnects, c, list);
ktunnel_connection_cleanup(c);
}
}
return (0);
}
void
ktunnel_peer_init(struct peer *peer, const char *name, void (*cb)(struct peer *,
struct addrinfo *))
{
int r;
struct addrinfo *ai, *results;
if ((peer->name = strdup(name)) == NULL)
fatal("strdup() messed up");
peer->host = peer->name;
if ((peer->port = strchr(peer->host, ':')) == NULL)
fatal("No port section in given local host '%s'", peer->name);
*(peer->port)++ = '\0';
r = getaddrinfo(peer->host, peer->port, NULL, &results);
if (r != 0)
fatal("%s: %s", name, gai_strerror(r));
for (ai = results; ai != NULL; ai = ai->ai_next) {
if (ai->ai_socktype != SOCK_STREAM)
continue;
if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
continue;
cb(peer, ai);
peer->family = ai->ai_family;
break;
}
freeaddrinfo(results);
}
void
ktunnel_accept(struct peer *peer)
{
int fd;
struct connection *c;
struct sockaddr_in sin4;
struct sockaddr_in6 sin6;
struct sockaddr *sin;
socklen_t slen;
sin = NULL;
switch (peer->family) {
case AF_INET:
sin = (struct sockaddr *)&sin4;
slen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
sin = (struct sockaddr *)&sin6;
slen = sizeof(struct sockaddr_in6);
break;
default:
fatal("Unknown peer family %d", peer->family);
/* NOTREACHED */
}
if ((fd = accept(peer->fd, sin, &slen)) == -1)
fatal("accept(): %s", errno_s);
if ((c = malloc(sizeof(*c))) == NULL)
fatal("malloc(): %s", errno_s);
memset(c, 0, sizeof(*c));
c->local.fd = fd;
TAILQ_INIT(&c->local.write_queue);
ktunnel_event_schedule(c->local.fd, EVFILT_READ, EV_ADD, &c->local);
ktunnel_event_schedule(c->local.fd, EVFILT_WRITE,
EV_ADD | EV_ONESHOT, &c->local);
c->local.connection = c;
c->local.opposite = &c->remote;
c->local.read = ktunnel_read_local;
c->local.write = ktunnel_write_local;
c->remote.connection = c;
c->remote.opposite = &c->local;
c->remote.read = ktunnel_read_remote;
c->remote.write = ktunnel_write_remote;
ktunnel_peer_init(&c->remote, remote_name, ktunnel_connect);
ktunnel_netbuf_create(&c->local.recv_buf,
NULL, NULL, NETBUF_RECV_MAX);
ktunnel_set_nonblock(c->local.fd);
ktunnel_set_nonblock(c->remote.fd);
TAILQ_INSERT_TAIL(&clients, c, list);
printf("new connection %p (%p<->%p)\n", c, &c->local, &c->remote);
}
void
ktunnel_bind(struct peer *peer, struct addrinfo *ai)
{
if ((peer->fd = socket(ai->ai_family, ai->ai_socktype, 0)) == -1)
fatal("socket(): %s", errno_s);
if (bind(peer->fd, ai->ai_addr, ai->ai_addrlen) == -1) {
fatal("Cannot bind to %s:%s: %s",
peer->host, peer->port, errno_s);
}
if (listen(peer->fd, 10) == -1)
fatal("Cannot listen on socket: %s", errno_s);
TAILQ_INIT(&peer->write_queue);
ktunnel_netbuf_create(&peer->recv_buf, NULL, NULL, NETBUF_RECV_MAX);
}
void
ktunnel_connect(struct peer *peer, struct addrinfo *ai)
{
int l;
char *req;
if ((peer->fd = socket(ai->ai_family, ai->ai_socktype, 0)) == -1)
fatal("socket(): %s", errno_s);
if (connect(peer->fd, ai->ai_addr, ai->ai_addrlen) == -1) {
fatal("Cannot connect to %s:%s: %s",
peer->host, peer->port, errno_s);
}
TAILQ_INIT(&peer->write_queue);
ktunnel_netbuf_create(&peer->recv_buf, NULL, NULL, NETBUF_RECV_MAX);
/*
* XXX
* - Add our client certs
* - Verify server cert properly
* - ...
*/
SSL_library_init();
SSL_load_error_strings();
if ((peer->ssl_ctx = SSL_CTX_new(SSLv23_method())) == NULL)
fatal("SSL_CTX_new(): %s", ssl_errno_s);
SSL_CTX_set_mode(peer->ssl_ctx, SSL_MODE_AUTO_RETRY);
SSL_CTX_set_options(peer->ssl_ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(peer->ssl_ctx, SSL_OP_NO_SSLv3);
SSL_CTX_set_options(peer->ssl_ctx, SSL_OP_NO_TLSv1);
SSL_CTX_set_options(peer->ssl_ctx, SSL_OP_NO_TLSv1_1);
if ((peer->ssl = SSL_new(peer->ssl_ctx)) == NULL)
fatal("SSL_new(): %s", ssl_errno_s);
if (!SSL_set_fd(peer->ssl, peer->fd))
fatal("SSL_set_fd(): %s", ssl_errno_s);
if (!SSL_connect(peer->ssl)) {
fatal("Could not establish an SSL connection to %s: %s",
peer->host, ssl_errno_s);
}
/* Send custom HTTP command. */
l = asprintf(&req, HTTP_REQUEST_FMT, http_path,
target_host, target_port, http_hostname);
if (l == -1)
fatal("asprintf(): %s", errno_s);
if (SSL_write(peer->ssl, req, l) != l) {
fatal("Failed to talk to %s:%s: %s",
peer->host, peer->port, ssl_errno_s);
}
free(req);
ktunnel_event_schedule(peer->fd, EVFILT_READ, EV_ADD, peer);
ktunnel_event_schedule(peer->fd, EVFILT_WRITE,
EV_ADD | EV_ONESHOT, peer);
printf("Connected over SSL to %s:%s\n", peer->host, peer->port);
}
int
ktunnel_peer_handle(struct peer *peer)
{
int r;
printf("handling peer %p (%d)\n", peer, peer->flags);
if (peer->flags & PEER_CAN_READ) {
printf("\treading\n");
r = peer->read(peer, peer->opposite);
}
if (peer->flags & PEER_CAN_WRITE) {
printf("\twriting\n");
r = peer->write(peer);
}
return (r);
}
void
ktunnel_connection_close(struct connection *c)
{
printf("ktunnel_connection_close(%p)\n", c);
if (!(c->flags & CONNECTION_WILL_DISCONNECT)) {
c->flags |= CONNECTION_WILL_DISCONNECT;
TAILQ_REMOVE(&clients, c, list);
TAILQ_INSERT_TAIL(&disconnects, c, list);
}
}
void
ktunnel_connection_cleanup(struct connection *c)
{
ktunnel_peer_cleanup(&c->local);
ktunnel_peer_cleanup(&c->remote);
free(c);
}
void
ktunnel_peer_cleanup(struct peer *peer)
{
struct netbuf *nb, *next;
printf("ktunnel_peer_cleanup(%p)\n", peer);
close(peer->fd);
if (peer->ssl != NULL)
SSL_free(peer->ssl);
if (peer->ssl_ctx != NULL)
SSL_CTX_free(peer->ssl_ctx);
for (nb = TAILQ_FIRST(&peer->write_queue); nb != NULL; nb = next) {
next = TAILQ_NEXT(nb, list);
TAILQ_REMOVE(&peer->write_queue, nb, list);
free(nb->data);
free(nb);
}
free(peer->recv_buf->data);
}
void
ktunnel_netbuf_create(struct netbuf **out, struct netbuf_list *head,
u_int8_t *data, u_int32_t length)
{
struct netbuf *nb;
if ((nb = malloc(sizeof(struct netbuf))) == NULL)
fatal("malloc(): %s", errno_s);
nb->offset = 0;
nb->length = length;
if ((nb->data = malloc(nb->length)) == NULL)
fatal("malloc(): %s", errno_s);
if (data != NULL)
memcpy(nb->data, data, nb->length);
if (head != NULL)
TAILQ_INSERT_TAIL(head, nb, list);
if (out != NULL)
*out = nb;
}
void
ktunnel_event_schedule(int fd, int type, int flags, void *udata)
{
if (nchanges >= KQUEUE_EVENT_COUNT)
fatal("nchanges > KQUEUE_EVENT_COUNT");
EV_SET(&changelist[nchanges], fd, type, flags, 0, 0, udata);
nchanges++;
}
int
ktunnel_read_local(struct peer *in, struct peer *out)
{
int r;
printf("ktunnel_read_local: %p\n", in);
r = read(in->fd, in->recv_buf->data, in->recv_buf->length);
if (r == -1) {
if (errno != EINTR && errno != EAGAIN) {
printf("read error on local peer: %s\n", errno_s);
return (-1);
}
return (0);
}
if (r == 0) {
printf("local peer closed connection\n");
return (-1);
}
printf("ktunnel_read_local: %p -- %d bytes --> %p\n", in, r, out);
ktunnel_netbuf_create(NULL, &(out->write_queue), in->recv_buf->data, r);
return (ktunnel_write_remote(out));
}
int
ktunnel_write_local(struct peer *peer)
{
int r;
struct netbuf *nb;
while (!TAILQ_EMPTY(&peer->write_queue)) {
nb = TAILQ_FIRST(&peer->write_queue);
printf("ktunnel_write_local: %p writing %d/%d\n", peer,
nb->offset, nb->length);
r = write(peer->fd, (nb->data + nb->offset),
(nb->length - nb->offset));
if (r == -1) {
switch (errno) {
case EINTR:
case EAGAIN:
peer->flags &= ~PEER_CAN_WRITE;
return (0);
default:
printf("failed to write to local peer: %s\n",
errno_s);
return (-1);
}
}
nb->offset += r;
printf("ktunnel_write_local: %p progress %d/%d\n", peer,
nb->offset, nb->length);
if (nb->offset == nb->length) {
TAILQ_REMOVE(&peer->write_queue, nb, list);
free(nb->data);
free(nb);
}
}
return (0);
}
int
ktunnel_read_remote(struct peer *in, struct peer *out)
{
int r;
r = SSL_read(in->ssl, in->recv_buf->data, in->recv_buf->length);
if (r <= 0) {
r = SSL_get_error(in->ssl, r);
switch (r) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
in->flags &= ~PEER_CAN_READ;
return (0);
default:
printf("failed to read from remote peer: %d, %s\n",
r, ssl_errno_s);
return (-1);
}
}
ktunnel_netbuf_create(NULL, &(out->write_queue), in->recv_buf->data, r);
return (ktunnel_write_local(out));
}
int
ktunnel_write_remote(struct peer *peer)
{
int r;
struct netbuf *nb;
while (!TAILQ_EMPTY(&peer->write_queue)) {
nb = TAILQ_FIRST(&peer->write_queue);
printf("ktunnel_write_remote: %p writing %d/%d bytes\n", peer,
nb->offset, nb->length);
r = SSL_write(peer->ssl, (nb->data + nb->offset),
(nb->length - nb->offset));
if (r <= 0) {
r = SSL_get_error(peer->ssl, r);
switch (r) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
peer->flags &= ~PEER_CAN_WRITE;
return (0);
default:
printf("failed to write to remote peer: %s\n",
ssl_errno_s);
return (-1);
}
}
nb->offset += r;
printf("ktunnel_write_remote: %p progress %d/%d\n", peer,
nb->offset, nb->length);
if (nb->offset == nb->length) {
TAILQ_REMOVE(&peer->write_queue, nb, list);
free(nb->data);
free(nb);
}
}
return (0);
}
void
ktunnel_set_nonblock(int fd)
{
int flags;
if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
fatal("fcntl(): get %s", errno_s);
flags |= O_NONBLOCK;
if (fcntl(fd, F_SETFL, flags) == -1)
fatal("fnctl(): set %s", errno_s);
}
void
fatal(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
printf("\n");
exit(1);
}

View File

@ -1,18 +0,0 @@
# ktunnel build config
# You can switch flavors using: kodev flavor [newflavor]
# The cflags below are shared between flavors
cflags=-Wall -Wmissing-declarations -Wshadow
cflags=-Wstrict-prototypes -Wmissing-prototypes
cflags=-Wpointer-arith -Wcast-qual -Wsign-compare
dev {
# These cflags are added to the shared ones when
# you build the "dev" flavor.
cflags=-g
}
#prod {
# You can specify additional CFLAGS here which are only
# included if you build with the "prod" flavor.
#}

View File

@ -1,25 +0,0 @@
# kTunnel configuration
bind 127.0.0.1 8888
load ./ktunnel.so
tls_dhparam dh2048.pem
# Regexes here are incorrect.
validator v_host regex ^.*$
validator v_port regex ^[0-9]*$
# Disable timeouts
http_keepalive_time 0
domain * {
certfile cert/server.pem
certkey cert/key.pem
static /connect open_connection
params qs:get /connect {
validate host v_host
validate port v_port
}
}

View File

@ -1,188 +0,0 @@
/*
* Copyright (c) 2014 Joris Vink <joris@coders.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/socket.h>
#include <kore/kore.h>
#include <kore/http.h>
#include <limits.h>
/*
* KTunnel shows how Kore exposes its net internals to its libraries
* and how we can "abuse" these internals to create a "anything"
* over HTTPS tunnel.
*/
int open_connection(struct http_request *);
static int ktunnel_pipe_data(struct netbuf *);
static void ktunnel_pipe_disconnect(struct connection *);
static int ktunnel_pipe_create(struct connection *,
const char *, const char *);
/*
* Receive a request to open a new connection.
*/
int
open_connection(struct http_request *req)
{
char *host, *port;
/* Make sure its HTTP. */
if (req->owner->proto != CONN_PROTO_HTTP) {
http_response(req, HTTP_STATUS_BAD_REQUEST, NULL, 0);
return (KORE_RESULT_OK);
}
/* Parse the query string and grab our arguments. */
http_populate_get(req);
if (!http_argument_get_string(req, "host", &host) ||
!http_argument_get_string(req, "port", &port)) {
http_response(req, HTTP_STATUS_BAD_REQUEST, NULL, 0);
return (KORE_RESULT_OK);
}
/* Create our tunnel. */
if (!ktunnel_pipe_create(req->owner, host, port)) {
http_response(req, HTTP_STATUS_INTERNAL_ERROR, NULL, 0);
return (KORE_RESULT_OK);
}
/*
* Hack so http_response() doesn't end up queueing a new
* netbuf for receiving more HTTP requests on the same connection.
*/
req->owner->flags |= CONN_CLOSE_EMPTY;
/* Respond to the client now that we're good to go. */
http_response(req, HTTP_STATUS_OK, NULL, 0);
/* Unset this so we don't disconnect after returning. */
req->owner->flags &= ~CONN_CLOSE_EMPTY;
return (KORE_RESULT_OK);
}
/*
* 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, 1)) {
close(fd);
return (KORE_RESULT_ERROR);
}
cpipe = kore_connection_new(c);
TAILQ_INSERT_TAIL(&connections, cpipe, list);
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_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);
}
/*
* Called everytime new data is read from any of the connections
* that are part of a pipe.
*/
static int
ktunnel_pipe_data(struct netbuf *nb)
{
struct connection *src = nb->owner;
struct connection *dst = src->hdlr_extra;
printf("received %zu bytes on pipe %p (-> %p)\n", nb->s_off, src, dst);
net_send_queue(dst, nb->buf, nb->s_off);
net_send_flush(dst);
net_recv_reset(src, NETBUF_SEND_PAYLOAD_MAX, ktunnel_pipe_data);
return (KORE_RESULT_OK);
}
/*
* Called when either part of the pipe disconnects.
*/
static void
ktunnel_pipe_disconnect(struct connection *c)
{
struct connection *cpipe = c->hdlr_extra;
printf("ktunnel_pipe_disconnect(%p)->%p\n", c, cpipe);
if (cpipe != NULL) {
/* Prevent Kore from calling kore_free() on hdlr_extra. */
c->hdlr_extra = NULL;
kore_connection_disconnect(cpipe);
}
}