HTTP for IPv6 from client side

By | January 12, 2021

IPv6 works in the same way as IPv4 address, however IPv6 addresses must be enclosed in square brackets. It is required to avoid conflict with colon character in protocol specification: http:, https:, ftp:. To test IPv6 installed Apache server on Ubuntu device and enable IPv6. The IPv6 of my Ubuntu device is “2002:ac7:fa01:c71e:250:56ff:fe98:bebd”. First I tried to connect from Google Chrome client, and it looks like this:
IPv6 in web browser address line


Then I did the same using wget:


# wget -d http://[2002:ac7:fa01:c71e:250:56ff:fe98:bebd] /
DEBUG output created by Wget 1.19.5 on linux-gnu.

Reading HSTS entries from /root/.wget-hsts
URI encoding = ‘UTF-8’
Converted file name ‘index.html’ (UTF-8) -> ‘index.html’ (UTF-8)
–2021-01-11 16:47:33– http://[2002:ac7:fa01:c71e:250:56ff:fe98:bebd]/
Connecting to [2002:ac7:fa01:c71e:250:56ff:fe98:bebd]:80… connected.
Created socket 3.
Releasing 0x0000555e14c0a110 (new refcount 0).
Deleting unused 0x0000555e14c0a110.

—request begin—
GET / HTTP/1.1
User-Agent: Wget/1.19.5 (linux-gnu)
Accept: */*
Accept-Encoding: identity
Host: [2002:ac7:fa01:c71e:250:56ff:fe98:bebd]
Connection: Keep-Alive

—request end—
HTTP request sent, awaiting response…
—response begin—
HTTP/1.1 200 OK
Date: Mon, 11 Jan 2021 22:47:33 GMT
Server: Apache/2.4.29 (Ubuntu)
Last-Modified: Thu, 28 May 2020 21:22:49 GMT
ETag: “2aa6-5a6bbee338df8”
Accept-Ranges: bytes
Content-Length: 10918
Vary: Accept-Encoding
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

—response end—
200 OK
Registered socket 3 for persistent reuse.
Length: 10918 (11K) [text/html]
Saving to: ‘index.html’

index.html 100%[===================>] 10.66K –.-KB/s in 0s

2021-01-11 16:47:33 (251 MB/s) – ‘index.html’ saved [10918/10918]

And finally I wrote my own HTTP IPv6 client:


// HTTP IPv6 Client. tcpc6.cpp
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
int main(int n, char ** s)
{
   const char httpRequestFormat[] = "GET / HTTP/1.1\r\n"
      "Host: [%s]\r\n\r\n";
   const char ipv6addr[] = "2002:ac7:fa01:c71e:250:56ff:fe98:bebd";
   struct sockaddr_in saddr;
   struct addrinfo hints, *res;
   memset (&hints, 0, sizeof (hints));
   hints.ai_family = AF_INET6;
   hints.ai_socktype = SOCK_STREAM;
   hints.ai_flags |= AI_NUMERICSERV;
   int rc = getaddrinfo (ipv6addr, NULL, &hints, &res);
   if (rc != 0)
   {
      perror ("getaddrinfo");
      return -1;
   }
   int sck = socket(AF_INET6, SOCK_STREAM, 0);
   if( sck < 0)
   {
      perror("Cannot create socket\n");
      return -1;
   }
   ((struct sockaddr_in*)res[0].ai_addr)->sin_port = htons(80);
   rc = connect (sck, res[0].ai_addr, res[0].ai_addrlen);
   if( rc < 0)
   {
      perror("Cannot connect socket\n");
      return -1;
   }
   int len = strlen(httpRequestFormat) + strlen(ipv6addr) + 1;
   char * httpStr = new char[len*2];
   sprintf(httpStr, httpRequestFormat, ipv6addr);
   printf("Request:\n%s\n", httpStr);
   rc = send(sck, httpStr, len, 0);
   if( rc < 0)
   {
      perror("Cannot send to server\n");
      return -1;
   }
   memset(httpStr,0,len*2);
   rc = recv(sck, httpStr, len*2, 0);
   if( rc < 0)
   {
      perror("Cannot receive from server\n");
      return -1;
   }
   char * lf = strchr(httpStr, 10);
   if(lf != NULL)
      *lf = ‘\0’;
   printf("Response:\n%s\n", httpStr);
   delete[] httpStr;
   return 0;
}

The result:


# ./tcpc6
Request:
GET / HTTP/1.1
Host: [2002:ac7:fa01:c71e:250:56ff:fe98:bebd]

Response:
HTTP/1.1 200 OK

Leave a Reply

Your email address will not be published. Required fields are marked *