186 lines
4.6 KiB
C
186 lines
4.6 KiB
C
#include "include/conf.h"
|
|
|
|
#include <netdb.h>
|
|
#include <signal.h>
|
|
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include <arpa/inet.h>
|
|
#include <openssl/ssl.h>
|
|
#include <openssl/err.h>
|
|
|
|
#include "include/pow.h"
|
|
#include "include/main.h"
|
|
#include "include/proto.h"
|
|
#include "include/commands.h"
|
|
|
|
#include "server/include/pow.h"
|
|
#include "server/include/log.h"
|
|
#include "server/include/blake2s.h"
|
|
|
|
static dp_Logger dc_logger = {0};
|
|
|
|
static inline int dc_parse_commands(SSL *ssl, int argc, const char *argv[]) {
|
|
while (argc > 0) {
|
|
int ret = 0;
|
|
|
|
if (strcmp(*argv, "command") == 0) {
|
|
ret = dc_cmd_command(ssl, argc, argv, &dc_logger);
|
|
} else {
|
|
dp_lohf(&dc_logger, DP_LOG_ERROR, "Unknown packet: %s", *argv);
|
|
return 1;
|
|
}
|
|
|
|
if (ret < 1) {
|
|
dp_loh(&dc_logger, DP_LOG_ERROR, "Command failed");
|
|
return 1;
|
|
}
|
|
|
|
argc -= ret;
|
|
argv += ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(const int argc, const char *argv[]) {
|
|
/* Initialize logger level */
|
|
dp_log_set_level(&dc_logger, DP_LOG_INFO);
|
|
|
|
if (argc < 4) {
|
|
dp_lohf(&dc_logger, DP_LOG_ERROR,
|
|
"Usage: %s <host> <port> <command...>", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
const char *hostname = argv[1];
|
|
const int port = atoi(argv[2]);
|
|
|
|
dp_log_set_target(&dc_logger, hostname);
|
|
|
|
/* Initialize OpenSSL */
|
|
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
|
dp_erh(&dc_logger, "Unsable to ignore SIGPIPE signal");
|
|
return 1;
|
|
}
|
|
|
|
SSL_library_init();
|
|
OpenSSL_add_all_algorithms();
|
|
SSL_load_error_strings();
|
|
|
|
/* Create an SSL context */
|
|
const SSL_METHOD *method = TLS_client_method();
|
|
SSL_CTX *ctx = SSL_CTX_new(method);
|
|
if (!ctx) {
|
|
dp_erh(&dc_logger, "Unable to create SSL context");
|
|
ERR_print_errors_fp(stderr);
|
|
return 1;
|
|
}
|
|
|
|
/* Resolve hostname */
|
|
struct hostent *host = gethostbyname(hostname);
|
|
if (!host) {
|
|
dp_lohf(&dc_logger, DP_LOG_ERROR, "Unable to resolve host: %s",
|
|
hostname);
|
|
SSL_CTX_free(ctx);
|
|
return 1;
|
|
}
|
|
|
|
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (sockfd < 0) {
|
|
dp_lohf(&dc_logger, DP_LOG_ERROR, "Unable to create socket: %s",
|
|
strerror(errno));
|
|
SSL_CTX_free(ctx);
|
|
return 1;
|
|
}
|
|
|
|
struct timeval timeout;
|
|
timeout.tv_sec = 5;
|
|
timeout.tv_usec = 0;
|
|
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) <
|
|
0) {
|
|
dp_loh(&dc_logger, DP_LOG_WARN,
|
|
"Failed to set receive timeout to 5 seconds");
|
|
SSL_CTX_free(ctx);
|
|
close(sockfd);
|
|
return 1;
|
|
}
|
|
|
|
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) <
|
|
0) {
|
|
dp_loh(&dc_logger, DP_LOG_WARN,
|
|
"Failed to set send timeout to 5 seconds");
|
|
SSL_CTX_free(ctx);
|
|
close(sockfd);
|
|
return 1;
|
|
}
|
|
|
|
struct sockaddr_in server_addr;
|
|
memset(&server_addr, 0, sizeof(server_addr));
|
|
server_addr.sin_family = AF_INET;
|
|
server_addr.sin_port = htons((uint16_t)port);
|
|
server_addr.sin_addr = *((struct in_addr *)host->h_addr_list[0]);
|
|
|
|
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) !=
|
|
0) {
|
|
dp_lohf(&dc_logger, DP_LOG_ERROR, "Connection to %s:%d failed: %s",
|
|
hostname, port, strerror(errno));
|
|
close(sockfd);
|
|
SSL_CTX_free(ctx);
|
|
return 1;
|
|
}
|
|
|
|
/* Create SSL object and attach to socket */
|
|
SSL *ssl = SSL_new(ctx);
|
|
SSL_set_fd(ssl, sockfd);
|
|
|
|
/* Perform SSL handshake */
|
|
if (SSL_connect(ssl) <= 0) {
|
|
dp_erh(&dc_logger, "SSL handshake failed");
|
|
ERR_print_errors_fp(stderr);
|
|
SSL_free(ssl);
|
|
close(sockfd);
|
|
SSL_CTX_free(ctx);
|
|
return 1;
|
|
}
|
|
|
|
dp_lohf(&dc_logger, DP_LOG_INFO, "Connected with %s encryption",
|
|
SSL_get_cipher(ssl));
|
|
|
|
int ret = 0;
|
|
|
|
/* Server info */
|
|
|
|
if (!dc_proto_read_server_info(ssl, &dc_logger)) {
|
|
dp_loh(&dc_logger, DP_LOG_FATAL, "Failed to read server information");
|
|
ret = 1;
|
|
goto finish;
|
|
}
|
|
|
|
/* Solve PoW */
|
|
|
|
if (!dc_proto_pow_solve(ssl, &dc_logger)) {
|
|
dp_loh(&dc_logger, DP_LOG_FATAL,
|
|
"Failed to solve proof-of-work challenge");
|
|
ret = 1;
|
|
goto finish;
|
|
}
|
|
|
|
/* Send command */
|
|
ret = dc_parse_commands(ssl, argc - 3, &argv[3]);
|
|
|
|
finish:
|
|
/* Cleanup */
|
|
dp_proto_exit(ssl);
|
|
|
|
SSL_shutdown(ssl);
|
|
SSL_free(ssl);
|
|
close(sockfd);
|
|
SSL_CTX_free(ctx);
|
|
|
|
dp_loh(&dc_logger, DP_LOG_INFO, "Connection closed");
|
|
|
|
return ret;
|
|
}
|