Created
January 8, 2023 01:09
-
-
Save angeloped/6a086667579d46937fec1dc37810028b to your computer and use it in GitHub Desktop.
A truly Cross-Platform socket client written in C language.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
// 1/8/2022 | |
// modified version of https://github.com/ApOgEE/mingw-c-socket | |
// WORKS ON Linux kali 4.19.0-kali4-686-pae #1 SMP Debian 4.19.28-2kali1 (2019-03-18) i686 GNU/Linux | |
////////////////////////////////////////////////////////////////////////// | |
// CROSS-PLATFORMING A SOCKET PROGRAM | |
// See https://stackoverflow.com/questions/28027937/cross-platform-sockets | |
////////////////////////////////////////////////////////// | |
// The header and lib files are different | |
// You'll need to include different header files depending on whether you're using Windows or not: | |
#ifdef _WIN32 | |
// FOR WINDOWS | |
/* See http://stackoverflow.com/questions/12765743/getaddrinfo-on-win32 */ | |
#ifndef _WIN32_WINNT | |
#define _WIN32_WINNT 0x0501 /* Windows XP. */ | |
#endif | |
/* winsock2.h was designed to replace winsock.h, not extend it. Everything that is defined in winsock.h is also defined in winsock2.h (https://stackoverflow.com/questions/9153911/) */ | |
#include <winsock2.h> | |
#else | |
// FOR UNIX/POSIX | |
/* Assume that any non-Windows platform uses POSIX-style sockets instead. */ | |
#include <sys/socket.h> | |
#include <arpa/inet.h> | |
#include <netdb.h> /* Needed for getaddrinfo() and freeaddrinfo() */ | |
#include <unistd.h> /* Needed for close() */ | |
#include <string.h> /* Needed to provide a declaration of memset */ | |
#include <stdlib.h> /* Needed to provide a declaration of exit */ | |
#endif | |
////////////////////////////////////////////////////////// | |
////////////////////////////////////////////////////////// | |
// WinSock requires initialisation and cleanup. | |
// The functions below illustrate how you can initialise WinSock v1.1 and clean up afterwards | |
int sockInit(void){ | |
#ifdef _WIN32 | |
WSADATA wsa_data; // winsock2.h | |
return WSAStartup(MAKEWORD(1,1), &wsa_data); // winsock2.h | |
//WSADATA wsaData; // winsock.h | |
//WSAStartup(MAKEWORD(2, 2), &wsaData); // winsock.h | |
#else | |
return 0; | |
#endif | |
} | |
int sockQuit(void){ | |
#ifdef _WIN32 | |
return WSACleanup(); | |
#else | |
return 0; | |
#endif | |
} | |
////////////////////////////////////////////////////////// | |
////////////////////////////////////////////////////////// | |
// socket connect error variable | |
#ifdef _WIN32 | |
// FOR WINDOWS | |
#define SOCKET_ERROR_ SOCKET_ERROR | |
#else | |
// FOR UNIX/POSIX | |
#define SOCKET_ERROR_ SO_ERROR | |
#endif | |
////////////////////////////////////////////////////////// | |
////////////////////////////////////////////////////////// | |
// Sockets are closed differently | |
// The function below illustrates the differences: | |
/* Note: For POSIX, typedef SOCKET as an int. */ | |
//int sockClose(SOCKET sock){ | |
int sockClose(int sock){ | |
int status = 0; | |
#ifdef _WIN32 | |
status = shutdown(sock, SD_BOTH); | |
if (status == 0) { status = closesocket(sock); } | |
#else | |
status = shutdown(sock, SHUT_RDWR); | |
if (status == 0) { status = close(sock); } | |
#endif | |
return status; | |
} | |
////////////////////////////////////////////////////////// | |
////////////////////////////////////////////////////////////////////////// | |
#define PORT 80 | |
#define USERAGENT "ApOgEE MinGW Socket Client 1.0" | |
char *build_get_query(char *, char *); | |
int main(int argc, char *argv[]){ | |
int client_socket; | |
char *host; | |
struct hostent *hent; | |
int iplen = 15; //XXX.XXX.XXX.XXX | |
struct sockaddr_in *remote; | |
int tmpres; | |
char *get; | |
char buf[BUFSIZ+1]; | |
//printf("Socket client example\n"); | |
// create tcp socket | |
sockInit(); | |
client_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | |
if (client_socket < 0) { | |
printf("client_socket = %d\n",client_socket); | |
perror("Can't create TCP socket\n"); | |
exit(1); | |
} | |
// get host ip | |
host = "static.licdn.com"; | |
//printf("Host: %s\n",host); | |
char *ip = (char *)malloc(iplen+1); | |
memset(ip, 0, iplen+1); | |
if((hent = gethostbyname(host)) == NULL) | |
{ | |
perror("Can't get IP"); | |
exit(1); | |
} | |
ip = inet_ntoa(*(struct in_addr *)*hent->h_addr_list); | |
//printf("The IP: %s\n",ip); | |
// setup remote socket | |
remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *)); | |
remote->sin_family = AF_INET; | |
//printf("s_addr:%d\n",remote->sin_addr.s_addr); | |
remote->sin_addr.s_addr = inet_addr(ip); | |
remote->sin_port = htons(PORT); | |
//printf("s_addr:%d\n",remote->sin_addr.s_addr); | |
// have to read | |
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms737625(v=vs.85).aspx | |
// connect socket | |
if(connect(client_socket, (struct sockaddr *)remote, sizeof(struct sockaddr)) == SOCKET_ERROR_){ | |
perror("Could not connect"); | |
sockClose(client_socket); // MULTIPLATFORM | |
sockQuit(); // FOR WINDOWS | |
exit(1); | |
} | |
// prepare query | |
get = build_get_query(host,"/sc/h/5q92mjc5c51bjlwaj3rs9aa82"); | |
//printf("query: \n%s\n",get); | |
//Send the query to the server | |
int sent = 0; | |
while(sent < strlen(get)) { | |
tmpres = send(client_socket, get+sent, strlen(get)-sent, 0); | |
if(tmpres == -1) { | |
perror("Can't send query"); | |
exit(1); | |
} | |
sent += tmpres; | |
} | |
//now it is time to receive the page | |
memset(buf, 0, sizeof(buf)); | |
int htmlstart = 0; | |
char * htmlcontent; | |
while((tmpres = recv(client_socket, buf, BUFSIZ, 0)) > 0) { | |
if(htmlstart == 0) { | |
/* Under certain conditions this will not work. | |
* If the \r\n\r\n part is splitted into two messages | |
* it will fail to detect the beginning of HTML content | |
*/ | |
htmlcontent = strstr(buf, "\r\n\r\n"); | |
if(htmlcontent != NULL){ | |
htmlstart = 1; | |
htmlcontent += 4; | |
} | |
} else { | |
htmlcontent = buf; | |
} | |
if(htmlstart) { | |
FILE *fp; | |
fp = fopen("file.svg", "ab+"); | |
fprintf(fp, htmlcontent); | |
//fputs(htmlcontent, fp); | |
fclose(fp); | |
// use only to show downloaded contents | |
//fprintf(stdout, htmlcontent); | |
} | |
memset(buf, 0, tmpres); | |
} | |
if(tmpres < 0) { | |
perror("Error receiving data"); | |
} | |
free(get); | |
free(remote); | |
sockClose(client_socket); // MULTIPLATFORM | |
sockQuit(); // FOR WINDOWS | |
//printf("Program end"); | |
return 0; | |
} | |
char *build_get_query(char *host, char *page){ | |
char *query; | |
char *getpage = page; | |
char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n"; | |
if(getpage[0] == '/'){ | |
getpage = getpage + 1; | |
//fprintf(stderr,"Removing leading \"/\", converting %s to %s\n", page, getpage); | |
} | |
// -5 is to consider the %s %s %s in tpl and the ending \0 | |
query = (char *)malloc(strlen(host)+strlen(getpage)+strlen(USERAGENT)+strlen(tpl)-5); | |
sprintf(query, tpl, getpage, host, USERAGENT); | |
return query; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment