/*
* ser2net - A program for allowing telnet connection to serial ports
* Copyright (C) 2001 Corey Minyard <minyard@acm.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This code handles the actual transfer of data between the serial
ports and the TCP ports. */
#include <sys/time.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <syslog.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <fcntl.h>
#include "ser2net.h"
#include "dataxfer.h"
#include "selector.h"
#include "utils.h"
#include "telnet.h"
#include "devio.h"
#include "buffer.h"
#include "locking.h"
#include "led.h"
#define SERIAL "term"
#define NET "tcp "
/** BASED ON sshd.c FROM openssh.com */
#ifdef HAVE_TCPD_H
#include <tcpd.h>
static char *progname = "ser2net";
#endif /* HAVE_TCPD_H */
/* States for the net_to_dev_state and dev_to_net_state. */
#define PORT_UNCONNECTED 0 /* The TCP port is not connected
to anything right now. */
#define PORT_WAITING_INPUT 1 /* Waiting for input from the
input side. */
#define PORT_WAITING_OUTPUT_CLEAR 2 /* Waiting for output to clear
so I can send data. */
#define PORT_CLOSING 3 /* Waiting for output close
string to be sent. */
char *state_str[] = { "unconnected", "waiting input", "waiting output",
"closing" };
#define PORT_DISABLED 0 /* The port is not open. */
#define PORT_RAW 1 /* Port will not do telnet negotiation. */
#define PORT_RAWLP 2 /* Port will not do telnet negotiation and
termios setting, open for output only. */
#define PORT_TELNET 3 /* Port will do telnet negotiation. */
char *enabled_str[] = { "off", "raw", "rawlp", "telnet" };
typedef struct trace_info_s
{
int hexdump; /* output each block as a hexdump */
int timestamp; /* preceed each line with a timestamp */
char *filename; /* open file. NULL if not used */
int fd; /* open file. -1 if not used */
} trace_info_t;
typedef struct port_info port_info_t;
typedef struct net_info net_info_t;
struct net_info {
port_info_t *port; /* My port. */
bool closing; /* Is the connection in the process
of closing? */
int fd; /* When connected, the file
descriptor for the network
port used for I/O. */
bool remote_fixed; /* Tells if the remote address was
set in the configuration, and
cannot be changed. */
struct sockaddr_storage remote; /* The socket address of who
is connected to this port. */
struct sockaddr *raddr; /* Points to remote, for convenience. */
socklen_t raddrlen;
struct sockaddr *udpraddr; /* Points to remote, only for UDP,
so sendto's addr will be NULL on
TCP. */
socklen_t udpraddrlen;
unsigned int bytes_received; /* Number of bytes read from the
network port. */
unsigned int bytes_sent; /* Number of bytes written to the
network port. */
struct sbuf *banner; /* Outgoing banner */
unsigned int write_pos; /* Our current position in the
output buffer where we need
to start writing next. */
bool data_to_write; /* There is data to write on
this network port. */
void (*write_handler)(port_info_t *, net_info_t *);
/* Data for the telnet processing */
telnet_data_t tn_data;
bool sending_tn_data; /* Are we sending tn data at the moment? */
int timeout_left; /* The amount of time left (in
seconds) before the timeout
goes off. */
sel_runner_t *runshutdown; /* Used to run things at the
base context. This way we
don't have to worry that we
are running inside a
handler context that needs
to be waited for exit. */
/*
* If a user gets kicked, store the information for the new user
* here since we have already accepted the connection or received
* the packet, we have to store it someplace.
*/
int new_fd;
struct sockaddr_storage new_remote;
socklen_t new_raddrlen;
unsigned char *new_buf;
int new_buf_len;
};
struct port_remaddr
{
char *name;
struct sockaddr_storage addr;
socklen_t addrlen;
bool is_port_set;
struct port_remaddr *next;
};
struct port_info
{
DEFINE_LOCK(, lock)
int enabled; /* If PORT_DISABLED, the port
is disabled and the TCP
accept port is not
operational. If PORT_RAW,
the port is enabled and
will not do any telnet
negotiations. If
PORT_RAWLP, the port is enabled
only for output without any
termios setting - it allows
to redirect /dev/lpX devices If
PORT_TELNET, the port is
enabled and it will do
telnet negotiations. */
int timeout; /* The number of seconds to
wait without any I/O before
we shut the port down. */
sel_timer_t *timer; /* Used to timeout when the no
I/O has been seen for a
certain period of time. */
sel_timer_t *send_timer; /* Used to delay a bit when
waiting for characters to
batch up as many characters
as possible. */
bool send_timer_running;
sel_runner_t *runshutdown; /* Used to run things at the
base context. This way we
don't have to worry that we
are running inside a
handler context that needs
to be waited for exit. */
int chardelay; /* The amount of time to wait after
receiving a character before
sending it, unless we receive
another character. Based on
bit rate. */
int bps; /* Bits per second rate. */
int bpc; /* Bits per character. */
bool enable_chardelay;
int chardelay_scale; /* The number of character
periods to wait for the
next character, in tenths of
a character period. */
int chardelay_min; /* The minimum chardelay, in
microseconds. */
int chardelay_max; /* Maximum amount of time to
wait before sending the data. */
struct timeval send_time; /* When using chardelay, the
time when we will send the
data, no matter what, set
by chardelay_max. */
int (*netread)(int fd, port_info_t *port, int *readerr,
net_info_t **netcon);
struct port_remaddr *remaddrs;
bool remaddr_set;
/* Information about the network port. */
char *portname; /* The name given for the port. */
int is_stdio; /* Do stdio on the port? */
struct addrinfo *ai; /* The address list for the portname. */
bool dgram; /* Is this a datagram (UDP) port? */
struct opensocks *acceptfds; /* The file descriptor used to
accept connections on the
TCP port. */
unsigned int nr_acceptfds;
waiter_t *accept_waiter; /* Wait for accept changes. */
unsigned int max_connections; /* Maximum number of TCP connections
we can