2014-09-17 08:53:13 +02:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2014-09-18 09:52:48 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
|
2014-09-17 08:53:13 +02:00
|
|
|
#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;
|
|
|
|
|
|
|
|
/* Don't want to deal with SPDY connections. */
|
|
|
|
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_arguments(req);
|
|
|
|
if (!http_argument_get_string("host", &host, NULL) ||
|
|
|
|
!http_argument_get_string("port", &port, NULL)) {
|
|
|
|
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;
|
2014-09-18 09:52:48 +02:00
|
|
|
struct connection *cpipe;
|
2014-09-17 08:53:13 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-09-03 08:24:55 +02:00
|
|
|
if (!kore_connection_nonblock(fd, 1)) {
|
2014-09-17 08:53:13 +02:00
|
|
|
close(fd);
|
|
|
|
return (KORE_RESULT_ERROR);
|
|
|
|
}
|
|
|
|
|
2014-09-18 09:52:48 +02:00
|
|
|
cpipe = kore_connection_new(c);
|
2015-10-23 12:13:23 +02:00
|
|
|
TAILQ_INSERT_TAIL(&connections, cpipe, list);
|
|
|
|
|
2014-09-18 09:52:48 +02:00
|
|
|
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;
|
|
|
|
|
2014-09-29 14:47:01 +02:00
|
|
|
/* Don't let these connections timeout any time soon. */
|
|
|
|
cpipe->idle_timer.length = 10000000000;
|
|
|
|
c->idle_timer.length = 10000000000;
|
|
|
|
|
2014-09-18 09:52:48 +02:00
|
|
|
c->hdlr_extra = cpipe;
|
|
|
|
cpipe->hdlr_extra = c;
|
2014-09-17 08:53:13 +02:00
|
|
|
c->disconnect = ktunnel_pipe_disconnect;
|
2014-09-18 09:52:48 +02:00
|
|
|
cpipe->disconnect = ktunnel_pipe_disconnect;
|
2014-09-17 08:53:13 +02:00
|
|
|
|
2014-09-18 09:52:48 +02:00
|
|
|
kore_connection_start_idletimer(cpipe);
|
|
|
|
kore_platform_event_all(cpipe->fd, cpipe);
|
2014-09-17 08:53:13 +02:00
|
|
|
|
2014-10-22 21:16:49 +02:00
|
|
|
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);
|
2014-09-17 08:53:13 +02:00
|
|
|
|
2014-09-18 09:52:48 +02:00
|
|
|
printf("connection started to %s (%p -> %p)\n", host, c, cpipe);
|
2014-09-17 08:53:13 +02:00
|
|
|
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 %d bytes on pipe %p (-> %p)\n", nb->s_off, src, dst);
|
|
|
|
|
2015-11-27 16:22:50 +01:00
|
|
|
net_send_queue(dst, nb->buf, nb->s_off);
|
2014-09-17 08:53:13 +02:00
|
|
|
net_send_flush(dst);
|
2014-10-22 21:16:49 +02:00
|
|
|
net_recv_reset(src, NETBUF_SEND_PAYLOAD_MAX, ktunnel_pipe_data);
|
2014-09-17 08:53:13 +02:00
|
|
|
|
|
|
|
return (KORE_RESULT_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called when either part of the pipe disconnects.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ktunnel_pipe_disconnect(struct connection *c)
|
|
|
|
{
|
2014-09-18 09:52:48 +02:00
|
|
|
struct connection *cpipe = c->hdlr_extra;
|
2014-09-17 08:53:13 +02:00
|
|
|
|
2014-09-18 09:52:48 +02:00
|
|
|
printf("ktunnel_pipe_disconnect(%p)->%p\n", c, cpipe);
|
2014-09-17 08:53:13 +02:00
|
|
|
|
2014-09-18 09:52:48 +02:00
|
|
|
if (cpipe != NULL) {
|
2014-09-17 08:53:13 +02:00
|
|
|
/* Prevent Kore from calling kore_mem_free() on hdlr_extra. */
|
|
|
|
c->hdlr_extra = NULL;
|
2014-09-18 09:52:48 +02:00
|
|
|
kore_connection_disconnect(cpipe);
|
2014-09-17 08:53:13 +02:00
|
|
|
}
|
|
|
|
}
|