Another copy of my dotfiles. Because I don't completely trust GitHub.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

314 lines
8.0 KiB

  1. /* See LICENSE file for copyright and license details. */
  2. #include <errno.h>
  3. #include <netinet/in.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <sys/socket.h>
  7. #include <sys/types.h>
  8. #include <time.h>
  9. #include <unistd.h>
  10. #include "connection.h"
  11. #include "data.h"
  12. #include "http.h"
  13. #include "server.h"
  14. #include "sock.h"
  15. #include "util.h"
  16. struct worker_data {
  17. int insock;
  18. size_t nslots;
  19. const struct server *srv;
  20. };
  21. void
  22. connection_log(const struct connection *c)
  23. {
  24. char inaddr_str[INET6_ADDRSTRLEN /* > INET_ADDRSTRLEN */];
  25. char tstmp[21];
  26. /* create timestamp */
  27. if (!strftime(tstmp, sizeof(tstmp), "%Y-%m-%dT%H:%M:%SZ",
  28. gmtime(&(time_t){time(NULL)}))) {
  29. warn("strftime: Exceeded buffer capacity");
  30. /* continue anyway (we accept the truncation) */
  31. }
  32. /* generate address-string */
  33. if (sock_get_inaddr_str(&c->ia, inaddr_str, LEN(inaddr_str))) {
  34. warn("sock_get_inaddr_str: Couldn't generate adress-string");
  35. inaddr_str[0] = '\0';
  36. }
  37. printf("%s\t%s\t%s%.*d\t%s\t%s%s%s%s%s\n",
  38. tstmp,
  39. inaddr_str,
  40. (c->res.status == 0) ? "dropped" : "",
  41. (c->res.status == 0) ? 0 : 3,
  42. c->res.status,
  43. c->req.field[REQ_HOST][0] ? c->req.field[REQ_HOST] : "-",
  44. c->req.path[0] ? c->req.path : "-",
  45. c->req.query[0] ? "?" : "",
  46. c->req.query,
  47. c->req.fragment[0] ? "#" : "",
  48. c->req.fragment);
  49. }
  50. void
  51. connection_reset(struct connection *c)
  52. {
  53. if (c != NULL) {
  54. shutdown(c->fd, SHUT_RDWR);
  55. close(c->fd);
  56. memset(c, 0, sizeof(*c));
  57. }
  58. }
  59. void
  60. connection_serve(struct connection *c, const struct server *srv)
  61. {
  62. enum status s;
  63. int done;
  64. switch (c->state) {
  65. case C_VACANT:
  66. /*
  67. * we were passed a "fresh" connection which should now
  68. * try to receive the header, reset buf beforehand
  69. */
  70. memset(&c->buf, 0, sizeof(c->buf));
  71. c->state = C_RECV_HEADER;
  72. /* fallthrough */
  73. case C_RECV_HEADER:
  74. /* receive header */
  75. done = 0;
  76. if ((s = http_recv_header(c->fd, &c->buf, &done))) {
  77. http_prepare_error_response(&c->req, &c->res, s);
  78. goto response;
  79. }
  80. if (!done) {
  81. /* not done yet */
  82. return;
  83. }
  84. /* parse header */
  85. if ((s = http_parse_header(c->buf.data, &c->req))) {
  86. http_prepare_error_response(&c->req, &c->res, s);
  87. goto response;
  88. }
  89. /* prepare response struct */
  90. http_prepare_response(&c->req, &c->res, srv);
  91. response:
  92. /* generate response header */
  93. if ((s = http_prepare_header_buf(&c->res, &c->buf))) {
  94. http_prepare_error_response(&c->req, &c->res, s);
  95. if ((s = http_prepare_header_buf(&c->res, &c->buf))) {
  96. /* couldn't generate the header, we failed for good */
  97. c->res.status = s;
  98. goto err;
  99. }
  100. }
  101. c->state = C_SEND_HEADER;
  102. /* fallthrough */
  103. case C_SEND_HEADER:
  104. if ((s = http_send_buf(c->fd, &c->buf))) {
  105. c->res.status = s;
  106. goto err;
  107. }
  108. if (c->buf.len > 0) {
  109. /* not done yet */
  110. return;
  111. }
  112. c->state = C_SEND_BODY;
  113. /* fallthrough */
  114. case C_SEND_BODY:
  115. if (c->req.method == M_GET) {
  116. if (c->buf.len == 0) {
  117. /* fill buffer with body data */
  118. if ((s = data_fct[c->res.type](&c->res, &c->buf,
  119. &c->progress))) {
  120. /* too late to do any real error handling */
  121. c->res.status = s;
  122. goto err;
  123. }
  124. /* if the buffer remains empty, we are done */
  125. if (c->buf.len == 0) {
  126. break;
  127. }
  128. } else {
  129. /* send buffer */
  130. if ((s = http_send_buf(c->fd, &c->buf))) {
  131. /* too late to do any real error handling */
  132. c->res.status = s;
  133. goto err;
  134. }
  135. }
  136. return;
  137. }
  138. break;
  139. default:
  140. warn("serve: invalid connection state");
  141. return;
  142. }
  143. err:
  144. connection_log(c);
  145. connection_reset(c);
  146. }
  147. static struct connection *
  148. connection_get_drop_candidate(struct connection *connection, size_t nslots)
  149. {
  150. struct connection *c, *minc;
  151. size_t i, j, maxcnt, cnt;
  152. /*
  153. * determine the most-unimportant connection 'minc' of the in-address
  154. * with most connections; this algorithm has a complexity of O(n²)
  155. * in time but is O(1) in space; there are algorithms with O(n) in
  156. * time and space, but this would require memory allocation,
  157. * which we avoid. Given the simplicity of the inner loop and
  158. * relatively small number of slots per thread, this is fine.
  159. */
  160. for (i = 0, minc = NULL, maxcnt = 0; i < nslots; i++) {
  161. /*
  162. * we determine how many connections have the same
  163. * in-address as connection[i], but also minimize over
  164. * that set with other criteria, yielding a general
  165. * minimizer c. We first set it to connection[i] and
  166. * update it, if a better candidate shows up, in the inner
  167. * loop
  168. */
  169. c = &connection[i];
  170. for (j = 0, cnt = 0; j < nslots; j++) {
  171. if (!sock_same_addr(&connection[i].ia,
  172. &connection[j].ia)) {
  173. continue;
  174. }
  175. cnt++;
  176. /* minimize over state */
  177. if (connection[j].state < c->state) {
  178. c = &connection[j];
  179. } else if (connection[j].state == c->state) {
  180. /* minimize over progress */
  181. if (c->state == C_SEND_BODY &&
  182. connection[i].res.type != c->res.type) {
  183. /*
  184. * mixed response types; progress
  185. * is not comparable
  186. *
  187. * the res-type-enum is ordered as
  188. * DIRLISTING, ERROR, FILE, i.e.
  189. * in rising priority, because a
  190. * file transfer is most important,
  191. * followed by error-messages.
  192. * Dirlistings as an "interactive"
  193. * feature (that take up lots of
  194. * resources) have the lowest
  195. * priority
  196. */
  197. if (connection[i].res.type <
  198. c->res.type) {
  199. c = &connection[j];
  200. }
  201. } else if (connection[j].progress <
  202. c->progress) {
  203. /*
  204. * for C_SEND_BODY with same response
  205. * type, C_RECV_HEADER and C_SEND_BODY
  206. * it is sufficient to compare the
  207. * raw progress
  208. */
  209. c = &connection[j];
  210. }
  211. }
  212. }
  213. if (cnt > maxcnt) {
  214. /* this run yielded an even greedier in-address */
  215. minc = c;
  216. maxcnt = cnt;
  217. }
  218. }
  219. return minc;
  220. }
  221. struct connection *
  222. connection_accept(int insock, struct connection *connection, size_t nslots)
  223. {
  224. struct connection *c = NULL;
  225. size_t i;
  226. /* find vacant connection (i.e. one with no fd assigned to it) */
  227. for (i = 0; i < nslots; i++) {
  228. if (connection[i].fd == 0) {
  229. c = &connection[i];
  230. break;
  231. }
  232. }
  233. if (i == nslots) {
  234. /*
  235. * all our connection-slots are occupied and the only
  236. * way out is to drop another connection, because not
  237. * accepting this connection just kicks this can further
  238. * down the road (to the next queue_wait()) without
  239. * solving anything.
  240. *
  241. * This may sound bad, but this case can only be hit
  242. * either when there's a (D)DoS-attack or a massive
  243. * influx of requests. The latter is impossible to solve
  244. * at this moment without expanding resources, but the
  245. * former has certain characteristics allowing us to
  246. * handle this gracefully.
  247. *
  248. * During an attack (e.g. Slowloris, R-U-Dead-Yet, Slow
  249. * Read or just plain flooding) we can not see who is
  250. * waiting to be accept()ed.
  251. * However, an attacker usually already has many
  252. * connections open (while well-behaved clients could
  253. * do everything with just one connection using
  254. * keep-alive). Inferring a likely attacker-connection
  255. * is an educated guess based on which in-address is
  256. * occupying the most connection slots. Among those,
  257. * connections in early stages (receiving or sending
  258. * headers) are preferred over connections in late
  259. * stages (sending body).
  260. *
  261. * This quantitative approach effectively drops malicious
  262. * connections while preserving even long-running
  263. * benevolent connections like downloads.
  264. */
  265. c = connection_get_drop_candidate(connection, nslots);
  266. c->res.status = 0;
  267. connection_log(c);
  268. connection_reset(c);
  269. }
  270. /* accept connection */
  271. if ((c->fd = accept(insock, (struct sockaddr *)&c->ia,
  272. &(socklen_t){sizeof(c->ia)})) < 0) {
  273. if (errno != EAGAIN && errno != EWOULDBLOCK) {
  274. /*
  275. * this should not happen, as we received the
  276. * event that there are pending connections here
  277. */
  278. warn("accept:");
  279. }
  280. return NULL;
  281. }
  282. /* set socket to non-blocking mode */
  283. if (sock_set_nonblocking(c->fd)) {
  284. /* we can't allow blocking sockets */
  285. return NULL;
  286. }
  287. return c;
  288. }