2 * Copyright (c) 2021, 2022, 2023 Omar Polo <op@omarpolo.com>
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.
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.
25 #define MIN(a, b) ((a) < (b) ? (a) : (b))
27 static const struct timeval handshake_timeout = { 5, 0 };
29 static void proxy_tls_readcb(int, short, void *);
30 static void proxy_tls_writecb(int, short, void *);
31 static void proxy_read(struct bufferevent *, void *);
32 static void proxy_write(struct bufferevent *, void *);
33 static void proxy_error(struct bufferevent *, short, void *);
36 proxy_tls_readcb(int fd, short event, void *d)
38 struct bufferevent *bufev = d;
39 struct client *c = bufev->cbarg;
40 char buf[IBUF_READ_SIZE];
41 int what = EVBUFFER_READ;
42 int howmuch = IBUF_READ_SIZE;
47 if (event == EV_TIMEOUT) {
48 what |= EVBUFFER_TIMEOUT;
52 if (bufev->wm_read.high != 0)
53 howmuch = MIN(sizeof(buf), bufev->wm_read.high);
55 switch (ret = tls_read(c->proxyctx, buf, howmuch)) {
57 case TLS_WANT_POLLOUT:
60 what |= EVBUFFER_ERROR;
70 res = evbuffer_add(bufev->input, buf, len);
72 what |= EVBUFFER_ERROR;
76 event_add(&bufev->ev_read, NULL);
78 len = EVBUFFER_LENGTH(bufev->input);
79 if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
82 if (bufev->readcb != NULL)
83 (*bufev->readcb)(bufev, bufev->cbarg);
87 event_add(&bufev->ev_read, NULL);
91 (*bufev->errorcb)(bufev, what, bufev->cbarg);
95 proxy_tls_writecb(int fd, short event, void *d)
97 struct bufferevent *bufev = d;
98 struct client *c = bufev->cbarg;
101 short what = EVBUFFER_WRITE;
103 if (event & EV_TIMEOUT) {
104 what |= EVBUFFER_TIMEOUT;
108 if (EVBUFFER_LENGTH(bufev->output) != 0) {
109 ret = tls_write(c->proxyctx, EVBUFFER_DATA(bufev->output),
110 EVBUFFER_LENGTH(bufev->output));
112 case TLS_WANT_POLLIN:
113 case TLS_WANT_POLLOUT:
116 what |= EVBUFFER_ERROR;
121 evbuffer_drain(bufev->output, len);
124 if (EVBUFFER_LENGTH(bufev->output) != 0)
125 event_add(&bufev->ev_write, NULL);
127 if (bufev->writecb != NULL &&
128 EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
129 (*bufev->writecb)(bufev, bufev->cbarg);
133 event_add(&bufev->ev_write, NULL);
137 (*bufev->errorcb)(bufev, what, bufev->cbarg);
141 proxy_read(struct bufferevent *bev, void *d)
143 struct client *c = d;
144 struct evbuffer *src = EVBUFFER_INPUT(bev);
149 /* intercept the header */
151 hdr = evbuffer_readln(src, &len, EVBUFFER_EOL_CRLF_STRICT);
153 /* max reply + \r\n */
154 if (EVBUFFER_LENGTH(src) > 1029) {
155 log_warnx("upstream server is trying to "
156 "send a header that's too long.");
157 proxy_error(bev, EVBUFFER_READ, c);
164 if (len < 3 || len > 1029 ||
165 !isdigit((unsigned char)hdr[0]) ||
166 !isdigit((unsigned char)hdr[1]) ||
167 !isspace((unsigned char)hdr[2])) {
169 log_warnx("upstream server is trying to send a "
170 "header that's too long.");
171 proxy_error(bev, EVBUFFER_READ, c);
176 code = (hdr[0] - '0') * 10 + (hdr[1] - '0');
178 if (code < 10 || code >= 70) {
179 log_warnx("upstream server is trying to send an "
180 "invalid reply code: %d", code);
181 proxy_error(bev, EVBUFFER_READ, c);
185 if (start_reply(c, code, hdr + 3) == -1 ||
186 c->code < 20 || c->code > 29) {
187 proxy_error(bev, EVBUFFER_EOF, c);
192 bufferevent_write_buffer(c->bev, src);
196 proxy_write(struct bufferevent *bev, void *d)
198 struct evbuffer *dst = EVBUFFER_OUTPUT(bev);
200 /* request successfully sent */
201 if (EVBUFFER_LENGTH(dst) == 0)
202 bufferevent_disable(bev, EV_WRITE);
206 proxy_error(struct bufferevent *bev, short error, void *d)
208 struct client *c = d;
211 * If we're here it means that some kind of non-recoverable
215 bufferevent_free(bev);
218 tls_free(c->proxyctx);
224 /* EOF and no header */
226 start_reply(c, PROXY_ERROR, "protocol error");
230 c->type = REQUEST_DONE;
231 client_write(c->bev, c);
235 proxy_enqueue_req(struct client *c)
237 struct proxy *p = c->proxy;
238 struct evbuffer *evb;
239 char iribuf[GEMINI_URL_LEN];
241 c->proxybev = bufferevent_new(c->pfd, proxy_read, proxy_write,
243 if (c->proxybev == NULL)
244 fatal("can't allocate bufferevent");
247 event_set(&c->proxybev->ev_read, c->pfd, EV_READ,
248 proxy_tls_readcb, c->proxybev);
249 event_set(&c->proxybev->ev_write, c->pfd, EV_WRITE,
250 proxy_tls_writecb, c->proxybev);
253 evbuffer_unfreeze(c->proxybev->input, 0);
254 evbuffer_unfreeze(c->proxybev->output, 1);
258 serialize_iri(&c->iri, iribuf, sizeof(iribuf));
260 evb = EVBUFFER_OUTPUT(c->proxybev);
261 evbuffer_add_printf(evb, "%s\r\n", iribuf);
263 bufferevent_enable(c->proxybev, EV_READ|EV_WRITE);
267 proxy_handshake(int fd, short event, void *d)
269 struct client *c = d;
271 if (event == EV_TIMEOUT) {
272 start_reply(c, PROXY_ERROR, "timeout");
276 switch (tls_handshake(c->proxyctx)) {
277 case TLS_WANT_POLLIN:
278 event_set(&c->proxyev, fd, EV_READ, proxy_handshake, c);
279 event_add(&c->proxyev, &handshake_timeout);
281 case TLS_WANT_POLLOUT:
282 event_set(&c->proxyev, fd, EV_WRITE, proxy_handshake, c);
283 event_add(&c->proxyev, &handshake_timeout);
286 log_warnx("handshake with proxy failed: %s",
287 tls_error(c->proxyctx));
288 start_reply(c, PROXY_ERROR, "handshake failed");
293 proxy_enqueue_req(c);
297 proxy_setup_tls(struct client *c)
299 struct proxy *p = c->proxy;
300 struct tls_config *conf = NULL;
303 if ((conf = tls_config_new()) == NULL)
307 tls_config_insecure_noverifyname(conf);
309 tls_config_insecure_noverifycert(conf);
310 tls_config_set_protocols(conf, p->protocols);
312 if (p->cert != NULL) {
315 r = tls_config_set_cert_mem(conf, p->cert, p->certlen);
319 r = tls_config_set_key_mem(conf, p->key, p->keylen);
324 if ((c->proxyctx = tls_client()) == NULL)
327 if (tls_configure(c->proxyctx, conf) == -1)
330 if (*(hn = p->sni) == '\0')
332 if (tls_connect_socket(c->proxyctx, c->pfd, hn) == -1)
336 event_set(&c->proxyev, c->pfd, EV_READ|EV_WRITE, proxy_handshake, c);
337 event_add(&c->proxyev, &handshake_timeout);
339 tls_config_free(conf);
343 tls_config_free(conf);
344 if (c->proxyctx != NULL) {
345 tls_free(c->proxyctx);
352 proxy_init(struct client *c)
354 struct proxy *p = c->proxy;
356 if (!p->notls && proxy_setup_tls(c) == -1)
359 proxy_enqueue_req(c);
361 c->type = REQUEST_PROXY;