1 /* $Id: http.c,v 1.13 2020/01/11 17:37:19 sthen Exp $ */
2 /*
3 * Copyright (c) 2016 Kristaps Dzonsons <kristaps@bsd.lv>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/types.h>
19 #include <sys/socket.h>
20
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
23
24 #include <ctype.h>
25 #include <err.h>
26 #include <limits.h>
27 #include <netdb.h>
28 #include <stdio.h>
29 #include <stdint.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <tls.h>
33 #include <unistd.h>
34
35 #include "http.h"
36 #include <tls.h>
37
38 /*
39 * A buffer for transferring HTTP/S data.
40 */
41 struct httpxfer {
42 char *hbuf; /* header transfer buffer */
43 size_t hbufsz; /* header buffer size */
44 int headok; /* header has been parsed */
45 char *bbuf; /* body transfer buffer */
46 size_t bbufsz; /* body buffer size */
47 int bodyok; /* body has been parsed */
48 char *headbuf; /* lookaside buffer for headers */
49 struct httphead *head; /* parsed headers */
50 size_t headsz; /* number of headers */
51 };
52
53 /*
54 * An HTTP/S connection object.
55 */
56 struct http {
57 int fd; /* connected socket */
58 short port; /* port number */
59 struct source src; /* endpoint (raw) host */
60 char *path; /* path to request */
61 char *host; /* name of endpoint host */
62 struct tls *ctx; /* if TLS */
63 writefp writer; /* write function */
64 readfp reader; /* read function */
65 };
66
67 struct tls_config *tlscfg;
68
69 static ssize_t
dosysread(char * buf,size_t sz,const struct http * http)70 dosysread(char *buf, size_t sz, const struct http *http)
71 {
72 ssize_t rc;
73
74 rc = read(http->fd, buf, sz);
75 if (rc == -1)
76 warn("%s: read", http->src.ip);
77 return rc;
78 }
79
80 static ssize_t
dosyswrite(const void * buf,size_t sz,const struct http * http)81 dosyswrite(const void *buf, size_t sz, const struct http *http)
82 {
83 ssize_t rc;
84
85 rc = write(http->fd, buf, sz);
86 if (rc == -1)
87 warn("%s: write", http->src.ip);
88 return rc;
89 }
90
91 static ssize_t
dotlsread(char * buf,size_t sz,const struct http * http)92 dotlsread(char *buf, size_t sz, const struct http *http)
93 {
94 ssize_t rc;
95
96 do {
97 rc = tls_read(http->ctx, buf, sz);
98 } while (rc == TLS_WANT_POLLIN || rc == TLS_WANT_POLLOUT);
99
100 if (rc == -1)
101 warnx("%s: tls_read: %s", http->src.ip,
102 tls_error(http->ctx));
103 return rc;
104 }
105
106 static ssize_t
dotlswrite(const void * buf,size_t sz,const struct http * http)107 dotlswrite(const void *buf, size_t sz, const struct http *http)
108 {
109 ssize_t rc;
110
111 do {
112 rc = tls_write(http->ctx, buf, sz);
113 } while (rc == TLS_WANT_POLLIN || rc == TLS_WANT_POLLOUT);
114
115 if (rc == -1)
116 warnx("%s: tls_write: %s", http->src.ip,
117 tls_error(http->ctx));
118 return rc;
119 }
120
121 int
http_init()122 http_init()
123 {
124 if (tlscfg != NULL)
125 return 0;
126
127 if (tls_init() == -1) {
128 warn("tls_init");
129 goto err;
130 }
131
132 tlscfg = tls_config_new();
133 if (tlscfg == NULL) {
134 warn("tls_config_new");
135 goto err;
136 }
137
138 if (tls_config_set_ca_file(tlscfg, tls_default_ca_cert_file()) == -1) {
139 warn("tls_config_set_ca_file: %s", tls_config_error(tlscfg));
140 goto err;
141 }
142
143 return 0;
144
145 err:
146 tls_config_free(tlscfg);
147 tlscfg = NULL;
148
149 return -1;
150 }
151
152 static ssize_t
http_read(char * buf,size_t sz,const struct http * http)153 http_read(char *buf, size_t sz, const struct http *http)
154 {
155 ssize_t ssz, xfer;
156
157 xfer = 0;
158 do {
159 if ((ssz = http->reader(buf, sz, http)) < 0)
160 return -1;
161 if (ssz == 0)
162 break;
163 xfer += ssz;
164 sz -= ssz;
165 buf += ssz;
166 } while (ssz > 0 && sz > 0);
167
168 return xfer;
169 }
170
171 static int
http_write(const char * buf,size_t sz,const struct http * http)172 http_write(const char *buf, size_t sz, const struct http *http)
173 {
174 ssize_t ssz, xfer;
175
176 xfer = sz;
177 while (sz > 0) {
178 if ((ssz = http->writer(buf, sz, http)) < 0)
179 return -1;
180 sz -= ssz;
181 buf += (size_t)ssz;
182 }
183 return xfer;
184 }
185
186 void
http_disconnect(struct http * http)187 http_disconnect(struct http *http)
188 {
189 int rc;
190
191 if (http->ctx != NULL) {
192 /* TLS connection. */
193 do {
194 rc = tls_close(http->ctx);
195 } while (rc == TLS_WANT_POLLIN || rc == TLS_WANT_POLLOUT);
196
197 if (rc < 0)
198 warnx("%s: tls_close: %s", http->src.ip,
199 tls_error(http->ctx));
200
201 tls_free(http->ctx);
202 }
203 if (http->fd != -1) {
204 if (close(http->fd) == -1)
205 warn("%s: close", http->src.ip);
206 }
207
208 http->fd = -1;
209 http->ctx = NULL;
210 }
211
212 void
http_free(struct http * http)213 http_free(struct http *http)
214 {
215
216 if (http == NULL)
217 return;
218 http_disconnect(http);
219 free(http->host);
220 free(http->path);
221 free(http->src.ip);
222 free(http);
223 }
224
225 struct http *
http_alloc(const struct source * addrs,size_t addrsz,const char * host,short port,const char * path)226 http_alloc(const struct source *addrs, size_t addrsz,
227 const char *host, short port, const char *path)
228 {
229 struct sockaddr_storage ss;
230 int family, fd, c;
231 socklen_t len;
232 size_t cur, i = 0;
233 struct http *http;
234
235 /* Do this while we still have addresses to connect. */
236 again:
237 if (i == addrsz)
238 return NULL;
239 cur = i++;
240
241 /* Convert to PF_INET or PF_INET6 address from string. */
242
243 memset(&ss, 0, sizeof(struct sockaddr_storage));
244
245 if (addrs[cur].family == 4) {
246 family = PF_INET;
247 ((struct sockaddr_in *)&ss)->sin_family = AF_INET;
248 ((struct sockaddr_in *)&ss)->sin_port = htons(port);
249 c = inet_pton(AF_INET, addrs[cur].ip,
250 &((struct sockaddr_in *)&ss)->sin_addr);
251 len = sizeof(struct sockaddr_in);
252 } else if (addrs[cur].family == 6) {
253 family = PF_INET6;
254 ((struct sockaddr_in6 *)&ss)->sin6_family = AF_INET6;
255 ((struct sockaddr_in6 *)&ss)->sin6_port = htons(port);
256 c = inet_pton(AF_INET6, addrs[cur].ip,
257 &((struct sockaddr_in6 *)&ss)->sin6_addr);
258 len = sizeof(struct sockaddr_in6);
259 } else {
260 warnx("%s: unknown family", addrs[cur].ip);
261 goto again;
262 }
263
264 if (c < 0) {
265 warn("%s: inet_ntop", addrs[cur].ip);
266 goto again;
267 } else if (c == 0) {
268 warnx("%s: inet_ntop", addrs[cur].ip);
269 goto again;
270 }
271
272 /* Create socket and connect. */
273
274 fd = socket(family, SOCK_STREAM, 0);
275 if (fd == -1) {
276 warn("%s: socket", addrs[cur].ip);
277 goto again;
278 } else if (connect(fd, (struct sockaddr *)&ss, len) == -1) {
279 warn("%s: connect", addrs[cur].ip);
280 close(fd);
281 goto again;
282 }
283
284 /* Allocate the communicator. */
285
286 http = calloc(1, sizeof(struct http));
287 if (http == NULL) {
288 warn("calloc");
289 close(fd);
290 return NULL;
291 }
292 http->fd = fd;
293 http->port = port;
294 http->src.family = addrs[cur].family;
295 http->src.ip = strdup(addrs[cur].ip);
296 http->host = strdup(host);
297 http->path = strdup(path);
298 if (http->src.ip == NULL || http->host == NULL || http->path == NULL) {
299 warn("strdup");
300 goto err;
301 }
302
303 /* If necessary, do our TLS setup. */
304
305 if (port != 443) {
306 http->writer = dosyswrite;
307 http->reader = dosysread;
308 return http;
309 }
310
311 http->writer = dotlswrite;
312 http->reader = dotlsread;
313
314 if ((http->ctx = tls_client()) == NULL) {
315 warn("tls_client");
316 goto err;
317 } else if (tls_configure(http->ctx, tlscfg) == -1) {
318 warnx("%s: tls_configure: %s",
319 http->src.ip, tls_error(http->ctx));
320 goto err;
321 }
322
323 if (tls_connect_socket(http->ctx, http->fd, http->host) != 0) {
324 warnx("%s: tls_connect_socket: %s, %s", http->src.ip,
325 http->host, tls_error(http->ctx));
326 goto err;
327 }
328
329 return http;
330 err:
331 http_free(http);
332 return NULL;
333 }
334
335 struct httpxfer *
http_open(const struct http * http,const void * p,size_t psz)336 http_open(const struct http *http, const void *p, size_t psz)
337 {
338 char *req;
339 int c;
340 struct httpxfer *trans;
341
342 if (p == NULL) {
343 c = asprintf(&req,
344 "GET %s HTTP/1.0\r\n"
345 "Host: %s\r\n"
346 "\r\n",
347 http->path, http->host);
348 } else {
349 c = asprintf(&req,
350 "POST %s HTTP/1.0\r\n"
351 "Host: %s\r\n"
352 "Content-Type: application/ocsp-request\r\n"
353 "Content-Length: %zu\r\n"
354 "\r\n",
355 http->path, http->host, psz);
356 }
357 if (c == -1) {
358 warn("asprintf");
359 return NULL;
360 } else if (!http_write(req, c, http)) {
361 free(req);
362 return NULL;
363 } else if (p != NULL && !http_write(p, psz, http)) {
364 free(req);
365 return NULL;
366 }
367
368 free(req);
369
370 trans = calloc(1, sizeof(struct httpxfer));
371 if (trans == NULL)
372 warn("calloc");
373 return trans;
374 }
375
376 void
http_close(struct httpxfer * x)377 http_close(struct httpxfer *x)
378 {
379
380 if (x == NULL)
381 return;
382 free(x->hbuf);
383 free(x->bbuf);
384 free(x->headbuf);
385 free(x->head);
386 free(x);
387 }
388
389 /*
390 * Read the HTTP body from the wire.
391 * If invoked multiple times, this will return the same pointer with the
392 * same data (or NULL, if the original invocation returned NULL).
393 * Returns NULL if read or allocation errors occur.
394 * You must not free the returned pointer.
395 */
396 char *
http_body_read(const struct http * http,struct httpxfer * trans,size_t * sz)397 http_body_read(const struct http *http, struct httpxfer *trans, size_t *sz)
398 {
399 char buf[BUFSIZ];
400 ssize_t ssz;
401 void *pp;
402 size_t szp;
403
404 if (sz == NULL)
405 sz = &szp;
406
407 /* Have we already parsed this? */
408
409 if (trans->bodyok > 0) {
410 *sz = trans->bbufsz;
411 return trans->bbuf;
412 } else if (trans->bodyok < 0)
413 return NULL;
414
415 *sz = 0;
416 trans->bodyok = -1;
417
418 do {
419 /* If less than sizeof(buf), at EOF. */
420 if ((ssz = http_read(buf, sizeof(buf), http)) < 0)
421 return NULL;
422 else if (ssz == 0)
423 break;
424
425 pp = recallocarray(trans->bbuf,
426 trans->bbufsz, trans->bbufsz + ssz, 1);
427 if (pp == NULL) {
428 warn("recallocarray");
429 return NULL;
430 }
431 trans->bbuf = pp;
432 memcpy(trans->bbuf + trans->bbufsz, buf, ssz);
433 trans->bbufsz += ssz;
434 } while (ssz == sizeof(buf));
435
436 trans->bodyok = 1;
437 *sz = trans->bbufsz;
438 return trans->bbuf;
439 }
440
441 struct httphead *
http_head_get(const char * v,struct httphead * h,size_t hsz)442 http_head_get(const char *v, struct httphead *h, size_t hsz)
443 {
444 size_t i;
445
446 for (i = 0; i < hsz; i++) {
447 if (strcmp(h[i].key, v))
448 continue;
449 return &h[i];
450 }
451 return NULL;
452 }
453
454 /*
455 * Look through the headers and determine our HTTP code.
456 * This will return -1 on failure, otherwise the code.
457 */
458 int
http_head_status(const struct http * http,struct httphead * h,size_t sz)459 http_head_status(const struct http *http, struct httphead *h, size_t sz)
460 {
461 int rc;
462 unsigned int code;
463 struct httphead *st;
464
465 if ((st = http_head_get("Status", h, sz)) == NULL) {
466 warnx("%s: no status header", http->src.ip);
467 return -1;
468 }
469
470 rc = sscanf(st->val, "%*s %u %*s", &code);
471 if (rc < 0) {
472 warn("sscanf");
473 return -1;
474 } else if (rc != 1) {
475 warnx("%s: cannot convert status header", http->src.ip);
476 return -1;
477 }
478 return code;
479 }
480
481 /*
482 * Parse headers from the transfer.
483 * Malformed headers are skipped.
484 * A special "Status" header is added for the HTTP status line.
485 * This can only happen once http_head_read has been called with
486 * success.
487 * This can be invoked multiple times: it will only parse the headers
488 * once and after that it will just return the cache.
489 * You must not free the returned pointer.
490 * If the original header parse failed, or if memory allocation fails
491 * internally, this returns NULL.
492 */
493 struct httphead *
http_head_parse(const struct http * http,struct httpxfer * trans,size_t * sz)494 http_head_parse(const struct http *http, struct httpxfer *trans, size_t *sz)
495 {
496 size_t hsz, szp;
497 struct httphead *h;
498 char *cp, *ep, *ccp, *buf;
499
500 if (sz == NULL)
501 sz = &szp;
502
503 /*
504 * If we've already parsed the headers, return the
505 * previously-parsed buffer now.
506 * If we have errors on the stream, return NULL now.
507 */
508
509 if (trans->head != NULL) {
510 *sz = trans->headsz;
511 return trans->head;
512 } else if (trans->headok <= 0)
513 return NULL;
514
515 if ((buf = strdup(trans->hbuf)) == NULL) {
516 warn("strdup");
517 return NULL;
518 }
519 hsz = 0;
520 cp = buf;
521
522 do {
523 if ((cp = strstr(cp, "\r\n")) != NULL)
524 cp += 2;
525 hsz++;
526 } while (cp != NULL);
527
528 /*
529 * Allocate headers, then step through the data buffer, parsing
530 * out headers as we have them.
531 * We know at this point that the buffer is NUL-terminated in
532 * the usual way.
533 */
534
535 h = calloc(hsz, sizeof(struct httphead));
536 if (h == NULL) {
537 warn("calloc");
538 free(buf);
539 return NULL;
540 }
541
542 *sz = hsz;
543 hsz = 0;
544 cp = buf;
545
546 do {
547 if ((ep = strstr(cp, "\r\n")) != NULL) {
548 *ep = '\0';
549 ep += 2;
550 }
551 if (hsz == 0) {
552 h[hsz].key = "Status";
553 h[hsz++].val = cp;
554 continue;
555 }
556
557 /* Skip bad headers. */
558 if ((ccp = strchr(cp, ':')) == NULL) {
559 warnx("%s: header without separator", http->src.ip);
560 continue;
561 }
562
563 *ccp++ = '\0';
564 while (isspace((int)*ccp))
565 ccp++;
566 h[hsz].key = cp;
567 h[hsz++].val = ccp;
568 } while ((cp = ep) != NULL);
569
570 trans->headbuf = buf;
571 trans->head = h;
572 trans->headsz = hsz;
573 return h;
574 }
575
576 /*
577 * Read the HTTP headers from the wire.
578 * If invoked multiple times, this will return the same pointer with the
579 * same data (or NULL, if the original invocation returned NULL).
580 * Returns NULL if read or allocation errors occur.
581 * You must not free the returned pointer.
582 */
583 char *
http_head_read(const struct http * http,struct httpxfer * trans,size_t * sz)584 http_head_read(const struct http *http, struct httpxfer *trans, size_t *sz)
585 {
586 char buf[BUFSIZ];
587 ssize_t ssz;
588 char *ep;
589 void *pp;
590 size_t szp;
591
592 if (sz == NULL)
593 sz = &szp;
594
595 /* Have we already parsed this? */
596
597 if (trans->headok > 0) {
598 *sz = trans->hbufsz;
599 return trans->hbuf;
600 } else if (trans->headok < 0)
601 return NULL;
602
603 *sz = 0;
604 ep = NULL;
605 trans->headok = -1;
606
607 /*
608 * Begin by reading by BUFSIZ blocks until we reach the header
609 * termination marker (two CRLFs).
610 * We might read into our body, but that's ok: we'll copy out
611 * the body parts into our body buffer afterward.
612 */
613
614 do {
615 /* If less than sizeof(buf), at EOF. */
616 if ((ssz = http_read(buf, sizeof(buf), http)) < 0)
617 return NULL;
618 else if (ssz == 0)
619 break;
620 pp = realloc(trans->hbuf, trans->hbufsz + ssz);
621 if (pp == NULL) {
622 warn("realloc");
623 return NULL;
624 }
625 trans->hbuf = pp;
626 memcpy(trans->hbuf + trans->hbufsz, buf, ssz);
627 trans->hbufsz += ssz;
628 /* Search for end of headers marker. */
629 ep = memmem(trans->hbuf, trans->hbufsz, "\r\n\r\n", 4);
630 } while (ep == NULL && ssz == sizeof(buf));
631
632 if (ep == NULL) {
633 warnx("%s: partial transfer", http->src.ip);
634 return NULL;
635 }
636 *ep = '\0';
637
638 /*
639 * The header data is invalid if it has any binary characters in
640 * it: check that now.
641 * This is important because we want to guarantee that all
642 * header keys and pairs are properly NUL-terminated.
643 */
644
645 if (strlen(trans->hbuf) != (uintptr_t)(ep - trans->hbuf)) {
646 warnx("%s: binary data in header", http->src.ip);
647 return NULL;
648 }
649
650 /*
651 * Copy remaining buffer into body buffer.
652 */
653
654 ep += 4;
655 trans->bbufsz = (trans->hbuf + trans->hbufsz) - ep;
656 trans->bbuf = malloc(trans->bbufsz);
657 if (trans->bbuf == NULL) {
658 warn("malloc");
659 return NULL;
660 }
661 memcpy(trans->bbuf, ep, trans->bbufsz);
662
663 trans->headok = 1;
664 *sz = trans->hbufsz;
665 return trans->hbuf;
666 }
667
668 void
http_get_free(struct httpget * g)669 http_get_free(struct httpget *g)
670 {
671
672 if (g == NULL)
673 return;
674 http_close(g->xfer);
675 http_free(g->http);
676 free(g);
677 }
678
679 struct httpget *
http_get(const struct source * addrs,size_t addrsz,const char * domain,short port,const char * path,const void * post,size_t postsz)680 http_get(const struct source *addrs, size_t addrsz, const char *domain,
681 short port, const char *path, const void *post, size_t postsz)
682 {
683 struct http *h;
684 struct httpxfer *x;
685 struct httpget *g;
686 struct httphead *head;
687 size_t headsz, bodsz, headrsz;
688 int code;
689 char *bod, *headr;
690
691 h = http_alloc(addrs, addrsz, domain, port, path);
692 if (h == NULL)
693 return NULL;
694
695 if ((x = http_open(h, post, postsz)) == NULL) {
696 http_free(h);
697 return NULL;
698 } else if ((headr = http_head_read(h, x, &headrsz)) == NULL) {
699 http_close(x);
700 http_free(h);
701 return NULL;
702 } else if ((bod = http_body_read(h, x, &bodsz)) == NULL) {
703 http_close(x);
704 http_free(h);
705 return NULL;
706 }
707
708 http_disconnect(h);
709
710 if ((head = http_head_parse(h, x, &headsz)) == NULL) {
711 http_close(x);
712 http_free(h);
713 return NULL;
714 } else if ((code = http_head_status(h, head, headsz)) < 0) {
715 http_close(x);
716 http_free(h);
717 return NULL;
718 }
719
720 if ((g = calloc(1, sizeof(struct httpget))) == NULL) {
721 warn("calloc");
722 http_close(x);
723 http_free(h);
724 return NULL;
725 }
726
727 g->headpart = headr;
728 g->headpartsz = headrsz;
729 g->bodypart = bod;
730 g->bodypartsz = bodsz;
731 g->head = head;
732 g->headsz = headsz;
733 g->code = code;
734 g->xfer = x;
735 g->http = h;
736 return g;
737 }
738
739 #if 0
740 int
741 main(void)
742 {
743 struct httpget *g;
744 struct httphead *httph;
745 size_t i, httphsz;
746 struct source addrs[2];
747 size_t addrsz;
748
749 #if 0
750 addrs[0].ip = "127.0.0.1";
751 addrs[0].family = 4;
752 addrsz = 1;
753 #else
754 addrs[0].ip = "2a00:1450:400a:806::2004";
755 addrs[0].family = 6;
756 addrs[1].ip = "193.135.3.123";
757 addrs[1].family = 4;
758 addrsz = 2;
759 #endif
760
761 if (http_init() == -1)
762 errx(EXIT_FAILURE, "http_init");
763
764 #if 0
765 g = http_get(addrs, addrsz, "localhost", 80, "/index.html");
766 #else
767 g = http_get(addrs, addrsz, "www.google.ch", 80, "/index.html",
768 NULL, 0);
769 #endif
770
771 if (g == NULL)
772 errx(EXIT_FAILURE, "http_get");
773
774 httph = http_head_parse(g->http, g->xfer, &httphsz);
775 warnx("code: %d", g->code);
776
777 for (i = 0; i < httphsz; i++)
778 warnx("head: [%s]=[%s]", httph[i].key, httph[i].val);
779
780 http_get_free(g);
781 return (EXIT_SUCCESS);
782 }
783 #endif
784