Creating a client in C: does not connect to the server - c

int createclientsock(char * hostname, int port){
struct hostent * hp;
printf("Attempting to create client socket!\n");
memset(&client_addr,'0',sizeof(client_addr));
client_addr.sin_family = AF_INET;
client_addr.sin_port = htons(port); /* holds the remote port */
/* If internet "a.d.c.d" address is specified, use inet_addr()
* to convert it into real address. If host name is specified,
* use gethostbyname() to resolve its address */
client_addr.sin_addr.s_addr = inet_addr(hostname); /* If "a.b.c.d" addr */
if (client_addr.sin_addr.s_addr == -1) {
hp = gethostbyname(hostname);
/* Call method to create server socketyname(hostname);*/
/*printf("host name: %s",hp);*/
if (hp == NULL) {
printf("ERROR: Host name %s not found\n", hostname);
exit(1);
}
}
/* Create an Address Family (AF) stream socket, implying the use of tcp as the underlying protocol */
client_fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Client_fd: %d\n",client_fd);/*ANDY: it gets to here without printing errors, the client_fd = 3 ...im not sure what that means*/
/* use the sockaddr_in struct in the to variable to connect */
if (connect(client_fd, (struct sockaddr *)&client_addr, sizeof(client_addr)) < 0) {
printf("ERROR: could not connect!\n");
exit(1);
}
return client_fd;
}
It gets to the connect part and takes a long time before finally printing the error statement "ERROR: could not connect!\n"

Not sure if this is your actual problem but the line:
memset(&client_addr,'0',sizeof(client_addr));
is probably not what you want. It's fills the structure with the character '0' rather than zero bytes. It would be better written as:
memset(&client_addr,'\0',sizeof(client_addr));
In addition, if you use a DNS name rather than an IP address, you never load it into the client_addr structure. You get back the hostent pointer but you should then use the h_addr_list field in that structure to populate client_addr.sin_addr.s_addr.

Related

OpenSSL in C - routines:ssl3_get_record:wrong version number when trying to connect to server using TLS1_2

I am trying to make a "curl" client that can send requests to servers in C.
I've done creating a TCP socket (using slides from college, tested):
int connect_to_host(char * hostname, int port) {
// AF_INET: create socket that uses IPv4; SOCK_STREAM: type of sequenced, reliable
// 2-way connection-based byte streams ~ TCP (as opposed to datagrams ~ UDP)
int socket_fd;
struct sockaddr_in server_addr;
struct hostent * hp;
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return -1; // remember to broadcast error, saved in errno (extern int errno)
}
// geting address (contained in struct hostent) from DNS
if ((hp = gethostbyname(hostname)) == NULL) {
return -2; // can't find hostname from DNS
}
// per documentation, must zero out bytes in the 'server' socket address before filling values
bzero((char *)&server_addr, sizeof(server_addr));
// filling necessary values of the 'server' socket address
server_addr.sin_family = AF_INET; // using IPv4
server_addr.sin_port = htons(port); // assign port value, remember to change int (host order byte)
// to network order byte. htons = host-to-network-short (short int)
bcopy((char *)hp->h_addr_list[0], (char *)&server_addr.sin_addr.s_addr, hp->h_length); // IP address, got from DNS
if (connect(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
return -1; // error, as above
}
return socket_fd;
}
And created a TLS-version-flexible SSL/TLS context:
SSL_CTX * init_CTX() {
SSL_METHOD * method;
SSL_CTX * ctx;
OpenSSL_add_all_algorithms(); // Load cryptos, et.al.
SSL_load_error_strings(); // Bring in and register error messages
method = TLS_client_method(); // create new client-method instance
if ((ctx = SSL_CTX_new(method)) == NULL) {; // create new context
return NULL;
}
return ctx;
}
My next step is to create an SSL connection state and "bind" it with the file descriptor return by the TCP function (connect_to_host()) above. Then I will try to make SSL_connect()
if (*tls_mode == 1) {
ctx = init_CTX();
ssl = SSL_new(ctx); // create new SSL connection state
SSL_set_fd(ssl, clientfd); // bind socket descriptor to ssl state
if (SSL_connect(ssl) == -1) {
printf("SSL connection failed\n");
ERR_print_errors_fp(stderr);
return -1;
}
printf("debug tls: connect\n");
if (show_cert) SSL_show_certs(ssl);
}
At this point I receive the error in the title. I have checked stackoverflow and places but I don't see questions using C and the OpenSSL library. If anyone can give me a hint, I would really appreciate it.
So for anyone who checks back on this later, I made a mistake with my port number, and connect to port 80 instead of 443, causing the error.

