telnetproxy/connection.c

150 lines
2.8 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <netinet/ip.h>
#include "connection.h"
#include "event.h"
#include "list.h"
#include "logging.h"
#include "network.h"
struct connection {
struct list_head list;
struct sockaddr_in src_addr;
struct sockaddr_in dst_addr;
int src_fd;
int dst_fd;
unsigned long login_time;
};
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;
}
con->src_fd = con->dst_fd = -1;
con->login_time = time(NULL);
return con;
}
static int destroy_connection(struct connection *con)
{
if (con->src_fd != -1) {
close(con->src_fd);
event_remove_fd(con->src_fd);
}
if (con->dst_fd != -1) {
close(con->dst_fd);
event_remove_fd(con->dst_fd);
}
free(con);
return 0;
}
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;
}
/* client -> device */
if (con->src_fd == fd)
write(con->dst_fd, buf, len);
/* device -> client */
else if (con->dst_fd == fd)
write(con->src_fd, buf, len);
return 0;
}
static int client_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;
}
if (parse_saddr(buf, &con->dst_addr) != 0) {
list_del(&con->list);
destroy_connection(con);
return -1;
}
// check destination
con->dst_fd = tcp_connect_socket(&con->dst_addr);
if (con->dst_fd < 0) {
list_del(&con->list);
destroy_connection(con);
return -1;
}
log_print(LOG_INFO, "forwarding to %s", get_sockaddr_buf(&con->dst_addr));
event_add_readfd(con->dst_fd, forward_handler, con);
event_add_readfd(con->src_fd, forward_handler, con);
/* dismiss client_handler */
return -1;
}
static int admin_handler(int fd, void *privdata)
{
return -1;
}
int listen_handler(int fd, void *privdata)
{
int mode = (int)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);
con->src_fd = accept(fd, (struct sockaddr *)&con->src_addr, &i);
if (con->src_fd < 0) {
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);
if (mode == CON_ADMIN)
event_add_readfd(con->src_fd, client_handler, con);
else
event_add_readfd(con->src_fd, admin_handler, con);
return 0;
}