| /* |
| * fuzzing proxy - network-level fuzzing injection proxy |
| * |
| * Copyright (C) 2016 Andy Green <andy@warmcat.com> |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation: |
| * version 2.1 of the License. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
| * MA 02110-1301 USA |
| * |
| * |
| * fuzxy is designed to go on the client path |
| * |
| * [ client <-> fuzxy ] <-> server |
| * |
| * you can arrange that with, eg, |
| * |
| * http_proxy=localhost:8880 |
| * |
| * env var before starting the client. |
| * |
| * Even though he is on the client side, he is able to see and change traffic |
| * in both directions, and so fuzz both the client and the server. |
| */ |
| |
| #if defined(_WIN32) && defined(EXTERNAL_POLL) |
| #define WINVER 0x0600 |
| #define _WIN32_WINNT 0x0600 |
| #define poll(fdArray, fds, timeout) WSAPoll((LPWSAPOLLFD)(fdArray), (ULONG)(fds), (INT)(timeout)) |
| #endif |
| |
| #include "lws_config.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <getopt.h> |
| #include <signal.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <assert.h> |
| #include <errno.h> |
| #include <libwebsockets.h> |
| |
| #ifdef _WIN32 |
| #include <io.h> |
| #include "gettimeofday.h" |
| #else |
| #include <syslog.h> |
| #include <sys/time.h> |
| #include <unistd.h> |
| #include <sys/socket.h> |
| #endif |
| |
| #if defined(__NetBSD__) |
| #include <netinet/in.h> |
| #endif |
| |
| #if defined(__sun) |
| #include <strings.h> /* bzero */ |
| #endif |
| |
| #define MAX_FUZZ_BUF (1024 * 1024) |
| |
| enum types { |
| FZY_S_DEAD = 0, |
| FZY_S_LISTENING = 1, |
| FZY_S_ACCEPTED = 2, |
| FZY_S_PROXIED = 3, |
| FZY_S_ONWARD = 4, |
| }; |
| |
| enum proxy_parser_states { |
| FZY_PP_CONNECT = 0, |
| FZY_PP_ADDRESS = 1, |
| FZY_PP_PORT = 2, |
| FZY_PP_CRLFS = 3, |
| }; |
| |
| enum fuzzer_parser_states { |
| FZY_FP_SEARCH = 0, |
| FZY_FP_SEARCH2 = 1, |
| FZY_FP_INJECT_PREPARE = 2, |
| FZY_FP_INJECT = 3, |
| FZY_FP_PENDING = 4, |
| }; |
| |
| struct ring { |
| char buf[4096]; |
| int head; |
| int tail; |
| }; |
| |
| struct state { |
| enum types type; |
| enum proxy_parser_states pp; |
| int ppc; |
| |
| struct ring in; |
| |
| char address[256]; |
| int port; |
| |
| enum fuzzer_parser_states fp; |
| int fuzc; |
| int pending; |
| |
| int twin; /* must be fixed up when arrays lose guys */ |
| unsigned int outbound:1; /* from local -> remote */ |
| unsigned int is_pending:1; |
| |
| unsigned char buf[MAX_FUZZ_BUF]; |
| unsigned int inject_len; |
| }; |
| |
| struct test { |
| const char *s[3]; |
| int len[2]; |
| unsigned int swallow:1; |
| }; |
| |
| int force_exit = 0; |
| int which = 5; |
| |
| static const struct test tests[] = { |
| { { NULL, "\x0d\x0a\x0d\x0a", |
| "{ 0xd9, 0x87, 0xd2, 0x88, 0xd2, (248){ 0x89, 0xd2 }, 0x0d, 0x0a }," |
| }, { 0, 4 }, 1 }, |
| { { NULL, "\x0d\x0a\x0d\x0a", |
| "{ 0xd9, 0x87, 0xd2, 0x88, 0xd2, (1373){ 0x89, 0xd2 }, 0x0d, 0x0a }," |
| }, { 0, 4 }, 1 }, |
| { { NULL, "\x0d\x0a\x0d\x0a", |
| "{ 0xd9, 0x87, 0xd2, 0x88, 0xd2, (16967){ 0x89, 0xd2 }, (87){ 0xe2, 0x82, 0xac }, 0x0d, 0x0a }," |
| }, { 0, 4 }, 1 }, |
| { { NULL, "\x0d\x0a\x0d\x0a", |
| "0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, " |
| "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " |
| "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, " |
| "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, " |
| "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, " |
| "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, " |
| "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, " |
| "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, " |
| "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " |
| "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, " |
| "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, " |
| "0xef, 0xbb, 0xbf, 0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, " |
| "0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, " |
| "0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, " |
| "0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, " |
| "0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x0d, 0x0a, " |
| }, { 0, 4 }, 1 }, |
| { { NULL, "\x0d\x0a\x0d\x0a", |
| "(20){0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, " |
| "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " |
| "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, " |
| "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, " |
| "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, " |
| "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, " |
| "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, " |
| "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, " |
| "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " |
| "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, " |
| "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, " |
| "0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, " |
| "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " |
| "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, " |
| "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, " |
| "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, " |
| "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, " |
| "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, " |
| "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, " |
| "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " |
| "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, " |
| "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, " |
| "0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, " |
| "0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, " |
| "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, " |
| "0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, " |
| "0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, " |
| "0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, " |
| "0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, " |
| "0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, " |
| "0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, " |
| "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, " |
| "0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, " |
| "0x0a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, " |
| "0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, " |
| "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, " |
| "0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, " |
| "0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, " |
| "0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, " |
| "0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, " |
| "0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, " |
| "0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, " |
| "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, " |
| "0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, " |
| "0x0a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, " |
| "0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, " |
| "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, " |
| "0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, " |
| "0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, " |
| "0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, " |
| "0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, " |
| "0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, " |
| "0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, " |
| "0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, " |
| "0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, " |
| "0x0a, 0xc0, 0x80, 0xef, 0xb7, 0x90, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, " |
| "0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, " |
| "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, " |
| "0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, " |
| "0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, " |
| "0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, " |
| "0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, " |
| "0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, " |
| "0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, " |
| "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, " |
| "0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, " |
| "0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, " |
| "0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, " |
| "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, " |
| "0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, " |
| "0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, " |
| "0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, " |
| "0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, 0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, " |
| "0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, 0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, " |
| "0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, " |
| "0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, " |
| "0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, " |
| "0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, 0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, " |
| "0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, " |
| "0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, " |
| "0x61, 0x64, 0x0d, 0x0a, }" |
| }, { 0, 4 }, 1 }, |
| { { NULL, "\x0d\x0a\x0d\x0a", |
| "0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, " |
| "0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " |
| "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x3a, 0x20, 0x77, 0x65, " |
| "0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, " |
| "0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x53, 0x65, " |
| "0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2d, 0x4b, 0x65, 0x79, 0x3a, " |
| "0x20, 0x64, 0x47, 0x68, 0x6c, 0x49, 0x48, 0x4e, 0x68, 0x62, 0x58, 0x42, 0x73, 0x5a, 0x53, 0x42, " |
| "0x75, 0x62, 0x32, 0x35, 0x6a, 0x5a, 0x51, 0x3d, 0x3d, 0x0d, 0x0a, 0x4f, 0x72, 0x69, 0x67, 0x69, " |
| "0x6e, 0x3a, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x31, 0x32, 0x37, 0x2e, 0x30, 0x2e, " |
| "0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x53, 0x65, 0x63, 0x2d, 0x57, 0x65, 0x62, 0x53, 0x6f, 0x63, 0x6b, " |
| "0x65, 0x74, 0x2d, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x31, 0x33, 0x0d, 0x0a, " |
| "0xef, 0xbb, 0xbf, 0xc2, 0x47, 0x45, 0x54, 0x20, 0x2f, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x48, 0x54, " |
| "0x54, 0x50, 0x2f, 0x31, 0x2e, 0x31, 0x0d, 0x0a, 0x48, 0x6f, 0x73, 0x74, 0x3a, 0x20, 0x31, 0x32, " |
| "0x37, 0x2e, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0d, 0x0a, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, " |
| "0x3a, 0x20, 0x77, 0x65, 0x62, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x0d, 0x0a, 0x43, 0x6f, 0x6e, " |
| "0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x20, 0x0d, 0x0a, (2048){ 0x0d, 0x0a}" |
| }, { 0, 4 }, 1 }, |
| }; |
| |
| static int ring_size(struct ring *r) |
| { |
| return sizeof(r->buf); |
| } |
| static int ring_used(struct ring *r) |
| { |
| return (r->head - r->tail) & (ring_size(r) - 1); |
| } |
| static int ring_free(struct ring *r) |
| { |
| return (ring_size(r) - 1) - ring_used(r); |
| } |
| static int ring_get_one(struct ring *r) |
| { |
| int n = r->buf[r->tail] & 255; |
| |
| if (r->tail == r->head) |
| return -1; |
| |
| r->tail++; |
| if (r->tail == ring_size(r)) |
| r->tail = 0; |
| |
| return n; |
| } |
| |
| static int hex(char c) |
| { |
| if (c >= '0' && c <= '9') |
| return c -'0'; |
| if (c >= 'a' && c <= 'f') |
| return c - 'a' + 10; |
| if (c >='A' && c <= 'F') |
| return c - 'A' + 10; |
| |
| return -1; |
| } |
| |
| static int |
| fuzxy_tok(const char **src, unsigned char **buf, int *len) |
| { |
| unsigned char *start; |
| unsigned int count, rlen; |
| |
| while (**src) { |
| |
| if (**src == ' ' || **src == ',' || **src == '\n') { |
| (*src)++; |
| continue; |
| } |
| |
| if ((*src)[0] == '}') { |
| (*src)++; |
| return 0; |
| } |
| |
| if ((*src)[0] == '0' && (*src)[1] == 'x') { |
| if (!len) { |
| lwsl_err("out of space\n"); |
| return -1; |
| } |
| |
| ((*buf)++)[0] = (hex((*src)[2]) << 4) | hex((*src)[3]); |
| *src += 4; |
| (*len)--; |
| } |
| |
| if (*src[0] == '(') { |
| start = *buf; |
| (*src)++; |
| count = atoi(*src) - 1; |
| lwsl_err("count %d\n", count); |
| while (**src && **src != ')') |
| (*src)++; |
| if (!(*src)[0]) { |
| lwsl_err("unexpected end in (\n"); |
| return -1; |
| } |
| (*src)++; |
| while (**src == ' ') |
| (*src)++; |
| if (**src != '{') { |
| lwsl_err("missing {\n"); |
| |
| return -1; |
| } |
| (*src)++; |
| if (fuzxy_tok(src, buf, len)) |
| return -1; |
| rlen = *buf - start; |
| while (count--) { |
| if (*len < (int)rlen) { |
| lwsl_err("out of space\n"); |
| return -1; |
| } |
| memcpy(*buf, start, rlen); |
| *buf += rlen; |
| *len -= rlen; |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| static int |
| fuzxy_create_pattern(const char *src, unsigned char *buf, int len) |
| { |
| unsigned char *old = buf; |
| int n; |
| |
| while (*src && (*src == '{' || *src == ' ')) |
| src++; |
| |
| if (!*src) |
| return -1; |
| |
| n = fuzxy_tok(&src, &buf, &len); |
| if (n) |
| return -1; |
| |
| return buf - old; |
| } |
| |
| void sighandler(int sig) |
| { |
| force_exit = 1; |
| } |
| |
| static struct option options[] = { |
| { "help", no_argument, NULL, 'h' }, |
| { "debug", required_argument, NULL, 'd' }, |
| { "port", required_argument, NULL, 'p' }, |
| { "ssl", no_argument, NULL, 's' }, |
| { "allow-non-ssl", no_argument, NULL, 'a' }, |
| { "interface", required_argument, NULL, 'i' }, |
| { "closetest", no_argument, NULL, 'c' }, |
| { "libev", no_argument, NULL, 'e' }, |
| #ifndef LWS_NO_DAEMONIZE |
| { "daemonize", no_argument, NULL, 'D' }, |
| #endif |
| { "resource_path", required_argument, NULL, 'r' }, |
| { NULL, 0, 0, 0 } |
| }; |
| |
| static struct pollfd pfd[128]; |
| static struct state state[128]; |
| static int pfds = 0; |
| |
| static void close_and_remove_fd(int index) |
| { |
| int n; |
| |
| lwsl_notice("%s: closing index %d\n", __func__, index); |
| close(pfd[index].fd); |
| pfd[index].fd = -1; |
| |
| n = state[index].twin; |
| if (n) { |
| assert(state[n].twin == index); |
| } |
| state[index].type = FZY_S_DEAD; |
| |
| if (index == pfds - 1) { |
| if (state[index].twin) |
| state[state[index].twin].twin = 0; |
| state[index].twin = 0; |
| goto bail; |
| } |
| |
| /* swap the end guy into the deleted guy and trim back one */ |
| |
| if (state[pfds - 1].twin) { |
| state[state[pfds - 1].twin].twin = index; |
| if (n && n == pfds - 1) |
| n = index; |
| } |
| |
| /* swap the last guy into dead guy's place and trim by one */ |
| pfd[index] = pfd[pfds - 1]; |
| state[index] = state[pfds - 1]; |
| |
| if (n) { |
| pfds--; |
| state[n].twin = 0; |
| close_and_remove_fd(n); |
| return; |
| } |
| |
| bail: |
| pfds--; |
| } |
| |
| static void construct_state(int n, enum types s, int flags) |
| { |
| memset(&state[n], 0, sizeof state[n]); |
| state[n].type = s; |
| pfd[n].events = flags | POLLHUP; |
| } |
| |
| static int |
| fuzxy_listen(const char *interface_name, int port, int *sockfd) |
| { |
| struct sockaddr_in serv_addr4; |
| socklen_t len = sizeof(struct sockaddr); |
| struct sockaddr_in sin; |
| int n, opt = 1; |
| |
| *sockfd = socket(AF_INET, SOCK_STREAM, 0); |
| |
| if (*sockfd == -1) { |
| lwsl_err("ERROR opening socket\n"); |
| goto bail1; |
| } |
| |
| if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, |
| (const void *)&opt, sizeof(opt)) < 0) { |
| lwsl_err("unable to set listen socket options\n"); |
| goto bail2; |
| } |
| |
| bzero((char *) &serv_addr4, sizeof(serv_addr4)); |
| serv_addr4.sin_addr.s_addr = INADDR_ANY; |
| serv_addr4.sin_family = AF_INET; |
| |
| if (interface_name[0] && |
| lws_interface_to_sa(0, interface_name, (struct sockaddr_in *) |
| (struct sockaddr *)&serv_addr4, |
| sizeof(serv_addr4)) < 0) { |
| lwsl_err("Unable to find interface %s\n", interface_name); |
| goto bail2; |
| } |
| |
| serv_addr4.sin_port = htons(port); |
| |
| n = bind(*sockfd, (struct sockaddr *)&serv_addr4, |
| sizeof(serv_addr4)); |
| if (n < 0) { |
| lwsl_err("ERROR on binding to port %d (%d %d)\n", |
| port, n, errno); |
| goto bail2; |
| } |
| |
| if (getsockname(*sockfd, (struct sockaddr *)&sin, &len) == -1) |
| lwsl_warn("getsockname: %s\n", strerror(errno)); |
| else |
| port = ntohs(sin.sin_port); |
| |
| listen(*sockfd, SOMAXCONN); |
| |
| return 0; |
| bail2: |
| close(*sockfd); |
| bail1: |
| return -1; |
| } |
| |
| |
| static int fuzz(int n, char *out, int len) |
| { |
| struct state *s = &state[n]; |
| const struct test *t = &tests[which]; |
| int m = 0; |
| int c; |
| |
| while (m < len) { |
| switch (s->fp) { |
| case FZY_FP_SEARCH: |
| if (t->s[0] == NULL) { |
| s->fuzc = 0; |
| s->is_pending = 0; |
| s->fp = FZY_FP_SEARCH2; |
| goto search2; |
| } |
| c = ring_get_one(&state[s->twin].in); |
| if (c < 0) |
| return m; |
| if (c == tests[which].s[0][s->fuzc++]) { |
| if (s->fuzc == t->len[0]) { |
| s->fuzc = 0; |
| s->fp = FZY_FP_SEARCH2; |
| } |
| } else |
| s->fuzc = 0; |
| out[m++] = c; |
| break; |
| |
| case FZY_FP_SEARCH2: |
| search2: |
| if (tests[which].s[1] == NULL) { |
| s->fuzc = 0; |
| s->is_pending = 0; |
| s->fp = FZY_FP_INJECT_PREPARE; |
| goto inject; |
| } |
| c = ring_get_one(&state[s->twin].in); |
| if (c < 0) |
| return m; |
| if (c == tests[which].s[1][s->fuzc++]) { |
| if (s->fuzc == tests[which].len[1]) { |
| lwsl_notice("+++++++fuzzer hit...\n"); |
| s->fuzc = 0; |
| s->fp = FZY_FP_INJECT_PREPARE; |
| s->is_pending = !t->swallow; |
| s->pending = c; |
| goto inject; |
| } |
| } else |
| s->fuzc = 0; |
| if (!t->swallow) |
| out[m++] = c; |
| break; |
| |
| case FZY_FP_INJECT_PREPARE: |
| inject: |
| s->inject_len = fuzxy_create_pattern(t->s[2], |
| s->buf, sizeof(s->buf)); |
| if (s->inject_len == (unsigned int) -1) |
| return -1; |
| s->fp = FZY_FP_INJECT; |
| /* fallthru */ |
| |
| case FZY_FP_INJECT: |
| out[m++] = s->buf[s->fuzc++]; |
| if (s->fuzc == (int)s->inject_len) |
| s->fp = FZY_FP_PENDING; |
| break; |
| |
| case FZY_FP_PENDING: |
| if (s->is_pending) |
| out[m++] = s->pending; |
| s->fp = FZY_FP_SEARCH; |
| s->fuzc = 0; |
| break; |
| } |
| } |
| |
| return m; |
| } |
| |
| static int |
| handle_accept(int n) |
| { |
| struct addrinfo ai, *res, *result; |
| struct sockaddr_in serv_addr4; |
| struct state *s = &state[n]; |
| void *p = NULL; |
| int m, sockfd; |
| |
| while (1) { |
| m = ring_get_one(&s->in); |
| if (m < 0) |
| return 0; |
| |
| switch (s->pp) { |
| case FZY_PP_CONNECT: |
| if (m != "CONNECT "[s->ppc++]) { |
| lwsl_notice("failed CONNECT match\n"); |
| return 1; |
| } |
| if (s->ppc == 8) { |
| s->pp = FZY_PP_ADDRESS; |
| s->ppc = 0; |
| } |
| break; |
| case FZY_PP_ADDRESS: |
| if (m == ':') { |
| s->address[s->ppc++] = '\0'; |
| s->pp = FZY_PP_PORT; |
| s->ppc = 0; |
| break; |
| } |
| if (m == ' ') { |
| s->address[s->ppc++] = '\0'; |
| s->pp = FZY_PP_CRLFS; |
| s->ppc = 0; |
| break; |
| } |
| |
| |
| s->address[s->ppc++] = m; |
| if (s->ppc == sizeof(s->address)) { |
| lwsl_notice("Failed on address length\n"); |
| return 1; |
| } |
| break; |
| case FZY_PP_PORT: |
| if (m == ' ') { |
| s->pp = FZY_PP_CRLFS; |
| s->ppc = 0; |
| break; |
| } |
| if (m >= '0' && m <= '9') { |
| s->port *= 10; |
| s->port += m - '0'; |
| break; |
| } |
| return 1; |
| |
| case FZY_PP_CRLFS: |
| if (m != "\x0d\x0a\x0d\x0a"[s->ppc++]) |
| s->ppc = 0; |
| if (s->ppc != 4) |
| break; |
| s->type = FZY_S_PROXIED; |
| |
| memset (&ai, 0, sizeof ai); |
| ai.ai_family = PF_UNSPEC; |
| ai.ai_socktype = SOCK_STREAM; |
| |
| if (getaddrinfo(s->address, NULL, &ai, &result)) { |
| lwsl_notice("failed to lookup %s\n", |
| s->address); |
| return 1; |
| } |
| |
| res = result; |
| while (!p && res) { |
| switch (res->ai_family) { |
| case AF_INET: |
| p = &((struct sockaddr_in *)res-> |
| ai_addr)->sin_addr; |
| break; |
| } |
| |
| res = res->ai_next; |
| } |
| |
| if (!p) { |
| lwsl_notice("Failed to get address result %s\n", |
| s->address); |
| freeaddrinfo(result); |
| return 1; |
| } |
| |
| serv_addr4.sin_family = AF_INET; |
| serv_addr4.sin_addr = *((struct in_addr *)p); |
| serv_addr4.sin_port = htons(s->port); |
| bzero(&serv_addr4.sin_zero, 8); |
| freeaddrinfo(result); |
| |
| lwsl_err("Conn %d req '%s' port %d\n", n, |
| s->address, s->port); |
| /* we need to open the associated onward connection */ |
| sockfd = socket(AF_INET, SOCK_STREAM, 0); |
| if (sockfd < 0) { |
| lwsl_err("Could not get socket\n"); |
| return -1; |
| } |
| |
| if (connect(sockfd, (struct sockaddr *)&serv_addr4, |
| sizeof(struct sockaddr)) == -1 || |
| errno == EISCONN) { |
| close(sockfd); |
| lwsl_err("proxied onward connection failed\n"); |
| return 1; |
| } |
| s->twin = pfds; |
| construct_state(pfds, FZY_S_ONWARD, |
| POLLOUT | POLLIN | POLLERR); |
| state[pfds].twin = n; |
| lwsl_notice("binding conns %d and %d\n", n, pfds); |
| state[pfds].outbound = s->outbound; |
| state[pfds].ppc = 0; |
| pfd[pfds++].fd = sockfd; |
| |
| lwsl_notice("onward connection in progress\n"); |
| if (ring_used(&s->in)) |
| pfd[s->twin].events |= POLLOUT; |
| if (write(pfd[n].fd, |
| "HTTP/1.0 200 \x0d\x0a\x0d\x0a", 17) < 17) |
| return 1; |
| } |
| } |
| |
| return 0; |
| } |
| |
| static void sigpipe_handler(int x) |
| { |
| } |
| |
| int |
| main(int argc, char **argv) |
| { |
| char interface_name[128] = "", interface_name_local[128] = "lo"; |
| int port_local = 8880, accept_fd; |
| struct sockaddr_in cli_addr; |
| int debug_level = 7; |
| socklen_t clilen; |
| struct state *s; |
| char out[4096]; |
| int opts = 0; |
| int n = 0, m; |
| |
| #ifndef _WIN32 |
| /* LOG_PERROR is not POSIX standard, and may not be portable */ |
| #ifdef __sun |
| int syslog_options = LOG_PID; |
| #else |
| int syslog_options = LOG_PID | LOG_PERROR; |
| #endif |
| #endif |
| #ifndef LWS_NO_DAEMONIZE |
| int daemonize = 0; |
| #endif |
| signal(SIGPIPE, sigpipe_handler); |
| |
| while (n >= 0) { |
| n = getopt_long(argc, argv, "eci:hsap:d:Dr:", options, NULL); |
| if (n < 0) |
| continue; |
| switch (n) { |
| case 'e': |
| opts |= LWS_SERVER_OPTION_LIBEV; |
| break; |
| #ifndef LWS_NO_DAEMONIZE |
| case 'D': |
| daemonize = 1; |
| #if !defined(_WIN32) && !defined(__sun) |
| syslog_options &= ~LOG_PERROR; |
| #endif |
| break; |
| #endif |
| case 'd': |
| debug_level = atoi(optarg); |
| break; |
| case 'p': |
| port_local = atoi(optarg); |
| break; |
| case 'i': |
| lws_strncpy(interface_name, optarg, sizeof interface_name); |
| break; |
| case 'h': |
| fprintf(stderr, "Usage: libwebsockets-test-fuzxy " |
| "[--port=<p>] [--ssl] " |
| "[-d <log bitfield>] " |
| "[--resource_path <path>]\n"); |
| exit(1); |
| } |
| } |
| |
| #if !defined(LWS_NO_DAEMONIZE) && !defined(WIN32) |
| /* |
| * normally lock path would be /var/lock/lwsts or similar, to |
| * simplify getting started without having to take care about |
| * permissions or running as root, set to /tmp/.lwsts-lock |
| */ |
| if (daemonize && lws_daemonize("/tmp/.lwsts-lock")) { |
| fprintf(stderr, "Failed to daemonize\n"); |
| return 1; |
| } |
| #endif |
| |
| signal(SIGINT, sighandler); |
| |
| #ifndef _WIN32 |
| /* we will only try to log things according to our debug_level */ |
| setlogmask(LOG_UPTO (LOG_DEBUG)); |
| openlog("fuzxy", syslog_options, LOG_DAEMON); |
| #endif |
| |
| /* tell the library what debug level to emit and to send it to syslog */ |
| lws_set_log_level(debug_level, lwsl_emit_syslog); |
| |
| lwsl_notice("libwebsockets fuzzing proxy - license LGPL2.1+SLE\n"); |
| lwsl_notice("(C) Copyright 2016 Andy Green <andy@warmcat.com>\n"); |
| |
| /* listen on local side */ |
| |
| if (fuzxy_listen(interface_name, port_local, &pfd[pfds].fd)) { |
| lwsl_err("Failed to listen on local side\n"); |
| goto bail1; |
| } |
| construct_state(pfds, FZY_S_LISTENING, POLLIN | POLLERR); |
| pfds++; |
| |
| (void)interface_name_local; |
| lwsl_notice("Local side listening on %s:%u\n", |
| interface_name_local, port_local); |
| |
| while (!force_exit) { |
| |
| m = poll(pfd, pfds, 50); |
| if (m < 0) |
| continue; |
| for (n = 0; n < pfds; n++) { |
| s = &state[n]; |
| if (s->type == FZY_S_LISTENING && |
| (pfd[n].revents & POLLIN)) { |
| /* first do the accept entry */ |
| |
| clilen = sizeof(cli_addr); |
| accept_fd = accept(pfd[0].fd, |
| (struct sockaddr *)&cli_addr, &clilen); |
| if (accept_fd < 0) { |
| if (errno == EAGAIN || |
| errno == EWOULDBLOCK) |
| continue; |
| |
| lwsl_warn("ERROR on accept: %s\n", |
| strerror(errno)); |
| continue; |
| } |
| construct_state(pfds, FZY_S_ACCEPTED, |
| POLLIN | POLLERR); |
| state[pfds].outbound = n == 0; |
| state[pfds].pp = FZY_PP_CONNECT; |
| state[pfds].ppc = 0; |
| pfd[pfds++].fd = accept_fd; |
| lwsl_notice("new connect accepted\n"); |
| continue; |
| } |
| if (pfd[n].revents & POLLIN) { |
| assert(ring_free(&s->in)); |
| m = (ring_size(&s->in) - 1) - |
| s->in.head; |
| if (s->in.head == ring_size(&s->in) - 1 && |
| s->in.tail) |
| m = 1; |
| m = read(pfd[n].fd, s->in.buf + s->in.head, m); |
| // lwsl_notice("read %d\n", m); |
| if (m <= 0) { |
| lwsl_err("Error on read\n"); |
| goto drop; |
| } |
| s->in.head += m; |
| if (s->in.head == ring_size(&s->in)) |
| s->in.head = 0; |
| |
| switch (s->type) { |
| case FZY_S_ACCEPTED: /* parse proxy CONNECT */ |
| if (handle_accept(n)) |
| goto drop; |
| break; |
| case FZY_S_PROXIED: |
| case FZY_S_ONWARD: |
| if (ring_used(&s->in)) |
| pfd[s->twin].events |= POLLOUT; |
| break; |
| default: |
| assert(0); |
| break; |
| } |
| if (s->in.head == s->in.tail) { |
| s->in.head = s->in.tail = 0; |
| pfd[n].events |= POLLIN; |
| } |
| if (!ring_free(&s->in)) |
| pfd[n].events &= ~POLLIN; |
| } |
| if (pfd[n].revents & POLLOUT) { |
| switch (s->type) { |
| case FZY_S_PROXIED: |
| case FZY_S_ONWARD: |
| /* |
| * draw down enough of the partner's |
| * in ring to either exhaust it |
| * or fill an output buffer |
| */ |
| m = fuzz(n, out, sizeof(out)); |
| if (m < 0) { |
| lwsl_err("Error on fuzz\n"); |
| goto drop; |
| } |
| lwsl_notice("got block %d\n", m); |
| if (m) { |
| m = write(pfd[n].fd, out, m); |
| if (m <= 0) { |
| lwsl_err("Error on write\n"); |
| goto drop; |
| } else |
| pfd[s->twin].events &= ~POLLIN; |
| } else { |
| pfd[n].events &= ~POLLOUT; |
| |
| if (ring_free(&state[s->twin].in)) |
| pfd[s->twin].events |= POLLIN; |
| } |
| |
| break; |
| default: |
| break; |
| } |
| } |
| |
| continue; |
| drop: |
| close_and_remove_fd(n); |
| n--; /* redo this slot */ |
| } |
| } |
| |
| bail1: |
| lwsl_notice("%s exited cleanly\n", argv[0]); |
| |
| #ifndef _WIN32 |
| closelog(); |
| #endif |
| |
| return 0; |
| } |