mirror of
https://github.com/eddyem/onionserver.git
synced 2026-01-31 12:25:17 +03:00
fixed websockets
This commit is contained in:
parent
c1873f23ff
commit
a7ff44b18a
@ -35,14 +35,14 @@ find_package(Threads REQUIRED)
|
||||
|
||||
###### pkgconfig ######
|
||||
# pkg-config modules (for pkg-check-modules)
|
||||
set(MODULES usefull_macros sqlite3)
|
||||
set(MODULES usefull_macros sqlite3 onion)
|
||||
|
||||
# find packages:
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(${PROJ} REQUIRED ${MODULES})
|
||||
|
||||
###### additional flags ######
|
||||
list(APPEND ${PROJ}_LIBRARIES "-lonion -lcrypt")
|
||||
list(APPEND ${PROJ}_LIBRARIES "-lcrypt")
|
||||
|
||||
# change wrong behaviour with install prefix
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND CMAKE_INSTALL_PREFIX MATCHES "/usr/local")
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
# onionserver
|
||||
Simple web-server based on libonion
|
||||
|
||||
default admin: toor, password: p@ssw0rd
|
||||
34
auth.c
34
auth.c
@ -149,6 +149,7 @@ sessinfo *qookieSession(onion_request *req){
|
||||
}
|
||||
|
||||
onion_connection_status auth(_U_ onion_handler *h, onion_request *req, onion_response *res){
|
||||
int retcode = OCS_CLOSE_CONNECTION;
|
||||
if(!req || !res) return OCS_CLOSE_CONNECTION;
|
||||
if(onion_request_get_flags(req) & OR_HEAD) {
|
||||
onion_response_write_headers(res);
|
||||
@ -195,33 +196,27 @@ onion_connection_status auth(_U_ onion_handler *h, onion_request *req, onion_res
|
||||
userinfo *U = getUserData(username);
|
||||
if(!U){
|
||||
WARNX("User %s not found", username);
|
||||
return OCS_FORBIDDEN;
|
||||
retcode = OCS_FORBIDDEN;
|
||||
goto closeconn;
|
||||
}
|
||||
char *pass = strdup(crypt(passwd, "$6$"));
|
||||
if(!pass){
|
||||
WARN("Error in ctypt or strdup");
|
||||
freeUserInfo(&U);
|
||||
return OCS_FORBIDDEN;
|
||||
retcode = OCS_FORBIDDEN;
|
||||
goto closeconn;
|
||||
}
|
||||
int comp = strcmp(pass, U->password);
|
||||
freeUserInfo(&U);
|
||||
FREE(pass);
|
||||
if(comp){
|
||||
WARNX("User %s give wrong password", username);
|
||||
return OCS_FORBIDDEN;
|
||||
retcode = OCS_FORBIDDEN;
|
||||
goto closeconn;
|
||||
}
|
||||
session = MALLOC(sessinfo, 1);
|
||||
session->atime = time(NULL);
|
||||
session->username = strdup(username);
|
||||
/*
|
||||
onion_dict *data = onion_dict_new();
|
||||
onion_dict_add(data, "UA", UA, 0);
|
||||
onion_dict_add(data, "IP", host, 0);
|
||||
onion_block *bl = onion_dict_to_json(data);
|
||||
if(bl){
|
||||
const char *json = onion_block_data(bl);
|
||||
if(json) session->data = strdup(json);
|
||||
}*/
|
||||
session->data = strdup(json);
|
||||
do{
|
||||
FREE(session->sessID);
|
||||
@ -238,7 +233,7 @@ onion_connection_status auth(_U_ onion_handler *h, onion_request *req, onion_res
|
||||
onion_response_write0(res, AUTH_ANS_AUTHOK);
|
||||
closeconn:
|
||||
freeSessInfo(&session);
|
||||
return OCS_CLOSE_CONNECTION;
|
||||
return retcode;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -552,22 +547,21 @@ int addSession(sessinfo *s, int modify){
|
||||
if(!s) return 1;
|
||||
sessinfo *byID = getSession(s->sessID);
|
||||
sessinfo *bysID = getSession(s->sockID);
|
||||
int errfound = 0;
|
||||
if(byID || bysID){ // found session with same IDs
|
||||
if(modify){
|
||||
if(bysID && strcmp(bysID->sessID, s->sessID)){
|
||||
freeSessInfo(&byID);
|
||||
freeSessInfo(&bysID);
|
||||
WARNX("Found another session with the same sockID");
|
||||
return 2;
|
||||
errfound = 2;
|
||||
}
|
||||
}else{
|
||||
if(byID) WARNX("Found another session with the same sessID");
|
||||
if(bysID) WARNX("Found another session with the same sockID");
|
||||
freeSessInfo(&byID);
|
||||
freeSessInfo(&bysID);
|
||||
return 3;
|
||||
errfound = 3;
|
||||
}
|
||||
}
|
||||
freeSessInfo(&byID);
|
||||
freeSessInfo(&bysID);
|
||||
if(errfound) return errfound;
|
||||
pthread_mutex_lock(&sessionDB->mutex);
|
||||
// 1-sessID, 2-sockID, 3-atime, 4-username, 5-data
|
||||
sqlite3_reset(sessionDB->add);
|
||||
|
||||
2
auth.h
2
auth.h
@ -29,6 +29,8 @@
|
||||
#define AUTH_ANS_AUTHOK "AuthOK"
|
||||
#define AUTH_ANS_LOGOUT "LogOut"
|
||||
#define AUTH_ANS_NOPASSWD "NoPassword"
|
||||
#define AUTH_ANS_NOUSERDATA "NoUserData"
|
||||
#define AUTH_ANS_WRONGIP "WrongIPUA"
|
||||
|
||||
typedef struct{
|
||||
char *username; // user name
|
||||
|
||||
84
main.c
84
main.c
@ -56,77 +56,64 @@ onion_connection_status get(_U_ onion_handler *h, onion_request *req, onion_resp
|
||||
return OCS_CLOSE_CONNECTION;
|
||||
}
|
||||
|
||||
static onion *os = NULL, *ow = NULL;
|
||||
static onion *os = NULL;//, *ow = NULL;
|
||||
static int STOP = 0;
|
||||
void signals(int signo){
|
||||
signal(signo, SIG_IGN);
|
||||
STOP = 1;
|
||||
if(os){
|
||||
onion_free(os);
|
||||
}
|
||||
/*if(ow){
|
||||
onion_free(ow);
|
||||
}*/
|
||||
closeSQLite();
|
||||
if(os) onion_free(os);
|
||||
if(ow) onion_free(ow);
|
||||
sleep(1);
|
||||
exit(signo);
|
||||
}
|
||||
|
||||
// POST/GET server
|
||||
static void *runPostGet(_U_ void *data){
|
||||
os = onion_new(O_THREADED);
|
||||
FNAME();
|
||||
if(STOP) return NULL;
|
||||
os = onion_new(O_POOL);
|
||||
if(!(onion_flags(os) & O_SSL_AVAILABLE)){
|
||||
ONION_ERROR("SSL support is not available");
|
||||
signals(1);
|
||||
}
|
||||
int error = onion_set_certificate(os, O_SSL_CERTIFICATE_KEY, G.certfile, G.keyfile);
|
||||
if(error){
|
||||
ONION_ERROR("Cant set certificate and key files (%s, %s)", G.certfile, G.keyfile);
|
||||
ONION_ERROR("Can't set certificate and key files (%s, %s)", G.certfile, G.keyfile);
|
||||
signals(1);
|
||||
}
|
||||
DBG("PostGet @ port %s", G.port);
|
||||
onion_set_port(os, G.port);
|
||||
onion_url *url = onion_root_url(os);
|
||||
onion_url_add_handler(url, "^static/", onion_handler_export_local_new("static"));
|
||||
onion_url_add_with_data(url, "", onion_shortcut_internal_redirect, "static/index.html", NULL);
|
||||
onion_url_add(url, "^auth/", auth);
|
||||
onion_url_add(url, "^get/", get);
|
||||
onion_url_add(url, "ws", websocket_run);
|
||||
error = onion_listen(os);
|
||||
if(error) ONION_ERROR("Cant create POST/GET server: %s", strerror(errno));
|
||||
if(error) ONION_ERROR("Can't create POST/GET server: %s", strerror(errno));
|
||||
onion_free(os);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Websocket server
|
||||
static void *runWS(_U_ void *data){
|
||||
ow = onion_new(O_THREADED);
|
||||
if(!(onion_flags(ow) & O_SSL_AVAILABLE)){
|
||||
ONION_ERROR("SSL support is not available");
|
||||
signals(1);
|
||||
}
|
||||
int error = onion_set_certificate(ow, O_SSL_CERTIFICATE_KEY, G.certfile, G.keyfile);
|
||||
if(error){
|
||||
ONION_ERROR("Cant set certificate and key files (%s, %s)", G.certfile, G.keyfile);
|
||||
signals(1);
|
||||
}
|
||||
onion_set_port(ow, G.wsport);
|
||||
onion_url *url = onion_root_url(ow);
|
||||
onion_url_add(url, "", websocket_run);
|
||||
DBG("Listen websocket");
|
||||
error = onion_listen(ow);
|
||||
if(error) ONION_ERROR("Cant create POST/GET server: %s", strerror(errno));
|
||||
onion_free(ow);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void runServer(){
|
||||
// if(G.logfilename) Cl_createlog();
|
||||
signal(SIGTERM, signals);
|
||||
signal(SIGINT, signals);
|
||||
signal(SIGQUIT, signals);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
|
||||
pthread_t pg_thread, ws_thread;
|
||||
// if(G.logfilename) Cl_createlog();
|
||||
pthread_t pg_thread;//, ws_thread;
|
||||
if(pthread_create(&pg_thread, NULL, runPostGet, NULL)){
|
||||
ERR("pthread_create()");
|
||||
}
|
||||
if(pthread_create(&ws_thread, NULL, runWS, NULL)){
|
||||
ERR("pthread_create()");
|
||||
}
|
||||
do{
|
||||
if(pthread_kill(pg_thread, 0) == ESRCH){ // POST/GET died
|
||||
if(STOP) return;
|
||||
if(pthread_kill(pg_thread, 0) == ESRCH){ // server died
|
||||
WARNX("POST/GET server thread died");
|
||||
putlog("POST/GET server thread died");
|
||||
pthread_join(pg_thread, NULL);
|
||||
@ -135,15 +122,6 @@ static void runServer(){
|
||||
ERR("pthread_create()");
|
||||
}
|
||||
}
|
||||
if((pthread_kill(pg_thread, 0) == ESRCH) || (pthread_kill(ws_thread, 0) == ESRCH)){ // died
|
||||
WARNX("Websocket server thread died");
|
||||
putlog("Websocket server thread died");
|
||||
pthread_join(ws_thread, NULL);
|
||||
if(pthread_create(&ws_thread, NULL, runWS, NULL)){
|
||||
putlog("pthread_create() failed");
|
||||
ERR("pthread_create()");
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
usleep(1000); // sleep a little or thread's won't be able to lock mutex
|
||||
if(dtime() - tgot < T_INTERVAL) continue;
|
||||
@ -231,24 +209,6 @@ int main(int argc, char **argv){
|
||||
}
|
||||
}
|
||||
if(G.useradd) adduser();
|
||||
/*
|
||||
sessinfo *x = MALLOC(sessinfo, 1);
|
||||
x->data = strdup("some data");
|
||||
x->atime = time(NULL);
|
||||
x->username = strdup("luser");
|
||||
do{
|
||||
FREE(x->sessID);
|
||||
FREE(x->sockID);
|
||||
x->sessID = onion_sessions_generate_id();
|
||||
x->sockID = onion_sessions_generate_id();
|
||||
if(!addSession(x)){
|
||||
green("Insert session: ID=%s, sockid=%s, atime=%lld, user=%s, data=%s\n",
|
||||
x->sessID, x->sockID, x->atime, x->username, x->data);
|
||||
break;
|
||||
}
|
||||
}while(1);
|
||||
freeSessInfo(&x);
|
||||
*/
|
||||
if(G.dumpSessDB) showAllSessions();
|
||||
if(G.delsession){
|
||||
if(!deleteSession(G.delsession))
|
||||
|
||||
@ -52,6 +52,7 @@ auth = function(){
|
||||
}
|
||||
function logout1(){
|
||||
sendrequest("auth/?LogOut=1", _ilogin);
|
||||
ws.close();
|
||||
}
|
||||
function sendlogpass(){
|
||||
$("shadow").style.display = "none";
|
||||
@ -67,7 +68,7 @@ auth = function(){
|
||||
var ws;
|
||||
function wsinit(){
|
||||
delete(ws);
|
||||
ws = new WebSocket('wss://localhost:8081');
|
||||
ws = new WebSocket('wss://localhost:8080/ws');
|
||||
ws.onopen = function(){ws.send("Akey="+wsKey);}; // send key after init
|
||||
ws.onclose = function(evt){
|
||||
var text = "WebSocket closed: ";
|
||||
|
||||
50
websockets.c
50
websockets.c
@ -20,6 +20,7 @@
|
||||
#include "websockets.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <onion/dict.h>
|
||||
#include <onion/log.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -29,12 +30,26 @@
|
||||
|
||||
// bit-fields of `data` field (websocket_cont)
|
||||
#define WS_FLAG_NOTAUTHORIZED 1
|
||||
typedef struct{
|
||||
uint64_t UAhash;
|
||||
uint64_t IPhash;
|
||||
uint64_t flags;
|
||||
} WSdata;
|
||||
|
||||
TODO: add logout!
|
||||
// https://stackoverflow.com/a/57960443/1965803
|
||||
static uint64_t MurmurOAAT64(const char *key){
|
||||
uint64_t h = 525201411107845655ull;
|
||||
for (;*key;++key){
|
||||
h ^= (uint64_t)*key;
|
||||
h *= 0x5bd1e9955bd1e995;
|
||||
h ^= h >> 47;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
static onion_connection_status websocket_cont(void *data, onion_websocket *ws, ssize_t dlen){
|
||||
FNAME();
|
||||
uint32_t flags = *((uint32_t*)data);
|
||||
WSdata *wsdata = (WSdata*)data;
|
||||
char tmp[BUFLEN+1];
|
||||
if(dlen > BUFLEN) dlen = BUFLEN;
|
||||
|
||||
@ -46,19 +61,36 @@ static onion_connection_status websocket_cont(void *data, onion_websocket *ws, s
|
||||
tmp[len] = 0;
|
||||
//ONION_INFO("Read from websocket: %s (len=%d)", tmp, len);
|
||||
DBG("WS: got %s", tmp);
|
||||
if(flags & WS_FLAG_NOTAUTHORIZED){ // not authorized over websocket
|
||||
if(wsdata->flags & WS_FLAG_NOTAUTHORIZED){ // not authorized over websocket
|
||||
sessinfo *session = NULL;
|
||||
if(strncmp(tmp, "Akey=", 5) == 0){ // got authorized key - check it
|
||||
char *key = tmp + 5;
|
||||
session = getSession(key);
|
||||
/* here we should make a proper check, but for now do simplest */
|
||||
}
|
||||
if(!session){
|
||||
onion_websocket_printf(ws, AUTH_ANS_NEEDAUTH);
|
||||
WARNX("Wrong websocket session ID");
|
||||
return OCS_FORBIDDEN;
|
||||
}
|
||||
flags &= ~WS_FLAG_NOTAUTHORIZED; // clear non-authorized flag
|
||||
//
|
||||
onion_dict *json = onion_dict_from_json(session->data);
|
||||
freeSessInfo(&session);
|
||||
if(json){
|
||||
uint64_t UAhash = MurmurOAAT64(onion_dict_get(json, "User-Agent"));
|
||||
uint64_t IPhash = MurmurOAAT64(onion_dict_get(json, "User-IP"));
|
||||
if(wsdata->IPhash != IPhash || wsdata->UAhash != UAhash){
|
||||
onion_websocket_printf(ws, AUTH_ANS_WRONGIP);
|
||||
WARNX("Websocket IP/UA are wrong");
|
||||
return OCS_FORBIDDEN;
|
||||
}
|
||||
red("WSdata checked!\n");
|
||||
onion_dict_free(json);
|
||||
}else{
|
||||
onion_websocket_printf(ws, AUTH_ANS_NOUSERDATA);
|
||||
WARNX("No user IP and/or UA in database");
|
||||
return OCS_FORBIDDEN;
|
||||
}
|
||||
wsdata->flags &= ~WS_FLAG_NOTAUTHORIZED; // clear non-authorized flag
|
||||
return OCS_NEED_MORE_DATA;
|
||||
}
|
||||
char *eq = strchr(tmp, '=');
|
||||
@ -75,7 +107,6 @@ onion_connection_status websocket_run(_U_ void *data, onion_request *req, onion_
|
||||
FNAME();
|
||||
onion_websocket *ws = onion_websocket_new(req, res);
|
||||
if (!ws){
|
||||
green("PROC\n");
|
||||
DBG("Processed");
|
||||
return OCS_PROCESSED;
|
||||
}
|
||||
@ -83,8 +114,11 @@ onion_connection_status websocket_run(_U_ void *data, onion_request *req, onion_
|
||||
const char *host = onion_request_get_client_description(req);
|
||||
const char *UA = onion_request_get_header(req, "User-Agent");
|
||||
green("Got WS connection from %s (UA: %s)\n", host, UA);
|
||||
uint32_t *flags = calloc(1, 4);
|
||||
onion_websocket_set_userdata(ws, (void*)flags, free);
|
||||
WSdata *wsdata = calloc(1, sizeof(WSdata));
|
||||
wsdata->flags = WS_FLAG_NOTAUTHORIZED;
|
||||
wsdata->IPhash = MurmurOAAT64(host);
|
||||
wsdata->UAhash = MurmurOAAT64(UA);
|
||||
onion_websocket_set_userdata(ws, (void*)wsdata, free);
|
||||
onion_websocket_set_callback(ws, websocket_cont);
|
||||
return OCS_WEBSOCKET;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user