c - in_addr_t variable as paramether of connect

I have a variable of in_addr_t type and I would like to use connect() with the given ip. I'm therefore needing a (struct sockaddr *) variable as parameter for the connect(). How to insert use the in_addr_t variable instead?
in_addr_t var; // Given variable, not actually declared here ofc
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in *srvraddr = malloc(sizeof(struct sockaddr_in));
memset((void *) srvraddr, 0, sizeof(struct sockaddr_in));
srvraddr->sin_family = AF_INET;
srvraddr->sin_port = htons(PORT_A); // Big - little endian arch compatibility
srvraddr->sin_addr.s_addr = var; // Somehow assign var here? <<<<<
connect(sockfd, (struct sockaddr *) srvraddr, sizeof(struct sockaddr_in));
Whatever I try to do connect always returns me -1.
Using perror I get the following error: Connection refused.
How to insert use the in_addr_t variable instead?
You cannot use an in_addr_t with connect() instead of a struct sockaddr_in. connect() accepts varying address structure types, but not arbitrary ones. The correct structure type for an IPv4 address is the struct sockaddr_in that you're already using. You need to store an appropriate representation of the remote host address into that.
Evidently, you already have an in_addr_t that you assert represents the remote address, but are uncertain how to use it:
in_addr_t var; // Given variable, not actually declared here ofc
[...]
srvraddr->sin_addr.s_addr = var; // Somehow assign var here? <<<<<
What you present is already exactly what POSIX expects you to do, however. POSIX requires that the sin_addr member of a struct sockaddr_in be a structure having at minimum a s_addr member of type in_addr_t. Supposing that the in_addr_t you have is in fact a correct representation of the machine address to which you want to connect, assigning that value to sin_addr.s_addr of your address structure is just right. In principle, there could be more members of that struct, but in practice, implementations that want to be interoperable will not require you to set any other members. Most don't have other members at all.
Do note, however, that just because connect() receives the address structure via a pointer does not mean you need to use dynamic allocation. It would be a bit more idiomatic to do this:
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in srvraddr = { 0 };
srvraddr.sin_family = AF_INET;
srvraddr.sin_port = htons(PORT_A);
srvraddr.sin_addr.s_addr = var;
connect(sockfd, (struct sockaddr *) &srvraddr, sizeof(srvraddr));
Among other things, that saves you having to free the memory afterward.
Whatever I try to do connect always returns me -1. Using perror I get the following error: Connection refused.
As far as I can see, the code you've presented is fine. You may want to check how you are obtaining the in_addr_t value in the first place, and to verify the port number you are using. On the other hand, do not overlook the possibility that the problem is at the remote host: perhaps the port you are trying to connect to is just not open (to you).
This is my way of using connect() to get a connection to "example.com" on port 80:
#include <stdio.h>
#include <netdb.h>
#include <unistd.h>
int main(void)
{
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
fprintf(stderr, "socket");
return 0;
}
char domain[] = "example.com";
struct hostent *he;
he = gethostbyname (domain);
if (!he)
{
switch (h_errno)
{
case HOST_NOT_FOUND:
fputs ("The host was not found.\n", stderr);
break;
case NO_ADDRESS:
fputs ("The name is valid but it has no address.\n", stderr);
break;
case NO_RECOVERY:
fputs ("A non-recoverable name server error occurred.\n", stderr);
break;
case TRY_AGAIN:
fputs ("The name server is temporarily unavailable.", stderr);
break;
}
return 1;
}
if (he->h_length < 4)
return 1;
struct sockaddr_in srvraddr;
srvraddr.sin_len = sizeof(srvraddr);
srvraddr.sin_family = AF_INET;
srvraddr.sin_port = htons(80);
srvraddr.sin_addr = * (struct in_addr *) he->h_addr_list[0];
if (connect(sockfd, (struct sockaddr*)&srvraddr, srvraddr.sin_len) == -1) {
fprintf(stderr,"connect() failed\n");
return 1;
}
// Use conection here...
close(sockfd);
return 0;
}

