1
0
mirror of https://github.com/sys-fs/tubes synced 2024-11-22 03:54:15 -05:00
tubes/tubes.c

219 lines
4.1 KiB
C
Raw Normal View History

2016-09-22 21:57:44 -04:00
/* See the LICENSE file for licensing information */
2016-09-18 10:31:33 -04:00
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
2016-11-02 07:23:35 -04:00
#include <syslog.h>
2016-09-18 10:31:33 -04:00
#include <time.h>
#include <unistd.h>
#define PING_TIMEOUT 240
static SSL_CTX *ctx;
static SSL *ssl;
static char *host = "chat.freenode.net";
2016-11-02 07:23:35 -04:00
static char port[6] = "6667";
2016-09-18 10:31:33 -04:00
static short use_ssl = 0;
static unsigned int last_response;
2016-11-02 07:23:35 -04:00
static int
tube(char *direction)
2016-09-22 21:57:44 -04:00
{
2016-11-02 07:23:35 -04:00
int fd;
char buf[512];
2016-09-22 21:57:44 -04:00
2016-11-02 07:23:35 -04:00
snprintf(buf, sizeof(buf), "/tmp/%s.%s", host, direction);
unlink(buf);
mkfifo(buf, 0660);
if ((fd = open(buf, O_RDWR)) < 0)
perror("tube");
2016-09-18 10:31:33 -04:00
2016-11-02 07:23:35 -04:00
return fd;
2016-09-22 21:57:44 -04:00
}
2016-11-01 17:42:07 -04:00
static int
2016-11-02 07:23:35 -04:00
dial(char *host, char *port)
2016-09-22 21:57:44 -04:00
{
int sockfd, err;
struct addrinfo hints, *serv;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
2016-11-02 07:23:35 -04:00
if ((err = getaddrinfo(host, port, &hints, &serv)) != 0) {
fprintf(stderr, "dial: %s\n", gai_strerror(err));
2016-09-22 21:57:44 -04:00
return -1;
2016-11-02 07:23:35 -04:00
}
if ((sockfd = socket(serv->ai_family, serv->ai_socktype,
serv->ai_protocol)) < 0) {
perror("dial");
2016-09-22 21:57:44 -04:00
return -1;
2016-11-02 07:23:35 -04:00
}
if (connect(sockfd, serv->ai_addr, serv->ai_addrlen) < 0) {
perror("dial");
2016-09-22 21:57:44 -04:00
close(sockfd);
return -1;
}
freeaddrinfo(serv);
return sockfd;
}
2016-11-01 17:42:07 -04:00
static int
2016-09-22 21:57:44 -04:00
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) {
2016-11-02 07:23:35 -04:00
fprintf(stderr, "sslify: %s\n", strerror(SSL_get_error(ssl, r)));
2016-09-22 21:57:44 -04:00
SSL_CTX_free(ctx);
return -1;
}
return 0;
}
int
main(int argc, char **argv)
2016-09-18 10:31:33 -04:00
{
int sockfd, in, out;
int maxfd;
fd_set rd;
struct timeval tv;
char buf[512];
2016-09-22 21:57:44 -04:00
int i, r, status;
2016-09-18 10:31:33 -04:00
2016-11-02 07:23:35 -04:00
while ((i = getopt(argc, argv, "Shp:")) != -1) {
switch (i) {
2016-09-18 10:31:33 -04:00
case 'S':
use_ssl = 1;
2016-11-02 07:23:35 -04:00
strncpy(port, "6697", sizeof(port));
2016-09-18 10:31:33 -04:00
break;
case 'h':
2016-11-02 07:23:35 -04:00
host = optarg;
2016-09-18 10:31:33 -04:00
break;
case 'p':
2016-11-02 07:23:35 -04:00
strncpy(port, optarg, sizeof(port));
2016-09-18 10:31:33 -04:00
break;
default:
2016-11-02 07:23:35 -04:00
fprintf(stderr, "usage: tubes [-S] [-h host] [-p port]\n");
return 1;
2016-09-18 10:31:33 -04:00
}
}
2016-11-02 07:23:35 -04:00
if ((sockfd = dial(host, port)) < 0)
return 1;
if (use_ssl && sslify(&sockfd) < 0)
return 1;
if ((in = tube("in")) < 0)
return 1;
if ((out = tube("out")) < 0)
return 1;
if (daemon(0, 0) < 0) {
perror("main");
return 1;
2016-09-18 10:31:33 -04:00
}
2016-11-02 07:23:35 -04:00
openlog(argv[0], LOG_PID, LOG_DAEMON);
2016-09-22 21:57:44 -04:00
for (status = 0;;) {
2016-09-18 10:31:33 -04:00
FD_ZERO(&rd);
maxfd = (out >= sockfd) ? out : sockfd;
FD_SET(out, &rd);
FD_SET(sockfd, &rd);
tv.tv_sec = 10;
tv.tv_usec = 0;
r = select(maxfd+1, &rd, 0, 0, &tv);
if (r < 0) {
if (errno == EINTR)
continue;
2016-11-02 07:23:35 -04:00
syslog(LOG_ERR, strerror(errno));
status = 1;
2016-09-22 21:57:44 -04:00
break;
2016-11-02 07:23:35 -04:00
} else if (r == 0 && last_response - time(NULL) >= PING_TIMEOUT) {
syslog(LOG_ERR, "ping timeout");
status = 1;
2016-09-22 21:57:44 -04:00
break;
2016-09-18 10:31:33 -04:00
}
2016-11-02 07:23:35 -04:00
if (FD_ISSET(out, &rd)) {
if ((i = read(out, buf, sizeof(buf))) < 0) {
if (errno == EINTR)
continue;
syslog(LOG_ERR, "broken pipe");
status = 1;
break;
} else if (i > 0) {
2016-09-18 10:31:33 -04:00
buf[i] = 0;
if (use_ssl)
SSL_write(ssl, buf, strlen(buf));
else
send(sockfd, buf, strlen(buf), 0);
}
2016-11-02 07:23:35 -04:00
}
2016-09-18 10:31:33 -04:00
if (FD_ISSET(sockfd, &rd)) {
if (use_ssl) {
do {
2016-10-18 19:30:32 -04:00
r = 0;
2016-09-18 10:31:33 -04:00
i = SSL_read(ssl, buf, sizeof(buf));
if (SSL_get_error(ssl, i)
== SSL_ERROR_WANT_READ)
2016-10-18 19:30:32 -04:00
r = 1;
} while (SSL_pending(ssl) && !r);
2016-09-18 10:31:33 -04:00
} else
i = recv(sockfd, buf, sizeof(buf), 0);
if (i != -1) {
if (i == 0) {
2016-11-02 07:23:35 -04:00
syslog(LOG_NOTICE, "connection closed");
2016-09-22 21:57:44 -04:00
break;
2016-09-18 10:31:33 -04:00
}
buf[i] = 0;
if (write(in, buf, strlen(buf)) < 0) {
if (errno == EINTR)
continue;
2016-11-02 07:23:35 -04:00
syslog(LOG_ERR, "broken pipe");
status = 1;
2016-09-22 21:57:44 -04:00
break;
2016-09-18 10:31:33 -04:00
}
last_response = time(NULL);
}
}
}
2016-09-22 21:57:44 -04:00
close(sockfd);
close(in);
close(out);
2016-11-02 07:23:35 -04:00
closelog();
2016-09-18 10:31:33 -04:00
ERR_free_strings();
EVP_cleanup();
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
snprintf(buf, 512, "/tmp/%s.in", host);
2016-09-22 21:57:44 -04:00
unlink(buf);
snprintf(buf, 512, "/tmp/%s.out", host);
2016-09-22 21:57:44 -04:00
unlink(buf);
2016-11-02 07:23:35 -04:00
return status;
2016-09-18 10:31:33 -04:00
}