HTTPS requests in socketwith proxy (https,socks4,socks5) in C - c

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.

Related

file server in C doesn't continually return files when requested

I'm new to network programming and recently finished reading through Beej's guide. I have a client/server program that I'm trying to get to continuously have the server return the contents of a file when the client requests it.
It works by the client sending the server a file path and the server reading it (if it exists) into a buffer then sending the buffer to the client which just prints the buffer.
It works, but it will only return one file then ignores any following requests. I have to shut down the client and reconnect again for it to work again. I can't figure out why. I've tried implementing select() and used aio_read() over the standard read() and I also forking a process for the send() function. Each of those those experiments had it working exactly the same pretty much.
Anyone have any tips? I'm at a loss where the problem could be.
Client
#define MAXDATASIZE 100 // max number of bytes at once
#define MAXMSG 25
#define MAXDATA 4096
#define SA struct sockaddr
// clean_str: make sure the string doesn't have junk spaces around it
void clean_str(char *s)
{
size_t len = strlen(s);
char tmp[MAXMSG] = {0};
strncpy(tmp, s, len-1);
memset(s, 0, len);
strncpy(s, tmp, len-1);
}
int main(int argc, char **argv)
{
int sockfd, numbytes;
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
char file_request[MAXMSG] = {0};
char file_buf[MAXDATA];
if (argc != 3) {
fprintf(stderr, "usage: client <hostname> <port>\n");
exit(EXIT_FAILURE);
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
// load the struct
if ((rv = getaddrinfo(argv[1], argv[2], &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(EXIT_FAILURE);
}
// loop trhough all results and connect to the first one we can
for (p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) < 0) {
close(sockfd);
perror("client: connect");
continue;
}
// if we make it here, we've got a connection
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
exit(EXIT_FAILURE);
}
inet_ntop(p->ai_family, (SA*)&p->ai_addr, s, sizeof s);
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo);
// stay connect until client exits
int n;
while (1) {
// make sure everything is cleared to minimize issues
memset(file_buf, 0, MAXDATA);
memset(file_request, 0, sizeof MAXMSG);
numbytes = 0;
// get client request from stdin
int b = read(STDIN_FILENO, file_request, MAXMSG);
if (b < 0) {
perror("client: read");
}
clean_str(file_request);
// send the request to the server
if ((numbytes = send(sockfd, file_request, strlen(file_request), 0)) < 0) {
perror("send");
exit(EXIT_FAILURE);
}
// now we wait for a response
while ((n = read(sockfd, file_buf, MAXDATA-1)) > 0)
printf("%s\n", file_buf);
if (n < 0) {
perror("read");
}
}
return 0;
}
Server
#define PORT 3490
#define MAXDATA 4096
#define FILENAME 256
#define SA struct sockaddr // for less messy casting
// get_file: open file, read contents info a buffer, return buffer
char *get_file(const char *path) {
int n, bytes;
static char buf[MAXDATA];
// try to open file
n = open(path, O_RDONLY);
if (n < 0) {
strcpy(buf, "problem opening file");
printf("%s\n", buf);
return buf;
}
// if exists, read it into buffer on
bytes = read(n, buf, sizeof buf-1);
if (bytes < 0) {
strcpy(buf, "problem reading file");
printf("%s\n", buf);
return buf;
}
close(n);
return buf;
}
int main()
{
int sockfd, filefd;
struct sockaddr_in servaddr;
struct sockaddr_storage client_addr;
socklen_t len;
int nbytes;
char file_request[FILENAME]; // buf to hold client's request string
// clear servaddr struct
memset(&servaddr, 0, sizeof servaddr);
servaddr.sin_family = AF_INET; // IPv4 for simplicity
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // use my IP
servaddr.sin_port = htons(PORT); // short, network by order
// create socket file descriptor
// #param3 is the protocol. 0 means TCP
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("socket");
exit(EXIT_FAILURE);
}
// bind the socket to the PORT
if (bind(sockfd, (SA*)&servaddr, sizeof servaddr) < 0) {
perror("bind");
exit(EXIT_FAILURE);
}
// this prevents the 'bind: address already in use' issue
int yes = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
perror("setsocket");
exit(EXIT_FAILURE);
}
if (listen(sockfd, 10) < 0) {
perror("listen");
exit(EXIT_FAILURE);
}
printf("server running and waiting for connection...\n");
int open = 1; // keep track if there's an accepted() fd
char *open_file;
while (1) {
// clear the file_request buffer
memset(file_request, 0, FILENAME);
memset(&open_file, 0, sizeof open_file);
nbytes = 0;
if (open) {
// we're only going to connect to one client for now
len = sizeof client_addr;
filefd = accept(sockfd, (SA*)&client_addr, &len);
if (filefd < 0) {
perror("accept");
continue;
} else {
printf("connected to a client\n");
open = 0; // keep track that there's an open fd
}
}
// recieve data from a client
if ((nbytes = recv(filefd, file_request, sizeof file_request, 0)) <= 0) {
// got error or connection was closed by client
if (nbytes == 0) {
printf("file-server: client hung up\n");
close(filefd);
open = 1;
continue;
} else {
perror("recv");
close(filefd);
open = 1;
continue;
}
close(filefd);
} else {
// we got some data
// manage it and get file contents
open_file = get_file(file_request);
if (strcmp(open_file, "0") == 0) {
continue;
}
if (send(filefd, open_file, strlen(open_file), 0) < 0) {
perror("send");
continue;
}
}
}
close(sockfd);
return 0;
}

