|
|
@@ -1,7 +1,4 @@ |
|
|
|
/** |
|
|
|
* See the LICENSE file for licensing information |
|
|
|
*/ |
|
|
|
|
|
|
|
/* See the LICENSE file for licensing information */ |
|
|
|
#include <sys/types.h> |
|
|
|
#include <sys/stat.h> |
|
|
|
#include <sys/socket.h> |
|
|
@@ -19,33 +16,92 @@ |
|
|
|
#include <unistd.h> |
|
|
|
|
|
|
|
#define PING_TIMEOUT 240 |
|
|
|
#define VERSION "1.1.0" |
|
|
|
#define VERSION "1.1.1" |
|
|
|
|
|
|
|
static char *server = "chat.freenode.net"; |
|
|
|
static char port[6] = "6667"; |
|
|
|
static FILE *log; |
|
|
|
static SSL_CTX *ctx; |
|
|
|
static SSL *ssl; |
|
|
|
static char *server = "chat.freenode.net"; |
|
|
|
static int port = 6667; |
|
|
|
static FILE *log; |
|
|
|
static short use_ssl = 0; |
|
|
|
static unsigned int last_response; |
|
|
|
|
|
|
|
/* connect to irc server */ |
|
|
|
int dial(char *server, char *port); |
|
|
|
/* get SSL up and running */ |
|
|
|
int sslify(int *sockfd); |
|
|
|
/* set up the error logging file */ |
|
|
|
FILE *slog(char *file); |
|
|
|
/* mop up so we exit cleanly */ |
|
|
|
void mop(void); |
|
|
|
FILE * |
|
|
|
slog(char *file) |
|
|
|
{ |
|
|
|
const char *home = getenv("HOME"); |
|
|
|
char path[100]; |
|
|
|
FILE *fp; |
|
|
|
|
|
|
|
snprintf(path, 100, "%s/%s", home, file); |
|
|
|
mknod(path, 0 | 0666, 0); |
|
|
|
fp = fopen(path, "w"); |
|
|
|
|
|
|
|
int main(int argc, char **argv) |
|
|
|
return fp; |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
dial(char *server, int port) |
|
|
|
{ |
|
|
|
int sockfd, err; |
|
|
|
struct addrinfo hints, *serv; |
|
|
|
|
|
|
|
char tmp[8]; |
|
|
|
snprintf(tmp, 8, "%d", port); |
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints)); |
|
|
|
hints.ai_family = AF_INET; |
|
|
|
hints.ai_socktype = SOCK_STREAM; |
|
|
|
if ((err = getaddrinfo(server, tmp, &hints, &serv)) != 0) { |
|
|
|
fprintf(log, "getaddrinfo: %s\n", gai_strerror(err)); |
|
|
|
return -1; |
|
|
|
} else if ((sockfd = socket(serv->ai_family, serv->ai_socktype, |
|
|
|
serv->ai_protocol)) == -1) { |
|
|
|
fprintf(log, "tubes: error on socket()\n"); |
|
|
|
return -1; |
|
|
|
} else if (connect(sockfd, serv->ai_addr, serv->ai_addrlen) == -1) { |
|
|
|
fprintf(log, "tubes: error on connect().\n"); |
|
|
|
close(sockfd); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
freeaddrinfo(serv); |
|
|
|
|
|
|
|
return sockfd; |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
sslify(int *sockfd) |
|
|
|
{ |
|
|
|
int r; |
|
|
|
|
|
|
|
SSL_library_init(); |
|
|
|
SSL_load_error_strings(); |
|
|
|
|
|
|
|
ctx = SSL_CTX_new(SSLv23_client_method()); |
|
|
|
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
|
|
| SSL_OP_SINGLE_DH_USE); |
|
|
|
ssl = SSL_new(ctx); |
|
|
|
SSL_set_fd(ssl, *sockfd); |
|
|
|
SSL_set_connect_state(ssl); |
|
|
|
|
|
|
|
if ((r = SSL_connect(ssl)) < 1) { |
|
|
|
fprintf(log, "sslify: %s\n", strerror(SSL_get_error(ssl, r))); |
|
|
|
SSL_CTX_free(ctx); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int |
|
|
|
main(int argc, char **argv) |
|
|
|
{ |
|
|
|
int sockfd, in, out; |
|
|
|
int maxfd; |
|
|
|
fd_set rd; |
|
|
|
struct timeval tv; |
|
|
|
char buf[512]; |
|
|
|
int i, r; |
|
|
|
int i, r, status; |
|
|
|
|
|
|
|
for (i = 1; i < argc; i++) { |
|
|
|
char c = argv[i][1]; |
|
|
@@ -54,7 +110,7 @@ int main(int argc, char **argv) |
|
|
|
switch (c) { |
|
|
|
case 'S': |
|
|
|
use_ssl = 1; |
|
|
|
snprintf(port, 6, "6697"); |
|
|
|
port = 6697; |
|
|
|
break; |
|
|
|
case 's': |
|
|
|
if (++i < argc) |
|
|
@@ -62,47 +118,44 @@ int main(int argc, char **argv) |
|
|
|
break; |
|
|
|
case 'p': |
|
|
|
if (++i < argc) |
|
|
|
snprintf(port, 6, "%s", argv[i]); |
|
|
|
port = atoi(argv[i]); |
|
|
|
break; |
|
|
|
case 'v': |
|
|
|
fprintf(stderr, "tubes-%s © 2016 Thomas Mannay\n", VERSION); |
|
|
|
exit(0); |
|
|
|
case 'v': /* fall through */ |
|
|
|
default: |
|
|
|
fprintf(stderr, |
|
|
|
"usage: tubes [-S] [-s server] [-p port] [-v]\n"); |
|
|
|
fprintf(stderr, "tubes-%s © 2016 Thomas Mannay\n", VERSION); |
|
|
|
exit(0); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if ((log = slog(".tubes.err")) == NULL) { |
|
|
|
fprintf(stderr, "tubes: error on slog()"); |
|
|
|
fprintf(stderr, "error on slog()"); |
|
|
|
exit(-1); |
|
|
|
} |
|
|
|
|
|
|
|
if (daemon(0, 0) == -1) { |
|
|
|
fprintf(log, "tubes: error on daemon()\n"); |
|
|
|
fprintf(log, "error on daemon()\n"); |
|
|
|
exit(-1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if ((sockfd = dial(server, port)) == -1) |
|
|
|
exit(-1); |
|
|
|
|
|
|
|
if (use_ssl && sslify(&sockfd) == -1) |
|
|
|
exit(-1); |
|
|
|
|
|
|
|
snprintf(buf, 512, "/tmp/%s.in", server); |
|
|
|
unlink(buf); |
|
|
|
mknod(buf, S_IFIFO | 0660, 0); |
|
|
|
in = open(buf, O_RDWR | O_NONBLOCK); |
|
|
|
mkfifo(buf, 0660); |
|
|
|
if ((in = open(buf, O_RDWR | O_NONBLOCK)) < 0) { |
|
|
|
fprintf(log, "in: error on open()\n"); |
|
|
|
exit(-1); |
|
|
|
} |
|
|
|
snprintf(buf, 512, "/tmp/%s.out", server); |
|
|
|
unlink(buf); |
|
|
|
mknod(buf, S_IFIFO | 0660, 0); |
|
|
|
out = open(buf, O_RDWR); |
|
|
|
|
|
|
|
atexit(mop); |
|
|
|
mkfifo(buf, 0660); |
|
|
|
if ((out = open(buf, O_RDWR)) < 0) { |
|
|
|
fprintf(log, "out: error on open()\n"); |
|
|
|
exit(-1); |
|
|
|
} |
|
|
|
|
|
|
|
for (;;) { |
|
|
|
for (status = 0;;) { |
|
|
|
FD_ZERO(&rd); |
|
|
|
maxfd = (out >= sockfd) ? out : sockfd; |
|
|
|
FD_SET(out, &rd); |
|
|
@@ -114,13 +167,13 @@ int main(int argc, char **argv) |
|
|
|
if (r < 0) { |
|
|
|
if (errno == EINTR) |
|
|
|
continue; |
|
|
|
fprintf(log, "tubes: error on select()\n"); |
|
|
|
exit(-1); |
|
|
|
} else if (r == 0) { |
|
|
|
if (time(NULL) - last_response >= PING_TIMEOUT) { |
|
|
|
fprintf(log, "tubes: ping timeout\n"); |
|
|
|
exit(-1); |
|
|
|
} |
|
|
|
fprintf(log, "error on select()\n"); |
|
|
|
status = -1; |
|
|
|
break; |
|
|
|
} else if (r == 0 && last_response-time(NULL) >= PING_TIMEOUT) { |
|
|
|
fprintf(log, "ping timeout\n"); |
|
|
|
status = -1; |
|
|
|
break; |
|
|
|
} |
|
|
|
if (FD_ISSET(out, &rd)) |
|
|
|
if ((i = read(out, buf, sizeof(buf))) > 0) { |
|
|
@@ -144,91 +197,26 @@ int main(int argc, char **argv) |
|
|
|
i = recv(sockfd, buf, sizeof(buf), 0); |
|
|
|
if (i != -1) { |
|
|
|
if (i == 0) { |
|
|
|
fprintf(log, "tubes: connection closed\n"); |
|
|
|
close(sockfd); |
|
|
|
if (use_ssl) |
|
|
|
SSL_CTX_free(ctx); |
|
|
|
exit(0); |
|
|
|
fprintf(log, "connection closed\n"); |
|
|
|
break; |
|
|
|
} |
|
|
|
buf[i] = 0; |
|
|
|
if (write(in, buf, strlen(buf)) < 0) { |
|
|
|
if (errno == EINTR) |
|
|
|
continue; |
|
|
|
fprintf(log, "tubes: error on write()\n"); |
|
|
|
exit(-1); |
|
|
|
fprintf(log, "error on write()\n"); |
|
|
|
status = -1; |
|
|
|
break; |
|
|
|
} |
|
|
|
last_response = time(NULL); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
int dial(char *server, char *port) |
|
|
|
{ |
|
|
|
int sockfd, err; |
|
|
|
struct addrinfo hints, *serv; |
|
|
|
|
|
|
|
memset(&hints, 0, sizeof(hints)); |
|
|
|
hints.ai_family = AF_INET; |
|
|
|
hints.ai_socktype = SOCK_STREAM; |
|
|
|
if ((err = getaddrinfo(server, port, &hints, &serv)) != 0) { |
|
|
|
fprintf(log, "getaddrinfo: %s\n", gai_strerror(err)); |
|
|
|
return -1; |
|
|
|
} else if ((sockfd = socket(serv->ai_family, serv->ai_socktype, |
|
|
|
serv->ai_protocol)) == -1) { |
|
|
|
fprintf(log, "tubes: error on socket()\n"); |
|
|
|
return -1; |
|
|
|
} else if (connect(sockfd, serv->ai_addr, serv->ai_addrlen) == -1) { |
|
|
|
fprintf(log, "tubes: error on connect().\n"); |
|
|
|
close(sockfd); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
freeaddrinfo(serv); |
|
|
|
|
|
|
|
return sockfd; |
|
|
|
} |
|
|
|
|
|
|
|
int sslify(int *sockfd) |
|
|
|
{ |
|
|
|
int r; |
|
|
|
|
|
|
|
SSL_library_init(); |
|
|
|
SSL_load_error_strings(); |
|
|
|
|
|
|
|
ctx = SSL_CTX_new(SSLv23_client_method()); |
|
|
|
SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
|
|
| SSL_OP_SINGLE_DH_USE); |
|
|
|
ssl = SSL_new(ctx); |
|
|
|
SSL_set_fd(ssl, *sockfd); |
|
|
|
SSL_set_connect_state(ssl); |
|
|
|
|
|
|
|
if ((r = SSL_connect(ssl)) < 1) { |
|
|
|
fprintf(log, "tubes: %s\n", strerror(SSL_get_error(ssl, r))); |
|
|
|
SSL_CTX_free(ctx); |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
FILE *slog(char *file) |
|
|
|
{ |
|
|
|
const char *home = getenv("HOME"); |
|
|
|
char path[100]; |
|
|
|
FILE *fp; |
|
|
|
|
|
|
|
snprintf(path, 100, "%s/%s", home, file); |
|
|
|
mknod(path, 0 | 0666, 0); |
|
|
|
fp = fopen(path, "w"); |
|
|
|
|
|
|
|
return fp; |
|
|
|
} |
|
|
|
|
|
|
|
void mop(void) |
|
|
|
{ |
|
|
|
char str[512]; |
|
|
|
close(sockfd); |
|
|
|
close(in); |
|
|
|
close(out); |
|
|
|
fclose(log); |
|
|
|
|
|
|
|
ERR_free_strings(); |
|
|
|
EVP_cleanup(); |
|
|
@@ -236,8 +224,9 @@ void mop(void) |
|
|
|
SSL_free(ssl); |
|
|
|
SSL_CTX_free(ctx); |
|
|
|
|
|
|
|
snprintf(str, 512, "/tmp/%s.in", server); |
|
|
|
unlink(str); |
|
|
|
snprintf(str, 512, "/tmp/%s.out", server); |
|
|
|
unlink(str); |
|
|
|
snprintf(buf, 512, "/tmp/%s.in", server); |
|
|
|
unlink(buf); |
|
|
|
snprintf(buf, 512, "/tmp/%s.out", server); |
|
|
|
unlink(buf); |
|
|
|
exit(status); |
|
|
|
} |