From 2766e50f473817cea0f312f357342399a0754926 Mon Sep 17 00:00:00 2001 From: reemo Date: Sun, 17 Dec 2023 08:30:44 -0600 Subject: [PATCH] wsock handshake works --- .gitignore | 3 +- src/main.c | 1 + src/wsock.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/wsock.h | 14 +++-- 4 files changed, 188 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index cd531cf..4194f36 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ *.i*86 *.x86_64 *.hex +clii # Debug files *.dSYM/ @@ -51,4 +52,4 @@ modules.order Module.symvers Mkfile.old dkms.conf - +*.swp diff --git a/src/main.c b/src/main.c index 6f4136e..d6e7812 100644 --- a/src/main.c +++ b/src/main.c @@ -67,6 +67,7 @@ int main(int argc, char** argv) { } printf("Connecting to Flashii ...\n"); + wsock_t* sock = wsock_open(FII_ADDR, "/", 80); for(;;); diff --git a/src/wsock.c b/src/wsock.c index 73f31f7..69feb9d 100644 --- a/src/wsock.c +++ b/src/wsock.c @@ -1,3 +1,178 @@ #include "wsock.h" +/** DATA BUFFER **/ +/*******************/ + +buffer_t* buffer_create() { + buffer_t* buf = malloc(sizeof(buffer_t)); + buf->data = NULL; + buf->next = NULL; + buf->length = 0; + + return buf; +} + +int buffer_is_empty(buffer_t* buf) { + return buf->data == NULL; +} + +int buffer_length(buffer_t* buf) { + if(buf == NULL) + return 0; + + return buf->length + buffer_length(buf->next); +} + +void buffer_append + (buffer_t* buf, const char* data, int length) +{ + if(buf->data != NULL) { + buf->next = buffer_create(); + buffer_append(buf->next, data, length); + } + + buf->data = malloc(length); + strncpy(buf->data, data, length); + buf->length = length; +} + +void buffer_append_str(buffer_t* buf, const char* data) { + buffer_append(buf, data, strlen(data)); +} + +void _buffer_read(buffer_t* buf, char* out) { + int i = 0; + while(buf != NULL) { + strncpy(out + i, buf->data, buf->length); + i += buf->length; + } +} + +char* buffer_read(buffer_t* buf, int* plen) { + int length = buffer_length(buf); + if(plen != NULL) + *plen = length; + + char* out = malloc(length); + _buffer_read(buf, out); + return out; +} + +char* buffer_read_str(buffer_t* buf, int* plen) { + int length = buffer_length(buf); + if(plen != NULL) + *plen = length; + + char* out = malloc(length + 1); + out[length] = '\0'; + _buffer_read(buf, out); + return out; +} + +char* buffer_flush(buffer_t* buf, int* plen) { + char* out = buffer_read(buf, plen); + buffer_clear(buf); + return out; +} + +char* buffer_flush_str(buffer_t* buf, int* plen) { + char* out = buffer_read_str(buf, plen); + buffer_clear(buf); + return out; +} + +void _buffer_clear(buffer_t* buf, int root) { + if(buf == NULL) + return; + _buffer_clear(buf->next, 0); + + free(buf->data); + if(!root) + free(buf); + else { + buf->data = NULL; + buf->next = NULL; + buf->length = 0; + } +} + +void buffer_clear(buffer_t* buf) { + _buffer_clear(buf, 1); +} + +void buffer_free(buffer_t* buf) { + buffer_clear(buf); + free(buf); +} + + +/** WEB SOCKET **/ +/******************/ + +wsock_t* wsock_open + (const char* host, const char* path, uint16_t port) +{ + char s_port[6]; + sprintf(s_port, "%i", port); + + int sock; + struct addrinfo hints, *result, *rp; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = 0; + hints.ai_protocol = 0; + + if(getaddrinfo(host, s_port, &hints, &result) != 0) + return NULL; + for(rp = result; rp != NULL; rp = rp->ai_next) { + if((sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) == -1) + continue; + if(connect(sock, rp->ai_addr, rp->ai_addrlen) != -1) + break; + } + freeaddrinfo(result); + if(rp == NULL) + return NULL; + + // todo: randomize wsock key + char s_shake[4096]; + sprintf(s_shake, + "GET %s HTTP/1.1\r\n" + "Host: %s:%i\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Key: AQIDBAUGBwgJCgsMDQ4PEC==\r\n" + "Sec-WebSocket-Version: 13\r\n\r\n", + path, + host, port + ); + if(send(sock, s_shake, strlen(s_shake), 0) <= 0) { + shutdown(sock, SHUT_RDWR); + return NULL; + } + s_shake[0] = '\0'; + + struct pollfd pfd; + pfd.fd = sock; + pfd.events = POLLIN; + + char* end; + int total = 0; + while((end = strstr(s_shake, "\r\n\r\n")) == NULL) { + if(total + 1 >= sizeof(s_shake) + || poll(&pfd, 1, 5000) <= 0) + { + shutdown(sock,SHUT_RDWR); + return NULL; + } + + total += recv(sock, s_shake + total, + sizeof(s_shake) - total - 1, 0); + s_shake[total] = '\0'; + } + + shutdown(sock, SHUT_RDWR); + return NULL; +} diff --git a/src/wsock.h b/src/wsock.h index 9e451db..10612fa 100644 --- a/src/wsock.h +++ b/src/wsock.h @@ -1,5 +1,10 @@ +#include +#include +#include + #include #include +#include #include /** DATA BUFFER **/ @@ -14,6 +19,7 @@ typedef struct buffer_t buffer_t; buffer_t* buffer_create(); +int buffer_is_empty(buffer_t*); int buffer_length(buffer_t*); void buffer_append(buffer_t*, const char*, int); void buffer_append_str(buffer_t*, const char*); @@ -47,15 +53,15 @@ typedef enum { // WS_FULL_SEND will block on the protocol level, until // a packet is fully sent or received -// for example, WS_BLOCK alone with block until data is +// for example, WS_BLOCK alone will block until data is // available, but will immediately return nothing if the // data received is not a full packet. however, using // WS_BLOCK | WS_FULL_RECV will block until data is // available, and then until a full websocket packet is -// fully constructed, after which the data is returned. -// noblock behaves in the same way except the system +// fully received, after which the data is then returned. +// WS_NOBLOCK behaves in the same way except the system // calls will not block, but with WS_FULL_RECV enabled -// it will then block until a full packet is constructed +// it will then block until a full packet is received // currently WS_FULL_SEND is set to be always enabled // when the mode is changed because i do not currently