I am trying to perform the C equivalent of the python's:
requests.get('http://test.com')
I am first using getaddrinfo() to resolve the hostname (it has 4 ips) to ip then server.sin_addr.s_addr = inet_addr(ip); and it connects successfully (doesn't give an error). But when I try to display the page by sending "GET / HTTP/1.1\r\n\r\n request, it basically returns 404 error (page not found) content. Here is the function:
void foo ()
{
struct addrinfo hints;
struct addrinfo *result = NULL;
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
char host[256], port [256];
strcpy(host, "www.test.com");
strcpy(port, "80");
getaddrinfo(host, port, &hints, &result);
struct sockaddr_in *sockaddr_ipv4 = (struct sockaddr_in *)result->ai_addr;
char ip [256];
strcpy(ip, inet_ntoa(sockaddr_ipv4->sin_addr));
struct sockaddr_in server;
SOCKET s = socket(AF_INET , SOCK_STREAM , 0 );
char *message , server_reply[2000];
int recv_size;
server.sin_addr.s_addr = inet_addr(ip);
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
message = "GET / HTTP/1.1\r\n\r\n";
if( send(s , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
if((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts("recv failed");
}
server_reply[recv_size] = '\0';
puts(server_reply);*/
system("PAUSE");
}
Result
HTTP/1.1 404 Not Found Date: Fri, 15 Sep 2017 03:19:41 GMT
Content-Type: text/html; charset=UTF-8 Server: ghs Content-Length:
1561 X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN
Error 404 (Not Found)!!1
{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{backgrou
nd:#fff;color:#222;padding:15px}body{margin:7% auto
0;max-width:390px;min-height :180px;padding:30px 0 15px} >
body{background:url(//www.google.com/images/error s/robot.png) 100%
5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflo
w:hidden}ins{color:#777;text-decoration:none}a img{border:0}#media
screen and (m
ax-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0
}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo
_color_150x54dp.png) no-repeat;margin-left:-5px}#media only screen and (min-reso
lution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/
2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100%
100%;-moz-border-image:ur
l(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png)
0}}#media only screen and
(-webkit-min-device-pixel-ratio:2){#logo{background:ur
l(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png)
no-repeat;-webkit-background-size:100%
100%}}#logo{display:inline-block;height:5 4px;width:150px}
404. Thata?Ts an error. The requested URL
/ was not found on this server. Thata? Ts all we
know.
What am I doing wrong? How must I approach this?
Within HTTP/1.1 you need to specify a Host header. Within HTTP/1.0 you do not. Therefore, you must either change this to be:
GET / HTTP/1.0\r\n\r\n
or
GET / HTTP/1.1\r\n
Host: the.hostname.com\r\n\r\n
This change was made since virtual hostnames had become so prevalent.
Related
I've got a small program with a client and server. The server starts, connects to the client and receives a host and second port number from the client, then sends some information back to the client about it's directory. The function in the server that sends data back works something like this:
void sendStuff(char *host, char *port) {
int sockfd, numbytes;
struct addrinfo hints, *servinfo;
struct sockaddr_storage client_info;
socklen_t addr_size;
size_t i = 0;
int rv;
// clear hints
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
memset(&servinfo, 0, sizeof(servinfo));
if ((rv = getaddrinfo(host, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
}
// create socket
sockfd = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol);
if (sockfd == -1) {
perror("There was an error creating your socket.");
close(sockfd);
exit(1);
}
// connect using socket
int conn;
conn = connect(sockfd, servinfo->ai_addr, servinfo->ai_addrlen);
if(conn == -1) {
perror("Error connecting to server.");
close(sockfd);
exit(1);
}
send(sockfd, "hey!", strlen("hey!"), 0);
}
Currently testing over localhost, which is being printed as 16.2.197.67 on the client. That doesn't seem like a localhost IP, so I suppose I could be screwing up the host somehow. Connecting to the waiting socket over telnet works, but not through this function.
I want to send post data to php script, but php never get my post data. Here my code :
#include<stdio.h>
#include<winsock2.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
char message[1024] , server_reply[2000];
int recv_size;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
//Connect to remote server
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
// Work well with Get Method
// strcat(message, "GET /voleur/receiver.php?arg1=Hello HTTP/1.1\n");
strcpy(message, "POST /voleur/receiver.php HTTP/1.1\r\n");
strcat(message, "Host: 127.0.0.1:80\r\n");
strcat(message, "Content-Type: application/x-www-form-urlencoded\r\n");
strcat(message, "Content-Length: 10\r\n");
strcat(message, "Accept-Charset: utf-8\r\n\r\n");
strcat(message, "arg1=Hello");
if( send(s , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
puts("Data Send\n");
//Receive a reply from the server
if((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts("recv failed");
}
puts("Reply received\n");
//Add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '\0';
puts(server_reply);
return 0;
}
This the php script :
<?php
echo "POST DATA : ".json_encode($_POST);
?>
Here the response :
Reply received
HTTP/1.1 200 OK
Date: Fri, 18 Nov 2016 10:34:21 GMT
Server: Apache/2.4.18 (Win32) OpenSSL/1.0.2e PHP/7.0.8
X-Powered-By: PHP/7.0.8
Content-Length: 14
Content-Type: text/html; charset=UTF-8
POST DATA : []
When i try send data throught GET method thats work well, but for POST method, PHP script doesn't receive any data from client.
Thankyou for David Schwartz, this the right code :
#include<stdio.h>
#include<winsock2.h>
#include <string.h>
#pragma comment(lib,"ws2_32.lib") //Winsock Library
int main(int argc , char *argv[])
{
WSADATA wsa;
SOCKET s;
struct sockaddr_in server;
char message[1024] , server_reply[2000];
int recv_size;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsa) != 0)
{
printf("Failed. Error Code : %d",WSAGetLastError());
return 1;
}
printf("Initialised.\n");
//Create a socket
if((s = socket(AF_INET , SOCK_STREAM , 0 )) == INVALID_SOCKET)
{
printf("Could not create socket : %d" , WSAGetLastError());
}
printf("Socket created.\n");
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons( 80 );
//Connect to remote server
if (connect(s , (struct sockaddr *)&server , sizeof(server)) < 0)
{
puts("connect error");
return 1;
}
puts("Connected");
// Work well with Get Method
// strcat(message, "GET /voleur/receiver.php?arg1=Hello HTTP/1.1\n");
strcpy(message, "POST /voleur/receiver.php HTTP/1.1\r\n");
strcat(message, "Host: 127.0.0.1:80\r\n");
strcat(message, "Content-Type: application/x-www-form-urlencoded\r\n");
strcat(message, "Content-Length: 16\r\n");
strcat(message, "Accept-Charset: utf-8\r\n\r\n");
strcat(message, "arg1=Hello World");
if( send(s , message , strlen(message) , 0) < 0)
{
puts("Send failed");
return 1;
}
puts("Data Send\n");
//Receive a reply from the server
if((recv_size = recv(s , server_reply , 2000 , 0)) == SOCKET_ERROR)
{
puts("recv failed");
}
puts("Reply received\n");
//Add a NULL terminating character to make it a proper string before printing
server_reply[recv_size] = '\0';
puts(server_reply);
return 0;
}
I have a simple code to send and receive ICMP packets like ping, everything works : my packet is sent and I received a result.
I have a problem in the recvfrom result, the ip dest/src in my buffer, isn't the server dest ip.
Result
$> ./my_ping qwant.com
IPv4: hdr-size=20 pkt-size=56 protocol=1 TTL=254 src=10.0.2.2 dest=172.17.0.2
But with the real ping:
$> ping qwant.com
PING qwant.com (194.187.168.99): 48 data bytes
56 bytes from 194.187.168.99: icmp_seq=0 ttl=61 time=101.742 ms
It's not the same TTL and ip
Code
Init struct addrinfo :
struct addrinfo hints;
struct addrinfo *a_info;
bzero(&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_ADDRCONFIG;
getaddrinfo(host, NULL, &hints, &a_info)
Init socket :
sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
setsockopt(sock, SOL_IP, IP_TTL, (void *)&val, sizeof(val);
Send & Receive while :
size_t i;
t_ping pack;
int count = 1;
struct iphdr buff;
while (TRUE)
{
bzero(&pack, sizeof(pack));
pack.head.type = 8;
pack.head.code = getpid();
pack.id = count++;
while (i < 15)
{
pack.seq[i] = i + '0';
i++;
}
pack.seq[i] = 0;
pack.head.chk = checksum(&pack, sizeof(pack));
ft_bzero((void *)&buff, sizeof(buff));
if (sendto(sock, &pack, sizeof(pack), 0, a_info->ai_addr, a_info->ai_addrlen) < 0)
perror("sendto");
if (recvfrom(sock, (void *)&buff, sizeof(buff), 0, a_info->ai_addr, &a_info->ai_addrlen) < 0)
perror("recvfrom");
display((void *)&buff);
sleep(1);
}
And finally my display func :
struct iphdr *ip = buff;
char src[INET6_ADDRSTRLEN];
char dest[INET6_ADDRSTRLEN];
inet_ntop( AF_INET, (void *)&ip->saddr, src, sizeof(src) );
inet_ntop( AF_INET, (void *)&ip->daddr, dest, sizeof(dest) );
printf("IPv%d: hdr-size=%d pkt-size=%d protocol=%d TTL=%d src=%s dest=%s\n",
ip->version,
ip->ihl*4,
ntohs(ip->tot_len),
ip->protocol,
ip->ttl,
src,
dest);
In my opinion, my buffer contains information about the last packet step (router -> my home) that explains why TTL value is 254 and why I found the same couple of IP with traceroute:
$> traceroute qwant.com
traceroute to qwant.com (194.187.168.99), 30 hops max, 60 byte packets
172.17.0.1 (172.17.0.1) 0.026 ms 0.011 ms 0.010 ms
10.0.2.2 (10.0.2.2) 0.149 ms 0.160 ms 0.156 ms
[...]
194.187.168.99 (194.187.168.99) 147.634 ms 147.506 ms 147.540 ms
Why is the information received not about my server target? How can I receive this information?
Solution :
I change my getaddrinfo call and my socket init :
getaddrinfo(stats.host, NULL, NULL, &addrinfo);
sd = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP);
setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val));
Next I have create 2 struct sockaddr_in : one for sendto and the 2nd for recvfrom.
struct sockaddr_in send;
struct sockaddr_in recv;
Now init the send struct for specify the destination at sendto, but no change recv : It was automaticly assigned during the first recvfrom call.
bzero(&send, sizeof(send));
send.sin_family = addrinfo->ai_family;
send.sin_port = 0;
send.sin_addr.s_addr = ((struct sockaddr_in *)addrinfo->ai_addr)->sin_addr.s_addr;
Finaly I have change my packet struct
struct packet
{
struct icmphdr hdr;
char msg[PACKETSIZE-sizeof(struct icmphdr)];
};
Now, just call sendto and recvfrom like that:
socklen_t len = sizeof(recv);
sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&send, sizeof(send));
recvfrom(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&recv, &len);
The Internet Assigned Numbers Authority (IANA) has reserved the
following three blocks of the IP address space for private networks:
10.0.0.0 - 10.255.255.255
172.16.0.0 - 172.31.255.255
192.168.0.0 - 192.168.255.255
172.17.0.2 is an address in of a private network. I guess your machine is inside this network, and also the server.
getaddrinfo() can return you more than one address. Try to run over all the responses and check if you get also the Internet address.
from man getaddrinfo:
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
break; /* Success */
close(sfd);
}
I am able to access resource from tomcat server using below URL from my browser,
http://localhost:8080/test/file1.xml
Request header:
Status Code:200 OK
Request Headersview parsed
GET /test/file1.xml HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.131 Safari/537.36
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Response Headersview parsed
Response header:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Accept-Ranges: bytes
ETag: W/"9-1399430961358"
Last-Modified: Wed, 07 May 2014 02:49:21 GMT
Content-Type: application/xml
Content-Length: 9
Date: Fri, 16 May 2014 16:37:10 GMT
but am unable to access the same resource using below windows client program, Can you please let me know the reason?
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdlib.h>
#include <stdio.h>
// Need to link with Ws2_32.lib, Mswsock.lib, and Advapi32.lib
#pragma comment (lib, "Ws2_32.lib")
#pragma comment (lib, "Mswsock.lib")
#pragma comment (lib, "AdvApi32.lib")
#define DEFAULT_BUFLEN 65536
int __cdecl main(int argc, char **argv)
{
WSADATA wsaData;
SOCKET ConnectSocket = INVALID_SOCKET;
struct addrinfo *result = NULL,
*ptr = NULL,
hints;
char *sendbuf = "GET /test/file1.xml HTTP/1.1";
char recvbuf[DEFAULT_BUFLEN];
int iResult;
int recvbuflen = DEFAULT_BUFLEN;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != 0) {
printf("WSAStartup failed with error: %d\n", iResult);
return 1;
}
ZeroMemory( &hints, sizeof(hints) );
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port
iResult = getaddrinfo("127.0.0.1", "8080", &hints, &result);
if ( iResult != 0 ) {
printf("getaddrinfo failed with error: %d\n", iResult);
WSACleanup();
return 1;
}
// Attempt to connect to an address until one succeeds
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {
// Create a SOCKET for connecting to server
ConnectSocket = socket(ptr->ai_family, ptr->ai_socktype,
ptr->ai_protocol);
if (ConnectSocket == INVALID_SOCKET) {
printf("socket failed with error: %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
// Connect to server.
iResult = connect( ConnectSocket, ptr->ai_addr, (int)ptr->ai_addrlen);
if (iResult == SOCKET_ERROR) {
closesocket(ConnectSocket);
ConnectSocket = INVALID_SOCKET;
continue;
}
break;
}
freeaddrinfo(result);
if (ConnectSocket == INVALID_SOCKET) {
printf("Unable to connect to server!\n");
WSACleanup();
return 1;
}
// Send an initial buffer
iResult = send( ConnectSocket, sendbuf, (int)strlen(sendbuf), 0 );
if (iResult == SOCKET_ERROR) {
printf("send failed with error: %d\n", WSAGetLastError());
closesocket(ConnectSocket);
WSACleanup();
return 1;
}
printf("Bytes Sent: %ld\n", iResult);
// Receive until the peer closes the connection
do {
iResult = recv(ConnectSocket, recvbuf, recvbuflen-1, 0);
if ( iResult > 0 ){
recvbuf[iResult]='\0';
printf("Bytes received: %d, httpresponse: %s\n", iResult,recvbuf);
}
else if ( iResult == 0 )
printf("Connection closed\n");
else
printf("recv failed with error: %d\n", WSAGetLastError());
} while( iResult > 0 );
// cleanup
closesocket(ConnectSocket);
WSACleanup();
return 0;
}
output is:
c:\code>client.exe
Bytes Sent: 28
Connection closed
This should work.
To send HTTP/1.0 request,
char *sendbuf = "GET /test/file1.xml HTTP/1.0\r\n\r\n ";
To send http 1.1 request,
char *sendbuf = "GET /test/file1.xml HTTP/1.1\r\nHost: localhost\r\n\r\n ";
The concept of virtual hosts allows more than one Web site on one system or Web server. HTTP/1.1 server supports so-called virtual hosts. Hence, in an HTTP/1.1 GET request, it is mandatory to include a request header called "Host", to select one of the virtual hosts.
I`m trying to send HTTP response to browser
char *reply =
"HTTP/1.1 200 OK\n"
"Date: Thu, 19 Feb 2009 12:27:04 GMT\n"
"Server: Apache/2.2.3\n"
"Last-Modified: Wed, 18 Jun 2003 16:05:58 GMT\n"
"ETag: \"56d-9989200-1132c580\"\n"
"Content-Type: text/html\n"
"Content-Length: 15\n"
"Accept-Ranges: bytes\n"
"Connection: close\n"
"\n"
"sdfkjsdnbfkjbsf";
int sd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8081);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sd,&addr,sizeof(addr))!=0)
{
printf("bind error\n");
}
if (listen(sd, 16)!=0)
{
printf("listen error\n");
}
for(;;)
{
int size = sizeof(addr);
int client = accept(sd, &addr, &size);
if (client > 0)
{
printf("client connected\n");
send(client, reply, sizeof(reply), 0);
}
}
but my browser cant understand this, waits for a long time and then print smth strange. I guess my response is wrong, but I dont know how to fix. Any ideas?
sizeof(reply) evaluates to the size of a char *, aka size of a pointer. Use strlen.
send(client, reply, strlen(reply), 0);