--- /dev/null
+/*
+ * @file protomod_url.c
+ * @brief protocol module of HTTP.
+ * @brief this module provide session persistence by URL.
+ *
+ * L7VSD: Linux Virtual Server for Layer7 Load Balancing
+ * Copyright (C) 2008 NTT COMWARE Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ **********************************************************************/
+
+#define __STDC_LIMIT_MACROS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <getopt.h>
+#include "l7vs_service.h"
+#include "l7vs_conn.h"
+#include "l7vs_dest.h"
+#include "l7vs_module.h"
+#include "module_http.h"
+#include <fnmatch.h>
+
+#include <iostream>
+#ifdef USE_BOOST_XPRESSIVE
+ #include <boost/xpressive/xpressive.hpp>
+#else
+ #include <boost/regex.hpp>
+#endif
+
+#define SERVICE_ARG_MAXSIZE (512)
+#define PATTERN_MATCH_MAXSIZE (128)
+#define REGEX_PATTERN_MATCH_MAXSIZE (32)
+#define URL_SERVICE_NUMBER (128)
+#define X_FORWARDED_FOR_LENGTH (48)
+
+struct l7vs_url_service {
+ handle_t service_handle;
+ char pattern_match[PATTERN_MATCH_MAXSIZE];
+ char uri_pattern_match[REGEX_PATTERN_MATCH_MAXSIZE];
+ char host_pattern_match[REGEX_PATTERN_MATCH_MAXSIZE];
+ int forwarded_for;
+#ifdef USE_BOOST_XPRESSIVE
+ boost::xpressive::sregex uri_regex;
+ boost::xpressive::sregex host_regex;
+#else
+ boost::regex uri_regex;
+ boost::regex host_regex;
+#endif
+ int reschedule;
+};
+
+struct l7vs_url_service_arg {
+ char pattern_match[PATTERN_MATCH_MAXSIZE];
+ char uri_pattern_match[REGEX_PATTERN_MATCH_MAXSIZE];
+ char host_pattern_match[REGEX_PATTERN_MATCH_MAXSIZE];
+ int forwarded_for;
+ int reschedule;
+};
+
+static void fini(void);
+static int create(void*, handle_t);
+static void* create_sa(struct l7vs_service_arg*);
+static int compare(handle_t, handle_t);
+static int match_cldata(struct l7vs_service*, struct l7vs_conn*,
+ char*, size_t*, struct l7vs_dest**, int*);
+static int analyze_rsdata(struct l7vs_service*, struct l7vs_conn*,
+ char*, size_t*);
+static int destroy(handle_t);
+static void destroy_sa(void**);
+static int service_arg(struct l7vs_service_arg_multi*, handle_t);
+static int parse(void*, int, char**);
+
+static struct l7vs_url_service *l7vs_protomod_url_search_service(handle_t);
+static struct l7vs_url_service *l7vs_protomod_url_create_service();
+static struct l7vs_url_service *l7vs_protomod_url_create_temp_service();
+
+static void l7vs_url_service_c_str(char*, struct l7vs_url_service*);
+static void l7vs_url_service_arg_c_str(char*, struct l7vs_url_service_arg*);
+
+struct l7vs_url_service *url_service_list[URL_SERVICE_NUMBER];
+
+static struct l7vs_protomod url_protomod = {
+ NULL, /* handle */
+ "url", /* modname */
+ 0, /* refcnt */
+ 0, /* fast schedule */
+ create, /* create function */
+ compare, /* compare function */
+ match_cldata, /* match_cldata function */
+ analyze_rsdata, /* analyze_rsdata function */
+ destroy, /* destroy function */
+ fini, /* fini function */
+ create_sa, /* create_sa function */
+ service_arg, /* service_arg function */
+ parse, /* parse function */
+ destroy_sa, /* destroy_sa function */
+ NULL, /* initialize function */
+ NULL, /* finalize function */
+ NULL, /* get_log_level function */
+ NULL, /* put_log_debug function */
+ NULL, /* put_log_info function */
+ NULL, /* put_log_warn function */
+ NULL, /* put_log_error function */
+ NULL /* put_log_fatal function */
+};
+
+/*!
+ * Protocol module initialize function. This function run when dlopen and dlsym at first time.
+ * @param[in] handle dlopen's handle
+ * @return l7vs_protomod struct
+ */
+extern "C" struct l7vs_protomod *
+init(void *handle)
+{
+ struct l7vs_protomod* return_value = NULL;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,135,
+ "in_function: struct l7vs_protomod* init(void* handle): handle=%p", handle);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check null */
+ if (handle == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,117, "Arg(handle) is NULL pointer.");
+ goto init_out;
+ }
+
+ /* initialize url service list */
+ memset(url_service_list, 0, sizeof(struct l7vs_url_service *) * URL_SERVICE_NUMBER);
+ /* set dlopen's handle */
+ url_protomod.handle = handle;
+
+ return_value = &url_protomod;
+
+init_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char protomod_str[DEBUG_STR_LEN] = {0};
+ l7vs_protomod_c_str(protomod_str, &url_protomod);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,136,
+ "out_function: struct l7vs_protomod* init(void* handle): return=&(%s)", protomod_str);
+ }
+ /*------ DEBUG LOG END ------*/
+ return return_value;
+}
+
+/*!
+ * Protocol module finalize function. free all url service list just in case.
+ * @param void
+ * @return void
+ */
+static void
+fini(void)
+{
+ /* url service list counter */
+ int service_number = 0;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,137, "in_function: void fini(void)");
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check all url service list */
+ for (service_number = 0; service_number < URL_SERVICE_NUMBER; ++service_number) {
+ /* if pointer that does not point NULL exists ... */
+ if (url_service_list[service_number] != NULL) {
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,34, "free: %p",
+ url_service_list[service_number]);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* free and points NULL */
+ free(url_service_list[service_number]);
+ url_service_list[service_number] = NULL;
+ }
+ }
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,138, "out_function: void fini(void)");
+ }
+ /*------ DEBUG LOG END ------*/
+}
+
+/*!
+ * Create url service struct.
+ * @param url_arg url service argument struct
+ * @param service_handle a unique service ID
+ * @retval 0 successfully create url service.
+ * @retval -1 some errors occur.
+ */
+static int
+create(void *url_arg, handle_t service_handle)
+{
+ struct l7vs_url_service *url_service;
+ struct l7vs_url_service_arg *url_service_arg;
+ int return_value = 0;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char url_arg_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_arg_c_str(url_arg_str, (struct l7vs_url_service_arg*) url_arg);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,139,
+ "in_function: int create(void* url_arg, handle_t service_handle):url_arg=&(%s), "
+ "service_handle=%d", url_arg_str, service_handle);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check null */
+ if (url_arg == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,118, "Arg(url_arg) is NULL pointer.");
+ return_value = -1;
+ goto create_out;
+ }
+
+ if (service_handle != TEMP_SERVICEHANDLE) {
+ /* search empty url service list and create url service */
+ url_service = l7vs_protomod_url_create_service();
+ } else {
+ /* create temporary url service */
+ url_service = l7vs_protomod_url_create_temp_service();
+ }
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char url_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_c_str(url_str, url_service);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,140, "pointer assign: url_service=&(%s)",
+ url_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ if (url_service == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,119, "Could not make url service.");
+ return_value = -1;
+ goto create_out;
+ }
+
+ url_service_arg = (struct l7vs_url_service_arg *) url_arg;
+
+ /* set service handle, pattern match and reschedule flag */
+ url_service->service_handle = service_handle;
+ strncpy(url_service->pattern_match, url_service_arg->pattern_match, PATTERN_MATCH_MAXSIZE);
+ strncpy(url_service->uri_pattern_match, url_service_arg->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE);
+ strncpy(url_service->host_pattern_match, url_service_arg->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE);
+ url_service->forwarded_for = url_service_arg->forwarded_for;
+ if ( strnlen(url_service_arg->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) ) {
+ try {
+#ifdef USE_BOOST_XPRESSIVE
+ url_service->uri_regex = boost::xpressive::sregex::compile(url_service_arg->uri_pattern_match);
+#else
+ url_service->uri_regex.assign(url_service_arg->uri_pattern_match);
+#endif
+ }
+ catch (...) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,284, "Regex pattern error of uri_pattern_match");
+ return_value = -1;
+ goto create_out;
+ }
+ }
+ if ( strnlen(url_service_arg->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) ) {
+ try {
+#ifdef USE_BOOST_XPRESSIVE
+ url_service->host_regex = boost::xpressive::sregex::compile(url_service_arg->host_pattern_match);
+#else
+ url_service->host_regex.assign(url_service_arg->host_pattern_match);
+#endif
+ }
+ catch (...) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,285, "Regex pattern error of host_pattern_match.");
+ return_value = -1;
+ goto create_out;
+ }
+ }
+ url_service->reschedule = url_service_arg->reschedule;
+
+create_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,141,
+ "out_function: int create(void* url_arg, handle_t service_handle):return_value=%d",
+ return_value);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Create url service argument struct.
+ * @param[out] srv_arg service argument struct
+ * @return url service argument struct
+ */
+static void *
+create_sa(struct l7vs_service_arg *srv_arg)
+{
+ struct l7vs_url_service_arg *url_service_arg;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char service_arg_str[DEBUG_STR_LEN] = {0};
+ l7vs_service_arg_c_str(service_arg_str, srv_arg);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,142,
+ "in_function: void* create_sa(struct l7vs_service_arg* srv_arg):srv_arg=&(%s)",
+ service_arg_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check null */
+ if (srv_arg == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,120, "Arg(srv_arg) is NULL pointer.");
+ url_service_arg = NULL;
+ goto create_sa_out;
+ }
+
+ /* create url service argument struct */
+ url_service_arg = (struct l7vs_url_service_arg *) calloc(1, sizeof(struct l7vs_url_service_arg));
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,35, "calloc: addr=%p, size=%ld",
+ url_service_arg, (unsigned long int) sizeof(struct l7vs_url_service_arg));
+ }
+ /*------ DEBUG LOG END ------*/
+
+ if (url_service_arg == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,27, "Could not allocate memory.");
+ goto create_sa_out;
+ }
+
+ /* set url service argument size and protomod name "url" */
+ srv_arg->len = sizeof(struct l7vs_url_service_arg);
+ strcpy(srv_arg->protomod, url_protomod.modname);
+
+create_sa_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char url_service_arg_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_arg_c_str(url_service_arg_str, url_service_arg);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,143,
+ "out_function: void* create_sa(struct l7vs_service_arg* srv_arg):return_value=&(%s)",
+ url_service_arg_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return (void*) url_service_arg;
+}
+
+/*!
+ * Compare two service.
+ * @param[in] srv_handle1 one of a unique service ID
+ * @param[in] srv_handle2 one of a unique service ID
+ * @retval 0 they matched perfectly.
+ * @retval -1 they are different.
+ */
+static int
+compare(handle_t srv_handle1, handle_t srv_handle2)
+{
+ struct l7vs_url_service *url_srv1, *url_srv2;
+ int return_value = 0;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,144,
+ "in_function: int compare(handle_t srv_handle1, handle_t srv_handle2):"
+ "srv_handle1=%u, srv_handle2=%u", srv_handle1, srv_handle2);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* search service that has such a service ID(1) */
+ url_srv1 = l7vs_protomod_url_search_service(srv_handle1);
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char url_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_c_str(url_str, url_srv1);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,145, "pointer assign: url_srv1=&(%s)",
+ url_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ if (url_srv1 == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,121,
+ "Could not find such service handle's url service.");
+ return_value = -1;
+ goto compare_out;
+ }
+
+ /* search service that has such a service ID(2) */
+ url_srv2 = l7vs_protomod_url_search_service(srv_handle2);
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char url_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_c_str(url_str, url_srv2);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,146, "pointer assign: url_srv2=&(%s)",
+ url_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ if (url_srv2 == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,122,
+ "Could not find such service handle's url service.");
+ return_value = -1;
+ goto compare_out;
+ }
+
+ /* compare two pattern match */
+ if (strncmp(url_srv1->pattern_match, url_srv2->pattern_match, PATTERN_MATCH_MAXSIZE) != 0) {
+ return_value = -1;
+ goto compare_out;
+ }
+ if (strncmp(url_srv1->uri_pattern_match, url_srv2->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) != 0) {
+ return_value = -1;
+ goto compare_out;
+ }
+ if (strncmp(url_srv1->host_pattern_match, url_srv2->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) != 0) {
+ return_value = -1;
+ goto compare_out;
+ }
+
+compare_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,147,
+ "out_function: int compare(handle_t srv_handle1, handle_t srv_handle2):return_value=%d",
+ return_value);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Check the client packet and determine a real server.
+ * @param[in] srv service struct include service handle, protocol module and schedule module.
+ * @param[in] conn connection data.
+ * @param[in] request packet data from client
+ * @param[in] len length of packet data
+ * @param[out] dest destination (real server) list
+ * @param[out] tcps TCP Splicer flag
+ * @retval 0 successfully check packet data
+ * @retval -1 some errors occur.
+ */
+static int
+match_cldata(struct l7vs_service *srv, struct l7vs_conn *conn,
+ char *request, size_t *len, struct l7vs_dest **dest, int *tcps)
+{
+ struct l7vs_url_service *url_service;
+ int ret;
+ int i;
+ int asterisk_num = 0;
+ size_t pattern_len;
+ size_t uri_len;
+ char *uri, *host, pattern[PATTERN_MATCH_MAXSIZE + 2];
+ int offset_length;
+ char *x_forwarded_value;
+ char *next_line = NULL;
+ char x_forwarded_for_header[X_FORWARDED_FOR_LENGTH];
+ char backup_char;
+ int return_value = 0;
+
+ std::string packet_data;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char srv_str[DEBUG_STR_LEN] = {0};
+ char conn_str[DEBUG_STR_LEN] = {0};
+ char dest_str[DEBUG_STR_LEN] = {0};
+ char len_str[DEBUG_STR_LEN] = {0};
+ char tcps_str[DEBUG_STR_LEN] = {0};
+ l7vs_service_c_str(srv_str, srv);
+ l7vs_conn_c_str(conn_str, conn);
+ if (dest != NULL) {
+ l7vs_dest_c_str(dest_str, *dest);
+ }
+ else {
+ strncpy(dest_str, "NULL", DEBUG_STR_LEN);
+ }
+ if (len != NULL) {
+ snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
+ }
+ else {
+ strncpy(len_str, "NULL", DEBUG_STR_LEN);
+ }
+ if (tcps != NULL) {
+ snprintf(tcps_str, DEBUG_STR_LEN, "%d", *tcps);
+ }
+ else {
+ strncpy(tcps_str, "NULL", DEBUG_STR_LEN);
+ }
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,148,
+ "in_function: int match_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+ "char* request, size_t* len, struct l7vs_dest** dest, int* tcps):srv=&(%s), conn=&(%s), "
+ "request=\"%s\", len=&(%s), dest=&(&(%s)), tcps=&(%s)",
+ srv_str, conn_str, request, len_str, dest_str, tcps_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check null */
+ if (srv == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,123, "Arg(srv) is NULL pointer.");
+ return_value = -1;
+ goto match_cldata_out;
+ }
+ if (srv->pm == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,124, "Arg(srv->pm) is NULL pointer.");
+ return_value = -1;
+ goto match_cldata_out;
+ }
+ if (request == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,125, "Arg(request) is NULL pointer.");
+ return_value = -1;
+ goto match_cldata_out;
+ }
+ if (len == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,126, "Arg(len) is NULL pointer.");
+ return_value = -1;
+ goto match_cldata_out;
+ }
+ if (dest == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,127, "Arg(dest) is NULL pointer.");
+ return_value = -1;
+ goto match_cldata_out;
+ }
+ if (tcps == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,128, "Arg(tcps) is NULL pointer.");
+ return_value = -1;
+ goto match_cldata_out;
+ }
+
+ /* search service that has such a service ID */
+ url_service = l7vs_protomod_url_search_service(srv->handle);
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char url_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_c_str(url_str, url_service);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,149, "pointer assign: url_service=&(%s)",
+ url_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ if (url_service == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,129, "Could not find such service handle's url service.");
+ return_value = -1;
+ goto match_cldata_out;
+ }
+
+ /* initialize protocol module ... clear destination list */
+ ret = srv->pm->initialize(srv, conn, request, *len, dest);
+ if (ret != 0) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,130, "Could not initialize protomod.");
+ return_value = -1;
+ goto match_cldata_out;
+ }
+
+ /* check pattern_match length */
+ if (url_service->pattern_match[0] != '\0') {
+// remove log because of add new key --uri-pattern-match, --host-pattern-match)
+// PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,131, "Pattern match is NULL pointer");
+ /* check the size of request data */
+ pattern_len = strnlen(url_service->pattern_match, PATTERN_MATCH_MAXSIZE);
+ /* When '*' is included in pattern_match, number of '*' is decreased from pattern_len */
+ for (i = 0; i < (int)pattern_len; i++) {
+ if (url_service->pattern_match[i] == '*') {
+ asterisk_num++;
+ }
+ }
+ pattern_len -= (size_t)asterisk_num;
+ if (*len < (15 + pattern_len) ) {
+ PUT_LOG_INFO(url_protomod, LOG_CAT_L7VSD_PROTOCOL,6, "Request data is too short.");
+ return_value = 1;
+ goto match_cldata_out;
+ }
+ }
+
+ /* check the HTTP method in HTTP request header */
+ uri_len = *len;
+ uri = http_check_request_method(request, &uri_len);
+ if (uri == NULL) {
+ PUT_LOG_INFO(url_protomod, LOG_CAT_L7VSD_PROTOCOL,7, "Client message is not HTTP request.");
+ return_value = 1;
+ goto match_cldata_out;
+ }
+
+ /* check keyword (URI/--uri-pattern-match)*/
+ if (url_service->uri_pattern_match[0] != '\0') {
+ packet_data = std::string(uri, uri_len);
+#ifdef USE_BOOST_XPRESSIVE
+ if ( !boost::xpressive::regex_search(packet_data, url_service->uri_regex) ) {
+#else
+ if ( !boost::regex_search(packet_data, url_service->uri_regex) ) {
+#endif
+ return_value = -1;
+ goto match_cldata_out;
+ }
+ }
+ /* check keyword (URI/--pattern-match)*/
+ if (url_service->pattern_match[0] != '\0') {
+ backup_char = uri[uri_len];
+ uri[uri_len] = '\0';
+ snprintf(pattern, pattern_len + 3, "*%s*", url_service->pattern_match);
+ ret = fnmatch(pattern, uri, 0);
+ uri[uri_len] = backup_char;
+ }
+ if ( (url_service->pattern_match[0] != '\0' && ret != 0) ||
+ (url_service->host_pattern_match[0] != '\0') ) {
+
+ /* search Host field in HTTP request header */
+ host = http_search_header_field(request, "Host");
+ if (host == NULL) {
+ PUT_LOG_INFO(url_protomod, LOG_CAT_L7VSD_PROTOCOL,8, "Could not find Host field.");
+ return_value = 1;
+ goto match_cldata_out;
+ }
+ else {
+ next_line = http_skip_header_line(host);
+ if (next_line) {
+ next_line--; // *next_line == '\n'
+ if (*(next_line - 1) == '\r') {
+ next_line--;
+ }
+ /* check keyword (HOST/--host-pattern-match) */
+ if (url_service->host_pattern_match[0] != '\0') {
+ packet_data = std::string(host, next_line - host);
+#ifdef USE_BOOST_XPRESSIVE
+ if ( !boost::xpressive::regex_search(packet_data, url_service->host_regex) ) {
+#else
+ if ( !boost::regex_search(packet_data, url_service->host_regex) ) {
+#endif
+ return_value = -1;
+ goto match_cldata_out;
+ }
+ }
+ /* check keyword (HOST/--pattern-match) */
+ if (url_service->pattern_match[0] != '\0' && ret != 0) {
+ backup_char = *next_line;
+ *next_line = '\0';
+ ret = fnmatch(pattern, host, 0);
+ *next_line = backup_char;
+ if ( ret != 0 ) {
+ return_value = 1;
+ goto match_cldata_out;
+ }
+ }
+ }
+ next_line = NULL;
+ }
+ }
+
+ /* add X-Forwarded-For field */
+ if (url_service->forwarded_for) {
+ x_forwarded_value = http_search_header_field(request, "X-Forwarded-For");
+
+ /* already exists X-Forwarded-For field */
+ if (x_forwarded_value) {
+ next_line = http_skip_header_line(x_forwarded_value);
+ /* backtrack to look up insert point */
+ if (next_line) {
+ next_line--; // *next_line == '\n'
+ if (*(next_line - 1) == '\r') {
+ next_line--;
+ }
+ /* append client IP address */
+ snprintf(x_forwarded_for_header, X_FORWARDED_FOR_LENGTH, ", %s", inet_ntoa(conn->caddr.sin_addr));
+ }
+ }
+
+ /* not exists X-Forwarded-For field */
+ if (!next_line) {
+ /* construct new X-Forwarded-For header item */
+ snprintf(x_forwarded_for_header, X_FORWARDED_FOR_LENGTH, "X-Forwarded-For: %s\r\n", inet_ntoa(conn->caddr.sin_addr));
+
+ next_line = http_skip_header_line(request);
+ }
+
+ /* when insert point exist */
+ if (next_line != NULL) {
+ offset_length = (int) (next_line - request);
+
+ /* insert X-Forwarded-For header field */
+ http_insert_field(request, offset_length, x_forwarded_for_header, *len);
+
+ /* add header length */
+ *len += strlen(x_forwarded_for_header);
+ }
+ }
+
+ *tcps = 0;
+
+ /* finalize */
+ ret = srv->pm->finalize(srv, conn, request, *len, dest, url_service->reschedule);
+ if (ret != 0) {
+ PUT_LOG_INFO(url_protomod, LOG_CAT_L7VSD_PROTOCOL,12, "Could not finalize protomod. (Realserver decision failure)");
+ return_value = -1;
+ goto match_cldata_out;
+ }
+
+match_cldata_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,150,
+ "out_function: int match_cldata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+ "char* request, size_t* len, struct l7vs_dest** dest, int* tcps):return_value=%d",
+ return_value);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Check the real server packet and insert a Set-Cookie field.
+ * @param[in] srv service struct include service handle, protocol module and schedule module.
+ * @param[in] conn connection data.
+ * @param[in] response packet data from real server
+ * @param[in] len length of packet data. it will be lengthened.
+ * @retval 0 successfully check packet data.
+ * @retval -1 some errors occur.
+ */
+static int
+analyze_rsdata(struct l7vs_service *srv, struct l7vs_conn *conn,
+ char *response, size_t *len)
+{
+ int return_value = 0;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char srv_str[DEBUG_STR_LEN] = {0};
+ char conn_str[DEBUG_STR_LEN] = {0};
+ char len_str[DEBUG_STR_LEN] = {0};
+ l7vs_service_c_str(srv_str, srv);
+ l7vs_conn_c_str(conn_str, conn);
+ if (len != NULL) {
+ snprintf(len_str, DEBUG_STR_LEN, "%lu", (unsigned long int) *len);
+ }
+ else {
+ strncpy(len_str, "NULL", DEBUG_STR_LEN);
+ }
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,151,
+ "in_function: int analyze_rsdata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+ "char* response, size_t* len):srv=&(%s), conn=&(%s), response=\"%s\", len=&(%s)",
+ srv_str, conn_str, response, len_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check null */
+ if (srv == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,133, "Arg(srv) is NULL pointer.");
+ return_value = -1;
+ goto analyze_rsdata_out;
+ }
+ if (conn == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,134, "Arg(conn) is NULL pointer.");
+ return_value = -1;
+ goto analyze_rsdata_out;
+ }
+ if (conn->dest == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,135, "Arg(conn->dest) is NULL pointer.");
+ return_value = -1;
+ goto analyze_rsdata_out;
+ }
+ if (response == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,136, "Arg(response) is NULL pointer.");
+ return_value = -1;
+ goto analyze_rsdata_out;
+ }
+ if (len == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,137, "Arg(len) is NULL pointer.");
+ return_value = -1;
+ goto analyze_rsdata_out;
+ }
+
+ /* sorry flag check */
+ if (conn->sorry_conn_flag == 1) {
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,152, "Response from sorry server.");
+ }
+ /*------ DEBUG LOG END ------*/
+ goto analyze_rsdata_out;
+ }
+
+analyze_rsdata_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,153,
+ "out_function: int analyze_rsdata(struct l7vs_service* srv, struct l7vs_conn* conn, "
+ "char* response, size_t* len):return_value=%d", return_value);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Destroy url service
+ * @param[in] srv_handle a unique service ID
+ * @retval 0 successfully check packet data.
+ * @retval -1 some errors occur.
+ */
+static int
+destroy(handle_t srv_handle)
+{
+ /* url service list counter */
+ int service_number = 0;
+ int free_flag = 0;
+ int return_value = 0;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,154,
+ "in_function: int destroy(handle_t srv_handle):srv_handle=%u",
+ srv_handle);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check all url service list */
+ for (service_number = 0; service_number < URL_SERVICE_NUMBER; ++service_number) {
+ /* found url service that has srv_handle */
+ if (url_service_list[service_number] != NULL &&
+ url_service_list[service_number]->service_handle == srv_handle) {
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,36, "free: %p",
+ url_service_list[service_number]);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* free and NULL */
+ free(url_service_list[service_number]);
+ url_service_list[service_number] = NULL;
+
+ free_flag = 1;
+ break;
+ }
+ }
+
+ /* url service was not found */
+ if (free_flag == 0) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,138, "Could not find such service handle's url service.");
+ return_value = -1;
+ goto destroy_out;
+ }
+
+destroy_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,155,
+ "out_function: int destroy(handle_t srv_handle):return_value=%d",
+ srv_handle);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Destroy url service argument
+ * @param[in] url_arg url service argument
+ * @return void
+ */
+static void
+destroy_sa(void **url_arg)
+{
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char url_arg_str[DEBUG_STR_LEN] = {0};
+ if (url_arg != NULL) {
+ l7vs_url_service_arg_c_str(url_arg_str, (struct l7vs_url_service_arg*) *url_arg);
+ }
+ else {
+ strncpy(url_arg_str, "NULL", DEBUG_STR_LEN);
+ }
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,156,
+ "in_function: void destroy_sa(void** url_arg):url_arg=&(&(%s))",
+ url_arg_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check null */
+ if (url_arg == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,139, "Arg(url_arg) is NULL pointer.");
+ }
+ else if (*url_arg == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,140, "Arg(*url_arg) is NULL pointer.");
+ }
+ else {
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,37, "free: %p",
+ *url_arg);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* free and NULL */
+ free((struct l7vs_url_service_arg*) *url_arg);
+ *url_arg = NULL;
+ }
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,157,
+ "out_function: void destroy_sa(void** url_arg)");
+ }
+ /*------ DEBUG LOG END ------*/
+}
+
+/*!
+ * Create strings for service list of l7vsadm
+ * @param srv_arg service argument struct
+ * @param srv_handle a unique service ID
+ * @retval 0 successfully create strings
+ * @retval -1 some errors occur.
+ */
+static int
+service_arg(struct l7vs_service_arg_multi *srv_arg_mt, handle_t srv_handle)
+{
+ struct l7vs_url_service *url_service;
+ struct l7vs_url_service_arg c_sarg;
+ char url_argument[SERVICE_ARG_MAXSIZE];
+ int return_value = 0;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char srv_arg_mt_str[DEBUG_STR_LEN] = {0};
+ l7vs_service_arg_multi_c_str(srv_arg_mt_str, srv_arg_mt);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,158,
+ "in_function: int service_arg(struct l7vs_service_arg_multi* srv_arg_mt, "
+ "handle_t srv_handle):srv_arg_mt=&(%s), srv_handle=%u",
+ srv_arg_mt_str, srv_handle);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check null */
+ if (srv_arg_mt == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,141, "Arg(srv_arg_mt) is NULL pointer.");
+ return_value = -1;
+ goto service_arg_out;
+ }
+
+ /* search service that has such a service ID */
+ url_service = l7vs_protomod_url_search_service(srv_handle);
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char url_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_c_str(url_str, url_service);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,159, "pointer assign: url_service=&(%s)",
+ url_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ if (url_service == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,142, "Could not find such service handle's url service.");
+ return_value = -1;
+ goto service_arg_out;
+ }
+
+ /* initialize argument strings */
+ memset(url_argument, 0, SERVICE_ARG_MAXSIZE);
+
+ /* set url args to service argument struct */
+ srv_arg_mt->srv_arg.reschedule = url_service->reschedule;
+
+ /* create long argument (l7vsadm option -L/-l) */
+ if ( strnlen(url_service->pattern_match, PATTERN_MATCH_MAXSIZE) ) {
+ snprintf(url_argument, SERVICE_ARG_MAXSIZE, "--pattern-match %s", url_service->pattern_match);
+ }
+ if ( strnlen(url_service->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) ) {
+ snprintf(url_argument + strlen(url_argument), SERVICE_ARG_MAXSIZE - strlen(url_argument),
+ " --uri-pattern-match %s", url_service->uri_pattern_match);
+ }
+ if ( strnlen(url_service->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE) ) {
+ snprintf(url_argument + strlen(url_argument), SERVICE_ARG_MAXSIZE - strlen(url_argument),
+ " --host-pattern-match %s", url_service->host_pattern_match);
+ }
+ strncpy(srv_arg_mt->srv_arg.protomod_key_string, url_argument, 256);
+
+ /* create verbose argument (l7vsadm option -V/-v) */
+ if (url_service->forwarded_for) {
+ snprintf(url_argument + strlen(url_argument), SERVICE_ARG_MAXSIZE - strlen(url_argument),
+ " --forwarded-for");
+ }
+ strncpy(srv_arg_mt->srv_arg.protomod_opt_string, url_argument, 512);
+
+ strncpy(c_sarg.pattern_match, url_service->pattern_match, PATTERN_MATCH_MAXSIZE);
+ strncpy(c_sarg.uri_pattern_match, url_service->uri_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE);
+ strncpy(c_sarg.host_pattern_match, url_service->host_pattern_match, REGEX_PATTERN_MATCH_MAXSIZE);
+ c_sarg.reschedule = url_service->reschedule;
+
+ memcpy(srv_arg_mt->protomod_arg, &c_sarg, sizeof(struct l7vs_url_service_arg));
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char url_arg_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_arg_c_str(url_arg_str, &c_sarg);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,160,
+ "pointer assign: srv_arg_mt->protomod_arg=&(%s)", url_arg_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+service_arg_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,161,
+ "out_function: int service_arg(struct l7vs_service_arg_multi* srv_arg_mt, "
+ "handle_t srv_handle):return_value=%d", return_value);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Parse l7vsadm options to url argument
+ * @param[out] url_arg url service argument struct
+ * @param[int] argc number of l7vsadm argument
+ * @param[int] argv l7vsadm argument list
+ * @retval 0 successfully parse argument
+ * @retval -1 some errors occur.
+ */
+static int
+parse(void *url_arg, int argc, char *argv[])
+{
+ struct l7vs_url_service_arg *url_service_arg;
+ static struct option opt[] = {
+ {"pattern-match", required_argument, NULL, 'P'},
+ {"uri-pattern-match", required_argument, NULL, 'U'},
+ {"host-pattern-match", required_argument, NULL, 'H'},
+ {"forwarded-for", no_argument, NULL, 'F'},
+ {NULL, 0, NULL, 0 }
+ };
+ int c;
+ int pattern_match_flag = 0;
+ int uri_pattern_match_flag = 0;
+ int host_pattern_match_flag = 0;
+ int forwarded_for_flag = 0;
+ int return_value = 0;
+#ifndef USE_BOOST_XPRESSIVE
+ boost::regex regex;
+#endif
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ int i;
+ char argv_str[DEBUG_STR_LEN] = {0};
+ char url_arg_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_arg_c_str(url_arg_str, (struct l7vs_url_service_arg*) url_arg);
+ argv_str[0] = '\0';
+ if (argv == NULL)
+ snprintf(argv_str, DEBUG_STR_LEN, "NULL");
+ else {
+ for (i = 0; i < argc; i++) {
+ snprintf(argv_str, DEBUG_STR_LEN, "%sargv[%d]=\"%s\", ", argv_str, i, argv[i]);
+ }
+ i = strnlen(argv_str, DEBUG_STR_LEN);
+ if (i > 1)
+ argv_str[i - 2] = '\0';
+ }
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,162,
+ "in_function: int parse(void* url_arg, int argc, char* argv[]):url_arg=&(%s), "
+ "argc=%d, %s", url_arg_str, argc, argv_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check null */
+ if (url_arg == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,143, "Arg(url_arg) is NULL pointer.");
+ return_value = -1;
+ goto parse_out;
+ }
+ if (argv == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,144, "Arg(argv) is NULL pointer.");
+ return_value = -1;
+ goto parse_out;
+ }
+
+ url_service_arg = (struct l7vs_url_service_arg *) url_arg;
+ optind = 0;
+
+ /* check all argument */
+ while ((c = getopt_long(argc, argv, "P:U:H:F", opt, NULL)) != -1) {
+ switch (c) {
+ /* --pattern-match / -P */
+ case 'P':
+ /* check maximum length */
+ if (strnlen(optarg, PATTERN_MATCH_MAXSIZE) >= PATTERN_MATCH_MAXSIZE) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,145,
+ "-P/--pattern-match option value '%s' too long", optarg);
+ return_value = -1;
+ goto parse_out;
+ }
+ /* check minimum length */
+ if (strnlen(optarg, PATTERN_MATCH_MAXSIZE) <= 0 ) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,146,
+ "-P/--pattern-match option value '%s' invalid", optarg);
+ return_value = -1;
+ goto parse_out;
+ }
+ strncpy(url_service_arg->pattern_match, optarg, PATTERN_MATCH_MAXSIZE);
+ pattern_match_flag++;
+ break;
+
+ /* --uri-pattern-match / -U */
+ case 'U':
+ /* check maximum length */
+ if (strnlen(optarg, REGEX_PATTERN_MATCH_MAXSIZE) >= REGEX_PATTERN_MATCH_MAXSIZE) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,286,
+ "-U/--uri-pattern-match option value '%s' too long", optarg);
+ return_value = -1;
+ goto parse_out;
+ }
+ /* check minimum length */
+ if (strnlen(optarg, REGEX_PATTERN_MATCH_MAXSIZE) <= 0 ) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,287,
+ "-U/--uri-pattern-match option value '%s' invalid", optarg);
+ return_value = -1;
+ goto parse_out;
+ }
+ strncpy(url_service_arg->uri_pattern_match, optarg, REGEX_PATTERN_MATCH_MAXSIZE);
+ uri_pattern_match_flag++;
+ break;
+
+ /* --host-pattern-match / -H */
+ case 'H':
+ /* check maximum length */
+ if (strnlen(optarg, REGEX_PATTERN_MATCH_MAXSIZE) >= REGEX_PATTERN_MATCH_MAXSIZE) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,288,
+ "-H/--host-pattern-match option value '%s' too long", optarg);
+ return_value = -1;
+ goto parse_out;
+ }
+ /* check minimum length */
+ if (strnlen(optarg, REGEX_PATTERN_MATCH_MAXSIZE) <= 0 ) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,289,
+ "-H/--host-pattern-match option value '%s' invalid", optarg);
+ return_value = -1;
+ goto parse_out;
+ }
+ strncpy(url_service_arg->host_pattern_match, optarg, REGEX_PATTERN_MATCH_MAXSIZE);
+ host_pattern_match_flag++;
+ break;
+
+ /* --forwarded-for / -F */
+ case 'F':
+ /* x-forwarded-for on */
+ url_service_arg->forwarded_for = 1;
+ forwarded_for_flag++;
+ break;
+
+ /* else error */
+ default:
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,147, "Option error.");
+ return_value = -1;
+ goto parse_out;
+ }
+ }
+
+ /* set default no forwarded_for */
+ if (forwarded_for_flag == 0) {
+ url_service_arg->forwarded_for = 0;
+ }
+
+ /* set default no reschedule */
+ url_service_arg->reschedule = 0;
+
+ /* no pattern-match value */
+ if (pattern_match_flag == 0 && uri_pattern_match_flag == 0 && host_pattern_match_flag ==0) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,148,
+ "You have to set any of '--pattern-match', '--uri-pattern-match' or '--host-pattern-match' option.");
+ return_value = -1;
+ goto parse_out;
+ }
+ /* same option */
+ if (pattern_match_flag > 1) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,149,
+ "Cannot set multiple option '--pattern-match/-P'.");
+ return_value = -1;
+ goto parse_out;
+ }
+ if (uri_pattern_match_flag > 1) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,290,
+ "Cannot set multiple option '--uri-pattern-match/-U'.");
+ return_value = -1;
+ goto parse_out;
+ }
+ if (host_pattern_match_flag > 1) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,291,
+ "Cannot set multiple option '--host-pattern-match/-H'.");
+ return_value = -1;
+ goto parse_out;
+ }
+ /* compile regex */
+ if (uri_pattern_match_flag) {
+ try {
+#ifdef USE_BOOST_XPRESSIVE
+ boost::xpressive::sregex::compile(url_service_arg->uri_pattern_match);
+#else
+ regex.assign(url_service_arg->uri_pattern_match);
+#endif
+ }
+ catch (...) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,292,
+ "Regex pattern error of option '--uri-pattern-match/-U'.");
+ return_value = -1;
+ goto parse_out;
+ }
+ }
+ if (host_pattern_match_flag) {
+ try {
+#ifdef USE_BOOST_XPRESSIVE
+ boost::xpressive::sregex::compile(url_service_arg->host_pattern_match);
+#else
+ regex.assign(url_service_arg->host_pattern_match);
+#endif
+ }
+ catch (...) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,293,
+ "Regex pattern error of option '--host-pattern-match/-H'.");
+ return_value = -1;
+ goto parse_out;
+ }
+ }
+
+parse_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,163,
+ "out_function: int parse(void* url_arg, int argc, char* argv[]):return_value=%d",
+ return_value);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Search url service from url service list using service handle
+ * @param[in] service_handle a unique service ID
+ * @return url service struct when service was found. NULL when service was not found.
+ */
+static struct l7vs_url_service *
+l7vs_protomod_url_search_service(handle_t service_handle)
+{
+ /* url service list counter */
+ int service_number = 0;
+ struct l7vs_url_service* return_value = NULL;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,164,
+ "in_function: struct l7vs_url_service* l7vs_protomod_url_search_service(handle_t service_handle):"
+ "service_handle=%d", service_handle);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check all url service list */
+ for (service_number = 0; service_number < URL_SERVICE_NUMBER; ++service_number) {
+ /* found the service has same service handle */
+ if (url_service_list[service_number] != NULL &&
+ url_service_list[service_number]->service_handle == service_handle) {
+ return_value = url_service_list[service_number];
+ break;
+ }
+ }
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char ssl_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_c_str(ssl_str, return_value);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,165,
+ "out_function: struct l7vs_url_service* l7vs_protomod_url_search_service(handle_t service_handle):"
+ "return_value=&(%s)", ssl_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Create url service.
+ * @param void
+ * @return url service struct when create a service. NULL when cannot create service.
+ */
+static struct l7vs_url_service *
+l7vs_protomod_url_create_service()
+{
+ struct l7vs_url_service* return_value = NULL;
+ int service_number = 0;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,166,
+ "in_function: struct l7vs_url_service* l7vs_protomod_url_create_service()");
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* check all url service list */
+ for (service_number = 0; service_number < URL_SERVICE_NUMBER - 1; ++service_number) {
+ /* if pointer that does not point NULL exists ... */
+ if (url_service_list[service_number] == NULL) {
+ /* create a service at empty pointer */
+ url_service_list[service_number] = (struct l7vs_url_service *) calloc(1, sizeof(struct l7vs_url_service));
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,38, "calloc: addr=%p, size=%ld",
+ url_service_list[service_number], (unsigned long int) sizeof(struct l7vs_url_service));
+ }
+ /*------ DEBUG LOG END ------*/
+
+ if (url_service_list[service_number] == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,28, "Could not allocate memory.");
+ goto create_service_out;
+ }
+ return_value = url_service_list[service_number];
+ goto create_service_out;
+ }
+ }
+
+ /* all service list is full */
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,150, "url service list is full.");
+
+create_service_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char ssl_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_c_str(ssl_str, return_value);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,167,
+ "out_function: struct l7vs_url_service* l7vs_protomod_url_create_service():"
+ "return_value=&(%s)", ssl_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Create temporary url service.
+ * @param void
+ * @return url service struct when create a service. NULL when cannot create service.
+ */
+static struct l7vs_url_service *
+l7vs_protomod_url_create_temp_service()
+{
+ struct l7vs_url_service* return_value = NULL;
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,168,
+ "in_function: struct l7vs_url_service* l7vs_protomod_url_create_temp_service()");
+ }
+ /*------ DEBUG LOG END ------*/
+
+ /* if pointer that does not point NULL exists ... */
+ if (url_service_list[URL_SERVICE_NUMBER - 1] != NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_PROTOCOL,151, "Temporary url service is being used by other process.");
+ goto create_temp_service_out;
+ }
+
+ /* create temp service */
+ url_service_list[URL_SERVICE_NUMBER - 1] = (struct l7vs_url_service *) calloc(1, sizeof(struct l7vs_url_service));
+
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_SYSTEM_MEMORY)) {
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,39, "calloc: addr=%p, size=%ld",
+ url_service_list[URL_SERVICE_NUMBER - 1], (unsigned long int) sizeof(struct l7vs_url_service));
+ }
+ /*------ DEBUG LOG END ------*/
+
+ if (url_service_list[URL_SERVICE_NUMBER - 1] == NULL) {
+ PUT_LOG_ERROR(url_protomod, LOG_CAT_L7VSD_SYSTEM_MEMORY,29, "Could not allocate memory");
+ goto create_temp_service_out;
+ }
+
+ return_value = url_service_list[URL_SERVICE_NUMBER - 1];
+
+create_temp_service_out:
+ /*-------- DEBUG LOG --------*/
+ if (url_protomod.get_log_level != NULL &&
+ LOG_LV_DEBUG == url_protomod.get_log_level(LOG_CAT_L7VSD_PROTOCOL)) {
+ char ssl_str[DEBUG_STR_LEN] = {0};
+ l7vs_url_service_c_str(ssl_str, return_value);
+ PUT_LOG_DEBUG(url_protomod, LOG_CAT_L7VSD_PROTOCOL,169,
+ "out_function: struct l7vs_url_service* l7vs_protomod_url_create_service():"
+ "return_value=&(%s)", ssl_str);
+ }
+ /*------ DEBUG LOG END ------*/
+
+ return return_value;
+}
+
+/*!
+ * Serialize struct l7vs_url_service for debug log.
+ * @param[out] buf serialized string
+ * @param[in] url l7vs_url_service struct
+ */
+static void l7vs_url_service_c_str(char* buf, struct l7vs_url_service* url) {
+ if (url == NULL) {
+ snprintf(buf, DEBUG_STR_LEN, "NULL");
+ }
+ else {
+ snprintf(buf, DEBUG_STR_LEN, "service_handle=%d, pattern_match=\"%s\", uri_pattern_match=\"%s\", host_pattern_match=\"%s\", "
+ "forwarded_for=%d, reschedule=%d", url->service_handle, url->pattern_match, url->uri_pattern_match, url->host_pattern_match,
+ url->forwarded_for, url->reschedule);
+ }
+}
+
+/*!
+ * Serialize struct l7vs_url_service_arg for debug log.
+ * @param[out] buf serialized string
+ * @param[in] url_arg l7vs_url_service_arg struct
+ */
+void l7vs_url_service_arg_c_str(char* buf, struct l7vs_url_service_arg* url_arg) {
+ if (url_arg == NULL) {
+ snprintf(buf, DEBUG_STR_LEN, "NULL");
+ }
+ else {
+ snprintf(buf, DEBUG_STR_LEN, "pattern_match=\"%s\", uri_pattern_match=\"%s\", host_pattern_match=\"%s\", forwarded_for=%d, reschedule=%d",
+ url_arg->pattern_match, url_arg->uri_pattern_match, url_arg->host_pattern_match, url_arg->forwarded_for, url_arg->reschedule);
+ }
+}