Blame genhash/main.c

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
}