Add passive mode (only for localhost) and fix random thread crashes
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
#include "filer.cpp"
|
#include "filer.cpp"
|
||||||
@@ -25,6 +26,7 @@ public:
|
|||||||
* 2 - Waiting for data
|
* 2 - Waiting for data
|
||||||
*/
|
*/
|
||||||
int state = 0;
|
int state = 0;
|
||||||
|
std::thread thread;
|
||||||
|
|
||||||
Client(int &_sock) {
|
Client(int &_sock) {
|
||||||
control_sock = _sock;
|
control_sock = _sock;
|
||||||
@@ -37,7 +39,7 @@ public:
|
|||||||
return -1;
|
return -1;
|
||||||
} else if (state > 0) {
|
} else if (state > 0) {
|
||||||
if (cmd == "SYST") {
|
if (cmd == "SYST") {
|
||||||
submit(215, "UNIX");
|
submit(215, "UNIX Type: L8");
|
||||||
} else if (cmd == "PWD") {
|
} else if (cmd == "PWD") {
|
||||||
submit(257, "'"+filer->cwd.string()+"'");
|
submit(257, "'"+filer->cwd.string()+"'");
|
||||||
} else if (cmd == "CWD") {
|
} else if (cmd == "CWD") {
|
||||||
@@ -69,7 +71,76 @@ public:
|
|||||||
sscanf(argstr.c_str(), "%c", &(filer->type));
|
sscanf(argstr.c_str(), "%c", &(filer->type));
|
||||||
submit(226, "OK");
|
submit(226, "OK");
|
||||||
} else if (cmd == "PASV") {
|
} else if (cmd == "PASV") {
|
||||||
submit(502, "Command not implemented");
|
if ((data_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
|
perror("pasv socket() failed");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(data_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, (char *)&opt, sizeof(opt)) < 0) {
|
||||||
|
perror("pasv setsockopt() failed");
|
||||||
|
close(data_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t dataport;
|
||||||
|
uint8_t netaddr[4];
|
||||||
|
uint8_t netport[2];
|
||||||
|
socklen_t datalen = sizeof(data_address);
|
||||||
|
|
||||||
|
data_address.sin_family = AF_INET;
|
||||||
|
data_address.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
data_address.sin_port = 0;
|
||||||
|
|
||||||
|
if (bind(data_fd, (struct sockaddr *)&data_address, sizeof(data_address)) < 0) {
|
||||||
|
perror("pasv bind() failed");
|
||||||
|
close(data_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(data_fd, 3) < 0) {
|
||||||
|
perror("pasv listen() failed");
|
||||||
|
close(data_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getsockname(data_fd, (struct sockaddr *)&data_address, &datalen) == 0) {
|
||||||
|
//memcpy(&netaddr[0], &data_address.sin_addr, 4);
|
||||||
|
netaddr[0] = 127;
|
||||||
|
netaddr[1] = netaddr[2] = 0;
|
||||||
|
netaddr[3] = 1;
|
||||||
|
dataport = ntohs(data_address.sin_port);
|
||||||
|
memcpy(&netport[0], &dataport, 2);
|
||||||
|
printf("[i] D(%i) PASV initialized: %u.%u.%u.%u:%u\n", data_fd, netaddr[0], netaddr[1], netaddr[2], netaddr[3], dataport);
|
||||||
|
} else {
|
||||||
|
perror("pasv getpeername() failed");
|
||||||
|
close(data_fd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* pasvok;
|
||||||
|
asprintf(
|
||||||
|
&pasvok,
|
||||||
|
"Entering Passive Mode (%u,%u,%u,%u,%u,%u)",
|
||||||
|
netaddr[0],
|
||||||
|
netaddr[1],
|
||||||
|
netaddr[2],
|
||||||
|
netaddr[3],
|
||||||
|
netport[1],
|
||||||
|
netport[0]
|
||||||
|
);
|
||||||
|
|
||||||
|
submit(227, std::string(pasvok));
|
||||||
|
free(pasvok);
|
||||||
|
|
||||||
|
if ((data_sock = accept(data_fd, NULL, NULL)) >= 0) {
|
||||||
|
printf("[i] D(%i) PASV accepted: %i\n", data_fd, data_sock);
|
||||||
|
state = 2;
|
||||||
|
//submit(200, "OK");
|
||||||
|
} else {
|
||||||
|
perror("accept() failed");
|
||||||
|
submit(425, "Unknown Error");
|
||||||
|
data_close();
|
||||||
|
}
|
||||||
} else if (cmd == "PORT") {
|
} else if (cmd == "PORT") {
|
||||||
data_sock = socket(AF_INET, SOCK_STREAM, 0);
|
data_sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
@@ -79,16 +150,15 @@ public:
|
|||||||
sscanf(argstr.c_str(), "%d,%d,%d,%d,%d,%d", &act_ip[0], &act_ip[1], &act_ip[2], &act_ip[3], (int*)&act_port[0], (int*)&act_port[1]);
|
sscanf(argstr.c_str(), "%d,%d,%d,%d,%d,%d", &act_ip[0], &act_ip[1], &act_ip[2], &act_ip[3], (int*)&act_port[0], (int*)&act_port[1]);
|
||||||
sprintf(ip_decimal, "%d.%d.%d.%d", act_ip[0], act_ip[1], act_ip[2], act_ip[3]);
|
sprintf(ip_decimal, "%d.%d.%d.%d", act_ip[0], act_ip[1], act_ip[2], act_ip[3]);
|
||||||
port_dec = act_port[0]*256+act_port[1];
|
port_dec = act_port[0]*256+act_port[1];
|
||||||
printf("[d] D(%i) Initialized data transport: %s:%d\n", control_sock, ip_decimal, port_dec);
|
printf("[d] D(%i) PORT initialized: %s:%d\n", control_sock, ip_decimal, port_dec);
|
||||||
|
|
||||||
data_address.sin_family = AF_INET;
|
data_address.sin_family = AF_INET;
|
||||||
data_address.sin_addr.s_addr = inet_addr(ip_decimal);
|
data_address.sin_addr.s_addr = inet_addr(ip_decimal);
|
||||||
data_address.sin_port = htons(port_dec);
|
data_address.sin_port = htons(port_dec);
|
||||||
|
|
||||||
if (connect(data_sock, (struct sockaddr *)&data_address, sizeof(data_address)) != 0) {
|
if (connect(data_sock, (struct sockaddr *)&data_address, sizeof(data_address)) != 0) {
|
||||||
close(data_sock);
|
|
||||||
data_sock = 0;
|
|
||||||
submit(425, "Unknown Error");
|
submit(425, "Unknown Error");
|
||||||
|
data_close();
|
||||||
} else {
|
} else {
|
||||||
state = 2;
|
state = 2;
|
||||||
submit(200, "OK");
|
submit(200, "OK");
|
||||||
@@ -152,9 +222,7 @@ public:
|
|||||||
}
|
}
|
||||||
submit(226, "OK");
|
submit(226, "OK");
|
||||||
}
|
}
|
||||||
if (data_close() != 0) {
|
data_close();
|
||||||
printf("[!] Data Sock returned %i instead of 0! Not closed!!!\n", data_sock);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
submit(502, "Command not implemented");
|
submit(502, "Command not implemented");
|
||||||
}
|
}
|
||||||
@@ -205,17 +273,22 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
int data_close() {
|
int data_close() {
|
||||||
|
if (data_sock <= 0) return 0;
|
||||||
printf("[d] D(%i) Closing...\n", data_sock);
|
printf("[d] D(%i) Closing...\n", data_sock);
|
||||||
close(data_sock);
|
close(data_sock);
|
||||||
data_sock = 0;
|
data_sock = -1;
|
||||||
|
close(data_fd);
|
||||||
|
data_fd = -1;
|
||||||
state = 1;
|
state = 1;
|
||||||
return data_sock; // Should be 0 if successful.
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string name;
|
std::string name;
|
||||||
Filer* filer = new Filer();
|
Filer* filer = new Filer();
|
||||||
|
const int opt = 1;
|
||||||
|
|
||||||
|
int data_fd;
|
||||||
int data_sock;
|
int data_sock;
|
||||||
struct sockaddr_in data_address;
|
struct sockaddr_in data_address;
|
||||||
};
|
};
|
||||||
65
src/main.cpp
65
src/main.cpp
@@ -28,7 +28,6 @@ using namespace std::chrono_literals;
|
|||||||
struct pollfd fds[MAXCLIENTS];
|
struct pollfd fds[MAXCLIENTS];
|
||||||
struct clientfd {
|
struct clientfd {
|
||||||
Client* client;
|
Client* client;
|
||||||
std::thread thread;
|
|
||||||
bool close = false;
|
bool close = false;
|
||||||
} fdc[MAXCLIENTS];
|
} fdc[MAXCLIENTS];
|
||||||
|
|
||||||
@@ -38,6 +37,7 @@ void runClient(struct clientfd* cfd) {
|
|||||||
char inbuf[BUFFERSIZE];
|
char inbuf[BUFFERSIZE];
|
||||||
printf("[d] C(%i) Initialized\n", cfd->client->control_sock);
|
printf("[d] C(%i) Initialized\n", cfd->client->control_sock);
|
||||||
// Loop as long as it is a valid file descriptor.
|
// Loop as long as it is a valid file descriptor.
|
||||||
|
try {
|
||||||
while (fcntl(cfd->client->control_sock, F_GETFD) != -1) {
|
while (fcntl(cfd->client->control_sock, F_GETFD) != -1) {
|
||||||
printf("[d] C(%i) Attempting read...\n", cfd->client->control_sock);
|
printf("[d] C(%i) Attempting read...\n", cfd->client->control_sock);
|
||||||
int rc = recv(cfd->client->control_sock, inbuf, sizeof(inbuf), 0);
|
int rc = recv(cfd->client->control_sock, inbuf, sizeof(inbuf), 0);
|
||||||
@@ -67,9 +67,12 @@ void runClient(struct clientfd* cfd) {
|
|||||||
if (cfd->client->receive(cmd, args) < 0) break;
|
if (cfd->client->receive(cmd, args) < 0) break;
|
||||||
inbuf[0] = '\0';
|
inbuf[0] = '\0';
|
||||||
}
|
}
|
||||||
|
} catch (...) {
|
||||||
|
printf("[!] C(%i) Caught error!\n", cfd->client->control_sock);
|
||||||
|
}
|
||||||
|
cfd->client->thread.detach();
|
||||||
printf("[d] C(%i) Marking for deletion...\n", cfd->client->control_sock);
|
printf("[d] C(%i) Marking for deletion...\n", cfd->client->control_sock);
|
||||||
cfd->close = true;
|
cfd->close = true;
|
||||||
cfd->thread.detach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc , char *argv[]) {
|
int main(int argc , char *argv[]) {
|
||||||
@@ -79,10 +82,9 @@ int main(int argc , char *argv[]) {
|
|||||||
nfds = 1,
|
nfds = 1,
|
||||||
current_size = 0;
|
current_size = 0;
|
||||||
|
|
||||||
char inbuf[BUFFERSIZE];
|
|
||||||
struct sockaddr_in ctrl_address;
|
struct sockaddr_in ctrl_address;
|
||||||
|
|
||||||
if ((master_socket = socket(AF_INET , SOCK_STREAM , 0)) < 0) {
|
if ((master_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
|
||||||
perror("socket() failed");
|
perror("socket() failed");
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
@@ -137,8 +139,6 @@ int main(int argc , char *argv[]) {
|
|||||||
|
|
||||||
current_size = nfds;
|
current_size = nfds;
|
||||||
for (int i = 0; i < current_size; i++) {
|
for (int i = 0; i < current_size; i++) {
|
||||||
inbuf[0] = '\0';
|
|
||||||
|
|
||||||
if(fds[i].revents == 0)
|
if(fds[i].revents == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -158,56 +158,22 @@ int main(int argc , char *argv[]) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("[d] C(%i) Accepted client%i\n", newsock);
|
printf("[d] C(%i) Accepted client\n", newsock);
|
||||||
// If we assign thead if it is still attached,
|
|
||||||
// we suffer greatly, and by we I mean me.
|
|
||||||
if (fdc[nfds].thread.joinable()) {
|
|
||||||
printf("[!] C(%i) Thread still joinable! Detaching...\n", newsock);
|
|
||||||
// Pray the thread will end itself.
|
|
||||||
fdc[nfds].thread.detach();
|
|
||||||
}
|
|
||||||
fds[nfds].fd = newsock;
|
fds[nfds].fd = newsock;
|
||||||
fds[nfds].events = POLLIN;
|
fds[nfds].events = POLLIN;
|
||||||
|
fdc[nfds].close = false;
|
||||||
fdc[nfds].client = new Client(newsock);
|
fdc[nfds].client = new Client(newsock);
|
||||||
fdc[nfds].thread = std::thread(runClient, &fdc[nfds]);
|
fdc[nfds].client->thread = std::thread(runClient, &fdc[nfds]);
|
||||||
nfds++;
|
nfds++;
|
||||||
} while (newsock != -1);
|
} while (newsock != -1);
|
||||||
} else {
|
} else {
|
||||||
/*
|
|
||||||
int rc = recv(fds[i].fd, inbuf, sizeof(inbuf), 0);
|
|
||||||
if (rc < 0) {
|
|
||||||
if (errno != EWOULDBLOCK) {
|
|
||||||
perror("recv() failed");
|
|
||||||
fdc[i].close = true;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == 0 || fdc[i].client == nullptr) {
|
|
||||||
printf("[d] (%i) closed\n", fds[i].fd);
|
|
||||||
fdc[i].close = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string lin(inbuf);
|
|
||||||
int len = lin.find("\r\n", 0);
|
|
||||||
int cmdend = lin.find(" ", 0);
|
|
||||||
if (cmdend >= len || cmdend == std::string::npos) cmdend = len;
|
|
||||||
std::string cmd = toUpper(lin.substr(0, cmdend));
|
|
||||||
std::string args = "";
|
|
||||||
if (len > cmdend) args = lin.substr(cmdend+1, len-cmdend-1);
|
|
||||||
|
|
||||||
printf("[d] (%i) >> '%s' '%s'\n", fds[i].fd, cmd.c_str(), args.c_str());
|
|
||||||
|
|
||||||
if (fdc[i].client->receive(cmd, args) < 0) fdc[i].close = true;
|
|
||||||
inbuf[0] = '\0';
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (fdc[i].close) {
|
if (fdc[i].close) {
|
||||||
conn_close:
|
conn_close:
|
||||||
printf("[d] C(%i) Deleting client...\n", fds[i].fd);
|
printf("[d] C(%i) Deleting client...\n", fds[i].fd);
|
||||||
close(fds[i].fd);
|
close(fds[i].fd);
|
||||||
fds[i].fd = -1;
|
fds[i].fd = -1;
|
||||||
if (fdc[i].thread.joinable()) fdc[i].thread.detach();
|
if (fdc[i].client->thread.joinable())
|
||||||
|
fdc[i].client->thread.detach();
|
||||||
fdc[i].client = nullptr;
|
fdc[i].client = nullptr;
|
||||||
fdc[i].close = false;
|
fdc[i].close = false;
|
||||||
compress_array = true;
|
compress_array = true;
|
||||||
@@ -217,18 +183,19 @@ int main(int argc , char *argv[]) {
|
|||||||
|
|
||||||
if (compress_array) {
|
if (compress_array) {
|
||||||
compress_array = false;
|
compress_array = false;
|
||||||
printf("[d] Compressing...\n");
|
|
||||||
for (int i = 0; i < nfds; i++) {
|
for (int i = 0; i < nfds; i++) {
|
||||||
if (fds[i].fd == -1) {
|
if (fds[i].fd == -1) {
|
||||||
for(int j = i; j < nfds; j++) {
|
for(int j = i; j < nfds; j++) {
|
||||||
printf("[d] Compressing: id %i to fd %i\n", j, fds[j+1].fd);
|
if (fds[j].fd == -1) {
|
||||||
fds[j].fd = fds[j+1].fd;
|
printf("[d] Compressing: %i(fd:%i) <= %i(fd:%i)\n", j, fds[j].fd, j+1, fds[j+1].fd);
|
||||||
|
fds[j].fd = fds[j+1].fd;
|
||||||
|
fdc[j].client = fdc[j+1].client;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i--;
|
i--;
|
||||||
nfds--;
|
nfds--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("[d] Compressing complete!\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user