I'm trying to connect to a secure service via SSL, however in the following code, the SSL_read never returns, this is of course normal behaviour if the server does not return any message, the server I am trying to connect to should however return some sort of message. Is there anything not allowing a read in the following?
//Initialize SSL library
OpenSSL_add_ssl_algorithms();
//Initialize Crypto algorithms
OpenSSL_add_all_algorithms();
//Create new SSL context accepting SSL V2, V3 or TLS V1.0, V1.1 and V1.2
const SSL_METHOD *method = SSLv23_client_method();
SSL_CTX *ctx = SSL_CTX_new(method);
if (ctx == NULL)
{
printf("Error initializing SSL context.\n");
return 0;
}
SSL *ssl = SSL_new(ctx);
//Create socket descriptor
int sd = 0;
//Create hints for connection
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;//Can be both IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
struct addrinfo * result;
//Get address info, this could potentially return multiple
int err = getaddrinfo("api.okcoin.com", "9880", &hints, &result);
if (err != 0)
{
printf("Could not get addr info.\n");
return 0;
}
//Try connecting to any of the returned addresses
struct addrinfo * res;
for (res = result; res != NULL; res = res->ai_next)
{
sd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sd == -1)
{
printf("Could not connect to host.\n");
return 0;
}
if (connect(sd, res->ai_addr, res->ai_addrlen) == 0)
{
//Socket is now connected, free addrinfo results
freeaddrinfo(result);
//Assign socket descriptor to SSL
if (SSL_set_fd(ssl, sd) == 0)
{
printf("Could not assign socket descriptor.\n");
return 0;
}
//Begin SSL-handshake
if(SSL_connect(ssl) == 0)
{
printf("Could not perform handshake.\n");
return 0;
}
break;
}
}
//Could not connect socket, free addrinfo results and return error
if (res == NULL)
{
printf("Could no connect to to any host.\n");
freeaddrinfo(result);
return 0;
}
printf("Connected.\n");
SSL_write(ssl, "HELLO\x01", 6);
char * m = malloc(8192);
SSL_read(ssl, m, 8192);
As there is no error checking, you have no way of knowing whether the SSL_write() succeeded, let alone why the SSL_read() is blocking. You can't write code like this at any time, let alone when dealing with networks or SSL.
What I get with an equivalent Java program is an untrusted server certificate error. When I fix that I get a read timeout after 60 seconds.
I conclude that it isn't your code that's at fault here but the request format.
Related
i develop a program where i make i HTTPS requests in multithreading.
All work fine, however i need toimpleent use of proxy.
At the moment, i have this function for HTTPS Request :
struct string_builder* webrequest(const char* DEST_IP, const int DEST_PORT, const char* REQUEST) {
// Initialize ssl libraries and error messages
SSL_CTX *ssl_ctx = SSL_CTX_new (SSLv23_client_method());
// create a socket
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("Unable to create socket");
return NULL;
}
// destination info
struct sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET; // host byte order
dest_addr.sin_port = htons(DEST_PORT); // short, network port
dest_addr.sin_addr.s_addr = inet_addr(DEST_IP); // destination address
memset(&(dest_addr.sin_zero), '\0', 8); // zero out the rest of the struct
// connect to the server
int status = connect(sockfd, (struct sockaddr*) &dest_addr, sizeof(struct sockaddr_in));
if (status == -1) {
perror("Unable to connect to the server");
close(sockfd);
return NULL;
}
// create SSL connection and attach it to the socket
SSL *conn = SSL_new(ssl_ctx);
SSL_set_fd(conn, sockfd);
SSL_connect(conn);
// send an encrypted message
ssize_t sendsize = SSL_write(conn, REQUEST, strlen(REQUEST));
if (sendsize == -1) {
perror("Unable to send to the server");
{
char *buf = malloc(sizeof(char) * 256);;
u_long err;
while ((err = ERR_get_error()) != 0) {
ERR_error_string_n(err, buf, sizeof(buf));
printf("*** %s\n", buf);
}
free(buf);
}
SSL_shutdown(conn);
ERR_free_strings();
ERR_remove_state(0);
SSL_CTX_free(ssl_ctx);
close(sockfd);
return NULL;
}
size_t i = 1;
struct string_builder *result = NULL;
result = string_builder_init();
while (i) {
// receive the response
const int RESPONSE_SIZE = 512;
char *response = malloc(sizeof(char)*512);
ssize_t recsize = SSL_read(conn, response, RESPONSE_SIZE-1);
if (recsize == -1) {
perror("Unable to send to the server");
SSL_shutdown(conn);
ERR_free_strings();
ERR_remove_state(0);
SSL_CTX_free(ssl_ctx);
close(sockfd);
return NULL;
}
response[recsize] = '\0';
if (recsize <= 0)
{
free(response);
break;
}
else if (i > 2 && recsize > 6)
{
string_builder_pushs(result, response);
}
free(response);
++i;
}
// close ssl connection
SSL_shutdown(conn);
ERR_free_strings();
ERR_remove_state(0);
SSL_free(conn);
SSL_CTX_free(ssl_ctx);
close(sockfd);
return result;
}
I use socket/send/recv function for socket, openssl library for HTTPS requests.
All work fine, no leak without proxy, but when i try to use a "CONNECT command" to connect to google (and socket connexion to proxy host), i have an error when i want to send.
Thanks in advance.
I'm coding a C application to connect with a router. The router does not filter any incoming connections, neither is behind any firewall. My problem is the C function "connect" returns SOCKET_ERROR, but the error message I get calling perror when this happens is: No error (¿?). That probably means I'm looking in the wrong direction (the place where perror gets the error msg from is not the place I'm interested in).
UPDATE: As suggested in comments, I called WSAGetLastError(), which returns 10061 (connection refused)
At same time, I have a web application that connects with the router and send it a json message via AJAX call. No problem at all. Using the same IP and same port to connect with.
If helps, the connect function I'm using is defined at WinSock2.h. Working with Windows 7 Home Premium and Visual Studio 2010.
Those are what I consider relevant parts of the code (UPDATE: Added the missing part of socket initialization)
// Enters here
#ifdef WIN32
WSADATA wsaData;
int error = WSAStartup(MAKEWORD(2,0), &wsaData);
if(error != 0) return false;
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0)
{
WSACleanup();
return false;
}
#endif
struct addrinfo hints;
struct addrinfo *m_data;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_socktype = SOCK_STREAM;
// hostname is a char * containing my IP, in the same subnetwork than the router,
// and I'm going to connect with 192.168.90.1 (connection correctly open) and port 5555
port = "5555";
getaddrinfo(hostname, port, &hints, &m_data);
int m_socket = socket(m_data->ai_family, m_data->ai_socktype, m_data->ai_protocol);
// more stuff here
if (connect(m_socket, (struct sockaddr *)m_data->ai_addr, m_data->ai_addrlen) == SOCKET_ERROR)
{
// I get "connection error: no error" here. Why?
perror("connection error");
closesocket(m_socket);
return false;
}
So, why can I connect via AJAX call but the C connect function returns SOCKET_ERROR? Any clues?
Many thanks in advance
You forgot to set the protocol.
hints.ai_protocol = IPPROTO_TCP;
And also, you should try initializing Winsock to version 2.2.
Snippet of how I connect using Winsock.
#ifdef WIN32
WSADATA wsaData;
int error = WSAStartup(MAKEWORD(2,2), &wsaData);
if(error != 0) return false;
if(LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
WSACleanup();
return false;
}
#endif
SOCKADDR_IN sin;
LPHOSTENT lpHost = gethostbyname(hostname);
bool bRet = false;
if(NULL != lpHost) {
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sin.sin_family = AF_INET;
sin.sin_port = htons(5555);
sin.sin_addr.S_un.S_addr = *(unsigned __int32*)lpHost->h_addr;
if(connect(m_socket, (SOCKADDR*)&sin,
sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
perror("connection error");
closesocket(m_socket);
} else bRet = true;
}
return bRet;
I'm writing a small C client/server application, but I cannot make the connection work when using the external IP address. The code for both client and server is taken from here, in particular the clients do:
char *default_server_name = "localhost";
char *server_name = NULL;
int nport = DEFAULT_DAMA_PORT;
char port[15];
// Parse the command line options
if (parse_options(argc, argv, &server_name, &nport) < 0) {
return -1;
}
if (server_name == NULL) {
server_name = default_server_name;
}
snprintf(port, 15, "%d", nport);
// Connect to the server
int client_socket;
struct addrinfo hints, *servinfo, *p;
int rv;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(server_name, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}
for (p=servinfo; p != NULL; p = p->ai_next) {
if ((client_socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
#ifdef DEBUG
perror("socket");
#endif
continue;
}
if (connect(client_socket, p->ai_addr, p->ai_addrlen) == -1) {
close(client_socket);
#ifdef DEBUG
perror("connect");
#endif
continue;
}
// Connected succesfully!
break;
}
if (p == NULL) {
// The loop wasn't able to connect to the server
fprintf(stderr, "Couldn't connect to the server\n.");
exit(1);
}
While the server:
int nport;
char port[15];
if (parse_options(argc, argv, &nport) < 0) {
return -1;
}
snprintf(port, 15, "%d", nport);
int server_socket;
struct addrinfo hints, *servinfo, *p;
int rv;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}
for (p=servinfo; p != NULL; p = p->ai_next) {
if ((server_socket = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
#ifdef DEBUG
perror("socket");
#endif
continue;
}
if (bind(server_socket, p->ai_addr, p->ai_addrlen) == -1) {
close(server_socket);
#ifdef DEBUG
perror("bind");
#endif
continue;
}
// We binded successfully!
break;
}
if (p == NULL) {
fprintf(stderr, "failed to bind socket\n");
exit(2);
}
int pl_one, pl_two;
socklen_t pl_one_len, pl_two_len;
struct sockaddr_in pl_one_addr, pl_two_addr;
if (listen(server_socket, 2) < 0) {
fatal_error("Error in syscall listen.", 2);
}
// Get the two clients connections.
pl_one_len = sizeof(pl_one_addr);
pl_one = accept(server_socket,
(struct sockaddr *)&pl_one_addr,
&pl_one_len);
if (pl_one < 0) {
fatal_error("Error in syscall accept.", 3);
}
pl_two_len = sizeof(pl_two_addr);
pl_two = accept(server_socket,
(struct sockaddr *)&pl_two_addr,
&pl_two_len);
if (pl_two < 0) {
fatal_error("Error in syscall accept.", 3);
}
If I specify the IP of my machine in the command line, and hence the server_name in the clients is set to a string like 151.51.xxx.xxx, then the sockets cannot connect to the server. Also using 127.0.0.1 shows the same behaviour, which makes me think that when the documentation states:
The host name that you're interested in goes in the nodename
parameter. The address can be either a host name, like
"www.example.com", or an IPv4 or IPv6 address (passed as a string).
it's just joking.
Am I doing something incorrectly? Could there be some problem with firewall etc. that is preventing the clients to connect using the IP addresses?
Note: I've already searched a lot for this problem and some people say to avoid using getaddrinfo at all and directly fill with INADDR_ANY, but the getaddrinfo documentation states that passing NULL as nodename should already fill the address with INADDR_ANY, so I don't see why should I use the old method when the new one does this automatically.
As written in comments you are trying to connect to a server that is located in a network behind a router.
127.0.0.1 or localhost are redirections of the operating system and will not go over the router. That's why it worked for you.
If you specify an external ip address, the connection is made via the router and the ports that you use need to be forwarded in the router configuration. Any normal home internet end user router blocks incoming connections from any port by default.
Firstly please bear me with the long question - I'm writing a UDP client-server program and odd enough I had this packet loss problem whenever I use this flag for protocol family. Symptom is packets never left the sender host (no captures from tcpdump) but sendto() returns the correct positive value, which is never bigger than 200 bytes. It took me a ridiculous amount of time to figure out this can be resolved by forcing IPv4 but I don't understand why? It's been tested numerous times with server and client running on the same system (scientific linux 6) so the common unreliable UDP transmission is probably not the cause here, nor is there any firewall rule that drops anything at all. I'm wondering if anyone happens to know the cause? Also I thought about posting some code but it doesn't seem to be necessary.. Simply put, AF_UNSPEC results in all UDP packets never leaving the sender but no error, and with AF_INET everything is perfect. This might be a weird question but any insight is appreciated. Thanks a lot!Code for server initialization:
int udp_srv_init(char * port)
{
struct addrinfo hints, *servinfo, *p;
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return EXIT_FAILURE;
}
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((self_udp = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("socket");
continue;
}
if (bind(self_udp, p->ai_addr, p->ai_addrlen) == -1) {
close(self_udp);
fprintf(stderr, "Port %s: ",port);
perror("bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "server: failed to bind socket\n");
return EXIT_FAILURE;
}
freeaddrinfo(servinfo);
int buffsize = 65536; // I added this because I thought it was some buffer problem, but didn't change a thing
setsockopt(self_udp, SOL_SOCKET, SO_RCVBUF, (void*)&buffsize, sizeof(buffsize));
return EXIT_SUCCESS;
}
and for sending:
//...
for(i=0; i<num_neighbors; i++)
{
if(neighbors[i].cost == -1)
continue;
int bytes_sent = 0, ret;
while(bytes_sent < packet_size)
{
if(-1 == (ret = sendto(neighbors[i].skt, (void*)&my_neighs +
(ptrdiff_t)bytes_sent, packet_size-bytes_sent,
0, neighbors[i].p->ai_addr, neighbors[i].p->ai_addrlen)))
{
perror("sendto1");
return EXIT_FAILURE;
}
bytes_sent += ret;
}
}
//....
neighbors is a structure array with elements that have member fields:
struct addrinfo *servinfo, *p;
They are obtained from socket initialization, and freeaddrinfo() is only called at the very end of program execution so they are all valid.
I was trying to do a simple tcp server client using ipv6. It works on the same machine for ipv6 and ipv4 but when on different machines ipv6 fails to connect.
Server Code
int main(int argc, char* argv[])
{
int sockfd,new_fd,rv,yes=1;
struct addrinfo hints,*servinfo,*p;
struct sockaddr_storage their_addr;
socklen_t addr_size;
SOCKET listenSocket,clientSocket;
WSADATA w;
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
//ip=argv[1];
//port=argv[2];
memset(&hints,0,sizeof(hints));
hints.ai_family=AF_INET6;
hints.ai_socktype=SOCK_STREAM;
hints.ai_flags=AI_NUMERICHOST;
if((rv = getaddrinfo("fe80::c0a8:0160","5002",&hints,&servinfo)) != 0)
{
perror("\nGetaddrinfo failed\n");
return 1;
}
//Creating socket
listenSocket = socket(servinfo->ai_family,servinfo->ai_socktype,servinfo->ai_protocol);
if(listenSocket == INVALID_SOCKET)
{
printf("\nSocket failed with error \n");
WSACleanup();
}
//setting non blocking mode
u_long iMode = 1;
rv = ioctlsocket(listenSocket,FIONBIO,&iMode);
if(rv == SOCKET_ERROR)
{
printf("\nioctl failed\n");
WSACleanup();
}
rv = bind(listenSocket,servinfo->ai_addr,(int)servinfo->ai_addrlen);
if(rv == SOCKET_ERROR)
{
perror("\nBind: \n");
}
freeaddrinfo(servinfo);
rv = listen(listenSocket,SOMAXCONN);
if(rv == SOCKET_ERROR)
{
perror("listen");
return 1;
}
// now accept an incoming connection:
char recvbuf[DEFAULT_BUFLEN];
int buflen = DEFAULT_BUFLEN;
SOCKET AcceptSocket;
while (1)
{
AcceptSocket = SOCKET_ERROR;
while (AcceptSocket == SOCKET_ERROR)
{
AcceptSocket = accept(listenSocket, NULL, NULL);
}
printf("Server: Client Connected!\n");
listenSocket = AcceptSocket;
rv = recv(listenSocket,recvbuf,buflen,0);
break;
}
printf("Received %d bytes from client \n",rv);
closesocket(listenSocket);
closesocket(AcceptSocket);
return 0;
}
Client Code
int main(int argc,char* argv[])
{
struct addrinfo hints,*servinfo,*p;
int rv;
SOCKET connectSocket;
WSADATA w;
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
//resetting memory
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST;
//getting values
if((rv = getaddrinfo("fe80::c0a8:160","5002",&hints,&servinfo)) != 0)
{
perror("Getaddrinfo failed");
return 1;
}
//Creating socket
connectSocket = socket(servinfo->ai_family,servinfo->ai_socktype,servinfo->ai_protocol);
if(connectSocket == INVALID_SOCKET)
{
perror("Socket create : ");
}
rv = connect(connectSocket,servinfo->ai_addr,(int)servinfo->ai_addrlen);
if(rv == SOCKET_ERROR)
{
perror("Socket Connect : ");
}
//free memory
freeaddrinfo(servinfo);
// Send and receive data.
int bytesSent;
char sendbuf[200] = "Client: Sending some test string to server...";
char recvbuf[200] = "";
bytesSent = send(connectSocket, sendbuf, strlen(sendbuf), 0);
printf("Client: send() - Bytes Sent: %ld\n", bytesSent);
closesocket(connectSocket);
return 0;
}
The aim is just to print how many bytes transferred.
It appears that you're using a link local address. Are you sure for that? Also, I'd suggest you check your firewall settings first.
EDIT:
Try to include the zone ID. When you issue the ipconfig in command prompt, you should be able to get addresses like fe80::c0a8:0160%21 where %21 is the zone ID. It's important when you use link local addresses according to this answer.