C socket programming: get IP address (IPv6 or IPv4) server bounds to, and client connected to?

I have written code like below. This code should enable to retrieve IP address both for PASSIVE_SOCKET (where server bound its socket), and CONNECTION_SOCKET (where client has connected to).
result_t print_socket_address(int sockfd, socket_type_t socket_type) {
char *ip_address; // address (passive) socket was binded to
int port; // port (passive) socket was binded to
switch(socket_type)
{
case PASSIVE_SOCKET:
if(get_current_address_and_port(sockfd, &ip_address, &port) == FAILURE) {
fprintf(stderr, "get_current_address_and_port: faild!\n");
free(ip_address);
return FAILURE;
}
printf("Created passive socket %d binded to %s:%d\n", sockfd, ip_address, port);
break;
case CONNECTION_SOCKET:
if(get_peer_address_and_port(sockfd, &ip_address, &port) == FAILURE) {
fprintf(stderr, "get_peer_address_and_port: faild!\n");
free(ip_address);
return FAILURE;
}
printf("Socket %d connected to %s:%d\n", sockfd, ip_address, port);
break;
default:
fprintf(stderr, "Incorrect socket type!\n");
free(ip_address);
return FAILURE;
}
free(ip_address);
return SUCCESS;
}
/**
* function retrieves current ip address and port
* socket is bound to for given socket file descriptor
*/
result_t get_current_address_and_port(int sockfd, char **ip_address, int *port) {
struct sockaddr sockaddr;
socklen_t sockaddrlen = sizeof(sockaddr);
if(getsockname(sockfd, &sockaddr, &sockaddrlen) < 0) {
fprintf(stderr, "getsockname: %s\n", strerror(errno));
return FAILURE;
}
sockaddr.sa_family = AF_INET6;
return get_address_and_port_from_sockaddr(&sockaddr, ip_address, port);
}
/**
* function retrieves peer ip address and port
* socket is connected to for given socket file descriptor
*/
result_t get_peer_address_and_port(int sockfd, char **ip_address, int *port) {
struct sockaddr sockaddr;
socklen_t sockaddrlen = sizeof(sockaddr);
if(getpeername(sockfd, &sockaddr, &sockaddrlen) < 0) {
fprintf(stderr, "getpeername: %s\n", strerror(errno));
return FAILURE;
}
return get_address_and_port_from_sockaddr(&sockaddr, ip_address, port);
}
/**
* function unwrap ip address and port from addrinfo structure
*/
result_t get_address_and_port_from_addrinfo(const struct addrinfo *addrinfo, char **ip_address, int *port) {
return get_address_and_port_from_sockaddr((struct sockaddr *)addrinfo->ai_addr, ip_address, port);
}
/**
* function unwrap ip address and port from sockaddr structure
*/
result_t get_address_and_port_from_sockaddr(const struct sockaddr *sockaddr, char **ip_address, int *port) {
*ip_address = (char *) malloc(INET6_ADDRSTRLEN * sizeof(char));
// converting network address to presentation address
if(inet_ntop(sockaddr->sa_family, get_in_addr(sockaddr), *ip_address, INET6_ADDRSTRLEN * sizeof(char)) == NULL) {
fprintf(stderr, "inet_ntop: %s\n", strerror(errno));
return FAILURE;
}
// converting network port to host port
*port = ntohs(get_in_port(sockaddr));
return SUCCESS;
}
/**
* function unwrap in_addr or in6_addr structure from
* sockaddr structure depending on address family
* AF_INET or AF_INET6
*/
void *get_in_addr(const struct sockaddr *sa) {
if( sa->sa_family == AF_INET) // IPv4 address
return &(((struct sockaddr_in*)sa)->sin_addr);
// else IPv6 address
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
/**
* function unwrap in_port from sockaddr structure
* depending on address family AF_INET or AF_INET6
*/
in_port_t get_in_port(const struct sockaddr *sa)
{
if( sa->sa_family == AF_INET ) // IPv4 address
return (((struct sockaddr_in*)sa)->sin_port);
// else IPv6 address
return (((struct sockaddr_in6*)sa)->sin6_port);
}
But when I use this code I get some odd behaviour. Returned IP address where my server bounds socket is for example:
Created passive socket 4 binded to ::ba54:431c:f9:55401
55401 is the port number and it is correct. But what is this ::ba54:431c:f9? I think maybe this is some IPv6. But why? My Computer in local area network has IP address 192.168.8.102!
More over when I try to connect with this server by the client program then I must use 192.168.8.102 IP address to get connected otherwise using this ::ba54:431c:f9 I get error like "No route found"? When the client connects using 192.168.8.102 IP address with the server and then it prints IP addres and port number of computer it connected to I am getting another ODD IP Address like this:
Socket 3 connected to ::3300:5208:6d16:9c88:55401
So here only port number matches and the IP address is not correct!
More over Client socket while binding locally before connecting with server has bound IP address the same as IP address of computer it is connecting to (it is physically different computer in my LAN network), i.e. ::3300:5208:6d16:9c88:52040, where 52040 is port where client bound its socket.
I have even tried to convert IP address of server computer 192.168.8.1 to IPv6 but I am getting something like this: 0:0:0:0:0:ffff:c0a8:866 and this address when used in client program to connect to server works correctly! But Client using above functions print this totally different IP address like: ::3300:5208:6d16:9c88:52040
So how should I write this function to:
enable server print IP address and port number it is bounded (in general IPv6 or IPv4 can connect to any address/any port it chooses)
enable client to print IP address and port number it is bounded to and it is connecting to (in general can be using IPv4 or IPv6 depending on the needs).
I would like to display in server program IP address and port number which then I could use in client program to connect both. Now I need to guess that it should be my computer address found in Network Preferences and assume port number is correct and then try to connect.
Remove this line from get_current_address_and_port.
sockaddr.sa_family = AF_INET6;
I don't know how that line got written into your code, but it's incorrect.
By removing that line, that will clear up most of your issues for IPv4.
Your code is hardwired to use a struct sockaddr. IIRC, sockaddr isn't big enough for IPv6 addresses anyway. May I suggest converting it to a sockaddr_storage for the initial call to getsockname and getpeername so your code can work better for both IPv4 and IPv6.
Example fixup:
result_t get_current_address_and_port(int sockfd, char **ip_address, int *port) {
struct sockaddr_storage address = {0};
socklen_t sockaddrlen = sizeof(address);
if(getsockname(sockfd, (struct sockaddr*)(&address), &sockaddrlen) < 0) {
fprintf(stderr, "getsockname: %s\n", strerror(errno));
return FAILURE;
}
return get_address_and_port_from_sockaddr((struct sockaddr*)(&address), ip_address, port);
}
result_t get_peer_address_and_port(int sockfd, char **ip_address, int *port) {
struct sockaddr_storage address = {0};
socklen_t sockaddrlen = sizeof(address);
if(getpeername(sockfd, (struct sockaddr*)(&address), &sockaddrlen) < 0) {
fprintf(stderr, "getpeername: %s\n", strerror(errno));
return FAILURE;
}
return get_address_and_port_from_sockaddr((struct sockaddr*)(&address), ip_address, port);
}

How to troubleshoot socket connection from Asterisk

I wrote a module for asterisk that needs to communicate to a service request information an return it, but for some reason my socket does not connect at all. When I telnet to the service it works fine, but I can not figure out why the it returns a -1 in the module
This is the code in my module
int SocketQuery(char buffer[BUFFSIZE],char *qrystr){
int sock;
struct sockaddr_in eserver;
int sockres = 0;
unsigned char receiving = 1;
memset(sendbuff,0,sizeof(sendbuff));
/* Create the TCP socket */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
ast_log(LOG_ERROR,"Failed to create socket for LCRROUTER");
return -1;
}
/* Construct the server sockaddr_in structure */
memset(&eserver, 0, sizeof(eserver)); /* Clear struct */
eserver.sin_family = AF_INET; /* Internet/IP */
eserver.sin_addr.s_addr = inet_addr(IP); /* IP address */
eserver.sin_port = htons(port); /* server port */
/* Establish connection */
ast_log(LOG_NOTICE,"LCRROUTER - Connection to %s on port %s\n", IP, port);
sockres = connect(sock,
(struct sockaddr *) &eserver,
sizeof(eserver));
if (sockres < 0) {
ast_log(LOG_ERROR,"LCRROUTER - Failed to connect with server on %s:%s. Error Code %d", IP,port,sockres);
return -1;
}
sockres returns -1. Do I miss something?
You can use
tcpdump port YOUR_PORT_HERE -v -s0
In that form it will show you all packets sent via socket.

Client server connection on loopback interface

I'm trying to test a client-server simple implementation using localhost address.
Here's the code.
Server:
/*
* Sequential busy-waiting
*/
int main(int argc, char** argv) {
int opt, client_addr_l, errsv;
unsigned short port;
struct sockaddr_in server_addr, client_addr;
/* ... */
printf("Port number retrieved (%d), server is starting ...\n", port);
/*TCP Socket creation*/
sock_ds = socket(AF_INET, SOCK_STREAM, 0);
if(sock_ds == -1){
fprintf(stderr, "Socket creation error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
/*Server address binding*/
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
server_addr.sin_addr.s_addr = INADDR_ANY;
/*!!!! */
int optval = 1;
if( (setsockopt(sock_ds,SOL_SOCKET,SO_REUSEADDR,&optval,sizeof(optval))) == -1 ) {
printf("Error on setsockopt\n");
exit(EXIT_FAILURE);
}
/*????*/
if(bind(sock_ds, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1){
fprintf(stderr, "Address binding error\n");
exit(EXIT_FAILURE);
}
/*Server with passive socket*/
if(listen(sock_ds, SOMAXCONN) == -1){
fprintf(stderr, "Listen call error: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
while(1){
memset(&client_addr, 0, sizeof(client_addr));
acc_sock_ds = accept(sock_ds, (struct sockaddr *)&client_addr, &client_addr_l);
printf("DEBUG: LINE201, acc_sock_ds = %d\n", acc_sock_ds);
/*Connect error management*/
if(acc_sock_ds == -1){
fprintf(stderr, "Fatal error on accept %d(%s)\n"
, errsv, strerror(errsv));
exit(EXIT_FAILURE);
}
//sin_addr to ASCII (string) );
printf("Connected with: %s\n", inet_ntoa(client_addr.sin_addr));
/*...*/
close(acc_sock_ds);
/*...*/
}
/*...*/
}
Client:
int main(){
int sock_ds;
struct sockaddr_in remote_addr;
struct hostent *hp;
/*TCP Socket creation*/
sock_ds = socket(AF_INET, SOCK_STREAM, 0);
if(sock_ds == -1){
fprintf(stderr, "Socket creation error\n");
exit(EXIT_FAILURE);
}
remote_addr.sin_family = AF_INET;
remote_addr.sin_port = htons(25556);
hp = gethostbyname("localhost");
bcopy(hp -> h_addr, &remote_addr.sin_addr, hp -> h_length); //fills address entry
if(connect(sock_ds, (struct sockaddr*)&remote_addr, sizeof(remote_addr)) == -1){ //connection attempt
fprintf(stderr, "Connect failure(%s)\n", strerror(errno));
exit(EXIT_FAILURE);
}
/*...*/
}
When i run them on two different terminals server returns me:
Port number retrieved (25556), server is starting ...
Server is ready. Waiting for client connections.
DEBUG: LINE201, acc_sock_ds = 4
Connected with: 0.0.0.0
My question is: why does the client address retrieved by the server is 0.0.0.0. It should not be 127.0.0.1?
It looks like you are passing the third parameter to accept() uninitialized, it should be set at the size of the second parameter. In addition to that, it should be a socklen_t, not an int, see http://pubs.opengroup.org/onlinepubs/009695399/functions/accept.html
Could try by declaring client_addr_l as a socklen_t, then setting it to sizeof( struct sockaddr_in) before passing to accept() ?
I'm guessing its unitialized value is zero, so accept() cannot set the remote address to your client_addr as it has a zero size. So, client_addr is untouched and, as you zeroed it earlier, you get 0.0.0.0.
0.0.0.0 means that your server accept connection from any interface in your equipment
so the loopback interface with the address 127.0..0.1 is included
It seems to be a special situation. All possible addresses are listening for your connection.
Here is a thread on this.
Quote:
0.0.0.0, in this context, means "all IP addresses on the local machine"
(in fact probably, "all IPv4 addresses on the local machine").
So, if your webserver machine has two ip addresses, 192.168.1.1 and 10.1.2.1,
and you allow a webserver daemon like apache to listen on 0.0.0.0,
it will be reachable at both of those IPs.
But only to what can contact those IPs and the web port(s).
server_addr.sin_addr.s_addr = INADDR_ANY;
probably should be
server_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);

Resources