2006-11-25 14:31:52 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2006-12-03 20:03:16 +01:00
|
|
|
#include <unistd.h>
|
2006-12-03 22:13:20 +01:00
|
|
|
#include <string.h>
|
2006-11-25 14:31:52 +01:00
|
|
|
#include <time.h>
|
|
|
|
|
2006-12-03 20:03:16 +01:00
|
|
|
#include <netinet/ip.h>
|
|
|
|
|
2006-11-25 14:31:52 +01:00
|
|
|
#include "connection.h"
|
2006-12-03 20:03:16 +01:00
|
|
|
#include "event.h"
|
|
|
|
#include "list.h"
|
|
|
|
#include "logging.h"
|
2007-04-17 18:31:59 +02:00
|
|
|
#include "sockaddr.h"
|
|
|
|
#include "tcpsocket.h"
|
2006-12-03 20:03:16 +01:00
|
|
|
|
|
|
|
struct connection {
|
|
|
|
struct list_head list;
|
|
|
|
|
|
|
|
struct sockaddr_in src_addr;
|
|
|
|
struct sockaddr_in dst_addr;
|
|
|
|
|
2007-03-11 17:52:51 +01:00
|
|
|
struct event_fd *src_event;
|
|
|
|
struct event_fd *dst_event;
|
|
|
|
struct event_timeout *timeout;
|
2006-12-03 20:03:16 +01:00
|
|
|
|
2006-12-03 22:13:20 +01:00
|
|
|
time_t login_time;
|
2006-12-03 20:03:16 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static LIST_HEAD(connection_list);
|
|
|
|
|
|
|
|
static struct connection * create_connection()
|
|
|
|
{
|
|
|
|
struct connection *con = malloc(sizeof(struct connection));
|
|
|
|
if (con == NULL) {
|
|
|
|
log_print(LOG_WARN, "listen_handler(): out of memory");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-03-11 17:23:34 +01:00
|
|
|
memset(con, 0, sizeof(struct connection));
|
2006-12-03 20:03:16 +01:00
|
|
|
con->login_time = time(NULL);
|
|
|
|
return con;
|
|
|
|
}
|
|
|
|
|
2007-03-11 17:52:51 +01:00
|
|
|
static void destroy_connection(struct connection *con)
|
2006-12-03 20:03:16 +01:00
|
|
|
{
|
2007-03-11 17:23:34 +01:00
|
|
|
if (con->timeout != NULL)
|
2007-03-11 17:52:51 +01:00
|
|
|
event_remove_timeout(con->timeout);
|
2006-12-28 20:22:13 +01:00
|
|
|
|
2007-03-11 17:23:34 +01:00
|
|
|
int src_fd = event_get_fd(con->src_event);
|
|
|
|
if (src_fd != -1) {
|
|
|
|
close(src_fd);
|
2007-03-11 17:52:51 +01:00
|
|
|
event_remove_fd(con->src_event);
|
2006-12-03 20:03:16 +01:00
|
|
|
}
|
|
|
|
|
2007-03-11 17:23:34 +01:00
|
|
|
int dst_fd = event_get_fd(con->dst_event);
|
|
|
|
if (dst_fd != -1) {
|
|
|
|
close(dst_fd);
|
2007-03-11 17:52:51 +01:00
|
|
|
event_remove_fd(con->dst_event);
|
2006-12-03 20:03:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
free(con);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int forward_handler(int fd, void *privdata)
|
|
|
|
{
|
|
|
|
struct connection *con = (struct connection *)privdata;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
int len = read(fd, buf, sizeof(buf));
|
|
|
|
if (len <= 0) {
|
|
|
|
list_del(&con->list);
|
|
|
|
destroy_connection(con);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-03-11 17:23:34 +01:00
|
|
|
int src_fd = event_get_fd(con->src_event);
|
|
|
|
int dst_fd = event_get_fd(con->dst_event);
|
|
|
|
|
2006-12-03 20:03:16 +01:00
|
|
|
/* client -> device */
|
2007-03-11 17:23:34 +01:00
|
|
|
if (src_fd == fd && dst_fd != -1)
|
|
|
|
write(dst_fd, buf, len);
|
2006-12-03 20:03:16 +01:00
|
|
|
|
|
|
|
/* device -> client */
|
2007-03-11 17:23:34 +01:00
|
|
|
if (dst_fd == fd && src_fd != -1)
|
|
|
|
write(src_fd, buf, len);
|
2006-12-03 20:03:16 +01:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-12-28 20:22:13 +01:00
|
|
|
static int connect_handler(int fd, void *privdata)
|
|
|
|
{
|
|
|
|
struct connection *con = (struct connection *)privdata;
|
|
|
|
|
|
|
|
if (tcp_connect_error(fd)) {
|
|
|
|
list_del(&con->list);
|
|
|
|
destroy_connection(con);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_print(LOG_INFO, "forwarding to %s", get_sockaddr_buf(&con->dst_addr));
|
|
|
|
|
2007-03-11 17:23:34 +01:00
|
|
|
/* everything from dst will be forwarded */
|
|
|
|
event_add_readfd(con->dst_event, 0, forward_handler, con);
|
|
|
|
|
|
|
|
/* remove connect_handler */
|
|
|
|
event_add_writefd(con->dst_event, 0, NULL, NULL);
|
|
|
|
|
|
|
|
/* remove timeout */
|
2007-03-11 17:52:51 +01:00
|
|
|
event_remove_timeout(con->timeout);
|
2007-03-11 17:23:34 +01:00
|
|
|
con->timeout = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int connect_timeout(void *privdata)
|
|
|
|
{
|
|
|
|
struct connection *con = (struct connection *)privdata;
|
|
|
|
|
|
|
|
log_print(LOG_INFO, "connect to %s timed out", get_sockaddr_buf(&con->dst_addr));
|
|
|
|
|
|
|
|
list_del(&con->list);
|
|
|
|
destroy_connection(con);
|
|
|
|
|
|
|
|
/* singleshot timer */
|
2006-12-28 20:22:13 +01:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-04-17 18:31:59 +02:00
|
|
|
int client_handler(int fd, void *privdata)
|
2006-12-03 20:03:16 +01:00
|
|
|
{
|
|
|
|
struct connection *con = (struct connection *)privdata;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
int len = read(fd, buf, sizeof(buf));
|
|
|
|
if (len <= 0) {
|
|
|
|
list_del(&con->list);
|
|
|
|
destroy_connection(con);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-04-17 18:31:59 +02:00
|
|
|
if (parse_sockaddr(buf, &con->dst_addr) != 0) {
|
2006-12-03 20:03:16 +01:00
|
|
|
list_del(&con->list);
|
|
|
|
destroy_connection(con);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-03-11 17:23:34 +01:00
|
|
|
// TODO: check destination
|
|
|
|
|
2007-04-17 18:31:59 +02:00
|
|
|
int dst_fd = tcp_connect(&con->dst_addr);
|
2007-03-11 17:23:34 +01:00
|
|
|
if (dst_fd < 0) {
|
2006-12-03 20:03:16 +01:00
|
|
|
list_del(&con->list);
|
|
|
|
destroy_connection(con);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-12-28 20:22:13 +01:00
|
|
|
log_print(LOG_INFO, "connecting to %s", get_sockaddr_buf(&con->dst_addr));
|
2006-12-03 20:03:16 +01:00
|
|
|
|
2007-03-11 17:23:34 +01:00
|
|
|
struct timeval tv;
|
2007-03-11 17:52:51 +01:00
|
|
|
tv.tv_sec = 2;
|
2007-03-11 17:23:34 +01:00
|
|
|
tv.tv_usec = 0;
|
|
|
|
con->timeout = event_add_timeout(&tv, connect_timeout, con);
|
|
|
|
|
|
|
|
/* wait for connect() (non-blocking) */
|
|
|
|
con->dst_event = event_add_writefd(NULL, dst_fd, connect_handler, con);
|
|
|
|
|
|
|
|
/* everything from src will be forwarded */
|
|
|
|
event_add_readfd(con->src_event, 0, forward_handler, con);
|
|
|
|
|
|
|
|
return 0;
|
2006-12-03 20:03:16 +01:00
|
|
|
}
|
|
|
|
|
2007-04-17 18:31:59 +02:00
|
|
|
int admin_handler(int fd, void *privdata)
|
2006-12-03 20:03:16 +01:00
|
|
|
{
|
2006-12-03 22:13:20 +01:00
|
|
|
struct connection *con = (struct connection *)privdata;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
int len = read(fd, buf, sizeof(buf));
|
|
|
|
if (len <= 0) {
|
|
|
|
list_del(&con->list);
|
|
|
|
destroy_connection(con);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strncmp(buf, "list", 4) == 0) {
|
|
|
|
struct connection *entry;
|
|
|
|
list_for_each_entry(entry, &connection_list, list) {
|
2007-03-11 17:23:34 +01:00
|
|
|
len = snprintf(buf, sizeof(buf), "%d,", event_get_fd(entry->src_event));
|
2007-04-17 18:31:59 +02:00
|
|
|
len += get_sockaddr(buf + len, sizeof(buf) - len, &entry->src_addr);
|
2007-03-11 17:23:34 +01:00
|
|
|
len += snprintf(buf + len, sizeof(buf) - len, ",%d,", event_get_fd(entry->dst_event));
|
2007-04-17 18:31:59 +02:00
|
|
|
len += get_sockaddr(buf + len, sizeof(buf) - len, &entry->dst_addr);
|
2006-12-03 22:13:20 +01:00
|
|
|
len += snprintf(buf + len, sizeof(buf) - len, ",%ld\n", (time(NULL) - entry->login_time));
|
|
|
|
write(fd, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (strncmp(buf, "kill", 4) == 0) {
|
|
|
|
|
|
|
|
|
|
|
|
} else if (strncmp(buf, "quit", 4) == 0) {
|
|
|
|
list_del(&con->list);
|
|
|
|
destroy_connection(con);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2006-12-03 20:03:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int listen_handler(int fd, void *privdata)
|
|
|
|
{
|
|
|
|
struct connection *con = create_connection();
|
|
|
|
if (con == NULL) {
|
|
|
|
log_print(LOG_WARN, "listen_handler(): out of memory");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int i = sizeof(con->src_addr);
|
2007-03-11 17:23:34 +01:00
|
|
|
int src_fd = accept(fd, (struct sockaddr *)&con->src_addr, &i);
|
|
|
|
if (src_fd < 0) {
|
2006-12-03 20:03:16 +01:00
|
|
|
free(con);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
log_print(LOG_INFO, "accepted connection from %s", get_sockaddr_buf(&con->src_addr));
|
|
|
|
|
|
|
|
list_add_tail(&con->list, &connection_list);
|
|
|
|
|
2007-04-17 18:31:59 +02:00
|
|
|
con->src_event = event_add_readfd(NULL, src_fd, privdata, con);
|
2006-12-03 20:03:16 +01:00
|
|
|
return 0;
|
|
|
|
}
|