coverity 156864 fuzxy close socket if connect fails
[platform/upstream/libwebsockets.git] / test-server / fuzxy.c
1 /*
2  * fuzzing proxy - network-level fuzzing injection proxy
3  *
4  * Copyright (C) 2016 Andy Green <andy@warmcat.com>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation:
9  *  version 2.1 of the License.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  *  MA  02110-1301  USA
20  *
21  *
22  * fuzxy is designed to go on the client path
23  *
24  * [ client <-> fuzxy ] <-> server
25  *
26  * you can arrange that with, eg,
27  *
28  *  http_proxy=localhost:8880
29  *
30  * env var before starting the client.
31  *
32  * Even though he is on the client side, he is able to see and change traffic
33  * in both directions, and so fuzz both the client and the server.
34  */
35
36 #if defined(_WIN32) && defined(EXTERNAL_POLL)
37 #define WINVER 0x0600
38 #define _WIN32_WINNT 0x0600
39 #define poll(fdArray, fds, timeout)  WSAPoll((LPWSAPOLLFD)(fdArray), (ULONG)(fds), (INT)(timeout))
40 #endif
41
42 #include "lws_config.h"
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <getopt.h>
47 #include <signal.h>
48 #include <string.h>
49 #include <sys/stat.h>
50 #include <fcntl.h>
51 #include <assert.h>
52 #include <errno.h>
53 #include "../lib/libwebsockets.h"
54
55 #ifdef _WIN32
56 #include <io.h>
57 #include "gettimeofday.h"
58 #else
59 #include <syslog.h>
60 #include <sys/time.h>
61 #include <unistd.h>
62 #endif
63
64
65 enum types {
66         FZY_S_DEAD              = 0,
67         FZY_S_LISTENING         = 1,
68         FZY_S_ACCEPTED          = 2,
69         FZY_S_PROXIED           = 3,
70         FZY_S_ONWARD            = 4,
71 };
72
73 enum proxy_parser_states {
74         FZY_PP_CONNECT          = 0,
75         FZY_PP_ADDRESS          = 1,
76         FZY_PP_PORT             = 2,
77         FZY_PP_CRLFS            = 3,
78 };
79
80 enum fuzzer_parser_states {
81         FZY_FP_SEARCH           = 0,
82         FZY_FP_SEARCH2          = 1,
83         FZY_FP_INJECT           = 2,
84         FZY_FP_PENDING          = 3,
85 };
86
87 struct ring {
88         char buf[4096];
89         int head;
90         int tail;
91 };
92
93 struct state {
94         enum types type;
95         enum proxy_parser_states pp;
96         int ppc;
97
98         struct ring in;
99
100         char address[256];
101         int port;
102
103         enum fuzzer_parser_states fp;
104         int fuzc;
105         int pending;
106
107         int twin; /* must be fixed up when arrays lose guys */
108         unsigned int outbound:1; /* from local -> remote */
109 };
110
111
112 int force_exit = 0;
113
114 static const int ring_size(struct ring *r)
115 {
116         return sizeof(r->buf);
117 }
118 static const int ring_used(struct ring *r)
119 {
120         return (r->head - r->tail) & (ring_size(r) - 1);
121 }
122 static const int ring_free(struct ring *r)
123 {
124         return (ring_size(r) - 1) - ring_used(r);
125 }
126 static const int ring_get_one(struct ring *r)
127 {
128         int n = r->buf[r->tail] & 255;
129
130         if (r->tail == r->head)
131                 return -1;
132
133         r->tail++;
134         if (r->tail == ring_size(r))
135                 r->tail = 0;
136
137         return n;
138 }
139
140 void sighandler(int sig)
141 {
142         force_exit = 1;
143 }
144
145 static struct option options[] = {
146         { "help",       no_argument,            NULL, 'h' },
147         { "debug",      required_argument,      NULL, 'd' },
148         { "port",       required_argument,      NULL, 'p' },
149         { "ssl",        no_argument,            NULL, 's' },
150         { "allow-non-ssl",      no_argument,    NULL, 'a' },
151         { "interface",  required_argument,      NULL, 'i' },
152         { "closetest",  no_argument,            NULL, 'c' },
153         { "libev",  no_argument,                NULL, 'e' },
154 #ifndef LWS_NO_DAEMONIZE
155         { "daemonize",  no_argument,            NULL, 'D' },
156 #endif
157         { "resource_path", required_argument,   NULL, 'r' },
158         { NULL, 0, 0, 0 }
159 };
160
161 static struct pollfd pfd[128];
162 static struct state state[128];
163 static int pfds = 0;
164
165 static void close_and_remove_fd(int index)
166 {
167         int n;
168
169         lwsl_notice("%s: closing index %d\n", __func__, index);
170         close(pfd[index].fd);
171         pfd[index].fd = -1;
172
173         n = state[index].twin;
174         if (n) {
175                 assert(state[n].twin == index);
176         }
177         state[index].type = FZY_S_DEAD;
178
179         if (index == pfds - 1) {
180                 if (state[index].twin)
181                         state[state[index].twin].twin = 0;
182                 state[index].twin = 0;
183                 goto bail;
184         }
185
186         /* swap the end guy into the deleted guy and trim back one */
187
188         if (state[pfds - 1].twin) {
189                 state[state[pfds - 1].twin].twin = index;
190                 if (n && n == pfds - 1)
191                         n = index;
192         }
193
194         /* swap the last guy into dead guy's place and trim by one */
195         pfd[index] = pfd[pfds - 1];
196         state[index] = state[pfds - 1];
197
198         if (n) {
199                 pfds--;
200                 state[n].twin = 0;
201                 close_and_remove_fd(n);
202                 return;
203         }
204
205 bail:
206         pfds--;
207 }
208
209 static void construct_state(int n, enum types s, int flags)
210 {
211         memset(&state[n], 0, sizeof state[n]);
212         state[n].type = s;
213         pfd[n].events = flags | POLLHUP;
214 }
215
216 static int
217 fuzxy_listen(const char *interface_name, int port, int *sockfd)
218 {
219         struct sockaddr_in serv_addr4;
220         socklen_t len = sizeof(struct sockaddr);
221         struct sockaddr_in sin;
222         int n, opt = 1;
223
224         *sockfd = socket(AF_INET, SOCK_STREAM, 0);
225
226         if (*sockfd == -1) {
227                 lwsl_err("ERROR opening socket\n");
228                 goto bail1;
229         }
230
231         if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR,
232                        (const void *)&opt, sizeof(opt)) < 0) {
233                 lwsl_err("unable to set listen socket options\n");
234                 goto bail2;
235         }
236
237         bzero((char *) &serv_addr4, sizeof(serv_addr4));
238         serv_addr4.sin_addr.s_addr = INADDR_ANY;
239         serv_addr4.sin_family = AF_INET;
240
241         if (interface_name[0] &&
242             lws_interface_to_sa(0, interface_name, (struct sockaddr_in *)
243                                 (struct sockaddr *)&serv_addr4,
244                                 sizeof(serv_addr4)) < 0) {
245                 lwsl_err("Unable to find interface %s\n", interface_name);
246                 goto bail2;
247         }
248
249         serv_addr4.sin_port = htons(port);
250
251         n = bind(*sockfd, (struct sockaddr *)&serv_addr4,
252                                 sizeof(serv_addr4));
253         if (n < 0) {
254                 lwsl_err("ERROR on binding to port %d (%d %d)\n",
255                          port, n, errno);
256                 goto bail2;
257         }
258
259         if (getsockname(*sockfd, (struct sockaddr *)&sin, &len) == -1)
260                 lwsl_warn("getsockname: %s\n", strerror(errno));
261         else
262                 port = ntohs(sin.sin_port);
263
264         listen(*sockfd, SOMAXCONN);
265
266         return 0;
267 bail2:
268         close(*sockfd);
269 bail1:
270         return -1;
271 }
272
273 struct fuzxy_rule {
274         const char *s[3];
275         int len[3];
276         int inject_len;
277 };
278
279 struct fuzxy_rule r = {
280                 { "Host:", "\x0d", " \x0d" },
281                 { 5, 1, 2 },
282                 65536
283 };
284
285 static int fuzz(int n, char *out, int len)
286 {
287         struct state *s = &state[n];
288         int m = 0;
289         int c;
290
291         while (m < len) {
292                 switch (s->fp) {
293                 case FZY_FP_SEARCH:
294                         c = ring_get_one(&state[s->twin].in);
295                         if (c < 0)
296                                 return m;
297                         if (c == r.s[0][s->fuzc++]) {
298                                 if (s->fuzc == r.len[0]) {
299                                         s->fuzc = 0;
300                                         s->fp = FZY_FP_SEARCH2;
301                                 }
302                         } else
303                                 s->fuzc = 0;
304                         out[m++] = c;
305                         break;
306
307                 case FZY_FP_SEARCH2:
308                         c = ring_get_one(&state[s->twin].in);
309                         if (c < 0)
310                                 return m;
311                         if (c == r.s[1][s->fuzc++]) {
312                                 if (s->fuzc == r.len[1]) {
313                                         lwsl_notice("+++++++fuzzer hit...\n");
314                                         s->fuzc = 0;
315                                         s->fp = FZY_FP_INJECT;
316                                         s->pending = c;
317                                         goto inject;
318                                 }
319                         } else
320                                 s->fuzc = 0;
321                         out[m++] = c;
322                         break;
323                 case FZY_FP_INJECT:
324 inject:
325                         out[m++] = r.s[2][s->fuzc++ % r.len[2]];
326                         if (s->fuzc == r.inject_len)
327                                 s->fp = FZY_FP_PENDING;
328                         break;
329
330                 case FZY_FP_PENDING:
331                         out[m++] = s->pending;
332                         s->fp = FZY_FP_SEARCH;
333                         s->fuzc = 0;
334                         break;
335                 }
336         }
337
338         return m;
339 }
340
341 static int
342 handle_accept(int n)
343 {
344         struct addrinfo ai, *res, *result;
345         struct sockaddr_in serv_addr4;
346         struct state *s = &state[n];
347         void *p = NULL;
348         int m, sockfd;
349
350         while (1) {
351                 m = ring_get_one(&s->in);
352                 if (m < 0)
353                         return 0;
354
355                 switch (s->pp) {
356                 case FZY_PP_CONNECT:
357                         if (m != "CONNECT "[s->ppc++]) {
358                                 lwsl_notice("failed CONNECT match\n");
359                                 return 1;
360                         }
361                         if (s->ppc == 8) {
362                                 s->pp = FZY_PP_ADDRESS;
363                                 s->ppc = 0;
364                         }
365                         break;
366                 case FZY_PP_ADDRESS:
367                         if (m == ':') {
368                                 s->address[s->ppc++] = '\0';
369                                 s->pp = FZY_PP_PORT;
370                                 s->ppc = 0;
371                                 break;
372                         }
373                         if (m == ' ') {
374                                 s->address[s->ppc++] = '\0';
375                                 s->pp = FZY_PP_CRLFS;
376                                 s->ppc = 0;
377                                 break;
378                         }
379
380
381                         s->address[s->ppc++] = m;
382                         if (s->ppc == sizeof(s->address)) {
383                                 lwsl_notice("Failed on address length\n");
384                                 return 1;
385                         }
386                         break;
387                 case FZY_PP_PORT:
388                         if (m == ' ') {
389                                 s->pp = FZY_PP_CRLFS;
390                                 s->ppc = 0;
391                                 break;
392                         }
393                         if (m >= '0' && m <= '9') {
394                                 s->port *= 10;
395                                 s->port += m - '0';
396                                 break;
397                         }
398                         return 1;
399
400                 case FZY_PP_CRLFS:
401                         if (m != "\x0d\x0a\x0d\x0a"[s->ppc++])
402                                 s->ppc = 0;
403                         if (s->ppc != 4)
404                                 break;
405                         s->type = FZY_S_PROXIED;
406
407                         memset (&ai, 0, sizeof ai);
408                         ai.ai_family = PF_UNSPEC;
409                         ai.ai_socktype = SOCK_STREAM;
410                         ai.ai_flags = AI_CANONNAME;
411
412                         if (getaddrinfo(s->address, NULL, &ai, &result)) {
413                                 lwsl_notice("failed to lookup %s\n",
414                                             s->address);
415                                 return 1;
416                         }
417
418                         res = result;
419                         while (!p && res) {
420                                 switch (res->ai_family) {
421                                 case AF_INET:
422                                         p = &((struct sockaddr_in *)res->
423                                               ai_addr)->sin_addr;
424                                         break;
425                                 }
426
427                                 res = res->ai_next;
428                         }
429
430                         if (!p) {
431                                 lwsl_notice("Failed to get address result %s\n",
432                                             s->address);
433                                 freeaddrinfo(result);
434                                 return 1;
435                         }
436
437                         serv_addr4.sin_family = AF_INET;
438                         serv_addr4.sin_addr = *((struct in_addr *)p);
439                         serv_addr4.sin_port = htons(s->port);
440                         bzero(&serv_addr4.sin_zero, 8);
441                         freeaddrinfo(result);
442
443                         lwsl_err("Conn %d req '%s' port %d\n", n,
444                                  s->address, s->port);
445                         /* we need to open the associated onward connection */
446                         sockfd = socket(AF_INET, SOCK_STREAM, 0);
447                         if (sockfd < 0) {
448                                 lwsl_err("Could not get socket\n");
449                                 return -1;
450                         }
451
452                         if (connect(sockfd, (struct sockaddr *)&serv_addr4,
453                                     sizeof(struct sockaddr)) == -1 ||
454                             errno == EISCONN) {
455                                 close(sockfd);
456                                 lwsl_err("proxied onward connection failed\n");
457                                 return 1;
458                         }
459                         s->twin = pfds;
460                         construct_state(pfds, FZY_S_ONWARD,
461                                         POLLOUT | POLLIN | POLLERR);
462                         state[pfds].twin = n;
463                         lwsl_notice("binding conns %d and %d\n", n, pfds);
464                         state[pfds].outbound = s->outbound;
465                         state[pfds].ppc = 0;
466                         pfd[pfds++].fd = sockfd;
467
468                         lwsl_notice("onward connection in progress\n");
469                         if (ring_used(&s->in))
470                                 pfd[s->twin].events |= POLLOUT;
471                         if (write(pfd[n].fd,
472                                   "HTTP/1.0 200 \x0d\x0a\x0d\x0a", 17) < 17)
473                                 return 1;
474                 }
475         }
476
477         return 0;
478 }
479
480 static void sigpipe_handler(int x)
481 {
482 }
483
484 int
485 main(int argc, char **argv)
486 {
487         char interface_name[128] = "", interface_name_local[128] = "lo";
488         int port_local = 8880, accept_fd;
489         struct sockaddr_in cli_addr;
490         int debug_level = 7;
491         socklen_t clilen;
492         struct state *s;
493         char out[4096];
494         int opts = 0;
495         int n = 0, m;
496
497 #ifndef _WIN32
498         int syslog_options = LOG_PID | LOG_PERROR;
499 #endif
500 #ifndef LWS_NO_DAEMONIZE
501         int daemonize = 0;
502 #endif
503         signal(SIGPIPE, sigpipe_handler);
504
505         while (n >= 0) {
506                 n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL);
507                 if (n < 0)
508                         continue;
509                 switch (n) {
510                 case 'e':
511                         opts |= LWS_SERVER_OPTION_LIBEV;
512                         break;
513 #ifndef LWS_NO_DAEMONIZE
514                 case 'D':
515                         daemonize = 1;
516                         #ifndef _WIN32
517                         syslog_options &= ~LOG_PERROR;
518                         #endif
519                         break;
520 #endif
521                 case 'd':
522                         debug_level = atoi(optarg);
523                         break;
524                 case 'p':
525                         port_local = atoi(optarg);
526                         break;
527                 case 'i':
528                         strncpy(interface_name, optarg, sizeof interface_name);
529                         interface_name[(sizeof interface_name) - 1] = '\0';
530                         break;
531                 case 'h':
532                         fprintf(stderr, "Usage: libwebsockets-test-fuzxy "
533                                         "[--port=<p>] [--ssl] "
534                                         "[-d <log bitfield>] "
535                                         "[--resource_path <path>]\n");
536                         exit(1);
537                 }
538         }
539
540 #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32)
541         /*
542          * normally lock path would be /var/lock/lwsts or similar, to
543          * simplify getting started without having to take care about
544          * permissions or running as root, set to /tmp/.lwsts-lock
545          */
546         if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) {
547                 fprintf(stderr, "Failed to daemonize\n");
548                 return 1;
549         }
550 #endif
551
552         signal(SIGINT, sighandler);
553
554 #ifndef _WIN32
555         /* we will only try to log things according to our debug_level */
556         setlogmask(LOG_UPTO (LOG_DEBUG));
557         openlog("fuzxy", syslog_options, LOG_DAEMON);
558 #endif
559
560         /* tell the library what debug level to emit and to send it to syslog */
561         lws_set_log_level(debug_level, lwsl_emit_syslog);
562
563         lwsl_notice("%s\n(C) Copyright 2016 Andy Green <andy@warmcat.com> - "
564                     "licensed under LGPL2.1\n", argv[0]);
565
566         /* listen on local side */
567
568         if (fuzxy_listen(interface_name, port_local, &pfd[pfds].fd)) {
569                 lwsl_err("Failed to listen on local side\n");
570                 goto bail1;
571         }
572         construct_state(pfds, FZY_S_LISTENING, POLLIN | POLLERR);
573         pfds++;
574
575         lwsl_notice("Local side listening on %s:%u\n",
576                     interface_name_local, port_local);
577
578         while (!force_exit) {
579
580                 m = poll(pfd, pfds, 50);
581                 if (m < 0)
582                         continue;
583                 for (n = 0; n < pfds; n++) {
584                         s = &state[n];
585                         if (s->type == FZY_S_LISTENING &&
586                             (pfd[n].revents & POLLIN)) {
587                                 /* first do the accept entry */
588
589                                 clilen = sizeof(cli_addr);
590                                 accept_fd = accept(pfd[0].fd,
591                                          (struct sockaddr *)&cli_addr, &clilen);
592                                 if (accept_fd < 0) {
593                                         if (errno == EAGAIN ||
594                                             errno == EWOULDBLOCK)
595                                                 continue;
596
597                                         lwsl_warn("ERROR on accept: %s\n",
598                                                   strerror(errno));
599                                         continue;
600                                 }
601                                 construct_state(pfds, FZY_S_ACCEPTED,
602                                                 POLLIN | POLLERR);
603                                 state[pfds].outbound = n == 0;
604                                 state[pfds].pp = FZY_PP_CONNECT;
605                                 state[pfds].ppc = 0;
606                                 pfd[pfds++].fd = accept_fd;
607                                 lwsl_notice("new connect accepted\n");
608                                 continue;
609                         }
610                         if (pfd[n].revents & POLLIN) {
611                                 assert(ring_free(&s->in));
612                                 m = (ring_size(&s->in) - 1) -
613                                     s->in.head;
614                                 if (s->in.head == ring_size(&s->in) - 1 &&
615                                     s->in.tail)
616                                         m = 1;
617                                 m = read(pfd[n].fd, s->in.buf + s->in.head, m);
618 //                              lwsl_notice("read %d\n", m);
619                                 if (m <= 0)
620                                         goto drop;
621                                 s->in.head += m;
622                                 if (s->in.head == ring_size(&s->in))
623                                         s->in.head = 0;
624
625                                 switch (s->type) {
626                                 case FZY_S_ACCEPTED: /* parse proxy CONNECT */
627                                         if (handle_accept(n))
628                                                 goto drop;
629                                         break;
630                                 case FZY_S_PROXIED:
631                                 case FZY_S_ONWARD:
632                                         if (ring_used(&s->in))
633                                                 pfd[s->twin].events |= POLLOUT;
634                                         break;
635                                 default:
636                                         assert(0);
637                                         break;
638                                 }
639                                 if (s->in.head == s->in.tail) {
640                                         s->in.head = s->in.tail = 0;
641                                         pfd[n].events |= POLLIN;
642                                 }
643                                 if (!ring_free(&s->in))
644                                         pfd[n].events &= ~POLLIN;
645                         }
646                         if (pfd[n].revents & POLLOUT) {
647                                 switch (s->type) {
648                                 case FZY_S_PROXIED:
649                                 case FZY_S_ONWARD:
650                                         /*
651                                          * draw down enough of the partner's
652                                          * in ring to either exhaust it
653                                          * or fill an output buffer
654                                          */
655                                         m = fuzz(n, out, sizeof(out));
656                                         if (m) {
657                                                 m = write(pfd[n].fd, out, m);
658                                                 if (m <= 0)
659                                                         goto drop;
660                                         } else
661                                                 pfd[n].events &= ~POLLOUT;
662
663                                         if (ring_free(&state[s->twin].in))
664                                                 pfd[s->twin].events |= POLLIN;
665
666                                         break;
667                                 default:
668                                         break;
669                                 }
670                         }
671
672                         continue;
673 drop:
674                         close_and_remove_fd(n);
675                         n--; /* redo this slot */
676                 }
677         }
678
679 bail1:
680         lwsl_notice("%s exited cleanly\n", argv[0]);
681
682 #ifndef _WIN32
683         closelog();
684 #endif
685
686         return 0;
687 }
688