diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index d28e14e..168b91d 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -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. diff --git a/EXAMPLES.txt b/EXAMPLES.txt index 9623de6..dcb7fb6 100644 --- a/EXAMPLES.txt +++ b/EXAMPLES.txt @@ -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 diff --git a/test/http_client.c b/test/http_client.c index 5a20807..91dd826 100644 --- a/test/http_client.c +++ b/test/http_client.c @@ -2,7 +2,6 @@ /* * http_client.c -- A simple HTTP/QUIC client */ - #ifndef WIN32 #include #include @@ -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)); diff --git a/test/prog.c b/test/prog.c index f52a5bd..e0d958e 100644 --- a/test/prog.c +++ b/test/prog.c @@ -1,6 +1,7 @@ /* Copyright (c) 2017 - 2018 LiteSpeed Technologies Inc. See LICENSE. */ #include #ifndef WIN32 +#include #include #include #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; } diff --git a/test/prog.h b/test/prog.h index 852f8e6..438542d 100644 --- a/test/prog.h +++ b/test/prog.h @@ -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; diff --git a/test/test_common.c b/test/test_common.c index b9f212a..05e84f0 100644 --- a/test/test_common.c +++ b/test/test_common.c @@ -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 diff --git a/test/test_common.h b/test/test_common.h index 3e8ffff..263e3d1 100644 --- a/test/test_common.h +++ b/test/test_common.h @@ -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