/* * RFC2217 test server */ #include #include #include #include #include #include #include #include "lib/nvt_log.h" #include "lib/nvt_socket.h" #include "telnet.h" #define HELP \ "Usage: nvtsrv -deq\n" struct { unsigned char mline; tn_ctx_t *tnct; } dd; struct pollfd pfds[3]; int nfds; #define fd_srv pfds[1].fd #define fd_cli pfds[2].fd static void _nvtsrv_usage(void) { printf("Usage:\n" " nvtsrv host:port\n"); exit(0); } static void _tn_cli_close(void) { int i = 2; nvt_log(LOG_INFO, "%d: fd=%d: Closed\n", i, pfds[i].fd); close(pfds[i].fd); pfds[i].fd = -1; nfds = 2; } static void _tn_tx(void *cctx, const void *buf, int len) { int nw; DBG2_BUF("Tx", buf, len); if (fd_cli < 0) { nvt_log(LOG_NOTICE, "Write fd is closed - drop Tx\n"); return; } nw = write(fd_cli, buf, len); if (nw != len) { nvt_log(LOG_ERR, "Write failed %d != %d\n", nw, len); _tn_cli_close(); } } static void _tn_ss(void *cctx, int signal, int value) { nvt_log(LOG_INFO, "RFC2217 signal %d: %02x", signal, value); } static void _nvtsrv_init(void) { free(dd.tnct); memset(&dd, 0, sizeof(dd)); dd.tnct = telnet_ctx_init(NULL, _tn_tx, _tn_ss); } static void _nvtsrv_cmd(tn_ctx_t *tcc, const char *line, int len) { int val; if (line[0] == '*' && len > 2) { /* Special features */ if (line[1] == 'm') { sscanf(line + 2, "%x", &val); telnet_rfc2217_change_modemstate(tcc, val); } } else { /* Send all input */ _tn_tx(NULL, line, len); } } static void _nvtsrv_set_signal_handlers(void) { struct sigaction sa = { .sa_handler = SIG_IGN, .sa_flags = SA_RESTART, }; sigemptyset(&sa.sa_mask); sigaction(SIGPIPE, &sa, NULL); } int main(int argc, char **argv) { int opt; char buf[128]; int rc, nr, i, len; int debug, quiet; bool do_echo; debug = quiet = 0; do_echo = false; while ((opt = getopt(argc, argv, "deq")) != -1) { switch (opt) { default: /* '?' */ fprintf(stderr, HELP); exit(EXIT_FAILURE); case 'd': debug += 1; break; case 'e': /* Echo received data */ do_echo = true; break; case 'q': quiet = 1; break; } } argc -= optind; argv += optind; if (argc <= 0) _nvtsrv_usage(); nvt_log_level(quiet, debug); nvt_log_dest(NVT_LOG_STDOUT); _nvtsrv_set_signal_handlers(); memset(pfds, 0, sizeof(pfds)); pfds[0].fd = STDIN_FILENO; pfds[0].events = POLLIN; pfds[1].fd = socket_create_server(argv[0]); pfds[1].events = POLLIN; pfds[2].fd = -1; pfds[2].events = POLLIN; nfds = 2; for (;;) { for (i = 0; i < 3; i++) pfds[i].revents = 0; rc = poll(pfds, nfds, -1); if (rc < 0) { nvt_log(LOG_ERR, "poll failed: %m\n"); break; } i = 0; if (pfds[i].revents) { nr = read(pfds[i].fd, buf, sizeof(buf) - 1); if (nr <= 0) break; buf[nr] = 0; DBG2_BUF("Con Rx", buf, nr); _nvtsrv_cmd(dd.tnct, buf, nr); } i = 2; if (pfds[i].revents) { nr = 0; if (pfds[i].revents & POLLIN) { nr = read(pfds[i].fd, buf, sizeof(buf)); if (nr <= 0) { _tn_cli_close(); continue; } } if (pfds[i].revents & (POLLERR | POLLHUP)) { _tn_cli_close(); } if (nr > 0) { buf[nr] = 0; DBG2_BUF("Rx", buf, nr); len = nr; rc = telnet_rx(dd.tnct, buf, &len); if (do_echo) { /* Echo received */ _tn_tx(NULL, buf, len); } } } i = 1; if (pfds[i].revents) { if (pfds[2].fd >= 0) { nvt_log(LOG_NOTICE, "Client already connected on fd=%d\n", pfds[2].fd); break; } pfds[2].fd = socket_create_server_client(pfds[i].fd); nvt_log(LOG_INFO, "%d: fd=%d: Connected\n", 2, pfds[2].fd); pfds[2].events = POLLIN; nfds = 3; _nvtsrv_init(); } } return 0; }