Added DNS Resolution feature to the client.

This commit is contained in:
Kaito 2018-05-16 18:14:02 +02:00
parent 355db7c65f
commit ee5aee6848
7 changed files with 117 additions and 44 deletions

View File

@ -5,7 +5,8 @@ to the LiteSpeed Client Library:
- Brian Prodoehl -- Docker file
- Amol Desphande -- Windows support
- Alexis La Goutte -- Travis-CI integration
- Bernhard Jaeger -- DNS Resolution
Thank you!
We welcome contributions in any form -- patches, issues, pull requests.

View File

@ -9,24 +9,25 @@ Usage Examples
Fetch Google's home page:
./http_client -H www.google.com -s 74.125.22.106:443 -p /
or even
./http_client -H www.google.co.uk -s 2a00:1450:4009:80c::2003:443 -p /
./http_client -H www.google.com -s 443 -p /
In the example above, -H specifies the domain; it is also used as the value
of SNI paramater in the handshake.
The IP address and the port number are specified using the -s flag.
The port number is specified using the -s flag.
The ip adress is determined automatically.
The -6 flag tells the program to use IPv6 instead of IPv4.
Note that -6 must be used before -s in order to work.
(Since www.google.com has different IP addresses in different regions, check
that you are using the correct IP address by resolving www.google.com first
by using nslookup, dig, ping, or some other tool.)
You can also specify a certain ip-address with the -s command.
Note that this example won't work everywhere since google has a lot of different ips.
You have to look up the correct one for yourself.
./http_client -H www.google.com -s 172.217.22.4:443 -p /
POST a file to calculate its CRC32 checksum:
./http_client -H www.litespeedtech.com -s 127.0.0.1:443 \
./http_client -H www.litespeedtech.com -s 443 \
-p /cgi-bin/crc32.cgi -P file-256M -M POST
HTTP/1.1 200 OK
@ -50,7 +51,7 @@ On the command line, I do
To submit several requests concurrently, one can use -n and -r options:
./http_client -H www.litespeedtech.com -s 127.0.0.1:443 \
./http_client -H www.litespeedtech.com -s 443 \
-p /cgi-bin/crc32.cgi -P file-256M -M POST -n 3 -r 10
This will open three parallel connections which will make ten POST

View File

