diff --git a/Makefile b/Makefile index e7c1c2b..720dec4 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,10 @@ -VERSION := v0.01 +CFLAGS := -O2 -pipe -Wall -CFLAGS := -O2 -pipe -Wall -DVERSION='"$(VERSION)"' - -OBJS := configfile.o connection.o event.o logging.o network.o telnetproxy.o +OBJS := configfile.o connection.o event.o logging.o tcpsocket.o sockaddr.o all: telnetproxy -telnetproxy: $(OBJS) +telnetproxy: $(OBJS) telnetproxy.o $(CC) $(CFLAGS) $^ -o $@ %.o: %.c diff --git a/configfile.c b/configfile.c index 73ff3ae..1314bb3 100644 --- a/configfile.c +++ b/configfile.c @@ -36,13 +36,13 @@ struct conf_section { struct list_head list; struct list_head tupel_list; - char *name; + const char *name; }; struct conf_tupel { struct list_head list; - char *option; - char *parameter; + const char *option; + const char *parameter; }; static LIST_HEAD(config_list); @@ -142,6 +142,23 @@ int config_parse(const char *config) return 0; } +void config_free(void) +{ + struct conf_section *section, *section_tmp; + struct conf_tupel *tupel, *tupel_tmp; + + list_for_each_entry_safe(section, section_tmp, &config_list, list) { + list_for_each_entry_safe(tupel, tupel_tmp, §ion->tupel_list, list) { + list_del(&tupel->list); + free((char *)tupel->option); + free((char *)tupel->parameter); + free(tupel); + } + list_del(§ion->list); + free(section); + } +} + static struct conf_section * config_get_section(const char *name) { struct conf_section *section; @@ -153,7 +170,7 @@ static struct conf_section * config_get_section(const char *name) return NULL; } -char * config_get_string(const char *section_str, const char *option, char *def) +const char * config_get_string(const char *section_str, const char *option, const char *def) { struct conf_section *section = config_get_section(section_str); if (section != NULL) { @@ -172,7 +189,7 @@ char * config_get_string(const char *section_str, const char *option, char *def) int config_get_int(const char *section, const char *option, int def) { - char *ret = config_get_string(section, option, NULL); + const char *ret = config_get_string(section, option, NULL); if (ret == NULL) { log_print(LOG_WARN, "config [%s:%s] not found, using default: '%d'", section, option, def); diff --git a/configfile.h b/configfile.h index 6528459..9a2b669 100644 --- a/configfile.h +++ b/configfile.h @@ -1,11 +1,10 @@ #ifndef _CONFIG_H_ #define _CONFIG_H_ -#include - int config_parse(const char *config); +void config_free(void); -char * config_get_string(const char *section_str, const char *option, char *def); +const char * config_get_string(const char *section_str, const char *option, const char *def); int config_get_int(const char *section, const char *option, int def); diff --git a/connection.c b/connection.c index 4159280..e58031c 100644 --- a/connection.c +++ b/connection.c @@ -10,7 +10,8 @@ #include "event.h" #include "list.h" #include "logging.h" -#include "network.h" +#include "sockaddr.h" +#include "tcpsocket.h" struct connection { struct list_head list; @@ -123,7 +124,7 @@ static int connect_timeout(void *privdata) return -1; } -static int client_handler(int fd, void *privdata) +int client_handler(int fd, void *privdata) { struct connection *con = (struct connection *)privdata; char buf[256]; @@ -135,7 +136,7 @@ static int client_handler(int fd, void *privdata) return -1; } - if (parse_saddr(buf, &con->dst_addr) != 0) { + if (parse_sockaddr(buf, &con->dst_addr) != 0) { list_del(&con->list); destroy_connection(con); return -1; @@ -143,7 +144,7 @@ static int client_handler(int fd, void *privdata) // TODO: check destination - int dst_fd = tcp_connect_socket(&con->dst_addr); + int dst_fd = tcp_connect(&con->dst_addr); if (dst_fd < 0) { list_del(&con->list); destroy_connection(con); @@ -166,7 +167,7 @@ static int client_handler(int fd, void *privdata) return 0; } -static int admin_handler(int fd, void *privdata) +int admin_handler(int fd, void *privdata) { struct connection *con = (struct connection *)privdata; char buf[256]; @@ -182,9 +183,9 @@ static int admin_handler(int fd, void *privdata) struct connection *entry; list_for_each_entry(entry, &connection_list, list) { len = snprintf(buf, sizeof(buf), "%d,", event_get_fd(entry->src_event)); - len += get_sockaddr(&entry->src_addr, buf + len, sizeof(buf) - len); + len += get_sockaddr(buf + len, sizeof(buf) - len, &entry->src_addr); len += snprintf(buf + len, sizeof(buf) - len, ",%d,", event_get_fd(entry->dst_event)); - len += get_sockaddr(&entry->dst_addr, buf + len, sizeof(buf) - len); + len += get_sockaddr(buf + len, sizeof(buf) - len, &entry->dst_addr); len += snprintf(buf + len, sizeof(buf) - len, ",%ld\n", (time(NULL) - entry->login_time)); write(fd, buf, len); } @@ -203,8 +204,6 @@ static int admin_handler(int fd, void *privdata) 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"); @@ -222,11 +221,6 @@ int listen_handler(int fd, void *privdata) list_add_tail(&con->list, &connection_list); - if (mode == CON_ADMIN) - con->src_event = event_add_readfd(NULL, src_fd, admin_handler, con); - - else if (mode == CON_NORMAL) - con->src_event = event_add_readfd(NULL, src_fd, client_handler, con); - + con->src_event = event_add_readfd(NULL, src_fd, privdata, con); return 0; } diff --git a/connection.h b/connection.h index 50433ce..4fd802d 100644 --- a/connection.h +++ b/connection.h @@ -1,9 +1,8 @@ #ifndef _CONNECTION_H_ #define _CONNECTION_H_ -#define CON_NORMAL 0x01 -#define CON_ADMIN 0x02 - int listen_handler(int fd, void *privdata); +int client_handler(int fd, void *privdata); +int admin_handler(int fd, void *privdata); #endif // _CONNECTION_H_ diff --git a/network.h b/network.h deleted file mode 100644 index bee2acc..0000000 --- a/network.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _NETWORK_H_ -#define _NETWORK_H_ - -#include - -int parse_saddr(const char *addr, struct sockaddr_in *sa); -int tcp_listen_socket(struct sockaddr_in *sa); -int tcp_connect_socket(struct sockaddr_in *sa); -int tcp_connect_error(int fd); - -int get_sockaddr(struct sockaddr_in *sa, char *buf, int size); -char * get_sockaddr_buf(struct sockaddr_in *sa); - -#endif // _NETWORK_H_ diff --git a/sockaddr.c b/sockaddr.c new file mode 100644 index 0000000..91a5c20 --- /dev/null +++ b/sockaddr.c @@ -0,0 +1,92 @@ +#include +#include +#include + +#include +#include +#include +#include + +int parse_sockaddr(const char *addr, struct sockaddr_in *sa) +{ + char *buf = strdup(addr); + if (buf == NULL) + return -1; + + char *tmp; + char *ipstr = strtok_r(buf, ":", &tmp); + if (ipstr == NULL) { + free(buf); + return -2; + } + + sa->sin_family = AF_INET; + if (inet_pton(AF_INET, ipstr, &sa->sin_addr) <= 0) { + free(buf); + return -3; + } + + char *portstr = strtok_r(NULL, " \r\n", &tmp); + if (portstr == NULL) { + free(buf); + return -4; + } + + int port = atoi(portstr); + if (port < 0 || port > 65535) { + free(buf); + return -5; + } + + sa->sin_port = htons(port); + free(buf); + return 0; +} + +int parse_subnet(const char *addr, struct in_addr *net, struct in_addr *mask) +{ + char *buf = strdup(addr); + if (buf == NULL) + return -1; + + char *tmp; + char *netstr = strtok_r(buf, "/", &tmp); + if (netstr == NULL) { + free(buf); + return -2; + } + + if (inet_pton(AF_INET, netstr, net) <= 0) { + free(buf); + return -3; + } + + char *maskstr = strtok_r(NULL, " \r\n", &tmp); + if (maskstr == NULL) { + mask->s_addr = ~0; + + } else if (inet_pton(AF_INET, maskstr, mask) <= 0) { + int maskbits = atoi(maskstr); + if (maskbits < 0 || maskbits > 32) { + free(buf); + return -4; + } + + mask->s_addr = htonl(~0 << (32 - maskbits)); + } + + free(buf); + return 0; +} + +int get_sockaddr(char *buf, int size, struct sockaddr_in *addr) +{ + return snprintf(buf, size, "%s:%d", inet_ntoa(addr->sin_addr), ntohs(addr->sin_port)); +} + +char * get_sockaddr_buf(struct sockaddr_in *addr) +{ + static char ret[24]; + get_sockaddr(ret, sizeof(ret), addr); + return ret; +} diff --git a/sockaddr.h b/sockaddr.h new file mode 100644 index 0000000..243cbc4 --- /dev/null +++ b/sockaddr.h @@ -0,0 +1,10 @@ +#ifndef _SOCKADDR_H_ +#define _SOCKADDR_H_ + +int parse_sockaddr(const char *addr, struct sockaddr_in *sa); +int parse_subnet(const char *addr, struct in_addr *net, struct in_addr *mask); + +int get_sockaddr(char *buf, int size, struct sockaddr_in *addr); +char * get_sockaddr_buf(struct sockaddr_in *addr); + +#endif /* _SOCKADDR_H_ */ diff --git a/network.c b/tcpsocket.c similarity index 60% rename from network.c rename to tcpsocket.c index b5d3165..4c4a8c1 100644 --- a/network.c +++ b/tcpsocket.c @@ -8,49 +8,9 @@ #include #include "logging.h" +#include "sockaddr.h" -int parse_saddr(const char *addr, struct sockaddr_in *sa) -{ - char *addr_cpy = strdup(addr); - if (addr_cpy == NULL) { - log_print(LOG_WARN, "parse_saddr(): out of memory"); - return -1; - } - - char *tmp; - char *ip = strtok_r(addr_cpy, ":", &tmp); - if (ip == NULL) { - free(addr_cpy); - return -1; - } - - char *port = strtok_r(NULL, ":", &tmp); - if (port == NULL) { - free(addr_cpy); - return -1; - } - - sa->sin_family = AF_INET; - sa->sin_port = htons(atoi(port)); - int ret = inet_aton(ip, &sa->sin_addr); - - free(addr_cpy); - return (ret != 0) ? 0 : -1; -} - -int get_sockaddr(struct sockaddr_in *sa, char *buf, int size) -{ - return snprintf(buf, size, "%s:%d", inet_ntoa(sa->sin_addr), ntohs(sa->sin_port)); -} - -char * get_sockaddr_buf(struct sockaddr_in *sa) -{ - static char buf[24]; - get_sockaddr(sa, buf, sizeof(buf)); - return buf; -} - -int tcp_listen_socket(struct sockaddr_in *sa) +int tcp_listen(struct sockaddr_in *sa) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0 ) { @@ -58,7 +18,7 @@ int tcp_listen_socket(struct sockaddr_in *sa) return -1; } - int i = 1; + int i = 1; if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i))) { log_print(LOG_ERROR, "tcp_listen_socket(): setsockopt(SO_REUSEADDR)"); close(sock); @@ -79,7 +39,7 @@ int tcp_listen_socket(struct sockaddr_in *sa) return sock; } -int tcp_connect_socket(struct sockaddr_in *sa) +int tcp_connect(struct sockaddr_in *sa) { int sock = socket(AF_INET, SOCK_STREAM, 0); if (sock < 0 ) { @@ -87,23 +47,41 @@ int tcp_connect_socket(struct sockaddr_in *sa) return -1; } + int ret = connect(sock, (struct sockaddr *)sa, sizeof(*sa)); + if (ret != 0) { + log_print(LOG_ERROR, "tcp_connect(): connect(%s)", get_sockaddr_buf(sa)); + close(sock); + return -1; + } + + return sock; +} + +int tcp_connect_nonblock(struct sockaddr_in *sa) +{ + int sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock < 0 ) { + log_print(LOG_ERROR, "tcp_connect_nonblock(): socket()"); + return -1; + } + int flags = fcntl(sock, F_GETFL, 0); if (flags < 0) { - log_print(LOG_ERROR, "tcp_connect_socket(): fcntl(F_GETFL)"); + log_print(LOG_ERROR, "tcp_connect_nonblock(): fcntl(F_GETFL)"); close(sock); return -1; } /* non-blocking connect() */ if (fcntl(sock, F_SETFL, flags | O_NONBLOCK)) { - log_print(LOG_ERROR, "tcp_connect_socket(): fcntl(F_SETFL)"); + log_print(LOG_ERROR, "tcp_connect_nonblock(): fcntl(F_SETFL)"); close(sock); return -1; } int ret = connect(sock, (struct sockaddr *)sa, sizeof(*sa)); if (ret && errno != EINPROGRESS) { - log_print(LOG_ERROR, "tcp_connect_socket(): bind(%s)", get_sockaddr_buf(sa)); + log_print(LOG_ERROR, "tcp_connect_nonblock(): connect(%s)", get_sockaddr_buf(sa)); close(sock); return -1; } @@ -113,7 +91,7 @@ int tcp_connect_socket(struct sockaddr_in *sa) /* all further actions are blocking */ if (fcntl(sock, F_SETFL, flags)) { - log_print(LOG_ERROR, "tcp_connect_socket(): fcntl(F_SETFL)"); + log_print(LOG_ERROR, "tcp_connect_nonblock(): fcntl(F_SETFL)"); close(sock); return -1; } diff --git a/tcpsocket.h b/tcpsocket.h new file mode 100644 index 0000000..310a8e8 --- /dev/null +++ b/tcpsocket.h @@ -0,0 +1,12 @@ +#ifndef _NETWORK_H_ +#define _NETWORK_H_ + +#include + +int tcp_listen(struct sockaddr_in *sa); +int tcp_connect(struct sockaddr_in *sa); + +int tcp_connect_nonblock(struct sockaddr_in *sa); +int tcp_connect_error(int fd); + +#endif // _NETWORK_H_ diff --git a/telnetproxy.c b/telnetproxy.c index 2a1d546..f42efa9 100644 --- a/telnetproxy.c +++ b/telnetproxy.c @@ -9,18 +9,19 @@ #include "connection.h" #include "event.h" #include "logging.h" -#include "network.h" +#include "tcpsocket.h" +#include "sockaddr.h" static int listen_init(const char *value, void *privdata) { struct sockaddr_in addr; - if (parse_saddr(value, &addr) == -1) { + if (parse_sockaddr(value, &addr) == -1) { log_print(LOG_WARN, "invalid listen addr: '%s'", value); return -1; } - int sock = tcp_listen_socket(&addr); + int sock = tcp_listen(&addr); if (sock < 0) return -1; @@ -34,13 +35,13 @@ int main(int argc, char *argv[]) if (config_parse("telnetproxy.conf") == -1) return -1; - int cnt = config_get_strings("global", "listen", listen_init, (void*)CON_NORMAL); + int cnt = config_get_strings("global", "listen", listen_init, client_handler); if (cnt <= 0) { log_print(LOG_ERROR, "no listen sockets defined!"); return -1; } - cnt = config_get_strings("global", "admin_listen", listen_init, (void*)CON_ADMIN); + cnt = config_get_strings("global", "admin_listen", listen_init, admin_handler); if (cnt <= 0) { log_print(LOG_ERROR, "no admin_listen sockets defined!"); return -1;