SSL_read not receiving

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.

server can't send message to Client over Socket in C

Hi I'm writing 2 Programs (Server, Client) which should communicate with each other over sockets. The Client is able to send its first message to the server with no problem, but when the server tries to answer, the client receives just an empty msg: recv(...) is 0.
The server suddenly stops after the send(...) function is called.
Here is my Code:
Server:
/* Create a new TCP/IP socket `sockfd`, and set the SO_REUSEADDR
option for this socket. Then bind the socket to localhost:portno,
listen, and wait for new connections, which should be assigned to
`connfd`. Terminate the program in case of an error.
*/
struct sockaddr_in sin,
peer_addr;
//-----gen socket-----//
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
bail_out(EXIT_PARITY_ERROR, "could not create Socket");
//-----bind-----//
memset(&sin, 0, sizeof (sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(options.portno);
sin.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *)&sin, sizeof sin) < 0)
bail_out(EXIT_PARITY_ERROR, "Failed to bind to Port");
//-----listen-----//
if (listen(sockfd, 5) < 0)
bail_out(EXIT_PARITY_ERROR, "Server can't accepted connection");
//-----accept-----//
int sock_len = sizeof peer_addr;
if ((connfd = accept(sockfd, (struct sockaddr*)&peer_addr, (socklen_t *)&sock_len)) < 0) //fragen
bail_out(EXIT_PARITY_ERROR, "Can't accept connection to Client");
/* accepted the connection */
//Some other Code which has nothing to do with my Error!
/* read from client (WORKS FINE!!)*/
if (read_from_client(connfd, &buffer[0], READ_BYTES) == NULL) {
if (quit) break; /* caught signal */
bail_out(EXIT_FAILURE, "read_from_client");
}
request = (buffer[1] << 8) | buffer[0];
DEBUG("Round %d: Received 0x%x\n", round, request);
/* compute answer */
correct_guesses = compute_answer(request, buffer, options.secret);
if (round == MAX_TRIES && correct_guesses != SLOTS) {
buffer[0] |= 1 << GAME_LOST_ERR_BIT;
}
DEBUG("Sending byte 0x%x\n", buffer[0]);
/* send message to client */
if (send_to_client(sockfd, &buffer[0], WRITE_BYTES) == NULL) { //Error in this Method!
if (quit) break; /* caught signal */
bail_out(EXIT_FAILURE, "can't send message!");
}
Methods:
static uint8_t *send_to_client(int fd, uint8_t *buffer, size_t n)
{
/* loop, as packet can arrive in several partial reads */
size_t bytes_send = 0;
do {
ssize_t r = send(fd, buffer + bytes_send, n - bytes_send, 0); //Program stops HERE!
printf("%d\n", (int)r); //This and the following lines will not be executed!
if (r <= 0) {
return NULL;
}
bytes_send += r;
} while (bytes_send < n);
if (bytes_send < n) {
return NULL;
}
return buffer;
}
Client: (Might be usefull)
sockfd = cnt_to_server(argv[1], argv[2]);
uint8_t buffer;
uint16_t msg_buffer;
do
{
msg_buffer = generate_msg(&msg);
printf("Sending byte 0x%x\n", msg_buffer);
if (send_to_server(sockfd, &msg_buffer, WRITE_BYTES) == NULL) //works
error_exit(EXIT_FAILURE, "can't send message!");
if (read_from_server(sockfd, &buffer, READ_BYTES) == NULL) //NULL
error_exit(EXIT_FAILURE, "can't read message!");
printf("received byte 0x%x\n", buffer);
} while (game_continue(buffer, &msg));
(void)close(sockfd);
Methods:
uint8_t* read_from_server(int fd, uint8_t *buffer, int n)
{
/* loop, as packet can arrive in several partial reads */
size_t bytes_recv = 0;
do {
ssize_t r;
r = recv(fd, buffer + bytes_recv, n - bytes_recv, 0); //0
printf("%d\n", (int)r);
if (r <= 0) {
return NULL;
}
bytes_recv += r;
} while (bytes_recv < n);
if (bytes_recv < n) {
return NULL;
}
return buffer;
}
int cnt_to_server(const char *par_server, const char *par_port)
{
struct sockaddr_in server;
struct hostent *hp;
int sockfd;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
error_exit(EXIT_FAILURE, "could not create Socket");
server.sin_family = AF_INET;
if ((hp = gethostbyname(par_server)) == 0)
error_exit(EXIT_FAILURE, "host error!");
memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
server.sin_port = htons(parse_port(par_port));
if (connect(sockfd, (struct sockaddr*) &server, sizeof server) < 0)
error_exit(EXIT_FAILURE, "could not connect!");
return sockfd;
}
Thx for helping me out with this!
Change
if (send_to_client(sockfd, &buffer[0], WRITE_BYTES) == NULL)
to
if (send_to_client(connfd, &buffer[0], WRITE_BYTES) == NULL)
The solution is to use connfd (File descriptor for connection socket) instead of sockfd:
/* read from client */
if (read_from_client(connfd, &buffer[0], READ_BYTES) == NULL) {
if (quit) break; /* caught signal */
bail_out(EXIT_FAILURE, "read_from_client");
}

