/* common.c Copyright (C) 1999, 2000 Lars Brinkhoff. See COPYING for terms and conditions. Code common to both htc and hts. */ #include #include #include #include #include #include #include #include #include #include "tunnel.h" #include "common.h" #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifdef DEBUG_MODE static void log_level (int level, char *fmt0, va_list ap) { if (debug_level >= level) { struct tm *t2; char s[40]; time_t t; int i; time (&t); t2 = localtime (&t); strftime (s, sizeof s, "%Y%m%d %H%M%S ", t2); fprintf (debug_file, "%s", s); for (i = 1; i < level; i++) fprintf (debug_file, " "); vfprintf (debug_file, fmt0, ap); fprintf (debug_file, "\n"); fflush (debug_file); } } #endif void log_exit (int status) { log_notice ("exit with status = %d", status); exit (status); } void log_notice (char *fmt0, ...) { va_list ap; va_start(ap, fmt0); #ifdef DEBUG_MODE log_level (1, fmt0, ap); #else vsyslog (LOG_NOTICE, fmt0, ap); #endif va_end(ap); } void log_error (char *fmt0, ...) { va_list ap; va_start(ap, fmt0); #ifdef DEBUG_MODE log_level (2, fmt0, ap); #else vsyslog (LOG_ERROR, fmt0, ap); #endif va_end(ap); } #ifdef DEBUG_MODE void log_debug (char *fmt0, ...) { va_list ap; va_start(ap, fmt0); log_level (3, fmt0, ap); va_end(ap); } #endif #ifdef DEBUG_MODE void log_verbose (char *fmt0, ...) { va_list ap; va_start(ap, fmt0); log_level (4, fmt0, ap); va_end(ap); } #endif #ifdef DEBUG_MODE void log_annoying (char *fmt0, ...) { va_list ap; va_start (ap, fmt0); log_level (5, fmt0, ap); va_end(ap); } #endif int server_socket (struct in_addr addr, int port, int backlog) { struct sockaddr_in address; int i, s; s = socket (PF_INET, SOCK_STREAM, 0); if (s == -1) return -1; i = 1; if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, (void *)&i, sizeof i) == -1) { log_error ("server_socket: setsockopt SO_REUSEADDR: %s", strerror (errno)); } memset (&address, '\0', sizeof address); #if defined(__FreeBSD__) || defined(__OpenBSD__) address.sin_len = sizeof address; #endif address.sin_family = PF_INET; address.sin_port = htons ((short)port); address.sin_addr = addr; if (bind (s, (struct sockaddr *)&address, sizeof (address)) == -1) { close (s); return -1; } if (listen (s, (unsigned)backlog) == -1) { close (s); return -1; } return s; } int set_address (struct sockaddr_in *address, const char *host, int port) { memset (address, '\0', sizeof *address); #if defined(__FreeBSD__) || defined(__OpenBSD__) address->sin_len = sizeof *address; #endif address->sin_family = PF_INET; address->sin_port = htons ((u_short)port); address->sin_addr.s_addr = inet_addr (host); if (address->sin_addr.s_addr == INADDR_NONE) { struct hostent *ent; unsigned int ip; log_annoying ("set_address: gethostbyname (\"%s\")", host); ent = gethostbyname (host); log_annoying ("set_address: ent = %p", ent); if (ent == 0) return -1; memcpy(&address->sin_addr.s_addr, ent->h_addr, (unsigned)ent->h_length); ip = ntohl (address->sin_addr.s_addr); log_annoying ("set_address: host = %d.%d.%d.%d", ntohl (ip) >> 24, (ntohl (ip) >> 16) & 0xff, (ntohl (ip) >> 8) & 0xff, ntohl (ip) & 0xff); } return 0; } int open_device (char *device) { struct termios t; int fd; fd = open (device, O_RDWR | O_NONBLOCK); if (fd == -1) return -1; if (tcgetattr (fd, &t) == -1) { if (errno == ENOTTY || errno == EINVAL) return fd; else return -1; } t.c_iflag = 0; t.c_oflag = 0; t.c_lflag = 0; if (tcsetattr (fd, TCSANOW, &t) == -1) return -1; return fd; } #ifdef DEBUG_MODE void dump_buf (FILE *f, unsigned char *buf, size_t len) { const int N = 20; int i, j; for (i = 0; i < len;) { fputc ('[', f); for (j = 0; j < N && i + j < len; j++) fprintf (f, "%02x", buf[i + j]); for (; j < N; j++) fprintf (f, " "); fputc (']', f); fputc ('[', f); for (j = 0; j < N && i + j < len; j++) { int c = buf[i + j]; if (c < ' ' || c > 126) fputc ('.', f); else fputc (c, f); } fputc (']', f); fputc ('\n', f); i += j; } } #endif int handle_device_input (Tunnel *tunnel, int fd, int events) { unsigned char buf[10240]; ssize_t n, m; if (events & POLLIN) { n = read (fd, buf, sizeof buf); if (n == 0 || n == -1) { if (n == -1 && errno != EAGAIN) log_error ("handle_device_input: read() error: %s", strerror (errno)); return n; } #ifdef DEBUG_MODE log_annoying ("read %d bytes from device:", n); if (debug_level >= 5) dump_buf (debug_file, buf, (size_t)n); #endif m = tunnel_write (tunnel, buf, (size_t)n); log_annoying ("tunnel_write (%p, %p, %d) = %d", tunnel, buf, n, m); return m; } else if (events & POLLHUP) { log_error ("handle_device_input: POLLHUP"); sleep (5); } else if (events & POLLERR) log_error ("handle_device_input: POLLERR"); else if (events & POLLNVAL) log_error ("handle_device_input: POLLINVAL"); else log_error ("handle_device_input: none of the above"); errno = EIO; return -1; } int handle_tunnel_input (Tunnel *tunnel, int fd, int events) { unsigned char buf[10240]; ssize_t n, m; if (events & POLLIN) { n = tunnel_read (tunnel, buf, sizeof buf); if (n <= 0) { log_annoying ("handle_tunnel_input: tunnel_read() = %d\n", n); if (n == -1 && errno != EAGAIN) log_error ("handle_tunnel_input: tunnel_read() error: %s", strerror (errno)); return n; } #ifdef DEBUG_MODE log_annoying ("read %d bytes from tunnel:", n); if (debug_level >= 5) dump_buf (debug_file, buf, (size_t)n); #endif /* If fd == 0, then we are using --stdin-stdout so write to stdout, * not fd. */ m = write_all (fd ? fd : 0, buf, (size_t)n); log_annoying ("write_all (%d, %p, %d) = %d", fd ? fd : 1, buf, n, m); return m; } else if (events & POLLHUP) log_error ("handle_device_input: POLLHUP"); else if (events & POLLERR) log_error ("handle_device_input: PULLERR"); else if (events & POLLNVAL) log_error ("handle_device_input: PULLINVAL"); else log_error ("handle_device_input: none of the above"); errno = EIO; return -1; } void name_and_port (const char *nameport, char **name, int *port) { char *p; *name = strdup (nameport); if (*name == NULL) { fprintf (stderr, "Out of memory\n"); exit (1); } p = strchr (*name, ':'); if (p != NULL) { *port = atoi (p + 1); *p = '\0'; } } int atoi_with_postfix (const char *s_) { char *s = strdup (s_); int n = strlen (s); int factor = 1; int x; if (s == NULL) { fprintf (stderr, "Out of memory\n"); exit (1); } switch (s[n - 1]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': break; case 'k': case 'K': factor = 1024; break; case 'M': factor = 1024 * 1024; break; case 'G': factor = 1024 * 1024 * 1024; break; default: fprintf (stderr, "Unknown postfix: %c\n", s[n - 1]); exit (1); } if (factor != 1) s[n - 1] = '\0'; x = factor * atoi (s); free (s); return x; } #ifdef DEBUG_MODE RETSIGTYPE log_sigpipe (int sig) { log_debug ("caught SIGPIPE"); signal (SIGPIPE, log_sigpipe); } #endif