@ -2,7 +2,6 @@
/*
* http_client.c -- A simple HTTP/QUIC client
*/
#ifndef WIN32
#include <arpa/inet.h>
#include <netinet/in.h>
@ -159,7 +158,6 @@ struct lsquic_stream_ctx {
struct lsquic_reader reader;
};
static lsquic_stream_ctx_t *
http_client_on_new_stream (void *stream_if_ctx, lsquic_stream_t *stream)
{
@ -313,7 +311,7 @@ http_client_on_read (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
unsigned char buf[0x200];
unsigned nreads = 0;
#ifdef WIN32
srand(GetTickCount());
srand(GetTickCount());
#endif
do
@ -409,6 +407,7 @@ usage (const char *prog)
"Usage: %s [opts]\n"
"\n"
"Options:\n"
" -6 MUST be entered before -s in order to work."
" -p PATH Path to request. May be specified more than once.\n"
" -n CONNS Number of concurrent connections. Defaults to 1.\n"
" -r NREQS Total number of requests to send. Defaults to 1.\n"
@ -421,6 +420,8 @@ usage (const char *prog)
" content-length\n"
" -K Discard server response\n"
" -I Abort on incomplete reponse from server\n"
" -6 IPv6 The client will try to connect via IPv6\n"
" if this flag is used. If not it will use IPv4.\n"
, prog);
}
@ -435,6 +436,8 @@ main (int argc, char **argv)
struct sport_head sports;
struct prog prog;
ipv6 = 0;
TAILQ_INIT(&sports);
memset(&client_ctx, 0, sizeof(client_ctx));
client_ctx.hcc_concurrency = 1;
@ -453,9 +456,12 @@ main (int argc, char **argv)
prog_init(&prog, LSENG_HTTP, &sports, &http_client_if, &client_ctx);
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "r:R:IKu:EP:M:n:H:p:h")))
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "6r:R:IKu:EP:M:n:H:p:h")))
{
switch (opt) {
case '6':
ipv6 = 1;
break;
case 'I':
client_ctx.hcc_flags |= HCC_ABORT_ON_INCOMPLETE;
break;
@ -499,7 +505,7 @@ main (int argc, char **argv)
break;
case 'H':
client_ctx.hostname = optarg;
prog.prog_hostname = optarg; /* Pokes into prog */
prog.prog_hostname = optarg; /* Pokes into prog */
break;
case 'p':
pe = calloc(1, sizeof(*pe));

View File

@ -1,6 +1,7 @@
/* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */
#include <assert.h>
#ifndef WIN32
#include <arpa/inet.h>
#include <netinet/in.h>
#include <signal.h>
#endif
@ -82,12 +83,12 @@ void
prog_print_common_options (const struct prog *prog, FILE *out)
{
fprintf(out,
" -s SVCPORT Service port. Takes on the form of IPv4:port or\n"
" IPv6:port. For example:\n"
" 127.0.0.1:12345\n"
" ::1:12345\n"
" If no -s option is given, 0.0.0.0:12345 address\n"
" -s SVCPORT The port on which the client should connect.\n"
" If no -s option is given, port 443\n"
" is used.\n"
" You can also specify an certain ipadress to be used here.\n"
" To do that enter an ipadress and the port seperated by :\n"
" e.g -s ::1:12345 or -s 0.0.0.0:12345 or -s 443 or -s example.com:443\n"
#if LSQUIC_DONTFRAG_SUPPORTED
" -D Set `do not fragment' flag on outgoing UDP packets\n"
#endif
@ -175,6 +176,7 @@ prog_set_opt (struct prog *prog, int opt, const char *arg)
case 'o':
return set_engine_option(&prog->prog_settings,
&prog->prog_version_cleared, arg);
case 's':
if (0 == (prog->prog_engine_flags & LSENG_SERVER) &&
!TAILQ_EMPTY(prog->prog_sports))
@ -371,7 +373,7 @@ prog_prep (struct prog *prog)
if (TAILQ_EMPTY(prog->prog_sports))
{
s = prog_add_sport(prog, "0.0.0.0:12345");
s = prog_add_sport(prog, "443");
if (0 != s)
return -1;
}

View File

@ -6,6 +6,8 @@
#ifndef PROG_H
#define PROG_H 1
int ipv6; /*True = Program uses ipv6, False = Program uses ipv4*/
struct event;
struct event_base;
struct lsquic_hash;

View File

@ -146,6 +146,45 @@ static void getExtensionPtrs()
#endif
int get_Ip_from_DNS(const char* hostname, struct service_port * sport, const char* port, int version)
{
struct sockaddr_in *const sa4 = (void *)&sport->sas;
struct sockaddr_in6 *const sa6 = (void *)&sport->sas;
struct addrinfo hints, *servinfo;
int rv;
char ip[INET6_ADDRSTRLEN];
memset(&hints, 0, sizeof(hints));
if (version)
hints.ai_family = AF_INET6;
else
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(hostname, port, &hints, &servinfo)) != 0){
LSQ_ERROR("getaddrinfo: %s\n", gai_strerror(rv));
freeaddrinfo(servinfo);
return 1;
}
if (version){ /*Ipv6*/
memset(sa6, 0, sizeof(*sa6));
sa6->sin6_addr = ((struct sockaddr_in6*) servinfo->ai_addr)->sin6_addr;
sa6->sin6_family = AF_INET6;
sa6->sin6_port = htons(atoi(port));
inet_ntop(AF_INET6, &sa6->sin6_addr, ip, INET6_ADDRSTRLEN);
}
else{/*Ipv4*/
sa4->sin_addr = ((struct sockaddr_in *) servinfo->ai_addr)->sin_addr;
sa4->sin_family = AF_INET;
sa4->sin_port = htons(atoi(port));
inet_ntop(AF_INET, &sa4->sin_addr, ip, INET6_ADDRSTRLEN);
}
memcpy(sport->host, ip, sizeof(ip));
freeaddrinfo(servinfo);
return 0;
}
static struct packets_in *
allocate_packets_in (SOCKET_TYPE fd)
@ -225,38 +264,51 @@ sport_new (const char *optarg, struct prog *prog)
if (if_name)
{
strncpy(sport->if_name, if_name + 1, sizeof(sport->if_name) - 1);
sport->if_name[ sizeof(sport->if_name) - 1 ] = '\0';
sport->if_name[sizeof(sport->if_name) - 1] = '\0';
*if_name = '\0';
}
else
sport->if_name[0] = '\0';
#endif
char *port = strrchr(addr, ':');
if (!port)
goto err;
*port = '\0';
++port;
if ((uintptr_t) port - (uintptr_t) addr > sizeof(sport->host))
goto err;
memcpy(sport->host, addr, port - addr);
if (!port){/*IpAdress wasn't specified by the user*/
if (get_Ip_from_DNS(prog->prog_hostname, sport, addr, ipv6) == 1)
goto err;
}
else {
*port = '\0';
++port;
struct sockaddr_in *const sa4 = (void *)&sport->sas;
struct sockaddr_in6 *const sa6 = (void *)&sport->sas;
if (inet_pton(AF_INET, addr, &sa4->sin_addr)){
sa4->sin_family = AF_INET;
sa4->sin_port = htons(atoi(port));
struct sockaddr_in *const sa4 = (void *) &sport->sas;
struct sockaddr_in6 *const sa6 = (void *) &sport->sas;
if (inet_pton(AF_INET, addr, &sa4->sin_addr)) {
sa4->sin_family = AF_INET;
sa4->sin_port = htons(atoi(port));
} else if (memset(sa6, 0, sizeof(*sa6)),
inet_pton(AF_INET6, addr, &sa6->sin6_addr)) {
sa6->sin6_family = AF_INET6;
sa6->sin6_port = htons(atoi(port));
} else
goto err;
if ((uintptr_t)port - (uintptr_t)addr > sizeof(sport->host))
goto err;
memcpy(sport->host, addr, port - addr);
}
else if (memset(sa6, 0, sizeof(*sa6)), inet_pton(AF_INET6, addr, &sa6->sin6_addr)){
sa6->sin6_family = AF_INET6;
sa6->sin6_port = htons(atoi(port));
if ((uintptr_t)port - (uintptr_t)addr > sizeof(sport->host))
goto err;
memcpy(sport->host, addr, port - addr);
}
else if (get_Ip_from_DNS(addr, sport, port, ipv6) != 0)
goto err;
}
free(addr);
sport->sp_prog = prog;
return sport;
err:
err:
LSQ_ERROR("Couldn't resolve hostname or ip-address");
free(sport);
free(addr);
return NULL;
@ -404,7 +456,7 @@ read_one_packet (struct read_iter *iter)
if (SOCKET_ERROR == socket_ret) {
if (WSAEWOULDBLOCK != WSAGetLastError())
LSQ_ERROR("recvmsg: %d", WSAGetLastError());
return ROP_ERROR;
return ROP_ERROR;
}
#endif

View File

@ -106,4 +106,13 @@ create_lsquic_reader_ctx (const char *filename);
void
destroy_lsquic_reader_ctx (struct reader_ctx *ctx);
/*Function resolves a Hostname into an Ip Adress
Parameters:
-hostname the URL of the website
-sport the service port structure that stores the ip
-port the port of the connection
-version 0 for ipv4 and 1 for ipv6
*/
int
get_Ip_from_DNS(const char* hostname, struct service_port * sport, const char* port, int version);
#endif