C: can I forward port for external application with libssh?

I'm implementing VNC connection for xen VM in my app. In order to connect I have to forward the port as XenServer accept only local connection. I do it like this:
ssh -L 5903:localhost:5903 root#192.168.1.4
After it a can connect my VNC to localhost with corresponding port. But I have to frequently reconnect to different hosts, and using bash is not a good idea as I have a windows build also. Installing ssh-client is not always possible.
I read http://api.libssh.org/stable/libssh_tutor_forwarding.html and tried to test it.
ssh_channel forwarding_channel;
forwarding_channel = ssh_channel_new(session);
int rc = channel_open_forward(forwarding_channel,
"192.168.1.4", 5903,
"localhost", 5903);
if (rc != SSH_OK)
{
ssh_channel_free(forwarding_channel);
return rc;
}
for(;;)
{
usleep(100000);
}
The tunnel itself is created, according to status. But I can see no ports listening via netstat. What I'm doing wrong and is it possible at all?
Update:
Here is resulted code that seems to work properly using libssh
int32_t forward_port (ssh_session session, char *remote_host, int32_t remote_port, int32_t local_port)
{
int32_t server_sock = 0;
int32_t client_sock = -1;
struct sockaddr_in client_name;
socklen_t client_name_len = sizeof client_name;
char buf[4096] = {0};
server_sock = server_startup(local_port);
client_sock = accept(server_sock,
(struct sockaddr *)&client_name,
&client_name_len);
if (client_sock == -1)
{
perror("Error on accept");
return SSH_ERROR;
}
int32_t client_port = ntohs(client_name.sin_port);
int32_t size_recv, nwritten, nread = 0;
uint8_t data[4096];
fcntl(client_sock, F_SETFL, O_NONBLOCK);
/* */
ssh_channel forwarding_channel;
forwarding_channel = ssh_channel_new(session);
int rc = channel_open_forward(forwarding_channel,
remote_host, remote_port,
"127.0.0.1", client_port);
if (rc != SSH_OK)
{
ssh_channel_free(forwarding_channel);
close(client_sock);
close(server_sock);
return rc;
}
while(!ssh_channel_is_eof (forwarding_channel))
{
if((size_recv = recv(client_sock, data, sizeof data, MSG_DONTWAIT) ) < 0)
{
if((nread = ssh_channel_read_nonblocking(forwarding_channel, data, sizeof data, 0))>0)
{
if(write(client_sock,data,nread)<0)
{
perror("Error writing to socket");
close(client_sock);
close(server_sock);
ssh_channel_free(forwarding_channel);
return SSH_ERROR;
}
}
}
else if (!size_recv)
{
puts("Local client disconnected, exiting");
goto exit;
}
nwritten = channel_write(forwarding_channel, data, size_recv);
if (size_recv != nwritten)
{
ssh_channel_free(forwarding_channel);
return SSH_ERROR;
}
}
exit:
close(client_sock);
close(server_sock);
ssh_channel_free(forwarding_channel);
return SSH_OK;
}
ssh_channel_open_forward documentation
## Warning ##
This function does not bind the local port and does not automatically forward the content of a socket to the channel. You still have to use channel_read and channel_write for this.

Unable to connect 2 machines using ipv6 (TCP server client )

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.

Resources