|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Soft: Perform a GET query to a remote HTTP/HTTPS server.
|
|
Packit |
c22fc9 |
* Set a timer to compute global remote server response
|
|
Packit |
c22fc9 |
* time.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Part: Main entry point.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Authors: Alexandre Cassen, <acassen@linux-vs.org>
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
c22fc9 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
c22fc9 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
Packit |
c22fc9 |
* See the GNU General Public License for more details.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* This program is free software; you can redistribute it and/or
|
|
Packit |
c22fc9 |
* modify it under the terms of the GNU General Public License
|
|
Packit |
c22fc9 |
* as published by the Free Software Foundation; either version
|
|
Packit |
c22fc9 |
* 2 of the License, or (at your option) any later version.
|
|
Packit |
c22fc9 |
*
|
|
Packit |
c22fc9 |
* Copyright (C) 2001-2017 Alexandre Cassen, <acassen@gmail.com>
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#include "config.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* system includes */
|
|
Packit |
c22fc9 |
#include <sys/stat.h>
|
|
Packit |
c22fc9 |
#include <sys/wait.h>
|
|
Packit |
c22fc9 |
#include <stdio.h>
|
|
Packit |
c22fc9 |
#include <sys/socket.h>
|
|
Packit |
c22fc9 |
#include <arpa/inet.h>
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* keepalived includes */
|
|
Packit |
c22fc9 |
#include "utils.h"
|
|
Packit |
c22fc9 |
#include "signals.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* genhash includes */
|
|
Packit |
c22fc9 |
#include "include/main.h"
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* global var */
|
|
Packit |
c22fc9 |
REQ *req = NULL;
|
|
Packit |
c22fc9 |
int exit_code;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Terminate handler */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
sigend(__attribute__((unused)) void *v, __attribute__((unused)) int sig)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
/* register the terminate thread */
|
|
Packit |
c22fc9 |
thread_add_terminate_event(master);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Initialize signal handler */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
signal_init(void)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
signal_set(SIGHUP, sigend, NULL);
|
|
Packit |
c22fc9 |
signal_set(SIGINT, sigend, NULL);
|
|
Packit |
c22fc9 |
signal_set(SIGTERM, sigend, NULL);
|
|
Packit |
c22fc9 |
signal_ignore(SIGPIPE);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Usage function */
|
|
Packit |
c22fc9 |
static void
|
|
Packit |
c22fc9 |
usage(const char *prog)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
enum feat_hashes i;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
fprintf(stderr, VERSION_STRING);
|
|
Packit |
c22fc9 |
fprintf(stderr,
|
|
Packit |
c22fc9 |
"Usage:\n"
|
|
Packit |
c22fc9 |
" %1$s -s server-address -p port -u url\n"
|
|
Packit |
c22fc9 |
" %1$s -S -s server-address -p port -u url\n"
|
|
Packit |
c22fc9 |
" %1$s -h\n" " %1$s -r\n\n", prog);
|
|
Packit |
c22fc9 |
fprintf(stderr,
|
|
Packit |
c22fc9 |
"Commands:\n"
|
|
Packit |
c22fc9 |
"Either long or short options are allowed.\n"
|
|
Packit |
c22fc9 |
" %1$s --use-ssl -S Use SSL connection to remote server.\n"
|
|
Packit |
c22fc9 |
#ifdef _HAVE_SSL_SET_TLSEXT_HOST_NAME_
|
|
Packit |
c22fc9 |
" %1$s --use-sni -I Use SNI during SSL handshake (uses virtualhost setting; see -V).\n"
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
" %1$s --server -s Use the specified remote server address.\n"
|
|
Packit |
c22fc9 |
" %1$s --port -p Use the specified remote server port.\n"
|
|
Packit |
c22fc9 |
" %1$s --url -u Use the specified remote server url.\n"
|
|
Packit |
c22fc9 |
" %1$s --use-virtualhost -V Use the specified virtualhost in GET query.\n"
|
|
Packit |
c22fc9 |
" %1$s --hash -H Use the specified hash algorithm.\n"
|
|
Packit |
c22fc9 |
" %1$s --verbose -v Use verbose mode output.\n"
|
|
Packit |
c22fc9 |
" %1$s --help -h Display this short inlined help screen.\n"
|
|
Packit |
c22fc9 |
" %1$s --release -r Display the release number.\n"
|
|
Packit |
c22fc9 |
" %1$s --fwmark -m Use the specified FW mark.\n",
|
|
Packit |
c22fc9 |
prog);
|
|
Packit |
c22fc9 |
fprintf(stderr, "\nSupported hash algorithms:\n");
|
|
Packit |
c22fc9 |
for (i = hash_first; i < hash_guard; i++)
|
|
Packit |
c22fc9 |
fprintf(stderr, " %s%s\n",
|
|
Packit |
c22fc9 |
hashes[i].id, i == hash_default ? " (default)": "");
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Command line parser */
|
|
Packit |
c22fc9 |
static int
|
|
Packit |
c22fc9 |
parse_cmdline(int argc, char **argv, REQ * req_obj)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
int c;
|
|
Packit |
c22fc9 |
enum feat_hashes i;
|
|
Packit |
c22fc9 |
struct addrinfo hint, *res = NULL;
|
|
Packit |
c22fc9 |
int ret;
|
|
Packit |
c22fc9 |
void *ptr;
|
|
Packit |
c22fc9 |
char *endptr;
|
|
Packit |
c22fc9 |
long port_num;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
memset(&hint, '\0', sizeof hint);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
hint.ai_family = PF_UNSPEC;
|
|
Packit |
c22fc9 |
hint.ai_flags = AI_NUMERICHOST;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
struct option long_options[] = {
|
|
Packit |
c22fc9 |
{"release", no_argument, 0, 'r'},
|
|
Packit |
c22fc9 |
{"help", no_argument, 0, 'h'},
|
|
Packit |
c22fc9 |
{"verbose", no_argument, 0, 'v'},
|
|
Packit |
c22fc9 |
{"use-ssl", no_argument, 0, 'S'},
|
|
Packit |
c22fc9 |
#ifdef _HAVE_SSL_SET_TLSEXT_HOST_NAME_
|
|
Packit |
c22fc9 |
{"use-sni", no_argument, 0, 'I'},
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
{"server", required_argument, 0, 's'},
|
|
Packit |
c22fc9 |
{"hash", required_argument, 0, 'H'},
|
|
Packit |
c22fc9 |
{"use-virtualhost", required_argument, 0, 'V'},
|
|
Packit |
c22fc9 |
{"port", required_argument, 0, 'p'},
|
|
Packit |
c22fc9 |
{"url", required_argument, 0, 'u'},
|
|
Packit |
c22fc9 |
{"fwmark", required_argument, 0, 'm'},
|
|
Packit |
c22fc9 |
{0, 0, 0, 0}
|
|
Packit |
c22fc9 |
};
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Parse the command line arguments */
|
|
Packit |
c22fc9 |
while ((c = getopt_long (argc, argv, "rhvSs:H:V:p:u:m:"
|
|
Packit |
c22fc9 |
#ifdef _HAVE_SSL_SET_TLSEXT_HOST_NAME_
|
|
Packit |
c22fc9 |
"I"
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
, long_options, NULL)) != EOF) {
|
|
Packit |
c22fc9 |
switch (c) {
|
|
Packit |
c22fc9 |
case 'r':
|
|
Packit |
c22fc9 |
fprintf(stderr, VERSION_STRING);
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case 'h':
|
|
Packit |
c22fc9 |
usage(argv[0]);
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case 'v':
|
|
Packit |
c22fc9 |
req_obj->verbose = 1;
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case 'S':
|
|
Packit |
c22fc9 |
req_obj->ssl = 1;
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
#ifdef _HAVE_SSL_SET_TLSEXT_HOST_NAME_
|
|
Packit |
c22fc9 |
case 'I':
|
|
Packit |
c22fc9 |
req_obj->sni = 1;
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
case 's':
|
|
Packit |
c22fc9 |
if ((ret = getaddrinfo(optarg, NULL, &hint, &res)) != 0){
|
|
Packit |
c22fc9 |
fprintf(stderr, "server should be an IP, not %s\n", optarg);
|
|
Packit |
c22fc9 |
return CMD_LINE_ERROR;
|
|
Packit |
c22fc9 |
} else {
|
|
Packit |
c22fc9 |
if(res->ai_family == AF_INET) {
|
|
Packit |
c22fc9 |
req_obj->dst = res;
|
|
Packit |
c22fc9 |
ptr = &((struct sockaddr_in *) res->ai_addr)->sin_addr;
|
|
Packit |
c22fc9 |
inet_ntop (res->ai_family, ptr, req_obj->ipaddress, INET_ADDRSTRLEN);
|
|
Packit |
c22fc9 |
} else if (res->ai_family == AF_INET6) {
|
|
Packit |
c22fc9 |
req_obj->dst = res;
|
|
Packit |
c22fc9 |
ptr = &((struct sockaddr_in6 *) res->ai_addr)->sin6_addr;
|
|
Packit |
c22fc9 |
inet_ntop (res->ai_family, ptr, req_obj->ipaddress, INET6_ADDRSTRLEN);
|
|
Packit |
c22fc9 |
} else {
|
|
Packit |
c22fc9 |
fprintf(stderr, "server should be an IP, not %s\n", optarg);
|
|
Packit |
c22fc9 |
return CMD_LINE_ERROR;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case 'H':
|
|
Packit |
c22fc9 |
for (i = hash_first; i < hash_guard; i++)
|
|
Packit |
c22fc9 |
if (!strcasecmp(optarg, hashes[i].id)) {
|
|
Packit |
c22fc9 |
req_obj->hash = i;
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
if (i == hash_guard) {
|
|
Packit |
c22fc9 |
fprintf(stderr, "unknown hash algorithm: %s\n", optarg);
|
|
Packit |
c22fc9 |
return CMD_LINE_ERROR;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case 'V':
|
|
Packit |
c22fc9 |
req_obj->vhost = optarg;
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case 'p':
|
|
Packit |
c22fc9 |
port_num = strtol(optarg, &endptr, 10);
|
|
Packit |
c22fc9 |
if (*endptr || port_num <= 0 || port_num > 65535) {
|
|
Packit |
c22fc9 |
fprintf(stderr, "invalid port number '%s'\n", optarg);
|
|
Packit |
c22fc9 |
return CMD_LINE_ERROR;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
req_obj->addr_port = htons(port_num);
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case 'u':
|
|
Packit |
c22fc9 |
req_obj->url = optarg;
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
case 'm':
|
|
Packit |
c22fc9 |
#ifdef _WITH_SO_MARK_
|
|
Packit |
c22fc9 |
req_obj->mark = (unsigned)strtoul(optarg + strspn(optarg, " \t"), &endptr, 10);
|
|
Packit |
c22fc9 |
if (*endptr || optarg[strspn(optarg, " \t")] == '-') {
|
|
Packit |
c22fc9 |
fprintf(stderr, "invalid fwmark '%s'\n", optarg);
|
|
Packit |
c22fc9 |
return CMD_LINE_ERROR;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
#else
|
|
Packit |
c22fc9 |
fprintf(stderr, "genhash built without fwmark support\n");
|
|
Packit |
c22fc9 |
return CMD_LINE_ERROR;
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
break;
|
|
Packit |
c22fc9 |
default:
|
|
Packit |
c22fc9 |
usage(argv[0]);
|
|
Packit |
c22fc9 |
return CMD_LINE_ERROR;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* check unexpected arguments */
|
|
Packit |
c22fc9 |
if (optind < argc) {
|
|
Packit |
c22fc9 |
fprintf(stderr, "Unexpected argument(s): ");
|
|
Packit |
c22fc9 |
while (optind < argc)
|
|
Packit |
c22fc9 |
printf("%s ", argv[optind++]);
|
|
Packit |
c22fc9 |
printf("\n");
|
|
Packit |
c22fc9 |
return CMD_LINE_ERROR;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
return CMD_LINE_SUCCESS;
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
int
|
|
Packit |
c22fc9 |
main(int argc, char **argv)
|
|
Packit |
c22fc9 |
{
|
|
Packit |
c22fc9 |
char *url_default = "/";
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
#ifdef _MEM_CHECK_
|
|
Packit |
c22fc9 |
mem_log_init("Genhash", "Genhash process");
|
|
Packit |
c22fc9 |
enable_mem_log_termination();
|
|
Packit |
c22fc9 |
#endif
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Allocate the room */
|
|
Packit |
c22fc9 |
req = (REQ *) MALLOC(sizeof (REQ));
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Preset (potentially) non-zero defaults */
|
|
Packit |
c22fc9 |
req->hash = hash_default;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Command line parser */
|
|
Packit |
c22fc9 |
if (!parse_cmdline(argc, argv, req)) {
|
|
Packit |
c22fc9 |
FREE(req);
|
|
Packit |
c22fc9 |
exit(1);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Check minimum configuration need */
|
|
Packit |
c22fc9 |
if (!req->dst && !req->addr_port && !req->url) {
|
|
Packit |
c22fc9 |
freeaddrinfo(req->dst);
|
|
Packit |
c22fc9 |
FREE(req);
|
|
Packit |
c22fc9 |
exit(1);
|
|
Packit |
c22fc9 |
}
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
if(!req->url)
|
|
Packit |
c22fc9 |
req->url = url_default;
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Init the reference timer */
|
|
Packit |
c22fc9 |
req->ref_time = timer_long(timer_now());
|
|
Packit |
c22fc9 |
DBG("Reference timer = %lu\n", req->ref_time);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Init SSL context */
|
|
Packit |
c22fc9 |
init_ssl();
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Create the master thread */
|
|
Packit |
c22fc9 |
master = thread_make_master();
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Signal handling initialization */
|
|
Packit |
c22fc9 |
signal_init();
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Register the GET request */
|
|
Packit |
c22fc9 |
init_sock();
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/*
|
|
Packit |
c22fc9 |
* Processing the master thread queues,
|
|
Packit |
c22fc9 |
* return and execute one ready thread.
|
|
Packit |
c22fc9 |
* Run until error, used for debuging only.
|
|
Packit |
c22fc9 |
* Note that not calling launch_thread_scheduler()
|
|
Packit |
c22fc9 |
* does not activate SIGCHLD handling, however,
|
|
Packit |
c22fc9 |
* this is no issue here.
|
|
Packit |
c22fc9 |
*/
|
|
Packit |
c22fc9 |
process_threads(master);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* Finalize output informations */
|
|
Packit |
c22fc9 |
if (req->verbose)
|
|
Packit |
c22fc9 |
printf("Global response time for [%s] =%lu\n",
|
|
Packit |
c22fc9 |
req->url, req->response_time - req->ref_time);
|
|
Packit |
c22fc9 |
|
|
Packit |
c22fc9 |
/* exit cleanly */
|
|
Packit |
c22fc9 |
thread_destroy_master(master);
|
|
Packit |
c22fc9 |
SSL_CTX_free(req->ctx);
|
|
Packit |
c22fc9 |
free_sock(sock);
|
|
Packit |
c22fc9 |
freeaddrinfo(req->dst);
|
|
Packit |
c22fc9 |
FREE(req);
|
|
Packit |
c22fc9 |
exit(exit_code);
|
|
Packit |
c22fc9 |
}
|