mirror of
https://github.com/warmcat/libwebsockets.git
synced 2025-03-09 00:00:04 +01:00
minimal-raw-netcat
Adapt attack.sh to use it instead of OS netcat and fox various bugs that exposed.
This commit is contained in:
parent
f1c56bc233
commit
da0be64f68
15 changed files with 496 additions and 74 deletions
|
@ -897,6 +897,9 @@ lws_cancel_service(struct lws_context *context)
|
|||
struct lws_context_per_thread *pt = &context->pt[0];
|
||||
short m = context->count_threads;
|
||||
|
||||
if (context->being_destroyed1)
|
||||
return;
|
||||
|
||||
lwsl_info("%s\n", __func__);
|
||||
|
||||
while (m--) {
|
||||
|
|
|
@ -23,16 +23,10 @@
|
|||
|
||||
#include <private-libwebsockets.h>
|
||||
|
||||
static int
|
||||
elops_destroy_context1_poll(struct lws_context *context)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct lws_event_loop_ops event_loop_ops_poll = {
|
||||
/* name */ "poll",
|
||||
/* init_context */ NULL,
|
||||
/* destroy_context1 */ elops_destroy_context1_poll,
|
||||
/* destroy_context1 */ NULL,
|
||||
/* destroy_context2 */ NULL,
|
||||
/* init_vhost_listen_wsi */ NULL,
|
||||
/* init_pt */ NULL,
|
||||
|
|
|
@ -91,15 +91,8 @@ signed char char_to_hex(const char c)
|
|||
void
|
||||
__lws_free_wsi(struct lws *wsi)
|
||||
{
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
struct lws_context_per_thread *pt;
|
||||
#endif
|
||||
|
||||
if (!wsi)
|
||||
return;
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Protocol user data may be allocated either internally by lws
|
||||
|
@ -116,35 +109,16 @@ __lws_free_wsi(struct lws *wsi)
|
|||
if (wsi->vhost && wsi->vhost->lserv_wsi == wsi)
|
||||
wsi->vhost->lserv_wsi = NULL;
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
// lws_peer_dump_from_wsi(wsi);
|
||||
|
||||
/* we may not have an ah, but may be on the waiting list... */
|
||||
lwsl_info("ah det due to close\n");
|
||||
__lws_header_table_detach(wsi, 0);
|
||||
|
||||
{
|
||||
struct allocated_headers *ah = pt->http.ah_list;
|
||||
while (ah) {
|
||||
if (ah->in_use && ah->wsi == wsi) {
|
||||
lwsl_err("%s: ah leak: wsi %p\n", __func__, wsi);
|
||||
ah->in_use = 0;
|
||||
ah->wsi = NULL;
|
||||
pt->http.ah_count_in_use--;
|
||||
break;
|
||||
}
|
||||
ah = ah->next;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (wsi->role_ops->destroy_role)
|
||||
wsi->role_ops->destroy_role(wsi);
|
||||
|
||||
#if defined(LWS_WITH_PEER_LIMITS)
|
||||
lws_peer_track_wsi_close(wsi->context, wsi->peer);
|
||||
wsi->peer = NULL;
|
||||
#endif
|
||||
|
||||
if (wsi->role_ops->destroy_role)
|
||||
wsi->role_ops->destroy_role(wsi);
|
||||
|
||||
/* since we will destroy the wsi, make absolutely sure now */
|
||||
|
||||
#if defined(LWS_WITH_OPENSSL)
|
||||
|
@ -847,8 +821,7 @@ just_kill_connection:
|
|||
|
||||
if (!wsi->protocol)
|
||||
pro = &wsi->vhost->protocols[0];
|
||||
//lwsl_notice("%s: est %d told %d cbin %d %s\n", __func__, lwsi_state_est_PRE_CLOSE(wsi), !wsi->told_user_closed,
|
||||
// wsi->role_ops->close_cb[lwsi_role_server(wsi)], pro->name);
|
||||
|
||||
pro->callback(wsi,
|
||||
wsi->role_ops->close_cb[lwsi_role_server(wsi)],
|
||||
wsi->user_space, NULL, 0);
|
||||
|
|
|
@ -1527,7 +1527,10 @@ enum lws_callback_reasons {
|
|||
/**< RAW mode file was adopted (equivalent to 'wsi created') */
|
||||
|
||||
LWS_CALLBACK_RAW_RX_FILE = 64,
|
||||
/**< RAW mode file has something to read */
|
||||
/**< This is the indication the RAW mode file has something to read.
|
||||
* This doesn't actually do the read of the file and len is always
|
||||
* 0... your code should do the read having been informed there is
|
||||
* something to read now. */
|
||||
|
||||
LWS_CALLBACK_RAW_WRITEABLE_FILE = 65,
|
||||
/**< RAW mode file is writeable */
|
||||
|
|
|
@ -199,6 +199,26 @@ lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,
|
|||
lws_context_unlock(context); /* ====================================> */
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_dump_from_wsi(struct lws *wsi)
|
||||
{
|
||||
struct lws_peer *peer;
|
||||
|
||||
if (!wsi || !wsi->peer)
|
||||
return;
|
||||
|
||||
peer = wsi->peer;
|
||||
|
||||
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
|
||||
lwsl_notice("%s: wsi %p: created %llu: wsi: %d/%d, ah %d/%d\n", __func__,
|
||||
wsi, (unsigned long long)peer->time_created, peer->count_wsi, peer->total_wsi,
|
||||
peer->http.count_ah, peer->http.total_ah);
|
||||
#else
|
||||
lwsl_notice("%s: wsi %p: created %llu: wsi: %d/%d\n", __func__,
|
||||
wsi, (unsigned long long)peer->time_created, peer->count_wsi, peer->total_wsi);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
lws_peer_track_wsi_close(struct lws_context *context, struct lws_peer *peer)
|
||||
{
|
||||
|
|
|
@ -1715,6 +1715,8 @@ lws_get_or_create_peer(struct lws_vhost *vhost, lws_sockfd_type sockfd);
|
|||
void
|
||||
lws_peer_add_wsi(struct lws_context *context, struct lws_peer *peer,
|
||||
struct lws *wsi);
|
||||
void
|
||||
lws_peer_dump_from_wsi(struct lws *wsi);
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -469,6 +469,7 @@ try_pollout:
|
|||
|
||||
|
||||
fail:
|
||||
lwsl_notice("%s: fail: closing\n", __func__);
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "server socket svc fail");
|
||||
|
||||
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
||||
|
@ -616,6 +617,32 @@ rops_alpn_negotiated_h1(struct lws *wsi, const char *alpn)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
rops_destroy_role_h1(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
struct allocated_headers *ah;
|
||||
|
||||
/* we may not have an ah, but may be on the waiting list... */
|
||||
lwsl_info("%s: ah det due to close\n", __func__);
|
||||
__lws_header_table_detach(wsi, 0);
|
||||
|
||||
ah = pt->http.ah_list;
|
||||
|
||||
while (ah) {
|
||||
if (ah->in_use && ah->wsi == wsi) {
|
||||
lwsl_err("%s: ah leak: wsi %p\n", __func__, wsi);
|
||||
ah->in_use = 0;
|
||||
ah->wsi = NULL;
|
||||
pt->http.ah_count_in_use--;
|
||||
break;
|
||||
}
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct lws_role_ops role_ops_h1 = {
|
||||
/* role name */ "h1",
|
||||
/* alpn id */ "http/1.1",
|
||||
|
@ -636,7 +663,7 @@ struct lws_role_ops role_ops_h1 = {
|
|||
/* close_via_role_protocol */ NULL,
|
||||
/* close_role */ NULL,
|
||||
/* close_kill_connection */ NULL,
|
||||
/* destroy_role */ NULL,
|
||||
/* destroy_role */ rops_destroy_role_h1,
|
||||
/* writeable cb clnt, srv */ { LWS_CALLBACK_CLIENT_HTTP_WRITEABLE,
|
||||
LWS_CALLBACK_HTTP_WRITEABLE },
|
||||
/* close cb clnt, srv */ { LWS_CALLBACK_CLOSED_CLIENT_HTTP,
|
||||
|
|
|
@ -503,6 +503,26 @@ rops_tx_credit_h2(struct lws *wsi)
|
|||
static int
|
||||
rops_destroy_role_h2(struct lws *wsi)
|
||||
{
|
||||
struct lws_context_per_thread *pt = &wsi->context->pt[(int)wsi->tsi];
|
||||
struct allocated_headers *ah;
|
||||
|
||||
/* we may not have an ah, but may be on the waiting list... */
|
||||
lwsl_info("%s: ah det due to close\n", __func__);
|
||||
__lws_header_table_detach(wsi, 0);
|
||||
|
||||
ah = pt->http.ah_list;
|
||||
|
||||
while (ah) {
|
||||
if (ah->in_use && ah->wsi == wsi) {
|
||||
lwsl_err("%s: ah leak: wsi %p\n", __func__, wsi);
|
||||
ah->in_use = 0;
|
||||
ah->wsi = NULL;
|
||||
pt->http.ah_count_in_use--;
|
||||
break;
|
||||
}
|
||||
ah = ah->next;
|
||||
}
|
||||
|
||||
if (wsi->upgraded_to_http2 || wsi->http2_substream) {
|
||||
lws_hpack_destroy_dynamic_header(wsi);
|
||||
|
||||
|
|
|
@ -1729,7 +1729,7 @@ lws_http_transaction_completed(struct lws *wsi)
|
|||
return 1;
|
||||
|
||||
if (wsi->http.connection_type != HTTP_CONNECTION_KEEP_ALIVE) {
|
||||
lwsl_info("%s: %p: close connection\n", __func__, wsi);
|
||||
lwsl_notice("%s: %p: close connection\n", __func__, wsi);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1961,10 +1961,10 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
|
|||
/* non-SSL */
|
||||
if (!(type & LWS_ADOPT_HTTP)) {
|
||||
if (!(type & LWS_ADOPT_SOCKET))
|
||||
lws_role_transition(new_wsi, 0, LRS_UNCONNECTED,
|
||||
lws_role_transition(new_wsi, 0, LRS_ESTABLISHED,
|
||||
&role_ops_raw_file);
|
||||
else
|
||||
lws_role_transition(new_wsi, 0, LRS_UNCONNECTED,
|
||||
lws_role_transition(new_wsi, 0, LRS_ESTABLISHED,
|
||||
&role_ops_raw_skt);
|
||||
}
|
||||
#if defined(LWS_ROLE_H1)
|
||||
|
|
|
@ -54,12 +54,17 @@ rops_handle_POLLIN_raw_skt(struct lws_context_per_thread *pt, struct lws *wsi,
|
|||
buffered = lws_buflist_aware_read(pt, wsi, &ebuf);
|
||||
switch (ebuf.len) {
|
||||
case 0:
|
||||
lwsl_info("%s: read 0 len a\n",
|
||||
__func__);
|
||||
lwsl_info("%s: read 0 len\n", __func__);
|
||||
wsi->seen_zero_length_recv = 1;
|
||||
lws_change_pollfd(wsi, LWS_POLLIN, 0);
|
||||
goto try_pollout;
|
||||
//goto fail;
|
||||
|
||||
/*
|
||||
* we need to go to fail here, since it's the only
|
||||
* chance we get to understand that the socket has
|
||||
* closed
|
||||
*/
|
||||
// goto try_pollout;
|
||||
goto fail;
|
||||
|
||||
case LWS_SSL_CAPABLE_ERROR:
|
||||
goto fail;
|
||||
|
@ -127,7 +132,7 @@ try_pollout:
|
|||
fail:
|
||||
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "raw svc fail");
|
||||
|
||||
return LWS_HPI_RET_PLEASE_CLOSE_ME;
|
||||
return LWS_HPI_RET_WSI_ALREADY_DIED;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,5 +3,6 @@
|
|||
minimal-raw-adopt-tcp|Shows how to have lws adopt an existing tcp socket something else had connected
|
||||
minimal-raw-adopt-udp|Shows how to create a udp socket and read and write on it
|
||||
minimal-raw-file|Shows how to adopt a file descriptor (device node, fifo, file, etc) into the lws event loop and handle events
|
||||
minimal-raw-netcat|Writes stdin to a remote server and prints results on stdout
|
||||
minimal-raw-vhost|Shows how to set up a vhost that listens and accepts RAW socket connections
|
||||
|
||||
|
|
76
minimal-examples/raw/minimal-raw-netcat/CMakeLists.txt
Normal file
76
minimal-examples/raw/minimal-raw-netcat/CMakeLists.txt
Normal file
|
@ -0,0 +1,76 @@
|
|||
cmake_minimum_required(VERSION 2.8)
|
||||
include(CheckCSourceCompiles)
|
||||
|
||||
set(SAMP lws-minimal-raw-netcat)
|
||||
set(SRCS minimal-raw-netcat.c)
|
||||
|
||||
# If we are being built as part of lws, confirm current build config supports
|
||||
# reqconfig, else skip building ourselves.
|
||||
#
|
||||
# If we are being built externally, confirm installed lws was configured to
|
||||
# support reqconfig, else error out with a helpful message about the problem.
|
||||
#
|
||||
MACRO(require_lws_config reqconfig _val result)
|
||||
|
||||
if (DEFINED ${reqconfig})
|
||||
if (${reqconfig})
|
||||
set (rq 1)
|
||||
else()
|
||||
set (rq 0)
|
||||
endif()
|
||||
else()
|
||||
set(rq 0)
|
||||
endif()
|
||||
|
||||
if (${_val} EQUAL ${rq})
|
||||
set(SAME 1)
|
||||
else()
|
||||
set(SAME 0)
|
||||
endif()
|
||||
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES AND NOT ${SAME})
|
||||
if (${_val})
|
||||
message("${SAMP}: skipping as lws being built without ${reqconfig}")
|
||||
else()
|
||||
message("${SAMP}: skipping as lws built with ${reqconfig}")
|
||||
endif()
|
||||
set(${result} 0)
|
||||
else()
|
||||
if (LWS_WITH_MINIMAL_EXAMPLES)
|
||||
set(MET ${SAME})
|
||||
else()
|
||||
CHECK_C_SOURCE_COMPILES("#include <libwebsockets.h>\nint main(void) {\n#if defined(${reqconfig})\n return 0;\n#else\n fail;\n#endif\n return 0;\n}\n" HAS_${reqconfig})
|
||||
if (NOT DEFINED HAS_${reqconfig} OR NOT HAS_${reqconfig})
|
||||
set(HAS_${reqconfig} 0)
|
||||
else()
|
||||
set(HAS_${reqconfig} 1)
|
||||
endif()
|
||||
if ((HAS_${reqconfig} AND ${_val}) OR (NOT HAS_${reqconfig} AND NOT ${_val}))
|
||||
set(MET 1)
|
||||
else()
|
||||
set(MET 0)
|
||||
endif()
|
||||
endif()
|
||||
if (NOT MET)
|
||||
if (${_val})
|
||||
message(FATAL_ERROR "This project requires lws must have been configured with ${reqconfig}")
|
||||
else()
|
||||
message(FATAL_ERROR "Lws configuration of ${reqconfig} is incompatible with this project")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
ENDMACRO()
|
||||
|
||||
set(requirements 1)
|
||||
require_lws_config(LWS_WITHOUT_SERVER 0 requirements)
|
||||
|
||||
if (requirements)
|
||||
add_executable(${SAMP} ${SRCS})
|
||||
|
||||
if (websockets_shared)
|
||||
target_link_libraries(${SAMP} websockets_shared)
|
||||
add_dependencies(${SAMP} websockets_shared)
|
||||
else()
|
||||
target_link_libraries(${SAMP} websockets)
|
||||
endif()
|
||||
endif()
|
38
minimal-examples/raw/minimal-raw-netcat/README.md
Normal file
38
minimal-examples/raw/minimal-raw-netcat/README.md
Normal file
|
@ -0,0 +1,38 @@
|
|||
# lws minimal raw netcat
|
||||
|
||||
This example shows to to create a "netcat" that copies its stdin to
|
||||
a remote socket and prints what is returned in stdout.
|
||||
|
||||
It has some advantage over the real netcat, it will wait 1s after stdin closes
|
||||
to print results that are in flight.
|
||||
|
||||
## build
|
||||
|
||||
```
|
||||
$ cmake . && make
|
||||
```
|
||||
|
||||
## usage
|
||||
|
||||
```
|
||||
$ echo -e -n "GET / http/1.1\r\n\r\n"| ./lws-minimal-raw-netcat
|
||||
[2018/05/02 08:53:53:2665] USER: LWS minimal raw netcat [--server ip] [--port port]
|
||||
[2018/05/02 08:53:53:2667] NOTICE: Creating Vhost 'default' (no listener), 1 protocols, IPv6 off
|
||||
[2018/05/02 08:53:53:2703] USER: Starting connect...
|
||||
[2018/05/02 08:53:53:5644] USER: Connected to libwebsockets.org:80...
|
||||
[2018/05/02 08:53:53:5645] USER: LWS_CALLBACK_RAW_ADOPT
|
||||
[2018/05/02 08:53:53:5645] USER: LWS_CALLBACK_RAW_ADOPT_FILE
|
||||
[2018/05/02 08:53:53:5646] USER: LWS_CALLBACK_RAW_RX_FILE
|
||||
[2018/05/02 08:53:53:5646] USER: LWS_CALLBACK_RAW_CLOSE_FILE
|
||||
[2018/05/02 08:53:53:8600] USER: LWS_CALLBACK_RAW_RX (186)
|
||||
HTTP/1.1 301 Redirect
|
||||
server: lwsws
|
||||
Strict-Transport-Security: max-age=15768000 ; includeSubDomains
|
||||
location: https://libwebsockets.org
|
||||
content-type: text/html
|
||||
content-length: 0
|
||||
|
||||
```
|
||||
|
||||
Note the example does everything itself, after 5s idle the remote server closes the connection
|
||||
after which the example continues until you ^C it.
|
254
minimal-examples/raw/minimal-raw-netcat/minimal-raw-netcat.c
Normal file
254
minimal-examples/raw/minimal-raw-netcat/minimal-raw-netcat.c
Normal file
|
@ -0,0 +1,254 @@
|
|||
/*
|
||||
* lws-minimal-raw-netcat
|
||||
*
|
||||
* Copyright (C) 2018 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* This file is made available under the Creative Commons CC0 1.0
|
||||
* Universal Public Domain Dedication.
|
||||
*
|
||||
* This demonstrates sending stdin to a remote socket and printing
|
||||
* what is returned to stdout.
|
||||
*
|
||||
* All the logging is on stderr, so you can tune it out with 2>log
|
||||
* or whatever.
|
||||
*/
|
||||
|
||||
#include <libwebsockets.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
static struct lws *raw_wsi, *stdin_wsi;
|
||||
static uint8_t buf[LWS_PRE + 4096];
|
||||
static int waiting, interrupted;
|
||||
static struct lws_context *context;
|
||||
|
||||
static int
|
||||
callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len)
|
||||
{
|
||||
|
||||
switch (reason) {
|
||||
|
||||
/* callbacks related to file descriptor */
|
||||
|
||||
case LWS_CALLBACK_RAW_ADOPT_FILE:
|
||||
lwsl_user("LWS_CALLBACK_RAW_ADOPT_FILE\n");
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_CLOSE_FILE:
|
||||
lwsl_user("LWS_CALLBACK_RAW_CLOSE_FILE\n");
|
||||
/* stdin close, wait 1s then close the raw skt */
|
||||
stdin_wsi = NULL; /* invalid now we close */
|
||||
if (raw_wsi)
|
||||
lws_set_timer_usecs(raw_wsi, LWS_USEC_PER_SEC / 10);
|
||||
else {
|
||||
interrupted = 1;
|
||||
lws_cancel_service(context);
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_RX_FILE:
|
||||
lwsl_user("LWS_CALLBACK_RAW_RX_FILE\n");
|
||||
waiting = read(0, buf, sizeof(buf));
|
||||
lwsl_notice("raw file read %d\n", waiting);
|
||||
if (waiting < 0)
|
||||
return -1;
|
||||
|
||||
if (raw_wsi)
|
||||
lws_callback_on_writable(raw_wsi);
|
||||
lws_rx_flow_control(wsi, 0);
|
||||
break;
|
||||
|
||||
|
||||
/* callbacks related to raw socket descriptor */
|
||||
|
||||
case LWS_CALLBACK_RAW_ADOPT:
|
||||
lwsl_user("LWS_CALLBACK_RAW_ADOPT\n");
|
||||
lws_callback_on_writable(wsi);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_CLOSE:
|
||||
lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
|
||||
/*
|
||||
* If the socket to the remote server closed, we must close
|
||||
* and drop any remaining stdin
|
||||
*/
|
||||
interrupted = 1;
|
||||
lws_cancel_service(context);
|
||||
/* our pointer to this wsi is invalid now we close */
|
||||
raw_wsi = NULL;
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_RX:
|
||||
lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
|
||||
while (len--)
|
||||
putchar(*((const char *)in++));
|
||||
fflush(stdout);
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_RAW_WRITEABLE:
|
||||
lwsl_user("LWS_CALLBACK_RAW_WRITEABLE\n");
|
||||
// lwsl_hexdump_info(buf, waiting);
|
||||
if (stdin_wsi)
|
||||
lws_rx_flow_control(stdin_wsi, 1);
|
||||
if (lws_write(wsi, buf, waiting, LWS_WRITE_RAW) != waiting) {
|
||||
lwsl_notice("%s: raw skt write failed\n", __func__);
|
||||
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_TIMER:
|
||||
lwsl_user("LWS_CALLBACK_TIMER\n");
|
||||
interrupted = 1;
|
||||
lws_cancel_service(context);
|
||||
return -1;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct lws_protocols protocols[] = {
|
||||
{ "raw-test", callback_raw_test, 0, 0 },
|
||||
{ NULL, NULL, 0, 0 } /* terminator */
|
||||
};
|
||||
|
||||
void sigint_handler(int sig)
|
||||
{
|
||||
interrupted = 1;
|
||||
}
|
||||
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
const char *server = "libwebsockets.org", *port = "80";
|
||||
struct lws_context_creation_info info;
|
||||
lws_sock_file_fd_type sock;
|
||||
struct addrinfo h, *r, *rp;
|
||||
struct lws_vhost *vhost;
|
||||
const char *p;
|
||||
int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
|
||||
/* for LLL_ verbosity above NOTICE to be built into lws,
|
||||
* lws must have been configured and built with
|
||||
* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
|
||||
/* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
|
||||
/* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
|
||||
/* | LLL_DEBUG */;
|
||||
|
||||
signal(SIGINT, sigint_handler);
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "-d")))
|
||||
logs = atoi(p);
|
||||
|
||||
lws_set_log_level(logs, NULL);
|
||||
lwsl_user("LWS minimal raw netcat [--server ip] [--port port]\n");
|
||||
|
||||
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
|
||||
info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (!context) {
|
||||
lwsl_err("lws init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
info.port = CONTEXT_PORT_NO_LISTEN_SERVER;
|
||||
info.protocols = protocols;
|
||||
|
||||
vhost = lws_create_vhost(context, &info);
|
||||
if (!vhost) {
|
||||
lwsl_err("lws vhost creation failed\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect our own "foreign" socket to libwebsockets.org:80
|
||||
*
|
||||
* Normally you would do this with lws_client_connect_via_info() inside
|
||||
* the lws event loop, hiding all this detail. But this example
|
||||
* demonstrates how to integrate an externally-connected "foreign"
|
||||
* socket, so we create one by hand.
|
||||
*/
|
||||
|
||||
memset(&h, 0, sizeof(h));
|
||||
h.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||
h.ai_socktype = SOCK_STREAM;
|
||||
h.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--port")))
|
||||
port = p;
|
||||
|
||||
if ((p = lws_cmdline_option(argc, argv, "--server")))
|
||||
server = p;
|
||||
|
||||
n = getaddrinfo(server, port, &h, &r);
|
||||
if (n) {
|
||||
lwsl_err("%s: problem resolving %s: %s\n", __func__,
|
||||
server, gai_strerror(n));
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (rp = r; rp; rp = rp->ai_next) {
|
||||
sock.sockfd = socket(rp->ai_family, rp->ai_socktype,
|
||||
rp->ai_protocol);
|
||||
if (sock.sockfd >= 0)
|
||||
break;
|
||||
}
|
||||
if (!rp) {
|
||||
lwsl_err("%s: unable to create INET socket\n", __func__);
|
||||
freeaddrinfo(r);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
lwsl_user("Starting connect to %s:%s...\n", server, port);
|
||||
if (connect(sock.sockfd, rp->ai_addr, sizeof(*rp->ai_addr)) < 0) {
|
||||
lwsl_err("%s: unable to connect\n", __func__);
|
||||
freeaddrinfo(r);
|
||||
return 1;
|
||||
}
|
||||
|
||||
freeaddrinfo(r);
|
||||
signal(SIGINT, sigint_handler);
|
||||
lwsl_user("Connected...\n");
|
||||
|
||||
/* our foreign socket is connected... adopt it into lws */
|
||||
|
||||
raw_wsi = lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_SOCKET, sock,
|
||||
protocols[0].name, NULL);
|
||||
if (!raw_wsi) {
|
||||
lwsl_err("%s: foreign socket adoption failed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
sock.filefd = 0;
|
||||
stdin_wsi = lws_adopt_descriptor_vhost(vhost, LWS_ADOPT_RAW_FILE_DESC,
|
||||
sock, protocols[0].name, NULL);
|
||||
if (!stdin_wsi) {
|
||||
lwsl_err("%s: stdin adoption failed\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
while (n >= 0 && !interrupted)
|
||||
n = lws_service(context, 1000);
|
||||
|
||||
bail:
|
||||
|
||||
lwsl_user("%s: destroying context\n", __func__);
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -2,7 +2,11 @@
|
|||
#
|
||||
# attack the test server and try to make it fall over
|
||||
#
|
||||
# Requires the library to have been built with cmake .. -DCMAKE_BUILD_TYPE=DEBUG
|
||||
# Requires the library to have been built with
|
||||
#
|
||||
# cmake .. -DCMAKE_BUILD_TYPE=DEBUG -DLWS_WITH_MINIMAL_EXAMPLES=1
|
||||
#
|
||||
# run it from the build dir
|
||||
|
||||
echo
|
||||
echo "----------------------------------------------"
|
||||
|
@ -19,6 +23,7 @@ INSTALLED=`dirname $A`
|
|||
SHAREDIR=$INSTALLED/../share/libwebsockets-test-server
|
||||
CORPUS=$SHAREDIR/test.html
|
||||
|
||||
LWS_NC=./bin/lws-minimal-raw-netcat
|
||||
|
||||
CPID=
|
||||
LEN=0
|
||||
|
@ -139,7 +144,7 @@ check
|
|||
echo
|
||||
echo "---- /cgi-bin/settingsjs?UPDATE_SETTINGS=1&Root_Channels_1_Channel_name_http_post=%3F&Root_Channels_1_Channel_location_http_post=%3F"
|
||||
rm -f /tmp/lwscap
|
||||
echo -n -e "GET /cgi-bin/settingsjs?UPDATE_SETTINGS=1&Root_Channels_1_Channel_name_http_post=%3F&Root_Channels_1_Channel_location_http_post=%3F HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -n -e "GET /cgi-bin/settingsjs?UPDATE_SETTINGS=1&Root_Channels_1_Channel_name_http_post=%3F&Root_Channels_1_Channel_location_http_post=%3F HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
cat /tmp/lwscap
|
||||
check 1 "UPDATE_SETTINGS=1"
|
||||
check 2 "Root_Channels_1_Channel_name_http_post=?"
|
||||
|
@ -149,14 +154,14 @@ check
|
|||
echo
|
||||
echo "---- ? processing (/cgi-bin/settings.js?key1=value1)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -n -e "GET /cgi-bin/settings.js?key1=value1 HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -n -e "GET /cgi-bin/settings.js?key1=value1 HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check 1 "key1=value1"
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- ? processing (/t%3dest?key1%3d2=value1)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -n -e "GET /t%3dest?key1%3d2=value1 HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -n -e "GET /t%3dest?key1%3d2=value1 HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check 0 "/t=est"
|
||||
check 1 "key1_2=value1"
|
||||
check
|
||||
|
@ -164,46 +169,46 @@ check
|
|||
echo
|
||||
echo "---- ? processing (%2f%2e%2e%2f%2e./xxtest.html?arg=1)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -n -e "GET %2f%2e%2e%2f%2e./xxtest.html?arg=1 HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -n -e "GET %2f%2e%2e%2f%2e./xxtest.html?arg=1 HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check 1 "arg=1"
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- ? processing (%2f%2e%2e%2f%2e./xxtest.html?arg=/../.)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -n -e "GET %2f%2e%2e%2f%2e./xxtest.html?arg=/../. HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -n -e "GET %2f%2e%2e%2f%2e./xxtest.html?arg=/../. HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check 1 "arg=/../."
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- spam enough crap to not be GET"
|
||||
echo "not GET" | nc $SERVER $PORT
|
||||
echo "not GET" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null > /tmp/lwscap
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- spam more than the name buffer of crap"
|
||||
dd if=/dev/urandom bs=1 count=80 2>/dev/null | nc -i1 $SERVER $PORT
|
||||
dd if=/dev/urandom bs=1 count=80 2>/dev/null | $LWS_NC --server $SERVER --port $PORT 2>/dev/null > /tmp/lwscap
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- spam 10MB of crap"
|
||||
dd if=/dev/urandom bs=1 count=655360 | nc -i1 $SERVER $PORT
|
||||
dd if=/dev/urandom bs=1 count=655360 | $LWS_NC --server $SERVER --port $PORT 2>/dev/null > /tmp/lwscap
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- malformed URI"
|
||||
echo "GET nonsense................................................................................................................" \
|
||||
| nc -i1 $SERVER $PORT
|
||||
| $LWS_NC --server $SERVER --port $PORT 2>/dev/null > /tmp/lwscap
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- missing URI"
|
||||
echo -n -e "GET HTTP/1.0\x0d\x0a\x0d\x0a" | nc -i1 $SERVER $PORT >/tmp/lwscap
|
||||
echo -n -e "GET HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null >/tmp/lwscap
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- repeated method"
|
||||
echo -n -e "GET blah HTTP/1.0\x0d\x0aGET blah HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT >/tmp/lwscap
|
||||
echo -n -e "GET blah HTTP/1.0\x0d\x0aGET blah HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null >/tmp/lwscap
|
||||
check
|
||||
|
||||
echo
|
||||
|
@ -225,7 +230,7 @@ echo -n -e "GET blah HTTP/1.0\x0d\x0a...........................................
|
|||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
| nc -i1 $SERVER $PORT
|
||||
| $LWS_NC --server $SERVER --port $PORT 2>/dev/null
|
||||
check
|
||||
|
||||
echo
|
||||
|
@ -247,20 +252,20 @@ echo -n -e "GET ................................................................
|
|||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
"......................................................................................................................." \
|
||||
| nc -i1 $SERVER $PORT
|
||||
| $LWS_NC --server $SERVER --port $PORT 2>/dev/null
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- good request but http payload coming too (test.html served then forbidden)"
|
||||
echo -n -e "GET /test.html HTTP/1.1\x0d\x0a\x0d\x0aILLEGAL-PAYLOAD........................................" \
|
||||
| cat - /dev/zero | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
| $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check defaultplusforbidden
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- nonexistent file"
|
||||
rm -f /tmp/lwscap
|
||||
echo -n -e "GET /nope HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -n -e "GET /nope HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
cat /tmp/lwscap
|
||||
check notfound
|
||||
check
|
||||
|
@ -268,63 +273,63 @@ check
|
|||
echo
|
||||
echo "---- relative uri path"
|
||||
rm -f /tmp/lwscap
|
||||
echo -n -e "GET nope HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -n -e "GET nope HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check forbidden
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- directory attack 1 (/../../../../etc/passwd should be /etc/passswd)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -n -e "GET /../../../../etc/passwd HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -n -e "GET /../../../../etc/passwd HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check notfound
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- directory attack 2 (/../ should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e -n "GET /../ HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -e -n "GET /../ HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- directory attack 3 (/./ should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e -n "GET /./ HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -e -n "GET /./ HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- directory attack 4 (/blah/.. should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e -n "GET /blah/.. HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -e -n "GET /blah/.. HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- directory attack 5 (/blah/../ should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e -n "GET /blah/../ HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -e -n "GET /blah/../ HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- directory attack 6 (/blah/../. should be /)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e -n "GET /blah/../. HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -e -n "GET /blah/../. HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check default
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- directory attack 7 (/%2e%2e%2f../../../etc/passwd should be /etc/passswd)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e -n "GET /%2e%2e%2f../../../etc/passwd HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -e -n "GET /%2e%2e%2f../../../etc/passwd HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check notfound
|
||||
check
|
||||
|
||||
echo
|
||||
echo "---- directory attack 8 (%2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd should be /etc/passswd)"
|
||||
rm -f /tmp/lwscap
|
||||
echo -e -n "GET %2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd HTTP/1.0\x0d\x0a\x0d\x0a" | nc $SERVER $PORT | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
echo -e -n "GET %2f%2e%2e%2f%2e./.%2e/.%2e%2fetc/passwd HTTP/1.0\x0d\x0a\x0d\x0a" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null | sed '1,/^\r$/d'> /tmp/lwscap
|
||||
check notfound
|
||||
check
|
||||
|
||||
|
@ -550,8 +555,9 @@ for i in \
|
|||
/path/to/dir/../other/dir \
|
||||
; do
|
||||
|
||||
R=`rm -f /tmp/lwscap ; echo -n -e "GET $i HTTP/1.0\r\n\r\n" | nc localhost 7681 2>/dev/null >/tmp/lwscap; head -n1 /tmp/lwscap| cut -d' ' -f2`
|
||||
R=`rm -f /tmp/lwscap ; echo -n -e "GET $i HTTP/1.0\r\n\r\n" | $LWS_NC --server $SERVER --port $PORT 2>/dev/null > /tmp/lwscap; head -n1 /tmp/lwscap| cut -d' ' -f2`
|
||||
|
||||
#cat $LOG
|
||||
#echo ==== $R
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue