commit 524eab401a2a695dd7ae27e9fa89ecf24f3603b1
parent 0094637ea1b32c0decd88b440a121864502dae48
Author: Remy Noulin <loader2x@gmail.com>
Date: Thu, 1 Sep 2022 21:07:03 +0200
add argument to server for a custom config, implement port setting in server configuration, add relay functionality
NOTES.md | 4 +-
README.md | 53 +++++++++++++-
sclient.c | 2 +-
serverPackage.yml | 2 +-
sserver.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
5 files changed, 260 insertions(+), 14 deletions(-)
Diffstat:
5 files changed, 260 insertions(+), 14 deletions(-)
diff --git a/NOTES.md b/NOTES.md
@@ -76,11 +76,11 @@ port 1032
alias:
hostname: ip
token: QE123123
- root: /home/rlp/tmp/
+ root: /home/USER/tmp/
port: 1022
~/.tuyau/serverConfig.yml
---
port: 1023 // optional
user:
token: QE123123
- root: /home/rlp/tmp/
+ root: /home/USER/tmp/
diff --git a/README.md b/README.md
@@ -10,33 +10,80 @@ spm -g install tuyau tuyauServer
# configuration
In server, create ~/.tuyau/serverConfig.yml
+```
---
- port: 1023 // optional
+ port: 1033 // optional
ausername(string):
token: 8 random non zero 8 bit values
root: apath(home)
-
+```
In client, create ~/.tuyau/config.yml
+```
---
ausername(string, this is the server name):
hostname: ip // server ip
token: 8 random non zero 8 bit values, same as server config
- port: 1022
+ port: 1032
+```
# usage
- start server
- run client
+Example configuration:
+```
+# client
+# ~/.tuyau/config.yml
+---
+ serverName:
+ hostname: ip
+ token: QE123123
+ root: /home/USER/tmp/
+ port: 1032
+# server
+~/.tuyau/serverConfig.yml
+---
+ port: 1032 // optional
+ serverName:
+ token: QE123123
+ root: /home/USER/tmp/
+ relay:
+ hostname: ip
+ token: a2345678
+ port: 1032
+```
+
+Start server on remote machine:
+```
+# create a certificate for the server (before first start)
+openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes -subj '/CN=your_fqdn'
+tuyauServer
+```
+
Upload files:
+```
tuyau files serverName
tuyau files serverName:path/
tuyau file serverName:path/newfilename
+```
+
+Upload files using `serverName` as a relay to the machine called `relay`:
+```
+tuyau files relay
+```
Downdload files (globbing is supported):
+```
tuyau serverName:path/files
>> downloads to current directory
tuyau serverName:path/files path/
tuyau serverName:path/file path/newfilename
+```
+
+Download files for the machine called `relay` using `serverName` as a relay:
+```
+tuyau relay:path/files
+```
# Commits
1 - send a single file
diff --git a/sclient.c b/sclient.c
@@ -164,7 +164,6 @@ int main(int ARGC, char** ARGV) {
int sock;
struct sockaddr_in server;
struct hostent *hp;
- int rval;
cleanAllocateNetFrame(netframe);
@@ -173,6 +172,7 @@ int main(int ARGC, char** ARGV) {
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0){
perror("Failed to create socket");
+ ret 1;
}
server.sin_family = AF_INET;
diff --git a/serverPackage.yml b/serverPackage.yml
@@ -1,6 +1,6 @@
---
name: tuyauServer
- version: 0.0.5
+ version: 0.0.6
description: "Server for copying files with tuyau"
bin: ./tuyauServer.c
#cflags: -DA -g3 -std=gnu11 -fPIC -pipe
diff --git a/sserver.c b/sserver.c
@@ -2,6 +2,7 @@
/* or direct path to sheepy: #! /usr/local/bin/sheepy */
/* Libsheepy documentation: https://spartatek.se/libsheepy/ */
+#include <netdb.h> // for gethostbyname
#include <netinet/in.h>
#include <string.h>
#include <stdlib.h>
@@ -40,6 +41,7 @@
#define CONFIG "~/.tuyau/serverConfig.yml"
int packetCount = 0;
+// file description for writing received chunks of big files
int fd = -1;
u64 transferSz = 0;
// client socket
@@ -49,12 +51,31 @@ rateLimitert *rateLim = null;
u32 clientIp = 0;
smallJsont *tokens = null;
+smallJsont *relays = null;
+
+// relay variables
+SSL_CTX *relay_ssl_ctx = null;
+SSL *relay_ssl = null;
+int relay_sock = -1;
+netFramet *relay_netframe = null;
+// when the client sends files to the destination
+// and the client closes the connection to this relay server,
+// close the connection to the destination normaly.
+// when the destination closes the connection only cleanup of the destination
+// connection is needed
+// This is needed because when the client closes the connection, the receive loop
+// breaks.
+bool closeDestConnection = no;
/* enable/disable logging */
/* #undef pLog */
/* #define pLog(...) */
+void closeRelayConnectionToDest(void);
void saveReceivedData(void *receiveB, size_t sz);
+bool relayForwardDataToClient(void *receiveB, size_t sz, void *context);
+
+// TODO return error from netframe callback
bool cb(void *buf, size_t size, void *context) {
saveReceivedData(buf, size);
@@ -118,20 +139,38 @@ int main(int ARGC, char** ARGV) {
// open listen socket
// start event loop
+ char *c = ARGV[1] ? ARGV[1] : CONFIG;
+
// load configuration
- cleanCharP(config) = expandHome(CONFIG);
+ cleanCharP(config) = expandHome(c);
cleanAllocateSmallJson(cfg);
readFileG(cfg, config);
- // create tokens dict
+ lv(cfg);
+
+ if (isEmptyG(cfg)) {
+ logC("Empty configuration %s", c);
+ ret 1;
+ }
+
tokens = allocG(rtSmallJsont);
+ relays = allocG(rtSmallJsont);
iter(cfg, D) {
+ if (!isOSmallDictG(D)) continue;
cast(smallDictt*,d,D);
- setG(tokens, $(d,"token"), $(d,"root"));
+ if (hasG(d, "root")) {
+ // local home
+ setG(tokens, $(d,"token"), $(d,"root"));
+ }
+ elif (hasG(d, "hostname")) {
+ // relay
+ setG(relays, $(d,"token"), d);
+ }
}
lv(tokens);
+ lv(relays);
// open listen socket
int sock;
@@ -144,9 +183,11 @@ int main(int ARGC, char** ARGV) {
XFailure;
}
+ u16 port = hasG(cfg, "port") ? u$(cfg, "port") : 1032;
+ lv(port);
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
- server.sin_port = htons(1032); // TODO allow changing port
+ server.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &server, sizeof(server))){
perror("bind failed");
@@ -184,20 +225,109 @@ int main(int ARGC, char** ARGV) {
else {
var r = o(netframe,receive, ssl);
logVarG(r);
+ if (closeDestConnection) {
+ // close client connection
+ o(netframe,end, relay_ssl);
+ }
}
// release SSL state
SSL_free(ssl);
close(mysock);
+ if (relay_sock != -1) {
+ if (closeDestConnection) {
+ // some data needs to be received in order to send all data to the server, SSL_write says all the data is sent but it is not true, why?
+ // 478 bytes are received. It seems to be encrypted.
+ // SSL_shutdown() and shutdown() don't help
+ u8 buf[1024*1024] = init0Var;
+ int r = recv(relay_sock, buf, sizeof(buf), 0);
+ if (r == -1) {
+ logE("recv before closing the socket");
+ }
+ }
+ closeRelayConnectionToDest();
+ }
}
}
SSL_CTX_free(ctx);
+ terminateG(relays);
terminateG(tokens);
terminateO(rateLim);
}
+// connect to destination, this server is a relay
+bool connectToDest(smallDictt *svrInfo) {
+
+ relay_sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (relay_sock < 0){
+ perror("Failed to create socket");
+ ret no;
+ }
+
+ struct sockaddr_in server;
+ struct hostent *hp;
+
+ server.sin_family = AF_INET;
+
+ hp = gethostbyname($(svrInfo, "hostname"));
+ if (hp==0) {
+ perror("gethostbyname failed");
+ close(relay_sock);
+ relay_sock = -1;
+ ret no;
+ }
+
+ memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
+ server.sin_port = htons(u$(svrInfo, "port"));
+
+ if (connect(relay_sock,(struct sockaddr *) &server, sizeof(server))){
+ perror("connect failed");
+ close(relay_sock);
+ relay_sock = -1;
+ ret no;
+ }
+
+ relay_ssl_ctx = SSL_CTX_new(TLS_method());
+ BIO *sbio = BIO_new(BIO_f_ssl());
+ relay_ssl = SSL_new(relay_ssl_ctx);
+ // attach the socket descriptor
+ SSL_set_fd(relay_ssl, relay_sock);
+
+ // perform the connection
+ if (SSL_connect(relay_ssl) == -1) {
+ logE("Couldn't establish the TLS connection");
+ // clean state
+ closeRelayConnectionToDest();
+ ret no;
+ }
+
+ ret yes;
+}
+
+void closeRelayConnectionToDest(void) {
+ // release SSL state
+ SSL_free(relay_ssl);
+ SSL_CTX_free(relay_ssl_ctx);
+ // TODO add recv to send all data?
+ close(relay_sock);
+ // clear relay state
+ relay_ssl = null;
+ relay_ssl_ctx = null;
+ relay_sock = -1;
+ terminateG(relay_netframe);
+}
+
void saveReceivedData(void *receiveB, size_t sz) {
logVarG(sz);
+
+ if (relay_sock != -1) {
+ // this server is a relay and the connection to the destination
+ // is already established
+ // forward data from client to destination
+ o(relay_netframe,send , relay_ssl, receiveB, sz);
+ ret;
+ }
+
if (packetCount == 0) {
// check packet size
if (sz < (1/*command*/ + 8/*token*/)) ret;
@@ -208,10 +338,21 @@ void saveReceivedData(void *receiveB, size_t sz) {
char tk[9] = init0Var;
memcpy(tk, token, 8);
+ cleanFinishSmallDictP(svrInfo) = null;
+
if (not hasG(tokens, tk)) {
- incomingG(rateLim, clientIp);
- logE("token not found");
- ret;
+ if (hasG(relays, tk)) {
+ // relay packets to destination
+ svrInfo = getG(relays, rtSmallDictt, tk);
+ logD("Relay to");
+ lv(svrInfo);
+ }
+ else {
+ // invalid connection, block ip
+ incomingG(rateLim, clientIp);
+ logE("token not found");
+ ret;
+ }
}
char *root = $(tokens, tk);
@@ -219,6 +360,19 @@ void saveReceivedData(void *receiveB, size_t sz) {
if (*command == 0) {
// receive file
+ if (svrInfo) {
+ // this server is a relay, connect to destination
+ if (not connectToDest(svrInfo)) {
+ logE("Relay: Can't connect to destination %m", svrInfo);
+ ret;
+ }
+ relay_netframe = allocNetFrame();
+ // forward data from client to destination
+ closeDestConnection = yes;
+ o(relay_netframe,send , relay_ssl, receiveB, sz);
+ ret;
+ }
+
// check packet size
if (sz < (1/*command*/ + 8/*token*/ + 2 /*filenameLength*/ + 1 /*filename*/)) ret;
u16 *filenameLength = (u16*)(receiveB + 9);
@@ -327,6 +481,19 @@ void saveReceivedData(void *receiveB, size_t sz) {
elif (*command == 1) {
// mkdir
+ if (svrInfo) {
+ // this server is a relay, connect to destination
+ if (not connectToDest(svrInfo)) {
+ logE("Relay: Can't connect to destination %m", svrInfo);
+ ret;
+ }
+ relay_netframe = allocNetFrame();
+ // forward data from client to destination
+ closeDestConnection = yes;
+ o(relay_netframe,send , relay_ssl, receiveB, sz);
+ ret;
+ }
+
// check packet size
if (sz < (1/*command*/ + 8/*token*/ + 2 /*filemode*/ + 2 /*pathLength*/ + 1 /*path*/)) ret;
u16 *filemode = (u16*)(receiveB + 9);
@@ -346,6 +513,31 @@ void saveReceivedData(void *receiveB, size_t sz) {
pError0(fileChmod(path, *filemode));
}
elif (*command == 2) {
+ // send files to client
+
+ if (svrInfo) {
+ // this server is a relay, connect to destination
+ if (not connectToDest(svrInfo)) {
+ logE("Relay: Can't connect to destination %m", svrInfo);
+ ret;
+ }
+ relay_netframe = allocNetFrame();
+ // forward data from client to destination
+ closeDestConnection = no;
+ o(relay_netframe,send , relay_ssl, receiveB, sz);
+
+ cleanAllocateNetFrame(netframe);
+
+ o(relay_netframe, setCallback, relayForwardDataToClient, netframe /*context*/);
+
+ var r = o(relay_netframe,receive, relay_ssl);
+ logVarG(r);
+
+ // close client connection
+ o(netframe,end, ssl);
+ ret;
+ }
+
// check packet size, sendFile path has to be at least 1 byte
if (sz < (1/*command*/ + 8/*token*/ + 2 /*sendFileLength*/ + 1 /*sendFile*/)) ret;
logD("send files to client");
@@ -564,4 +756,11 @@ void saveReceivedData(void *receiveB, size_t sz) {
else transferSz -= sz;
}
}
+
+bool relayForwardDataToClient(void *receiveB, size_t sz, void *context) {
+ cast(netFramet*, netframe, context);
+ // forward data from destination to client
+ o(netframe,send , ssl, receiveB, sz);
+ ret yes;
+}
// vim: set expandtab ts=2 sw=2: