Add proper logging
This commit is contained in:
@@ -2,6 +2,9 @@
|
|||||||
server_name=My FTP Server
|
server_name=My FTP Server
|
||||||
motd_file=motd
|
motd_file=motd
|
||||||
auth_engine=noauth
|
auth_engine=noauth
|
||||||
|
[logging]
|
||||||
|
file=digftp.log
|
||||||
|
level=0
|
||||||
[net]
|
[net]
|
||||||
listen_address=127.0.0.1
|
listen_address=127.0.0.1
|
||||||
control_port=21
|
control_port=21
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ public:
|
|||||||
sscanf(config->getValue("net", "listen_address", "127.0.0.1").c_str(), "%d.%d.%d.%d", &netaddr[0], &netaddr[1], &netaddr[2], &netaddr[3]);
|
sscanf(config->getValue("net", "listen_address", "127.0.0.1").c_str(), "%d.%d.%d.%d", &netaddr[0], &netaddr[1], &netaddr[2], &netaddr[3]);
|
||||||
dataport = ntohs(data_address.sin_port);
|
dataport = ntohs(data_address.sin_port);
|
||||||
memcpy(&netport[0], &dataport, 2);
|
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);
|
logger->print(LOGLEVEL_DEBUG, "D(%i) PASV initialized: %u.%u.%u.%u:%u", data_fd, netaddr[0], netaddr[1], netaddr[2], netaddr[3], dataport);
|
||||||
} else {
|
} else {
|
||||||
perror("pasv getpeername() failed");
|
perror("pasv getpeername() failed");
|
||||||
close(data_fd);
|
close(data_fd);
|
||||||
@@ -119,7 +119,7 @@ public:
|
|||||||
free(pasvok);
|
free(pasvok);
|
||||||
|
|
||||||
if ((data_sock = accept(data_fd, NULL, NULL)) >= 0) {
|
if ((data_sock = accept(data_fd, NULL, NULL)) >= 0) {
|
||||||
printf("[i] D(%i) PASV accepted: %i\n", data_fd, data_sock);
|
logger->print(LOGLEVEL_INFO, "D(%i) PASV accepted: %i", data_fd, data_sock);
|
||||||
state = 2;
|
state = 2;
|
||||||
} else {
|
} else {
|
||||||
perror("accept() failed");
|
perror("accept() failed");
|
||||||
@@ -135,7 +135,7 @@ 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) PORT initialized: %s:%d\n", control_sock, ip_decimal, port_dec);
|
logger->print(LOGLEVEL_DEBUG, "D(%i) PORT initialized: %s:%d", 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);
|
||||||
@@ -217,7 +217,7 @@ public:
|
|||||||
submit(331, "Password required");
|
submit(331, "Password required");
|
||||||
} else if (cmd == "PASS") {
|
} else if (cmd == "PASS") {
|
||||||
if (auth->check(name, argstr)) {
|
if (auth->check(name, argstr)) {
|
||||||
printf("[d] (%i) logged in as '%s'\n", control_sock, name.c_str());
|
logger->print(LOGLEVEL_INFO, "(%i) logged in as '%s'", control_sock, name.c_str());
|
||||||
// We can now set the root safely (I hope).
|
// We can now set the root safely (I hope).
|
||||||
filer->setRoot(auth->getUserDirectory(name));
|
filer->setRoot(auth->getUserDirectory(name));
|
||||||
state = 1;
|
state = 1;
|
||||||
@@ -240,26 +240,26 @@ public:
|
|||||||
std::string out = std::to_string(code)+" "+msg+"\r\n";
|
std::string out = std::to_string(code)+" "+msg+"\r\n";
|
||||||
int bytes = send(control_sock, out.c_str(), out.size(), 0);
|
int bytes = send(control_sock, out.c_str(), out.size(), 0);
|
||||||
if (bytes < 0) {
|
if (bytes < 0) {
|
||||||
printf("[d] C(%i) !< %i %s\n", control_sock, code, msg.c_str());
|
logger->print(LOGLEVEL_ERROR, "C(%i) !< %i %s", control_sock, code, msg.c_str());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("[d] C(%i) << %i %s\n", control_sock, code, msg.c_str());
|
logger->print(LOGLEVEL_DEBUG, "C(%i) << %i %s", control_sock, code, msg.c_str());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int data_submit(char* out, int size) {
|
int data_submit(char* out, int size) {
|
||||||
int bytes = send(data_sock, out, size, 0);
|
int bytes = send(data_sock, out, size, 0);
|
||||||
if (bytes < 0) {
|
if (bytes < 0) {
|
||||||
printf("[d] D(%i) !< %i\n", data_sock, size);
|
logger->print(LOGLEVEL_DEBUG, "D(%i) !< %i", data_sock, size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
printf("[d] D(%i) << %i\n", data_sock, size);
|
logger->print(LOGLEVEL_DEBUG, "D(%i) << %i", data_sock, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int data_close() {
|
int data_close() {
|
||||||
if (data_sock <= 0) return 0;
|
if (data_sock <= 0) return 0;
|
||||||
printf("[d] D(%i) Closing...\n", data_sock);
|
logger->print(LOGLEVEL_DEBUG, "D(%i) Closing...", data_sock);
|
||||||
close(data_sock);
|
close(data_sock);
|
||||||
data_sock = -1;
|
data_sock = -1;
|
||||||
close(data_fd);
|
close(data_fd);
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public:
|
|||||||
int traverse(std::string dir) {
|
int traverse(std::string dir) {
|
||||||
fs::path ndir = fs::weakly_canonical(cwd / dir);
|
fs::path ndir = fs::weakly_canonical(cwd / dir);
|
||||||
fs::path fdir = fullPath(dir);
|
fs::path fdir = fullPath(dir);
|
||||||
printf("[i] Traversing: %s\n", ndir.c_str());
|
logger->print(LOGLEVEL_INFO, "Traversing: %s", ndir.c_str());
|
||||||
if (fdir.string().rfind(root.string(), 0) != 0) return -2;
|
if (fdir.string().rfind(root.string(), 0) != 0) return -2;
|
||||||
else if (!fs::exists(fdir) || !fs::is_directory(fdir)) return -1;
|
else if (!fs::exists(fdir) || !fs::is_directory(fdir)) return -1;
|
||||||
else {
|
else {
|
||||||
@@ -52,7 +52,7 @@ public:
|
|||||||
|
|
||||||
int setRoot(std::string _root) {
|
int setRoot(std::string _root) {
|
||||||
fs::path froot = fs::weakly_canonical(_root);
|
fs::path froot = fs::weakly_canonical(_root);
|
||||||
printf("[i] Setting root: %s\n", froot.c_str());
|
logger->print(LOGLEVEL_INFO, "Setting root: %s", froot.c_str());
|
||||||
if (!fs::exists(froot)) fs::create_directory(froot);
|
if (!fs::exists(froot)) fs::create_directory(froot);
|
||||||
root = fs::absolute(froot);
|
root = fs::absolute(froot);
|
||||||
cwd = "/";
|
cwd = "/";
|
||||||
@@ -89,7 +89,7 @@ public:
|
|||||||
int fileSize(std::string name) {
|
int fileSize(std::string name) {
|
||||||
fs::path nfile = fs::weakly_canonical(cwd / name);
|
fs::path nfile = fs::weakly_canonical(cwd / name);
|
||||||
fs::path ffile = fullPath(name);
|
fs::path ffile = fullPath(name);
|
||||||
printf("[i] Retreiving filesize: %s\n", nfile.c_str());
|
logger->print(LOGLEVEL_INFO, "Retreiving filesize: %s", nfile.c_str());
|
||||||
if (ffile.string().rfind(root.string(), 0) != 0) return -2;
|
if (ffile.string().rfind(root.string(), 0) != 0) return -2;
|
||||||
else if (!fs::exists(ffile)) return -1;
|
else if (!fs::exists(ffile)) return -1;
|
||||||
else if (type == 'A') return -3;
|
else if (type == 'A') return -3;
|
||||||
@@ -105,7 +105,7 @@ public:
|
|||||||
int deleteFile(std::string name) {
|
int deleteFile(std::string name) {
|
||||||
fs::path nfile = fs::weakly_canonical(cwd / name);
|
fs::path nfile = fs::weakly_canonical(cwd / name);
|
||||||
fs::path ffile = fullPath(name);
|
fs::path ffile = fullPath(name);
|
||||||
printf("[i] Deleting file: %s\n", nfile.c_str());
|
logger->print(LOGLEVEL_INFO, "Deleting file: %s", nfile.c_str());
|
||||||
if (ffile.string().rfind(root.string(), 0) != 0) return -2;
|
if (ffile.string().rfind(root.string(), 0) != 0) return -2;
|
||||||
else if (!fs::exists(ffile)) return -1;
|
else if (!fs::exists(ffile)) return -1;
|
||||||
else {
|
else {
|
||||||
@@ -119,7 +119,7 @@ public:
|
|||||||
|
|
||||||
fs::path nfile = fs::weakly_canonical(cwd / name);
|
fs::path nfile = fs::weakly_canonical(cwd / name);
|
||||||
fs::path ffile = fullPath(name);
|
fs::path ffile = fullPath(name);
|
||||||
printf("[i] Retreiving file: %s\n", nfile.c_str());
|
logger->print(LOGLEVEL_INFO, "Retreiving file: %s", nfile.c_str());
|
||||||
if (ffile.string().rfind(root.string(), 0) != 0) fd.ecode = -2;
|
if (ffile.string().rfind(root.string(), 0) != 0) fd.ecode = -2;
|
||||||
else if (!fs::exists(ffile)) fd.ecode = -1;
|
else if (!fs::exists(ffile)) fd.ecode = -1;
|
||||||
else if (type != 'A') {
|
else if (type != 'A') {
|
||||||
@@ -142,7 +142,7 @@ public:
|
|||||||
int writeFile(std::string name, unsigned char* data, int size) {
|
int writeFile(std::string name, unsigned char* data, int size) {
|
||||||
fs::path nfile = fs::weakly_canonical(cwd / name);
|
fs::path nfile = fs::weakly_canonical(cwd / name);
|
||||||
fs::path ffile = fullPath(name);
|
fs::path ffile = fullPath(name);
|
||||||
printf("[i] Storing file: %s\n", nfile.c_str());
|
logger->print(LOGLEVEL_INFO, "Storing file: %s", nfile.c_str());
|
||||||
if (ffile.string().rfind(root.string(), 0) != 0) return -2;
|
if (ffile.string().rfind(root.string(), 0) != 0) return -2;
|
||||||
else {
|
else {
|
||||||
std::ofstream outfile(ffile, std::ios::out|std::ios::binary);
|
std::ofstream outfile(ffile, std::ios::out|std::ios::binary);
|
||||||
|
|||||||
51
src/logger.h
Normal file
51
src/logger.h
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
#ifndef LOGGER_H
|
||||||
|
#define LOGGER_H
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#define LOGLEVEL_ERROR 3
|
||||||
|
#define LOGLEVEL_WARNING 2
|
||||||
|
#define LOGLEVEL_INFO 1
|
||||||
|
#define LOGLEVEL_DEBUG 0
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
public:
|
||||||
|
Logger(const char* path) {
|
||||||
|
logfile.open(path, std::ios::binary|std::ios::app);
|
||||||
|
};
|
||||||
|
|
||||||
|
void setLevel(int level) { this->logLevel = level; }
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
void print(int level, const char* message, Args... args) {
|
||||||
|
if (level >= this->logLevel) {
|
||||||
|
char* prepared;
|
||||||
|
char* formatted;
|
||||||
|
asprintf(&prepared, "[%c] %s\n", logTypeChar(level), message);
|
||||||
|
asprintf(&formatted, prepared, args...);
|
||||||
|
fprintf(stdout, formatted);
|
||||||
|
if (logfile.is_open()) {
|
||||||
|
logfile.write(formatted, strlen(formatted));
|
||||||
|
logfile.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
logfile.close();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::ofstream logfile;
|
||||||
|
int logLevel = 0;
|
||||||
|
|
||||||
|
static const char logTypeChar(int level) {
|
||||||
|
switch(level) {
|
||||||
|
default: return ' ';
|
||||||
|
case LOGLEVEL_ERROR: return 'E';
|
||||||
|
case LOGLEVEL_WARNING: return 'W';
|
||||||
|
case LOGLEVEL_INFO: return 'I';
|
||||||
|
case LOGLEVEL_DEBUG: return 'D';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
32
src/main.cpp
32
src/main.cpp
@@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
const int max_clients = config->getInt("net", "max_clients", 255);
|
const uint16_t max_clients = config->getInt("net", "max_clients", 255);
|
||||||
const int cport = config->getInt("net", "control_port", 21);
|
const uint16_t cport = config->getInt("net", "control_port", 21);
|
||||||
|
|
||||||
struct pollfd fds[65535];
|
struct pollfd fds[65535];
|
||||||
struct clientfd {
|
struct clientfd {
|
||||||
@@ -41,10 +41,9 @@ void runClient(struct clientfd* cfd) {
|
|||||||
//while (fcntl(cfd->client->control_sock, F_GETFD) != -1) {
|
//while (fcntl(cfd->client->control_sock, F_GETFD) != -1) {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (cfd->client == nullptr) { break; }
|
if (cfd->client == nullptr) { break; }
|
||||||
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);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
printf("[d] C(%i) Recieved empty packet\n", cfd->client->control_sock);
|
logger->print(LOGLEVEL_WARNING, "C(%i) Recieved empty packet", cfd->client->control_sock);
|
||||||
if (errno != EWOULDBLOCK) {
|
if (errno != EWOULDBLOCK) {
|
||||||
perror("recv() failed");
|
perror("recv() failed");
|
||||||
break;
|
break;
|
||||||
@@ -65,19 +64,20 @@ void runClient(struct clientfd* cfd) {
|
|||||||
std::string args = "";
|
std::string args = "";
|
||||||
if (len > cmdend) args = lin.substr(cmdend+1, len-cmdend-1);
|
if (len > cmdend) args = lin.substr(cmdend+1, len-cmdend-1);
|
||||||
|
|
||||||
printf("[d] C(%i) >> '%s' '%s'\n", cfd->client->control_sock, cmd.c_str(), args.c_str());
|
logger->print(LOGLEVEL_DEBUG, "C(%i) >> '%s' '%s'", cfd->client->control_sock, cmd.c_str(), args.c_str());
|
||||||
|
|
||||||
if (cfd->client->receive(cmd, args) < 0) break;
|
if (cfd->client->receive(cmd, args) < 0) break;
|
||||||
inbuf[0] = '\0';
|
inbuf[0] = '\0';
|
||||||
}
|
}
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
printf("[!] C(%i) Caught error!\n", cfd->client->control_sock);
|
logger->print(LOGLEVEL_ERROR, "C(%i) Caught error!", cfd->client->control_sock);
|
||||||
}
|
}
|
||||||
//printf("[d] C(%i) Marking for deletion...\n", cfd->client->control_sock);
|
|
||||||
cfd->close = true;
|
cfd->close = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc , char *argv[]) {
|
int main(int argc , char *argv[]) {
|
||||||
|
logger = new Logger(config->getValue("logging", "file", "digftp.log").c_str());
|
||||||
|
logger->setLevel(config->getInt("logging", "level", 0));
|
||||||
std::string authType = config->getValue("main", "auth_engine", "plain");
|
std::string authType = config->getValue("main", "auth_engine", "plain");
|
||||||
auth = getAuthByName(authType);
|
auth = getAuthByName(authType);
|
||||||
auth->setOptions(config->get(authType));
|
auth->setOptions(config->get(authType));
|
||||||
@@ -129,7 +129,7 @@ int main(int argc , char *argv[]) {
|
|||||||
fds[0].fd = master_socket;
|
fds[0].fd = master_socket;
|
||||||
fds[0].events = POLLIN;
|
fds[0].events = POLLIN;
|
||||||
|
|
||||||
printf("[i] Server started.\n");
|
logger->print(LOGLEVEL_INFO, "Server started.");
|
||||||
while (run) {
|
while (run) {
|
||||||
int pc = poll(fds, nfds, -1);
|
int pc = poll(fds, nfds, -1);
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ int main(int argc , char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pc == 0) {
|
if (pc == 0) {
|
||||||
printf("poll() timed out\n");
|
perror("poll() timed out\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +149,7 @@ int main(int argc , char *argv[]) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if(fds[i].revents != POLLIN) {
|
if(fds[i].revents != POLLIN) {
|
||||||
printf("[!] C(%i) Error! revents = %d\n", fds[i].fd, fds[i].revents);
|
logger->print(LOGLEVEL_ERROR, "C(%i) Error! revents = %d", fds[i].fd, fds[i].revents);
|
||||||
goto conn_close;
|
goto conn_close;
|
||||||
}
|
}
|
||||||
if (fds[i].fd == master_socket) {
|
if (fds[i].fd == master_socket) {
|
||||||
@@ -162,8 +162,7 @@ int main(int argc , char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
logger->print(LOGLEVEL_DEBUG, "C(%i) Accepted client", newsock);
|
||||||
printf("[d] C(%i) Accepted client\n", newsock);
|
|
||||||
fds[nfds].fd = newsock;
|
fds[nfds].fd = newsock;
|
||||||
fds[nfds].events = POLLIN;
|
fds[nfds].events = POLLIN;
|
||||||
fdc[nfds].close = false;
|
fdc[nfds].close = false;
|
||||||
@@ -174,7 +173,7 @@ int main(int argc , char *argv[]) {
|
|||||||
} else {
|
} else {
|
||||||
if (fdc[i].close) {
|
if (fdc[i].close) {
|
||||||
conn_close:
|
conn_close:
|
||||||
printf("[d] C(%i) Deleting client...\n", fds[i].fd);
|
logger->print(LOGLEVEL_DEBUG, "C(%i) Deleting client...", fds[i].fd);
|
||||||
close(fds[i].fd);
|
close(fds[i].fd);
|
||||||
fds[i].fd = -1;
|
fds[i].fd = -1;
|
||||||
if (fdc[i].client->thread.joinable())
|
if (fdc[i].client->thread.joinable())
|
||||||
@@ -193,15 +192,15 @@ int main(int argc , char *argv[]) {
|
|||||||
if (fds[i].fd == -1) {
|
if (fds[i].fd == -1) {
|
||||||
for(int j = i; j < nfds; j++) {
|
for(int j = i; j < nfds; j++) {
|
||||||
if (fds[j].fd == -1) {
|
if (fds[j].fd == -1) {
|
||||||
printf("[d] Compressing: %i(fd:%i) <= %i(fd:%i)\n", j, fds[j].fd, j+1, fds[j+1].fd);
|
logger->print(LOGLEVEL_DEBUG, "Compressing: %i(fd:%i) <= %i(fd:%i)", j, fds[j].fd, j+1, fds[j+1].fd);
|
||||||
fds[j].fd = fds[j+1].fd;
|
fds[j].fd = fds[j+1].fd;
|
||||||
fds[j].revents = fds[j+1].revents;
|
fds[j].revents = fds[j+1].revents;
|
||||||
fds[j+1].fd = -1;
|
fds[j+1].fd = -1;
|
||||||
printf("[d] Reinitialized fds of %i\n", j+1);
|
logger->print(LOGLEVEL_DEBUG, "Reinitialized fds of %i", j+1);
|
||||||
fdc[j].client = fdc[j+1].client;
|
fdc[j].client = fdc[j+1].client;
|
||||||
fdc[j].close = fdc[j+1].close;
|
fdc[j].close = fdc[j+1].close;
|
||||||
fdc[j+1] = {};
|
fdc[j+1] = {};
|
||||||
printf("[d] Reinitialized fdc of %i\n", j+1);
|
logger->print(LOGLEVEL_DEBUG, "[d] Reinitialized fdc of %i", j+1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i--;
|
i--;
|
||||||
@@ -210,5 +209,6 @@ int main(int argc , char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logger->close();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
#ifndef MAIN_H
|
#ifndef MAIN_H
|
||||||
#define MAIN_H
|
#define MAIN_H
|
||||||
|
|
||||||
|
#define CONF_DIR "conf"
|
||||||
|
#define LOG_DIR "log"
|
||||||
|
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
|
#include "logger.h"
|
||||||
|
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
#include "auth/noauth.h"
|
#include "auth/noauth.h"
|
||||||
|
|
||||||
ConfigFile* config = new ConfigFile("conf/ftp.conf");
|
ConfigFile* config = new ConfigFile("conf/ftp.conf");
|
||||||
Auth* auth;
|
Auth* auth;
|
||||||
|
Logger* logger;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
Reference in New Issue
Block a user