#c #ipv6 #libssh2
Вопрос:
Я работаю над проектом на C , которому необходимо установить соединение по SSH с удаленным сервером, выполнить некоторые команды и передать файлы через SFTP. Однако мне нужно, чтобы это приложение работало в режиме двойного стека (например, с IPv6 и IPv4).
В приведенном ниже фрагменте моя программа изначально получает имя хоста, адрес IPv6 или IPv4. На входе IPv4 соединение выполнено успешно. Однако у меня возникают странные проблемы в режиме IPv6, когда я замечаю, что соединение установлено через сокет, и сеанс SSH не запускается.
В настоящее время я считаю, что это может быть что-то связанное с методом inet_ntop (). Пожалуйста, обратите внимание, что переменная remoteHost имеет тип char*, а удаленный порт-тип uint16_t.
// Initialize some important variables uint32_t hostaddr = 0, hostaddr6 = 0; struct sockaddr_in sin = {}; struct sockaddr_in6 sinV6 = {}; int rc = 0, sock = 0, i = 0, auth_pw = 0; // Here we will initialize our base class with username and password this-gt;username = usrName; this-gt;password = usrPassword; // Firstly, we need to translate the hostname into an IPv4 or IPv6 address struct addrinfo hints={}, *sAdrInfo = {}; char addrstr[100]={}; void *ptr= nullptr; char addrParsed[50]={}; memset (amp;hints, 0, sizeof (hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags |= AI_CANONNAME; // Now we need to get some address info from the one supplied that remoteHost parameter int errcode = getaddrinfo (remoteHost, nullptr, amp;hints, amp;sAdrInfo); if (errcode != 0) { SERVER_ERROR("[SSH] Error while getaddrinfo at SSHConnect() code %d", errno); return -4; } inet_ntop(sAdrInfo-gt;ai_family, sAdrInfo-gt;ai_addr-gt;sa_data, addrstr, 100); // Here we need to determine if we are using IPv6 or IPv4 switch (sAdrInfo-gt;ai_family) { case AF_INET6: ptr = amp;((struct sockaddr_in6 *) sAdrInfo-gt;ai_addr)-gt;sin6_addr; break; case AF_INET: ptr = amp;((struct sockaddr_in *) sAdrInfo-gt;ai_addr)-gt;sin_addr; break; } inet_ntop(sAdrInfo-gt;ai_family, ptr, addrstr, 100); sprintf(addrParsed, "%s", addrstr); //This part is responsible for creating the socket and establishing the connection // Now if we have an IPv4 based host if (sAdrInfo-gt;ai_family == AF_INET) { this-gt;hostaddr = inet_addr(addrParsed); sock = socket(AF_INET, SOCK_STREAM, 0); sin.sin_family = AF_INET; // Now we need to set these (address and port to our sockaddr_in variable sin) sin.sin_port = htons(remotePort); memcpy(amp;sin.sin_addr, amp;hostaddr, sizeof(hostaddr)); } // Now if we have an IPv6 based host else if (sAdrInfo-gt;ai_family == AF_INET6) { this-gt;hostaddr6 = inet_addr(addrParsed); sock = socket(AF_INET6, SOCK_STREAM, 0); sin.sin_family = AF_INET6; // Now we need to set these (address and port to our sockaddr_in variable sin) sinV6.sin6_port = htons(remotePort); memcpy(amp;sinV6.sin6_addr.s6_addr32, amp;hostaddr6, sizeof(this-gt;hostaddr6)); } // Now we need to connect to our socket :D if (sAdrInfo-gt;ai_family == AF_INET) { int resCon = connect(sock, (struct sockaddr*)(amp;sin), sizeof(struct sockaddr_in)); if (resCon != 0){ SERVER_ERROR("[SSH] failed to connect with error code: %d!n", errno); return -1; } } else if (sAdrInfo-gt;ai_family == AF_INET6) { int resCon = connect(sock, (struct sockaddr*)(amp;sinV6), sizeof(struct sockaddr_in6)); if (resCon != 0){ SERVER_ERROR("[SSH] failed to connect with error code: %d!n", errno); return -1; } } // Free our result variables freeaddrinfo(sAdrInfo); // Create a session instance session = libssh2_session_init(); if(!session) { return -2; } /* Now to start the session. Here will trade welcome banners, exchange keys and setup crypto, compression, * and MAC layers */ rc = libssh2_session_handshake(session, sock); if(rc) { SERVER_ERROR("Failure establishing SSH session: %dn", rc); return -3; }
Что не так с реализацией, которая генерирует сообщение «Сбой при установлении сеанса SSH» со стеком IPv6?
С уважением,
Комментарии:
1. Что такое
inet_ntop()
возвращение? Согласно справочной странице, он возвращаетсяNULL
, если возникает системная ошибка, и устанавливаетerrno
значение, указывающее, в чем заключалась ошибка. Похоже, это было бы полезной информацией для вас.2. Он возвращает большое количество. Я повторно реализовал с помощью inet_pton и внес много изменений. Кажется, это решено. Я скоро опубликую здесь решение.