/* * Implements the <IfVersion> container */ static const char *start_ifversion(cmd_parms *cmd, void *mconfig, const char *arg1, const char *arg2, const char *arg3) { const char *endp; int reverse = 0, done = 0, match = 0, compare; const char *p, *error; char c; /* supplying one argument is possible, we assume an equality check then */ if (!arg2) { arg2 = arg1; arg1 = "="; } /* surrounding quotes without operator */ if (!arg3 && *arg2 == '>' && !arg2[1]) { arg3 = ">"; arg2 = arg1; arg1 = "="; } /* the third argument makes version surrounding quotes plus operator * possible. */ endp = arg2 + strlen(arg2); if ( endp == arg2 || (!(arg3 && *arg3 == '>' && !arg3[1]) && *--endp != '>')) { return apr_pstrcat(cmd->pool, cmd->cmd->name, "> directive missing closing '>'", NULL); } p = arg1; if (*p == '!') { reverse = 1; if (p[1]) { ++p; } } c = *p++; if (!*p || (*p == '=' && !p[1] && c != '~')) { if (!httpd_version.major) { ap_get_server_revision(&httpd_version); } done = 1; switch (c) { case '=': /* normal comparison */ if (*arg2 != '/') { compare = compare_version(apr_pstrmemdup(cmd->pool, arg2, endp-arg2), &error); if (error) { return error; } match = !compare; break; } /* regexp otherwise */ if (endp == ++arg2 || *--endp != '/') { return "Missing delimiting / of regular expression."; } case '~': /* regular expression */ match = match_version(cmd->pool, apr_pstrmemdup(cmd->pool, arg2, endp-arg2), &error); if (error) { return error; } break; case '<': compare = compare_version(apr_pstrmemdup(cmd->pool, arg2, endp-arg2), &error); if (error) { return error; } match = ((-1 == compare) || (*p && !compare)); break; case '>': compare = compare_version(apr_pstrmemdup(cmd->pool, arg2, endp-arg2), &error); if (error) { return error; } match = ((1 == compare) || (*p && !compare)); break; default: done = 0; break; } } if (!done) { return apr_pstrcat(cmd->pool, "unrecognized operator '", arg1, "'", NULL); } if ((!reverse && match) || (reverse && !match)) { ap_directive_t *parent = NULL; ap_directive_t *current = NULL; const char *retval; retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd, ¤t, &parent, "<IfVersion"); *(ap_directive_t **)mconfig = current; return retval; } *(ap_directive_t **)mconfig = NULL; return ap_soak_end_container(cmd, "<IfVersion"); }
int main(int argc, char **argv) { struct nl_sock *nsd; int family = NET_MAT_DFLT_FAMILY; struct sockaddr_nl dest_addr; unsigned char *buf; int rc = EXIT_SUCCESS; int err, opt; const char *backend = NULL; struct switch_args sw_args; struct sigaction sig_act; int verbose = 0; int opt_index = 0; static struct option long_options[] = { { "version", no_argument, NULL, 0 }, { 0, 0, 0, 0} }; memset(&sw_args, 0, sizeof(sw_args)); while ((opt = getopt_long(argc, argv, "b:f:vhls", long_options, &opt_index)) != -1) { switch (opt) { case 0: if (!strcmp(long_options[opt_index].name, "version")) { printf("Match Version: %s\n", match_version()); exit(0); } break; case 'b': backend = optarg; break; case 'f': family = atoi(optarg); break; case 'h': matchd_usage(); exit(-1); case 'l': match_backend_list_all(); exit(0); case 's': sw_args.single_vlan = true; break; case 'v': ++verbose; break; default: matchd_usage(); exit(-1); } } if (verbose > 1) mat_setlogmask(MAT_LOG_UPTO(MAT_LOG_DEBUG)); else if (verbose > 0) mat_setlogmask(MAT_LOG_UPTO(MAT_LOG_INFO)); else mat_setlogmask(MAT_LOG_UPTO(MAT_LOG_ERR)); nsd = nl_socket_alloc(); nl_socket_set_local_port(nsd, (uint32_t)getpid()); nl_connect(nsd, NETLINK_GENERIC); if (backend == NULL) backend = DEFAULT_BACKEND_NAME; rc = matchd_init(nsd, family, backend, &sw_args); if (rc) { MAT_LOG(ERR, "Error: cannot init matchd\n"); exit(-1); } err = matchd_create_pid(); if (err) { MAT_LOG(ERR, "matchd create pid failed\n"); exit(-1); } sig_act.sa_handler = matchd_int_handler; sigaction(SIGINT, &sig_act, NULL); sigaction(SIGTERM, &sig_act, NULL); while (1) { MAT_LOG(DEBUG, "Waiting for message\n"); rc = nl_recv(nsd, &dest_addr, &buf, NULL); if(rc <= 0) { printf("%s:receive error on netlink socket:%d\n", __func__, errno); rc = EXIT_FAILURE; break; } /*printf("%s:recvfrom received %d bytes from pid %d\n", __func__, rc, dest_addr.nl_pid); */ err = matchd_rx_process((struct nlmsghdr *)buf); if (err < 0) MAT_LOG(ERR, "%s: Warning: parsing error\n", __func__); free(buf); } matchd_uninit(); nl_close(nsd); nl_socket_free(nsd); return rc; }
/* Usage: <IfVersion [!]op version-string|regex> */ MODRET start_ifversion(cmd_rec *cmd) { unsigned int ifversion_ctx_count = 1; int compared, matched = FALSE, negated = FALSE; char buf[PR_TUNABLE_BUFFER_SIZE], *config_line = NULL; char *error = NULL, *version_str = NULL, *op_str = NULL; size_t op_len; if (cmd->argc-1 == 0 || cmd->argc-1 > 2) { CONF_ERROR(cmd, "wrong number of parameters"); } if (cmd->argc-1 == 2) { op_str = cmd->argv[1]; if (*op_str == '!' && strlen(op_str) > 1) { negated = TRUE; op_str++; } op_len = strlen(op_str); version_str = cmd->argv[2]; } else { /* Assume that if only a version-string was supplied, the operator * is intended to be the equality operator. */ op_str = "="; op_len = 1; version_str = cmd->argv[1]; } switch (*op_str) { case '=': if (*version_str != '/') { /* Normal equality comparison */ compared = compare_version(cmd->tmp_pool, version_str, &error); if (error != NULL) { CONF_ERROR(cmd, error); } matched = (compared == 0); break; } /* Otherwise, it's a regular expression */ if (version_str[strlen(version_str)-1] != '/') { CONF_ERROR(cmd, "Missing terminating '/' of regular expression"); } /* Fall through to the next case in order to handle/evaluate the * regular expression. Be sure to remove the bracketing '/' characters * for the regex compilation. */ version_str[strlen(version_str)-1] = '\0'; version_str++; case '~': /* Regular expression */ matched = match_version(cmd->tmp_pool, version_str, &error); if (error != NULL) { CONF_ERROR(cmd, error); } break; case '<': compared = compare_version(cmd->tmp_pool, version_str, &error); if (error != NULL) { CONF_ERROR(cmd, error); } if (compared == -1 || (op_len == 2 && compared == 0)) { matched = TRUE; } break; case '>': compared = compare_version(cmd->tmp_pool, version_str, &error); if (error != NULL) { CONF_ERROR(cmd, error); } if (compared == 1 || (op_len == 2 && compared == 0)) { matched = TRUE; } break; default: CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unknown comparison operator '", op_str, "'", NULL)); } if ((matched && !negated) || (!matched && negated)) { pr_log_debug(DEBUG3, "%s: using '%s %s' section at line %u", cmd->argv[0], cmd->argv[1], cmd->argv[2], pr_parser_get_lineno()); return PR_HANDLED(cmd); } pr_log_debug(DEBUG3, "%s: skipping '%s %s' section at line %u", cmd->argv[0], cmd->argv[1], cmd->argv[2], pr_parser_get_lineno()); while (ifversion_ctx_count > 0 && (config_line = pr_parser_read_line(buf, sizeof(buf))) != NULL) { pr_signals_handle(); if (strncasecmp(config_line, "<IfVersion", 10) == 0) { ifversion_ctx_count++; } if (strcasecmp(config_line, "</IfVersion>") == 0) { ifversion_ctx_count--; } } /* If there are still unclosed <IfVersion> sections, signal an error. */ if (ifversion_ctx_count > 0) { CONF_ERROR(cmd, "unclosed <IfVersion> section"); } return PR_HANDLED(cmd); }