#ifdef HAVE_CONFIG_H # include "config.h" #endif #include "xwrap.h" #include "socktool.h" #include <arpa/inet.h> #include <errno.h> #include <inttypes.h> #include <locale.h> #include <netdb.h> #include <netinet/in.h> #include <stdbool.h> #include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/un.h> #include <time.h> #include <unistd.h> static int client_rw_cb (int fd[2], RasBuffer buf[2]) { return true; } int main (int argc, char* argv[]) { setlocale (LC_ALL, ""); tzset (); const char* logincmd = isatty (STDIN_FILENO) ? "LOGINTTY\n" : "LOGIN\n"; const char* conn[2] = { NULL, NULL }; bool allowv4 = true; bool allowv6 = true; int conncnt = 0; for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { for (int j = 1; argv[i][j] != '\0'; j++) { switch (argv[i][j]) { case 't': logincmd = "LOGINTTY\n"; break; case 'T': logincmd = "LOGIN\n"; break; case 'I': allowv4 = true; allowv6 = true; break; case 'U': allowv4 = false; allowv6 = false; break; case '4': allowv4 = true; allowv6 = false; break; case '6': allowv4 = false; allowv6 = true; break; case 'h': case '?': case '-': printf ( "Usage: %s [-46hItTU] host|file [port]\n" " -h View this help message\n" " -t Force pseudo terminal allocation\n" " -T Disable pseudo terminal allocation\n" " -U Connect to a UNIX-domain socket file\n" " -I Connect to the Internet\n" " -4 Try IPv4 only\n" " -6 Try IPv6 only\n", argv[0]); return 0; break; default: fprintf (stderr, "%s: -%c: unknown option\n", argv[0], argv[i][j]); return 1; } } } else { if (conncnt >= 2) { fprintf (stderr, "%s: %s: unknown argument\n", argv[0], argv[i]); return 1; } conn[conncnt++] = argv[i]; } } if (allowv4 || allowv6) { if (conn[0] == NULL) { fprintf (stderr, "%s: host name is required\n", argv[0]); return 1; } if (conn[1] == NULL) { fprintf (stderr, "%s: port number is requried\n", argv[0]); return 1; } } else { if (conn[0] == NULL) { fprintf (stderr, "%s: socket file name is required\n", argv[0]); return 1; } } int sockfd = -1; if (allowv4 || allowv6) { printf ("Getting information for host %s (service %s) ... ", conn[0], conn[1]); fflush (stdout); struct addrinfo* iaddr; struct addrinfo* result; struct addrinfo hints; memset (&hints, 0, sizeof (hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; int gaierr = getaddrinfo (conn[0], conn[1], &hints, &result); if (gaierr != 0) { puts (gai_strerror (gaierr)); return 2; } else { puts ("OK"); } bool connected = false; for (iaddr = result; iaddr != NULL; iaddr = iaddr->ai_next) { sockfd = socket (iaddr->ai_family, SOCK_STREAM, 0); if (sockfd < 0) { perror ("socket"); continue; } const size_t ipstrlen = xmax (INET_ADDRSTRLEN, INET6_ADDRSTRLEN); char* ipstr = xmalloc (ipstrlen); uint16_t ipport = ntohs ( iaddr->ai_family == AF_INET ? SOCKADDR_IN (iaddr->ai_addr)->sin_port : SOCKADDR_IN6 (iaddr->ai_addr)->sin6_port); fputs ("Connecting to host ", stdout); if (inet_ntop ( iaddr->ai_family, iaddr->ai_family == AF_INET ? (void*) &SOCKADDR_IN (iaddr->ai_addr)->sin_addr : (void*) &SOCKADDR_IN6 (iaddr->ai_addr)->sin6_addr, ipstr, ipstrlen) == NULL) { printf ("unknown, port %" PRIu16 " ... ", ipport); } else { printf ("%s, port %" PRIu16 " ... ", ipstr, ipport); free (ipstr); } fflush (stdout); if (connect (sockfd, iaddr->ai_addr, iaddr->ai_addrlen) < 0) { puts (strerror (errno)); } else { puts ("OK"); connected = true; break; } } if (result != NULL) { freeaddrinfo (result); } if (!connected) { return 3; } } else { struct sockaddr_un uaddr; socklen_t uaddrlen; sockfd = socket (AF_UNIX, SOCK_STREAM, 0); if (sockfd < 0) { perror ("socket"); return 3; } printf ("Try to connect to UNIX-domain socket %s ... ", conn[0]); fflush (stdout); uaddrlen = sizeof (struct sockaddr_un); SOCKADDR_UN (&uaddr)->sun_family = AF_UNIX; strncpy (SOCKADDR_UN (&uaddr)->sun_path, conn[0], uaddrlen - offsetof (struct sockaddr_un, sun_path) - 1); if (connect (sockfd, SOCKADDR (&uaddr), uaddrlen) < 0) { puts (strerror (errno)); return 3; } else { puts ("OK"); } } if (sockfd < 0) { return 3; } ras_socktool_write_string (sockfd, logincmd, 0); int fd[2] = { STDIN_FILENO, sockfd }; ras_socktool_exchange_data (fd, client_rw_cb); shutdown (sockfd, SHUT_RDWR); close (sockfd); return 0; }