Files
NeoTachyon/tachyon/files/usr/lib/providers/nfqueue/check.uc
T

357 lines
12 KiB
Ucode

#!/usr/bin/env ucode
let fs = require("fs");
function as_string(value) {
return value == null ? "" : "" + value;
}
function read_stdin() {
let data = fs.readfile("/dev/stdin");
return data == null ? "" : data;
}
function strip_trailing_cr(line) {
line = as_string(line);
return length(line) > 0 && substr(line, length(line) - 1) == "\r" ? substr(line, 0, length(line) - 1) : line;
}
function trim_left_space(value) {
value = as_string(value);
let i = 0;
while (i < length(value) && match(substr(value, i, 1), /[ \t\r\n]/) != null)
i++;
return substr(value, i);
}
function strip_binary_prefix(line, binary) {
line = as_string(line);
binary = as_string(binary || "nfqws");
let path_marker = "/" + binary + ":";
let path_index = rindex(line, path_marker);
if (path_index >= 0)
return trim_left_space(substr(line, path_index + length(path_marker)));
let name_marker = binary + ":";
if (index(line, name_marker) == 0)
return trim_left_space(substr(line, length(name_marker)));
return line;
}
function summary_line_matches(line) {
return index(line, "unrecognized option:") >= 0 ||
index(line, "option requires an argument:") >= 0 ||
index(line, "option does not take an argument:") >= 0 ||
match(line, /[Ii]nvalid /) != null ||
match(line, /bad [^ ]/) != null ||
index(line, "must be ") >= 0 ||
index(line, "fooling allowed values") >= 0 ||
index(line, "incompatible") >= 0 ||
index(line, "only one ") >= 0 ||
index(line, "No such file") >= 0 ||
index(line, "not found") >= 0 ||
index(line, "cannot ") >= 0 ||
index(line, "failed to ") >= 0 ||
index(line, "unable to ") >= 0 ||
index(line, "should be ") >= 0 ||
index(line, "Too much splits") >= 0 ||
index(line, "out of memory") >= 0 ||
index(line, "not supported") >= 0 ||
index(line, "value error") >= 0;
}
function ignored_fallback_line(line) {
return match(line, /^github version /) != null ||
match(line, /^we have [0-9]+ user defined desync profile/) != null ||
match(line, /^Running as UID=/) != null ||
line == "command line parameters verified" ||
trim(line) == "";
}
function validation_summary(binary) {
let lines = split(read_stdin(), "\n");
for (let line in lines) {
line = strip_trailing_cr(line);
if (summary_line_matches(line)) {
print(strip_binary_prefix(line, binary), "\n");
return;
}
}
for (let line in lines) {
line = strip_trailing_cr(line);
if (ignored_fallback_line(line))
continue;
print(strip_binary_prefix(line, binary), "\n");
return;
}
}
function value_after_last_colon(summary) {
let colon = rindex(summary, ":");
if (colon < 0)
return "";
let fields = split(trim_left_space(substr(summary, colon + 1)), /[ \t\r\n]+/);
return length(fields) > 0 ? fields[0] : "";
}
function validation_value_hint_value(summary) {
summary = as_string(summary);
if (index(summary, "Invalid port filter :") >= 0 ||
index(summary, "Invalid l7 filter :") >= 0 ||
index(summary, "invalid debug mode :") >= 0 ||
index(summary, "invalid ip_id mode :") >= 0 ||
index(summary, "Invalid fakedsplit mod :") >= 0 ||
index(summary, "Invalid hostfakesplit mod :") >= 0 ||
index(summary, "Invalid tcp mod :") >= 0 ||
index(summary, "Invalid tls mod :") >= 0 ||
index(summary, "invalid dup ip_id mode :") >= 0)
return value_after_last_colon(summary);
return "";
}
function validation_value_hint(summary) {
let value = validation_value_hint_value(summary);
if (value != "")
print(value, "\n");
}
function first_option_token(summary) {
let matched = match(summary, /(--[[:alnum:]][[:alnum:]-]*)/);
return matched ? matched[1] : "";
}
function option_after(summary, pattern, prefix) {
let matched = match(summary, pattern);
if (!matched || length(matched) < 2)
return "";
return as_string(prefix) + matched[1];
}
function validation_option_hint_value(summary) {
summary = as_string(summary);
let option = first_option_token(summary);
if (option != "")
return option;
if (index(summary, "unrecognized option:") >= 0) {
option = option_after(summary, /unrecognized option:[ \t]*([^ \t\r\n]+)/, "");
if (option == "")
return "";
if (index(option, "--") == 0)
return option;
else if (index(option, "-") == 0)
return "-" + option;
else
return "--" + option;
}
if (index(summary, "option requires an argument:") >= 0) {
option = option_after(summary, /option requires an argument:[ \t]*([^ \t\r\n]+)/, "--");
return option;
}
if (index(summary, "option does not take an argument:") >= 0) {
option = option_after(summary, /option does not take an argument:[ \t]*([^ \t\r\n]+)/, "--");
return option;
}
let mappings = [
["invalid debug mode :", "--debug"],
["hostspell must be exactly 4 chars long", "--hostspell"],
["invalid ip_id mode :", "--ip-id"],
["invalid dup ip_id mode :", "--dup-ip-id"],
["dup-autottl value error", "--dup-autottl"],
["dup-autottl6 value error", "--dup-autottl6"],
["dpi-desync-autottl value error", "--dpi-desync-autottl"],
["dpi-desync-autottl6 value error", "--dpi-desync-autottl6"],
["orig-autottl value error", "--orig-autottl"],
["orig-autottl6 value error", "--orig-autottl6"],
["invalid dpi-desync mode", "--dpi-desync"],
["invalid desync combo :", "--dpi-desync"],
["invalid wssize-cutoff value", "--wssize-cutoff"],
["invalid synack-split value", "--synack-split"],
["invalid ctrack-timeouts value", "--ctrack-timeouts"],
["invalid ipcache-lifetime value", "--ipcache-lifetime"],
["dpi-desync-repeats must be within ", "--dpi-desync-repeats"],
["dup-repeats must be within ", "--dup"],
["invalid desync-cutoff value", "--dpi-desync-cutoff"],
["invalid desync-start value", "--dpi-desync-start"],
["Invalid fakedsplit mod :", "--dpi-desync-fakedsplit-mod"],
["Invalid hostfakesplit mod :", "--dpi-desync-hostfakesplit-mod"],
["Invalid tcp mod :", "--dpi-desync-fake-tcp-mod"],
["Invalid tls mod :", "--dpi-desync-fake-tls-mod"],
["Invalid argument for dpi-desync-split-http-req", "--dpi-desync-split-http-req"],
["Invalid argument for dpi-desync-split-tls", "--dpi-desync-split-tls"],
["Invalid argument for dpi-desync-split-seqovl", "--dpi-desync-split-seqovl"],
["Invalid argument for dpi-desync-hostfakesplit-midhost", "--dpi-desync-hostfakesplit-midhost"],
["dpi-desync-ipfrag-pos-tcp must be within ", "--dpi-desync-ipfrag-pos-tcp"],
["dpi-desync-ipfrag-pos-tcp must be multiple of 8", "--dpi-desync-ipfrag-pos-tcp"],
["dpi-desync-ipfrag-pos-udp must be within ", "--dpi-desync-ipfrag-pos-udp"],
["dpi-desync-ipfrag-pos-udp must be multiple of 8", "--dpi-desync-ipfrag-pos-udp"],
["dpi-desync-ts-increment should be ", "--dpi-desync-ts-increment"],
["dpi-desync-badseq-increment should be ", "--dpi-desync-badseq-increment"],
["dpi-desync-badack-increment should be ", "--dpi-desync-badack-increment"],
["dup-ts-increment should be ", "--dup-ts-increment"],
["dup-badseq-increment should be ", "--dup-badseq-increment"],
["dup-badack-increment should be ", "--dup-badack-increment"],
["bad value for --filter-l3", "--filter-l3"],
["auto hostlist fail time is not valid", "--hostlist-auto-fail-time"],
["auto hostlist fail threshold must be within 1..20", "--hostlist-auto-fail-threshold"],
["auto hostlist fail threshold must be within 2..10", "--hostlist-auto-retrans-threshold"],
["dpi-desync-udplen-increment must be integer within ", "--dpi-desync-udplen-increment"]
];
for (let mapping in mappings) {
if (index(summary, mapping[0]) >= 0)
return mapping[1];
}
return "";
}
function validation_option_hint(summary) {
let option = validation_option_hint_value(summary);
if (option != "")
print(option, "\n");
}
function validation_needles(summary) {
let option = validation_option_hint_value(summary);
let value = validation_value_hint_value(summary);
if (option != "")
print(option, "\n");
if (value != "")
print(value, "\n");
}
function cleaned_queue_token(token) {
return replace(as_string(token), /[{},;]/g, "");
}
function queue_token_overlaps(token, range_start, range_end) {
token = cleaned_queue_token(token);
if (match(token, /^[0-9]+(-[0-9]+)?$/) == null)
return false;
let parts = split(token, "-");
let first = int(parts[0]);
let last = length(parts) > 1 && parts[1] != "" ? int(parts[1]) : first;
return first <= range_end && last >= range_start;
}
function nft_queue_overlap(own_table, range_start, range_end) {
own_table = as_string(own_table);
range_start = int(range_start || 0);
range_end = int(range_end || 0);
let in_own_table = false;
for (let line in split(read_stdin(), "\n")) {
let fields = split(trim(as_string(line)), /[ \t\r\n]+/);
if (length(fields) == 0 || fields[0] == "")
continue;
if (fields[0] == "table")
in_own_table = length(fields) >= 3 && fields[1] == "inet" && fields[2] == own_table;
if (in_own_table)
continue;
for (let i = 0; i < length(fields); i++) {
if (fields[i] != "queue")
continue;
for (let j = i + 1; j < length(fields); j++) {
if ((fields[j] == "num" || fields[j] == "to") && j + 1 < length(fields)) {
if (queue_token_overlaps(fields[j + 1], range_start, range_end))
return true;
}
else if (queue_token_overlaps(fields[j], range_start, range_end)) {
return true;
}
}
}
}
return false;
}
function rewrite_legacy_runtime_path(legacy_path, provider_path) {
let data = read_stdin();
legacy_path = as_string(legacy_path);
if (legacy_path == "") {
print(data);
return;
}
print(replace(data, legacy_path, as_string(provider_path)));
}
function stdin_contains(needle) {
return index(read_stdin(), as_string(needle)) >= 0;
}
function ps_matching_pids(needle) {
needle = as_string(needle);
if (needle == "")
return;
for (let line in split(read_stdin(), "\n")) {
line = as_string(line);
if (index(line, needle) < 0 ||
index(line, "grep") >= 0 ||
index(line, "ps-matching-pids") >= 0)
continue;
let fields = split(trim(line), /[ \t\r\n]+/);
if (length(fields) > 0 && fields[0] != "")
print(fields[0], "\n");
}
}
function run(argv, usage_path) {
argv = type(argv) == "array" ? argv : [];
usage_path = as_string(usage_path || "providers/nfqueue/check.uc");
let mode = argv[0] || "";
if (mode == "summary")
validation_summary(argv[1]);
else if (mode == "value-hint")
validation_value_hint(argv[1]);
else if (mode == "option-hint")
validation_option_hint(argv[1]);
else if (mode == "needles")
validation_needles(argv[1]);
else if (mode == "nft-queue-overlap")
exit(nft_queue_overlap(argv[1], argv[2], argv[3]) ? 0 : 1);
else if (mode == "rewrite-legacy-runtime-path")
rewrite_legacy_runtime_path(argv[1], argv[2]);
else if (mode == "stdin-contains")
exit(stdin_contains(argv[1]) ? 0 : 1);
else if (mode == "ps-matching-pids")
ps_matching_pids(argv[1]);
else {
warn("Usage: " + usage_path + " <summary|value-hint|option-hint|needles|nft-queue-overlap|rewrite-legacy-runtime-path|stdin-contains|ps-matching-pids> ...\n");
exit(1);
}
}
if (sourcepath(1) != null && sourcepath(1) != "") {
return {
run,
nft_queue_overlap
};
}
run(ARGV, "providers/nfqueue/check.uc");