@roflsec/fail2scan 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/daemon.js +45 -20
- package/package.json +1 -1
package/bin/daemon.js
CHANGED
|
@@ -5,19 +5,23 @@ const { execFile, spawn } = require('child_process');
|
|
|
5
5
|
const { promisify } = require('util');
|
|
6
6
|
const execFileP = promisify(execFile);
|
|
7
7
|
require('dotenv').config({ quiet:true})
|
|
8
|
+
|
|
8
9
|
// -------------------- IPGeolocation --------------------
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
let getGeo = async (ip) => null;
|
|
11
|
+
if(process.env.IPGEO_API_KEY){
|
|
12
|
+
const IPGeolocationAPI = require("ip-geolocation-api-javascript-sdk");
|
|
13
|
+
const GeolocationParams = require("ip-geolocation-api-javascript-sdk/GeolocationParams.js");
|
|
14
|
+
const ipGeo = new IPGeolocationAPI(`${process.env.IPGEO_API_KEY}`, true);
|
|
15
|
+
|
|
16
|
+
getGeo = (ip) => {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
const params = new GeolocationParams();
|
|
19
|
+
params.setIPAddress(ip);
|
|
20
|
+
params.setFields("geo,time_zone,currency,asn,security");
|
|
21
|
+
ipGeo.getGeolocation((res) => resolve(res), params);
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
}
|
|
21
25
|
|
|
22
26
|
// -------------------- CLI / CONFIG --------------------
|
|
23
27
|
const argv = process.argv.slice(2);
|
|
@@ -60,7 +64,14 @@ function saveState(s){try{fs.mkdirSync(path.dirname(STATE_FILE),{recursive:true,
|
|
|
60
64
|
const STATE=loadState();
|
|
61
65
|
|
|
62
66
|
// -------------------- IP extraction --------------------
|
|
63
|
-
function extractIpFromLine(line){
|
|
67
|
+
function extractIpFromLine(line){
|
|
68
|
+
// garde ton extracteur d’origine (IPv4 + IPv6)
|
|
69
|
+
const v4 = line.match(/\b(?:\d{1,3}\.){3}\d{1,3}\b/);
|
|
70
|
+
if(v4&&v4[0]) return v4[0];
|
|
71
|
+
const v6 = line.match(/\b([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}\b/);
|
|
72
|
+
if(v6&&v6[0]) return v6[0];
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
64
75
|
|
|
65
76
|
// -------------------- nmap helpers (parallel support) --------------------
|
|
66
77
|
function spawnOneNmap(args, outFile) {
|
|
@@ -149,16 +160,17 @@ async function performScan(ip){
|
|
|
149
160
|
|
|
150
161
|
try{ fs.writeFileSync(path.join(outDir,'summary.json'),JSON.stringify(summary,null,2)); } catch (e) {}
|
|
151
162
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
163
|
+
if(process.env.IPGEO_API_KEY){
|
|
164
|
+
getGeo(ip)
|
|
165
|
+
.then(geo => { try{ fs.writeFileSync(path.join(outDir,'geo.json'), JSON.stringify(geo, null, 2)); }catch{} })
|
|
166
|
+
.catch(()=>{});
|
|
167
|
+
}
|
|
156
168
|
|
|
157
169
|
try{ fs.chmodSync(outDir,0o750); } catch (e) {}
|
|
158
170
|
log('Scan written for',ip,'->',outDir);
|
|
159
171
|
}
|
|
160
172
|
|
|
161
|
-
// -------------------- queue
|
|
173
|
+
// -------------------- queue --------------------
|
|
162
174
|
class ScanQueue{
|
|
163
175
|
constructor(concurrency=1){this.concurrency=concurrency;this.running=0;this.q=[];this.set=STATE.seen;this.tmpCache=new Set();}
|
|
164
176
|
push(ip){
|
|
@@ -192,7 +204,9 @@ const concurrency = CORE_OVERRIDE||USER_CONCURRENCY||os.cpus().length||1;
|
|
|
192
204
|
const q = new ScanQueue(concurrency);
|
|
193
205
|
log(`Fail2Scan started. Watching ${LOG_PATH} -> output ${OUT_ROOT}, concurrency ${concurrency}`);
|
|
194
206
|
|
|
195
|
-
|
|
207
|
+
// -------------------- FIX : regex BAN correct --------------------
|
|
208
|
+
const BAN_RE = /Ban\s+(\d{1,3}(?:\.\d{1,3}){3})/;
|
|
209
|
+
|
|
196
210
|
class FileTail{
|
|
197
211
|
constructor(filePath,onLine){this.filePath=filePath;this.onLine=onLine;this.pos=0;this.inode=null;this.buf='';this.watch=null;this.start();}
|
|
198
212
|
start(){try{const st=fs.statSync(this.filePath);this.inode=st.ino;this.pos=st.size;}catch{this.inode=null;this.pos=0;}this._watch();this._readNew().catch(()=>{});}
|
|
@@ -200,7 +214,18 @@ class FileTail{
|
|
|
200
214
|
async _readNew(){try{const st=fs.statSync(this.filePath);if(st.size<this.pos)this.pos=0;if(st.size===this.pos)return;const stream=fs.createReadStream(this.filePath,{start:this.pos,end:st.size-1,encoding:'utf8'});for await(const chunk of stream){this.buf+=chunk;let idx;while((idx=this.buf.indexOf('\n'))>=0){const line=this.buf.slice(0,idx);this.buf=this.buf.slice(idx+1);if(line.trim())this.onLine(line);}}this.pos=st.size;}catch{}}
|
|
201
215
|
close(){try{this.watch?.close();}catch{}}
|
|
202
216
|
}
|
|
203
|
-
|
|
217
|
+
|
|
218
|
+
const tail=new FileTail(LOG_PATH,line=>{
|
|
219
|
+
try{
|
|
220
|
+
const m=line.match(BAN_RE);
|
|
221
|
+
if(!m) return;
|
|
222
|
+
const ip = m[1];
|
|
223
|
+
if(!ip) return;
|
|
224
|
+
q.push(ip);
|
|
225
|
+
}catch(e){
|
|
226
|
+
log('onLine handler error',e.message||e);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
204
229
|
|
|
205
230
|
function shutdown(){log('Shutting down Fail2Scan...');tail.close();const start=Date.now();const wait=()=>{if(q.running===0||Date.now()-start>10000)process.exit(0);setTimeout(wait,500);};wait();}
|
|
206
231
|
process.on('SIGINT',shutdown);
|