|
|
@ -2,6 +2,7 @@ import fs from "fs"; |
|
|
|
import assert from "assert"; |
|
|
|
import assert from "assert"; |
|
|
|
import UAParser from "ua-parser-js"; |
|
|
|
import UAParser from "ua-parser-js"; |
|
|
|
import readline from "readline"; |
|
|
|
import readline from "readline"; |
|
|
|
|
|
|
|
import { program } from "commander"; |
|
|
|
|
|
|
|
|
|
|
|
class Parser { |
|
|
|
class Parser { |
|
|
|
constructor() { |
|
|
|
constructor() { |
|
|
@ -195,12 +196,26 @@ const chain_to_set = (requests) => { |
|
|
|
return path.values(); |
|
|
|
return path.values(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const sort_request_chains = (by_ip) => { |
|
|
|
const chain_to_list = (requests) => { |
|
|
|
|
|
|
|
const path = []; |
|
|
|
|
|
|
|
let seen; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(let r of requests) { |
|
|
|
|
|
|
|
if(r.url != seen) { |
|
|
|
|
|
|
|
path.push(r.url); |
|
|
|
|
|
|
|
seen = r.url; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return path.values(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const sort_request_chains = (by_ip, as_set) => { |
|
|
|
let ip_chains = {}; |
|
|
|
let ip_chains = {}; |
|
|
|
let seen; |
|
|
|
let seen; |
|
|
|
|
|
|
|
|
|
|
|
for(let [ip, requests] of Object.entries(by_ip)) { |
|
|
|
for(let [ip, requests] of Object.entries(by_ip)) { |
|
|
|
const chain = chain_to_set(requests); |
|
|
|
const chain = as_set ? chain_to_set(requests) : chain_to_list(requests); |
|
|
|
|
|
|
|
|
|
|
|
const ref = requests[0].refer ? `[${requests[0].refer}]` : ""; |
|
|
|
const ref = requests[0].refer ? `[${requests[0].refer}]` : ""; |
|
|
|
const url_set = [ref, ...chain].join(" "); |
|
|
|
const url_set = [ref, ...chain].join(" "); |
|
|
@ -214,11 +229,29 @@ const sort_request_chains = (by_ip) => { |
|
|
|
return chains_sorted; |
|
|
|
return chains_sorted; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const [by_ip, stats] = await parse_logs(process.argv[2]); |
|
|
|
const output_results = (min, chains_sorted) => { |
|
|
|
const chains_sorted = sort_request_chains(by_ip); |
|
|
|
for(let [url, count] of chains_sorted) { |
|
|
|
|
|
|
|
if(count >= min) { |
|
|
|
|
|
|
|
console.log(count, url); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for(let [url, count] of chains_sorted) { |
|
|
|
console.log(stats); |
|
|
|
console.log(count, url); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
console.log(stats); |
|
|
|
program |
|
|
|
|
|
|
|
.option("--no-set", "Use a Set instead of a list for chains.") |
|
|
|
|
|
|
|
.option("--min <Number>", "The lowest count to print. Stop at this.", 1) |
|
|
|
|
|
|
|
.requiredOption("--input <String>", "Input file.") |
|
|
|
|
|
|
|
.description("Processes different web server logs to determine request chain frequency.") |
|
|
|
|
|
|
|
.version(0.1); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
program.parse(); |
|
|
|
|
|
|
|
const OPTS = program.opts(); |
|
|
|
|
|
|
|
OPTS.min = parseInt(OPTS.min); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assert(!isNaN(OPTS.min), `min must be a number, you have ${OPTS.min}`); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const [by_ip, stats] = await parse_logs(OPTS.input); |
|
|
|
|
|
|
|
const chains_sorted = sort_request_chains(by_ip, OPTS.set); |
|
|
|
|
|
|
|
output_results(OPTS.min, chains_sorted); |
|
|
|