static gint sock_connect_by_hostname(gint sock, const gchar *hostname, gushort port) { struct hostent *hp; struct sockaddr_in ad; resolver_init(); memset(&ad, 0, sizeof(ad)); ad.sin_family = AF_INET; ad.sin_port = htons(port); if (!my_inet_aton(hostname, &ad.sin_addr)) { if ((hp = my_gethostbyname(hostname)) == NULL) { fprintf(stderr, "%s: unknown host.\n", hostname); errno = 0; return -1; } if (hp->h_length != 4 && hp->h_length != 8) { fprintf(stderr, "illegal address length received for host %s\n", hostname); errno = 0; return -1; } memcpy(&ad.sin_addr, hp->h_addr, hp->h_length); } return sock_connect_with_timeout(sock, (struct sockaddr *)&ad, sizeof(ad), io_timeout); }
gint socks4_connect(SockInfo *sock, const gchar *hostname, gushort port) { guchar socks_req[1024]; struct hostent *hp; g_return_val_if_fail(sock != NULL, -1); g_return_val_if_fail(hostname != NULL, -1); debug_print("socks4_connect: connect to %s:%u\n", hostname, port); socks_req[0] = 4; socks_req[1] = 1; *((gushort *)(socks_req + 2)) = htons(port); /* lookup */ if ((hp = my_gethostbyname(hostname)) == NULL) { g_warning("socks4_connect: cannot lookup host: %s", hostname); return -1; } if (hp->h_length != 4) { g_warning("socks4_connect: invalid address length for host: %s", hostname); return -1; } memcpy(socks_req + 4, (guchar *)hp->h_addr, 4); /* userid (empty) */ socks_req[8] = 0; if (sock_write_all(sock, (gchar *)socks_req, 9) != 9) { g_warning("socks4_connect: SOCKS4 initial request write failed"); return -1; } if (sock_read(sock, (gchar *)socks_req, 8) != 8) { g_warning("socks4_connect: SOCKS4 response read failed"); return -1; } if (socks_req[0] != 0) { g_warning("socks4_connect: SOCKS4 response has invalid version"); return -1; } if (socks_req[1] != 90) { g_warning("socks4_connect: SOCKS4 connection to %u.%u.%u.%u:%u failed. (%u)", socks_req[4], socks_req[5], socks_req[6], socks_req[7], ntohs(*(gushort *)(socks_req + 2)), socks_req[1]); return -1; } debug_print("socks4_connect: SOCKS4 connection to %s:%u successful.\n", hostname, port); return 0; }
/* use sens functions for these, if found. */ struct hostent *ei_gethostbyname(const char *name) { struct hostent *h = NULL; if (!sens_gethostbyname) { h = my_gethostbyname(name); } else { /* FIXME problem for threaded ? */ static char buf[1024]; h = sens_gethostbyname(name,buf,1024); } return h; }
/* * Read bytes from the server */ bool VNCSockets::ReadFromRFBServer(char *out, uint32_t n) { if (n <= buffered) { memcpy(out, bufoutptr, n); bufoutptr += n; buffered -= n; return true; } memcpy(out, bufoutptr, buffered); out += buffered; n -= buffered; bufoutptr = buf; buffered = 0; if (n <= sizeof(buf)) { while (buffered < n) { #ifdef _WIN32 int i = recv(rfbsock, (char *)buf + buffered, sizeof(buf) - buffered, 0); #else int i = read(rfbsock, buf + buffered, sizeof(buf) - buffered); #endif if (i <= 0) { if (i < 0) { #ifdef _WIN32 if (errno == EAGAIN || (errno == EINTR)) { #else if (errno == EWOULDBLOCK || errno == EAGAIN || (errno == EINTR)) { #endif i = 0; } else { fprintf(stderr, "VNCSockets::ReadFromRFBServer(): read\n"); return false; } } else { fprintf(stderr, "VNCSockets::ReadFromRFBServer(): VNC server closed connection\n"); return false; } } buffered += i; } memcpy(out, bufoutptr, n); bufoutptr += n; buffered -= n; return true; } else { while (n > 0) { #ifdef _WIN32 int i = recv(rfbsock, out, n, 0); #else int i = read(rfbsock, out, n); #endif if (i <= 0) { if (i < 0) { #ifdef _WIN32 if (errno == EAGAIN || (errno == EINTR)) { #else if (errno == EWOULDBLOCK || errno == EAGAIN || (errno == EINTR)) { #endif i = 0; } else { fprintf(stderr, "VNCSockets::ReadFromRFBServer(): read\n"); return false; } } else { fprintf(stderr, "VNCSockets::ReadFromRFBServer(): VNC server closed connection\n"); return false; } } out += i; n -= i; } return true; } } /* * Write an exact number of bytes, and don't return until you've sent them. */ bool VNCSockets::WriteExact(char *buf, int n) { for (int i = 0; i < n;) { #ifdef _WIN32 int j = send(rfbsock, buf + i, (n - i), 0); #else int j = write(rfbsock, buf + i, (n - i)); #endif if (j <= 0) { if (j < 0) { #ifdef _WIN32 if (errno == EAGAIN || (errno == EINTR)) { #else if (errno == EWOULDBLOCK || errno == EAGAIN || (errno == EINTR)) { #endif fd_set fds; FD_ZERO(&fds); FD_SET(rfbsock, &fds); if (select(rfbsock + 1, NULL, &fds, NULL, NULL) <= 0) { fprintf(stderr, "VNCSockets::WriteExact(): select\n"); return false; } j = 0; } else { fprintf(stderr, "VNCSockets::WriteExact(): write\n"); return false; } } else { fprintf(stderr, "VNCSockets::WriteExact() err: write failed\n"); return false; } } i += j; } return true; } /* * ConnectToTcpAddr connects to the given TCP port. */ int VNCSockets::ConnectToTcpAddr() { if ((rfbsock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { fprintf(stderr, "VNCSockets::ConnectToTcpAddr() err: socket\n"); return -1; } struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_port = htons(port); sa.sin_addr.s_addr = htonl(ipaddr); fprintf(stderr, "VNCSockets::ConnectToTcpAddr(): connecting to %s:%i %x\n", ServerName, ntohs(sa.sin_port), ntohl(sa.sin_addr.s_addr)); if (connect(rfbsock, (const struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("VNC: connect"); fprintf(stderr, "VNCSockets::ConnectToTcpAddr() err: %s (%d) sock=%d\n", strerror(errno), errno, rfbsock); closesocket(rfbsock); return -1; } if (setTcpNoDelay(rfbsock) < 0) { fprintf(stderr, "VNCSockets::ConnectToTcpAddr() err: TCP_NODELAY %s (%d)\n", strerror(errno), errno); //pd close(rfbsock); //pd return -1; } return rfbsock; } /* * SetNonBlocking sets a socket into non-blocking mode. */ bool VNCSockets::SetNonBlocking() { if (setNoBlocking(rfbsock) < 0) return false; return true; } /* * StringToIPAddr - convert a host string to an IP address. */ bool VNCSockets::StringToIPAddr() { struct hostent *hp; if ((hp = my_gethostbyname(ServerName, AF_INET)) != NULL) { memcpy(&ipaddr, hp->h_addr, hp->h_length); ipaddr = ntohl(ipaddr); fprintf(stderr, "VNCSockets::StringToIPAddr(): ServerName=%s (%x)\n", ServerName, ipaddr); return true; } return false; } /* * Test if the other end of a socket is on the same machine. */ bool VNCSockets::SameMachine() { struct sockaddr_in peersa, mysa; #ifdef WIN32 int slen = sizeof(struct sockaddr_in); #else socklen_t slen = sizeof(struct sockaddr_in); #endif getpeername(rfbsock, (struct sockaddr *)&peersa, &slen); getsockname(rfbsock, (struct sockaddr *)&mysa, &slen); return (peersa.sin_addr.s_addr == mysa.sin_addr.s_addr); } #if 0 //unused /* * Print out the contents of a packet for debugging. */ void VNCSockets::PrintInHex(char *buf, int len) { int i; char c, str[17]; str[16] = 0; trace(DBG_VNC, "ReadExact: "); for (i = 0; i < len; i++) { if ((i % 16 == 0) && (i != 0)) fprintf(stderr, " "); c = buf[i]; str[i % 16] = (((c > 31) && (c < 127)) ? c : '.'); fprintf(stderr,"%02x ", (uint8_t) c); if ((i % 4) == 3) fprintf(stderr, " "); if ((i % 16) == 15) fprintf(stderr,"%s\n", str); } if ((i % 16) != 0) { for (int j = i % 16; j < 16; j++) { fprintf(stderr, " "); if ((j % 4) == 3) fprintf(stderr, " "); } str[i % 16] = 0; fprintf(stderr,"%s\n", str); } fflush(stderr); } #endif //unused /* * Returns the socket used */ int VNCSockets::GetSock() { return rfbsock; }
static SockLookupData *sock_get_address_info_async(const gchar *hostname, gushort port, SockAddrFunc func, gpointer data) { SockLookupData *lookup_data = NULL; gint pipe_fds[2]; pid_t pid; resolver_init(); if (pipe(pipe_fds) < 0) { perror("pipe"); func(NULL, data); return NULL; } if ((pid = fork()) < 0) { perror("fork"); func(NULL, data); return NULL; } /* child process */ if (pid == 0) { #ifdef INET6 gint gai_err; struct addrinfo hints, *res, *ai; gchar port_str[6]; #else /* !INET6 */ struct hostent *hp; gchar **addr_list_p; struct sockaddr_in ad; #endif /* INET6 */ gint ai_member[4] = {AF_UNSPEC, 0, 0, 0}; close(pipe_fds[0]); #ifdef INET6 memset(&hints, 0, sizeof(hints)); /* hints.ai_flags = AI_CANONNAME; */ hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; g_snprintf(port_str, sizeof(port_str), "%d", port); gai_err = getaddrinfo(hostname, port_str, &hints, &res); if (gai_err != 0) { g_warning("getaddrinfo for %s:%s failed: %s\n", hostname, port_str, gai_strerror(gai_err)); fd_write_all(pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); close(pipe_fds[1]); _exit(1); } for (ai = res; ai != NULL; ai = ai->ai_next) { ai_member[0] = ai->ai_family; ai_member[1] = ai->ai_socktype; ai_member[2] = ai->ai_protocol; ai_member[3] = ai->ai_addrlen; fd_write_all(pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); fd_write_all(pipe_fds[1], (gchar *)ai->ai_addr, ai->ai_addrlen); } if (res != NULL) freeaddrinfo(res); #else /* !INET6 */ hp = my_gethostbyname(hostname); if (hp == NULL || hp->h_addrtype != AF_INET) { fd_write_all(pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); close(pipe_fds[1]); _exit(1); } ai_member[0] = AF_INET; ai_member[1] = SOCK_STREAM; ai_member[2] = IPPROTO_TCP; ai_member[3] = sizeof(ad); memset(&ad, 0, sizeof(ad)); ad.sin_family = AF_INET; ad.sin_port = htons(port); for (addr_list_p = hp->h_addr_list; *addr_list_p != NULL; addr_list_p++) { memcpy(&ad.sin_addr, *addr_list_p, hp->h_length); fd_write_all(pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); fd_write_all(pipe_fds[1], (gchar *)&ad, sizeof(ad)); } #endif /* INET6 */ close(pipe_fds[1]); _exit(0); } else { close(pipe_fds[1]); lookup_data = g_new0(SockLookupData, 1); lookup_data->hostname = g_strdup(hostname); lookup_data->child_pid = pid; lookup_data->func = func; lookup_data->data = data; lookup_data->channel = g_io_channel_unix_new(pipe_fds[0]); lookup_data->io_tag = g_io_add_watch (lookup_data->channel, G_IO_IN, sock_get_address_info_async_cb, lookup_data); } return lookup_data; }
/* subset of getaddrinfo() */ static int my_getaddrinfo(const char *node, const char *service, const struct addrinfo *hintp, struct addrinfo **res) { struct addrinfo *ai; struct sockaddr_in addr, *paddr; struct addrinfo hints; gint port = 0; if (win32_ipv6_supported()) return getaddrinfo_func(node, service, hintp, res); if (!hintp) { memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; } else memcpy(&hints, hintp, sizeof(hints)); if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET) return EAI_FAMILY; if (hints.ai_socktype == 0) hints.ai_socktype = SOCK_STREAM; if (hints.ai_protocol == 0) hints.ai_protocol = IPPROTO_TCP; if (hints.ai_socktype != SOCK_STREAM) return EAI_SOCKTYPE; if (hints.ai_protocol != IPPROTO_TCP) return EAI_SOCKTYPE; #if 0 if (!node && !service) return EAI_NONAME; #endif if (!node || !service) return EAI_NONAME; port = atoi(service); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); if (!my_inet_aton(node, &addr.sin_addr)) { struct hostent *hp; if ((hp = my_gethostbyname(node)) == NULL) { fprintf(stderr, "%s: unknown host.\n", node); errno = 0; return EAI_NONAME; } if (hp->h_length != 4 && hp->h_length != 8) { fprintf(stderr, "illegal address length received for host %s\n", node); errno = 0; return EAI_FAIL; } memcpy(&addr.sin_addr, hp->h_addr, hp->h_length); } ai = g_malloc0(sizeof(struct addrinfo)); paddr = g_malloc(sizeof(struct sockaddr_in)); memcpy(paddr, &addr, sizeof(struct sockaddr_in)); ai->ai_flags = 0; ai->ai_family = AF_INET; ai->ai_socktype = hints.ai_socktype; ai->ai_protocol = hints.ai_protocol; ai->ai_addrlen = sizeof(struct sockaddr_in); ai->ai_addr = (struct sockaddr *)paddr; ai->ai_canonname = NULL; ai->ai_next = NULL; *res = ai; return 0; }
/* For better readability we use a separate function to implement the child code of sock_get_address_info_async. Note, that under W32 this is actually not a child but a thread and this is the reason why we pass only a void pointer. */ static void address_info_async_child(void *opaque) { SockLookupData *parm = opaque; #ifdef INET6 gint gai_err; struct addrinfo hints, *res, *ai; gchar port_str[6]; #else /* !INET6 */ struct hostent *hp; gchar **addr_list_p; struct sockaddr_in ad; #endif /* INET6 */ gint ai_member[4] = {AF_UNSPEC, 0, 0, 0}; #ifndef G_OS_WIN32 close(parm->pipe_fds[0]); parm->pipe_fds[0] = -1; #endif #ifdef INET6 memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; g_snprintf(port_str, sizeof(port_str), "%d", parm->port); gai_err = getaddrinfo(parm->hostname, port_str, &hints, &res); if (gai_err != 0) { gchar len = 0; g_warning("getaddrinfo for %s:%s failed: %s\n", parm->hostname, port_str, gai_strerror(gai_err)); log_error(LOG_PROTOCOL, _("%s:%s: host lookup failed (%s).\n"), parm->hostname, port_str, gai_strerror(gai_err)); fd_write_all(parm->pipe_fds[1], &len, sizeof(len)); fd_write_all(parm->pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); close(parm->pipe_fds[1]); parm->pipe_fds[1] = -1; #ifdef G_OS_WIN32 _endthread(); #else _exit(1); #endif } if (res != NULL) { if (res->ai_canonname && strlen(res->ai_canonname) < 255) { gchar len = strlen(res->ai_canonname); fd_write_all(parm->pipe_fds[1], &len, sizeof(len)); fd_write_all(parm->pipe_fds[1], res->ai_canonname, len); } else { gchar len = 0; fd_write_all(parm->pipe_fds[1], &len, sizeof(len)); } } else { gchar len = 0; fd_write_all(parm->pipe_fds[1], &len, sizeof(len)); } for (ai = res; ai != NULL; ai = ai->ai_next) { ai_member[0] = ai->ai_family; ai_member[1] = ai->ai_socktype; ai_member[2] = ai->ai_protocol; ai_member[3] = ai->ai_addrlen; fd_write_all(parm->pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); fd_write_all(parm->pipe_fds[1], (gchar *)ai->ai_addr, ai->ai_addrlen); } if (res != NULL) freeaddrinfo(res); #else /* !INET6 */ hp = my_gethostbyname(parm->hostname); if (hp == NULL || hp->h_addrtype != AF_INET) { gchar len = 0; fd_write_all(parm->pipe_fds[1], &len, sizeof(len)); fd_write_all(parm->pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); close(parm->pipe_fds[1]); parm->pipe_fds[1] = -1; #ifdef G_OS_WIN32 _endthread(); #else _exit(1); #endif } ai_member[0] = AF_INET; ai_member[1] = SOCK_STREAM; ai_member[2] = IPPROTO_TCP; ai_member[3] = sizeof(ad); memset(&ad, 0, sizeof(ad)); ad.sin_family = AF_INET; ad.sin_port = htons(parm->port); if (hp->h_name && strlen(hp->h_name) < 255) { gchar len = strlen(hp->h_name); fd_write_all(parm->pipe_fds[1], &len, sizeof(len)); fd_write_all(parm->pipe_fds[1], hp->h_name, len); } else { gchar len = 0; fd_write_all(parm->pipe_fds[1], &len, sizeof(len)); } for (addr_list_p = hp->h_addr_list; *addr_list_p != NULL; addr_list_p++) { memcpy(&ad.sin_addr, *addr_list_p, hp->h_length); fd_write_all(parm->pipe_fds[1], (gchar *)ai_member, sizeof(ai_member)); fd_write_all(parm->pipe_fds[1], (gchar *)&ad, sizeof(ad)); } #endif /* INET6 */ close(parm->pipe_fds[1]); parm->pipe_fds[1] = -1; #ifdef G_OS_WIN32 _endthread(); #else _exit(0); #endif }