proxy.c (7534B)
1 /*
2 * Copyright (c) 2015 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <sys/param.h>
18 #include <sys/socket.h>
19
20 #include <kore/kore.h>
21
22 /*
23 * In this example Kore acts as a TLS proxy shuffling data between
24 * an encrypted connection and a plain text backend.
25 *
26 * It will look at the TLS SNI extension to figure out what backend
27 * to use for the connection when it comes in.
28 *
29 * Add your backends to the data structure below.
30 */
31
32 /* Default timeouts, 5 seconds for connecting, 15 seconds otherwise. */
33 #define PROXY_TIMEOUT (15 * 1000)
34 #define PROXY_CONNECT_TIMEOUT (5 * 1000)
35
36 /* All domains and their backends. */
37 struct {
38 const char *name;
39 const char *ip;
40 const u_int16_t port;
41 } backends[] = {
42 { "localhost", "127.0.0.1", 8080 },
43 { NULL, NULL, 0 }
44 };
45
46 int client_handle(struct connection *);
47 void client_setup(struct connection *);
48
49 void disconnect(struct connection *);
50 int pipe_data(struct netbuf *);
51
52 int backend_handle_connect(struct connection *);
53 int backend_handle_default(struct connection *);
54
55 /*
56 * Called for every new connection on a certain ip/port. Which one is
57 * configured in the TLS proxy its configuration file.
58 */
59 void
60 client_setup(struct connection *c)
61 {
62 int i, fd;
63 const char *name;
64 struct connection *backend;
65
66 /* Paranoia. */
67 name = SSL_get_servername(c->ssl, TLSEXT_NAMETYPE_host_name);
68 if (name == NULL) {
69 kore_connection_disconnect(c);
70 return;
71 }
72
73 /* Figure out what backend to use. */
74 for (i = 0; backends[i].name != NULL; i++) {
75 if (!strcasecmp(backends[i].name, name))
76 break;
77 }
78
79 /* If we don't have any backends, we just disconnect the client. */
80 if (backends[i].name == NULL) {
81 kore_connection_disconnect(c);
82 return;
83 }
84
85 /* Create new socket for the backend connection. */
86 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
87 kore_log(LOG_ERR, "socket(): %s", errno_s);
88 kore_connection_disconnect(c);
89 return;
90 }
91
92 /* Set it to non blocking as well. */
93 if (!kore_connection_nonblock(fd, 1)) {
94 close(fd);
95 kore_connection_disconnect(c);
96 return;
97 }
98
99 /* Grab a new connection from Kore to hook backend into. */
100 backend = kore_connection_new(NULL);
101
102 /* Prepare our connection. */
103 backend->family = AF_INET;
104 backend->addr.ipv4.sin_family = AF_INET;
105 backend->addr.ipv4.sin_port = htons(backends[i].port);
106 backend->addr.ipv4.sin_addr.s_addr = inet_addr(backends[i].ip);
107
108 /* Set the file descriptor for the backend. */
109 backend->fd = fd;
110
111 /* Default write/read callbacks for backend. */
112 backend->read = net_read;
113 backend->write = net_write;
114
115 /* Connection type (unknown to Kore). */
116 backend->proto = CONN_PROTO_UNKNOWN;
117 backend->state = CONN_STATE_ESTABLISHED;
118
119 /* The backend idle timer is set first to connection timeout. */
120 backend->idle_timer.length = PROXY_CONNECT_TIMEOUT;
121
122 /* The client idle timer is set to default idle time. */
123 c->idle_timer.length = PROXY_TIMEOUT;
124
125 /* Now link both the client and the backend connection together. */
126 c->hdlr_extra = backend;
127 backend->hdlr_extra = c;
128
129 /*
130 * The handle function pointer for the backend is set to the
131 * backend_handle_connect() while connecting.
132 */
133 c->handle = client_handle;
134 backend->handle = backend_handle_connect;
135
136 /* Set the disconnect method for both connections. */
137 c->disconnect = disconnect;
138 backend->disconnect = disconnect;
139
140 /* Queue write events for the backend connection for now. */
141 kore_platform_schedule_write(backend->fd, backend);
142
143 /* Start idle timer for the backend. */
144 kore_connection_start_idletimer(backend);
145
146 /* Set our client connection to established. */
147 c->state = CONN_STATE_ESTABLISHED;
148
149 /* Insert the backend into the list of Kore connections. */
150 TAILQ_INSERT_TAIL(&connections, backend, list);
151
152 /* Kick off connecting. */
153 backend->evt.flags |= KORE_EVENT_WRITE;
154 backend->handle(backend);
155 }
156
157 /*
158 * This function is called for backends while they are connecting.
159 * In here we check for write events and attempt to connect() to the
160 * backend.
161 *
162 * Once a connection is established we set the backend handle function
163 * pointer to the backend_handle_default() callback and setup the reads
164 * for both the backend and the client connection we received.
165 */
166 int
167 backend_handle_connect(struct connection *c)
168 {
169 int ret;
170 struct connection *src;
171
172 /* We will get a write notification when we can progress. */
173 if (!(c->evt.flags & KORE_EVENT_WRITE))
174 return (KORE_RESULT_OK);
175
176 kore_connection_stop_idletimer(c);
177
178 /* Attempt connecting. */
179 ret = connect(c->fd, (struct sockaddr *)&c->addr.ipv4,
180 sizeof(c->addr.ipv4));
181
182 /* If we failed check why, we are non blocking. */
183 if (ret == -1) {
184 /* If we got a real error, disconnect. */
185 if (errno != EALREADY && errno != EINPROGRESS &&
186 errno != EISCONN) {
187 kore_log(LOG_ERR, "connect(): %s", errno_s);
188 return (KORE_RESULT_ERROR);
189 }
190
191 /* Clean the write flag, we'll be called later. */
192 if (errno != EISCONN) {
193 c->evt.flags &= ~KORE_EVENT_WRITE;
194 kore_connection_start_idletimer(c);
195 return (KORE_RESULT_OK);
196 }
197 }
198
199 /* The connection to the backend succeeded. */
200 c->handle = backend_handle_default;
201
202 /* Setup read calls for both backend and its client. */
203 net_recv_queue(c, NETBUF_SEND_PAYLOAD_MAX,
204 NETBUF_CALL_CB_ALWAYS, pipe_data);
205 net_recv_queue(c->hdlr_extra, NETBUF_SEND_PAYLOAD_MAX,
206 NETBUF_CALL_CB_ALWAYS, pipe_data);
207
208 /* Allow for all events now. */
209 kore_connection_start_idletimer(c);
210 kore_platform_event_all(c->fd, c);
211
212 /* Allow events from source now. */
213 src = c->hdlr_extra;
214 kore_platform_event_all(src->fd, src);
215
216 /* Now lets start. */
217 return (c->handle(c));
218 }
219
220 /*
221 * Called for connection activity on a backend, just forwards
222 * to the default Kore connection handling for now.
223 */
224 int
225 backend_handle_default(struct connection *c)
226 {
227 return (kore_connection_handle(c));
228 }
229
230 /*
231 * Called for connection activity on a client, just forwards
232 * to the default Kore connection handling for now.
233 */
234 int
235 client_handle(struct connection *c)
236 {
237 return (kore_connection_handle(c));
238 }
239
240 /*
241 * Called whenever a client or its backend have disconnected.
242 * This will disconnect the matching paired connection as well.
243 */
244 void
245 disconnect(struct connection *c)
246 {
247 struct connection *pair = c->hdlr_extra;
248
249 c->hdlr_extra = NULL;
250
251 if (pair != NULL) {
252 pair->hdlr_extra = NULL;
253 kore_connection_disconnect(pair);
254 }
255 }
256
257 /*
258 * Called whenever data is available that must be piped through
259 * to the paired connection. (client<>backend or backend<>client).
260 */
261 int
262 pipe_data(struct netbuf *nb)
263 {
264 struct connection *src = nb->owner;
265 struct connection *dst = src->hdlr_extra;
266
267 /* Flush data out towards destination. */
268 net_send_queue(dst, nb->buf, nb->s_off);
269 net_send_flush(dst);
270
271 /* Reset read for source. */
272 net_recv_reset(src, NETBUF_SEND_PAYLOAD_MAX, pipe_data);
273
274 return (KORE_RESULT_OK);
275 }