problem of using ssh_connect API in windows - libssh

I have tested a simple code using libssh on OS X and it worked simply find.
But when I port this code on Windows7 using vc10 it doesn't work correctly.
The ssh_connect API blocks and not progress any more.
The following code is part of the my test program.
#include <libssh/libssh.h>
...
int _tmain(..)
{
ssh_session session;
session = ssh_new();
if (session == NULL)
exit(EXIT_FAILURE);
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
int port = 1234;
ssh_options_set(session, SSH_OPTIONS_PORT, &port); // <-block here !!!
int rc = ssh_connect(session);
if (rc != SSH_OK)
{
...
}
}
I downloaded include, lib and dll files from www.libssh.org no compile and link errors.
What's wrong with my code or do I miss something important?

Maybe it blocks cause the port is wrong? The timeout is 30 min by default iirc. libssh 0.6 will have better timeout handling.

Related

How to link .so file to a cpp program

I have libssh2.so.1.0.1(.so) binary on my local machine and I don't have any header files present on my machine.
This is the basic ssh program I have been trying to connect to my server through ssh protocol.
Reference: How to establish a simple ssh connection with c++
Now I am unable to link library (libssh2.so.1.0.1) to the below sample program.
Following is the sample program I have written and followed by errors.
sshsample.cpp:
#include <stdlib.h>
#include <stdio.h>
int main()
{
ssh_session my_ssh_session;
int rc;
int port = 22;
int verbosity = SSH_LOG_PROTOCOL;
char *password;
// Open session and set options
my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
exit(-1);
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "192.168.1.6");
ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, "john");
ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
// Connect to server
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
{
fprintf(stderr, "Error: %s\n", ssh_get_error(my_ssh_session));
ssh_free(my_ssh_session);
exit(-1);
}
// Authenticate ourselves
password = "pass";
rc = ssh_userauth_password(my_ssh_session, NULL, password);
if (rc != SSH_AUTH_SUCCESS)
{
fprintf(stderr, "Error authenticating with password: %s\n",
ssh_get_error(my_ssh_session));
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
exit(-1);
}
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
}
I have compiled the above file with below command
g++ -L. -llibssh2 -o main sshsample.cpp
but I get the following error
sshsample.cpp: In function 'int main()':
sshsample.cpp:8: error: 'ssh_session' was not declared in this scope
sshsample.cpp:8: error: expected `;' before 'my_ssh_session'
sshsample.cpp:11: error: 'SSH_LOG_PROTOCOL' was not declared in this scope
sshsample.cpp:14: error: 'my_ssh_session' was not declared in this scope
sshsample.cpp:14: error: 'ssh_new' was not declared in this scope
Any suggestions/help would be of great use
Thanks in advance ...
You need to include the libssh2 header file into your compilation units where ssh APIs are invoked. You cannot expect the compiler to resolve what an ssh_session is without this. If you have the library properly installed, you should have access to the header files to invoke it.
#include <libssh2.h>
Edit: Honestly the APIs you are using in your example belong to the original libssh library I don't see anything in your example that would need to link with libssh2.
#include <libssh/libssh.h>

Bluetooth socket returns WSAEPROTONOSUPPORT

For a project I am working on I would like to have an Embedded System to act as a Bluetooth server. I got the driver for my USb-Bluetooth working and in the Control Panel I now have a "Bluetooth Device Properties"-option which works and detects other devices via the Bluetooth USB dongle.
However when I try to use the dongle in code, I get an error.
The Includes are:
winsock2.h, ws2bth.h, bt_sdp.h, bthapi.h, bt_api.h, winioctl.h, windows.h
This is the code:
int Main(int argc, char **argv)
{
WSADATA wsd;
if (WSAStartup(MAKEWORD(2, 2), &wsd)){
wprintf(L"Initialization of socket subsystem failed! Error = %d\n", WSAGetLastError());
return 0;
}
SOCKET server = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
if(server == INVALID_SOCKET){
printf("socket failed, error %d\n", WSAGetLastError());
return 0;
}
return 0;
}
This compiles, but when running it fails at the socket creation. GetLastError returns 10043, which means WSAEPROTONOSUPPORT. A quick search gives me this list with error codes: https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx
I have no idea what I'm doing wrong. The code runs on a normal laptop with bluetooth, so I suspect it has something to do with the driver or so.
Any help is appreciated!
Kind Regards

How to establish a simple ssh connection with c++

I am trying to make a c++ program which will connect to an ssh server (my laptop). The server is ok because I can get connected via putty. Although the program I wrote so far can not. In my code I am using the library libssh.h and for development I used visual studio 2015. The error I get is: crypt_set_algorithms2: no crypto algorithm function found for 3des-cbc
I haven't found anything so far so I hope to your help.
The code I use:
#include <libssh/libssh.h>
#include <stdlib.h>
#include <stdio.h>
int main()
{
ssh_session my_ssh_session;
int rc;
int port = 22;
int verbosity = SSH_LOG_PROTOCOL;
char *password;
// Open session and set options
my_ssh_session = ssh_new();
if (my_ssh_session == NULL)
exit(-1);
ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, "192.168.1.6");
ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, "john");
ssh_options_set(my_ssh_session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
ssh_options_set(my_ssh_session, SSH_OPTIONS_CIPHERS_C_S,"aes128-ctr");
//ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT, &port);
// Connect to server
rc = ssh_connect(my_ssh_session);
if (rc != SSH_OK)
{
fprintf(stderr, "Error: %s\n", ssh_get_error(my_ssh_session)); //HERE IS WHERE I GET THE ERROR
ssh_free(my_ssh_session);
exit(-1);
}
// Verify the server's identity
// For the source code of verify_knowhost(), check previous example
/* if (verify_knownhost(my_ssh_session) < 0)
{
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
exit(-1);
}
*/
// Authenticate ourselves
password = "pass";
rc = ssh_userauth_password(my_ssh_session, NULL, password);
if (rc != SSH_AUTH_SUCCESS)
{
fprintf(stderr, "Error authenticating with password: %s\n",
ssh_get_error(my_ssh_session));
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
exit(-1);
}
ssh_disconnect(my_ssh_session);
ssh_free(my_ssh_session);
}
Try to use different cipher. 3des-cbc is broken and probably disabled on your server already.
There is really nice tutorial with simple session.
Removing the line makes it working for me on Ubuntu (don't know where you found it):
ssh_options_set(my_ssh_session, SSH_OPTIONS_CIPHERS_C_S,"aes128-ctr");
If not, what version of libssh are you using? Isn't it some obsolete one?
Finally got it! I removed the line
ssh_options_set(my_ssh_session, SSH_OPTIONS_CIPHERS_C_S,"aes128-ctr");
Then I used the ssh.dll from libssh v0-7.2 instead of the ssh.dll of v0-7.1 I used before. The ssh.dll is located in libssh-0.7.2\bin. If you take an error like the msvcr120d.dll is missing try to change from debug to release in visual studio.

Obtaining ssl certificate on windows using C++

I am trying to obtain a remote server's ssl certificate on windows. One option I have found is to use openssl. The command to do that as indicated by some posts on the internet is:
openssl.exe s_client -showcerts -connect {REMOTE_SERVER_IP}:{REMOTE_SERVER_PORT}
This works perfectly, but my problem is that the above command has a timeout of 300 seconds. The certificate itself gets printed pretty fast and I see no reason to wait 300 seconds when I get all I want in the first few seconds. Still I think there is no way to change the timeout parameter on s_client. So I tried to figure a way to kill a process on windows after a given period of time but again had no luck there. Any ideas on how can this be done? If there is some other windows way to a obtain a remote servers ssl certificate and store it in a file this will also do the job.
EDIT: as per Bruno's request adding more information.
I am trying to create a c++ application that gets the SSL certificate of a remote server and stores it in a file for further processing. As my application already makes use of openssl.exe I either need a solution that uses openssl.exe or a standard windows command(i.e. does not require any additional libraries).
EDIT2: I have found a way to avoid the waiting in linux - just create an empty file and redirect the input of openssl s_client to it(or use pipe to pass empty input). This works on windows as well but with older versions of openssl(0.9.8l). I tried it with 0.9.8r and with 1.0.1b and redirecting the input to an empty file does not help there.
Here is a minimalistic program I created that connects to a server and prints its ssl certificate to the standard output. Hope it will help someone else to resolve similar issue:
#ifdef WIN32
#include <windows.h>
#include <winsock2.h>
#else
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif
#include <openssl/ssl.h>
#include <cstdlib>
#include <iostream>
static const char *host= "10.23.10.12";
static int port=443;
int tcp_connect(const char *host,int port)
{
#ifdef WIN32
WSADATA wsaData;
WORD version;
int error;
version = MAKEWORD( 2, 0 );
error = WSAStartup( version, &wsaData );
/* check for error */
if ( error != 0 )
{
/* error occured */
return -1;
}
/* check for correct version */
if ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 0 )
{
/* incorrect WinSock version */
WSACleanup();
return -1;
}
/* WinSock has been initialized */
#endif
struct hostent *hp;
struct sockaddr_in addr;
int sock;
if(!(hp=gethostbyname(host)))
printf("Couldn't resolve host");
memset(&addr,0,sizeof(addr));
addr.sin_addr=*(struct in_addr*)
hp->h_addr_list[0];
addr.sin_family=AF_INET;
addr.sin_port=htons(port);
if((sock=(int)socket(AF_INET,SOCK_STREAM,
IPPROTO_TCP))<0)
printf("Couldn't create socket");
if(connect(sock,(struct sockaddr *)&addr,
sizeof(addr))<0)
printf("Couldn't connect socket");
return sock;
}
int main(int argc,char **argv)
{
SSL_CTX *ctx;
SSL *ssl;
BIO *sbio;
int sock;
SSL_METHOD *meth=NULL;
meth=SSLv23_client_method();
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
ctx=SSL_CTX_new(meth);
/* Connect the TCP socket*/
sock=tcp_connect(host,port);
/* Connect the SSL socket */
ssl=SSL_new(ctx);
sbio=BIO_new_socket(sock,BIO_NOCLOSE);
SSL_set_bio(ssl,sbio,sbio);
if(SSL_connect(ssl)<=0)
printf("SSL connect error");
X509 *peer;
peer=SSL_get_peer_certificate(ssl);
PEM_write_X509(stdout, peer);
SSL_CTX_free(ctx);
close(sock);
#ifdef WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
exit(0);
}
The code is modified version of the examples found here as suggested by this post.
EDIT: I kept getting the error OPENSSL_UPLINK: no OPENSSL_APPLINK on windows. After a lot of searching around the internet I found this post and added this to my code:
extern "C" {
#include <openssl/applink.c>
}
Seems this is some work around to avoid the requirement for compiler and run-time options compatibility.

Get Local IP-Address using Boost.Asio

I'm currently searching for a portable way of getting the local IP-addresses. Because I'm using Boost anyway I thought it would be a good idea to use Boost.Asio for this task.
There are several examples on the net which should do the trick. Examples:
Official Boost.Asio Documentation
Some Asian Page
I tried both codes with just slight modifications. The Code on Boost.Doc was changed to not resolve "www.boost.org" but "localhost" or my hostname instead. For getting the hostname I used boost::asio::ip::host_name() or typed it directly as a string.
Additionally I wrote my own code which was a merge of the above examples and my (little) knowledge I gathered from the Boost Documentation and other examples.
All the sources worked, but they did just return the following IP:
127.0.1.1 (That's not a typo, its .1.1 at the end)
I run and compiled the code on Ubuntu 9.10 with GCC 4.4.1
A colleague tried the same code on his machine and got
127.0.0.2 (Not a typo too...)
He compiled and run on Suse 11.0 with GCC 4.4.1 (I'm not 100% sure)
I don't know if it is possible to change the localhost (127.0.0.1), but I know that neither me or my colleague did it. ifconfig says loopback uses 127.0.0.1. ifconfig also finds the public IP I am searching for (141.200.182.30 in my case, subnet is 255.255.0.0)
So is this a Linux-issue and the code is not as portable as I thought? Do I have to change something else or is Boost.Asio not working as a solution for my problem at all?
I know there are much questions about similar topics on Stackoverflow and other pages, but I cannot find information which is useful in my case. If you got useful links, it would be nice if you could point me to it.
PS:
Here is the modified code I used from Boost.Doc:
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(boost::asio::ip::host_name(), "");
tcp::resolver::iterator iter = resolver.resolve(query);
tcp::resolver::iterator end; // End marker.
while (iter != end)
{
tcp::endpoint ep = *iter++;
std::cout << ep << std::endl;
}
Here's a trick I learned from python network programming (google) to figure out my machine's ip address. This only works if you have an internet connection and can connect to google.com and does give me my home machine's 192.168.x.x private address.
try {
boost::asio::io_service netService;
udp::resolver resolver(netService);
udp::resolver::query query(udp::v4(), "google.com", "");
udp::resolver::iterator endpoints = resolver.resolve(query);
udp::endpoint ep = *endpoints;
udp::socket socket(netService);
socket.connect(ep);
boost::asio::ip::address addr = socket.local_endpoint().address();
std::cout << "My IP according to google is: " << addr.to_string() << std::endl;
} catch (std::exception& e){
std::cerr << "Could not deal with socket. Exception: " << e.what() << std::endl;
}
You can find "your" address with the code you posted. BUT... it gets complicated. There may be multiple NICs, there may be LAN and WAN addresses, wired and wireless, loopback... On my desktop i had one NIC but two ips here from two diff DHCP servers on my lan...
I found it was better to let the user provide the IP to bind to as a command line parameter. And yes, that's a portable solution! :-)
If you edit your /etc/hosts file (this is *nix only, might work for windows too... I'm not sure) you can correct this issue.
Inside the hosts file you'll find something like: (this is Ubuntu, note the 1.1)
127.0.0.1 localhost
127.0.1.1 yourPcName.yourNetwork.tld
if you change this file to
127.0.0.1 localhost
127.0.1.1 yourPcName.yourNetwork.tld
your.real.ip.here yourPcName
then the hostname should resolve properly.
One method of testing proper resolution is with the "hostname -i" command which should print your ip address incorrectly before you change hosts, and then correctly afterwards.
Of course this is terrible solution for dynamic IPs... eh.
For me, resolving-based methods have always proven unreliable in various corner cases.
Operating systems provide APIs such as
getifaddrs on Linux (https://man7.org/linux/man-pages/man3/getifaddrs.3.html)
The same on macOS and BSD (https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getifaddrs.3.html)
GetAdaptersAddresses on Win32 (https://learn.microsoft.com/en-us/windows/win32/api/iphlpapi/nf-iphlpapi-getadaptersaddresses).
Notice that at no point Boost.ASIO contains calls to these functions so you are stuck with the local-domain resolving method.
If you are looking for a cross-platform solution that does call the above OS functions, Qt provides it:
for (const QNetworkInterface& iface : QNetworkInterface::allInterfaces())
for (const QNetworkAddressEntry& entry : iface.addressEntries())
qDebug() << entry.ip();
Cross platform, but only because of the #ifdef _WIN32 … #else:
boost::asio::ip::address_v6 sinaddr_to_asio(sockaddr_in6 *addr) {
boost::asio::ip::address_v6::bytes_type buf;
memcpy(buf.data(), addr->sin6_addr.s6_addr, sizeof(addr->sin6_addr));
return boost::asio::ip::make_address_v6(buf, addr->sin6_scope_id);
}
#if defined(_WIN32)
#undef UNICODE
#include <winsock2.h>
// Headers that need to be included after winsock2.h:
#include <iphlpapi.h>
#include <ws2ipdef.h>
typedef IP_ADAPTER_UNICAST_ADDRESS_LH Addr;
typedef IP_ADAPTER_ADDRESSES *AddrList;
std::vector<boost::asio::ip::address> get_local_interfaces() {
// It's a windows machine, we assume it has 512KB free memory
DWORD outBufLen = 1 << 19;
AddrList ifaddrs = (AddrList) new char[outBufLen];
std::vector<boost::asio::ip::address> res;
ULONG err = GetAdaptersAddresses(AF_UNSPEC,
GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, ifaddrs,
&outBufLen);
if (err == NO_ERROR) {
for (AddrList addr = ifaddrs; addr != 0; addr = addr->Next) {
if (addr->OperStatus != IfOperStatusUp) continue;
// if (addr->NoMulticast) continue;
// Find the first IPv4 address
if (addr->Ipv4Enabled) {
for (Addr *uaddr = addr->FirstUnicastAddress; uaddr != 0; uaddr = uaddr->Next) {
if (uaddr->Address.lpSockaddr->sa_family != AF_INET) continue;
res.push_back(boost::asio::ip::make_address_v4(ntohl(reinterpret_cast<sockaddr_in *>(addr->ifa_addr)->sin_addr.s_addr)));
}
}
if (addr->Ipv6Enabled) {
for (Addr *uaddr = addr->FirstUnicastAddress; uaddr != 0; uaddr = uaddr->Next) {
if (uaddr->Address.lpSockaddr->sa_family != AF_INET6) continue;
res.push_back(sinaddr_to_asio(reinterpret_cast<sockaddr_in6 *>(addr->ifa_addr)));
}
}
}
} else {
}
delete[]((char *)ifaddrs);
return res;
}
#elif defined(__APPLE__) || defined(__linux__)
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <sys/types.h>
std::vector<boost::asio::ip::address> get_local_interfaces() {
std::vector<boost::asio::ip::address> res;
ifaddrs *ifs;
if (getifaddrs(&ifs)) {
return res;
}
for (auto addr = ifs; addr != nullptr; addr = addr->ifa_next) {
// No address? Skip.
if (addr->ifa_addr == nullptr) continue;
// Interface isn't active? Skip.
if (!(addr->ifa_flags & IFF_UP)) continue;
if(addr->ifa_addr->sa_family == AF_INET) {
res.push_back(boost::asio::ip::make_address_v4(ntohl(
reinterpret_cast<sockaddr_in *>(addr->ifa_addr)->sin_addr.s_addr)));
} else if(addr->ifa_addr->sa_family == AF_INET6) {
res.push_back(sinaddr_to_asio(reinterpret_cast<sockaddr_in6 *>(addr->ifa_addr)));
} else continue;
}
freeifaddrs(ifs);
return res;
}
#else
#error "..."
#endif
Assuming you have one network card / one local ip address:
#include <boost/asio.hpp>
namespace ip = boost::asio::ip;
std::string getAddress()
{
boost::asio::io_service ioService;
ip::tcp::resolver resolver(ioService);
return resolver.resolve(ip::host_name(), "")->endpoint().address().to_string();
}