Jeff Becker
8 years ago
8 changed files with 126 additions and 5 deletions
@ -0,0 +1,29 @@
@@ -0,0 +1,29 @@
|
||||
# |
||||
# |
||||
# |
||||
|
||||
import netdb |
||||
|
||||
|
||||
from argparse import ArgumentParser as AP |
||||
|
||||
from . import settings |
||||
from . import filter |
||||
from . import processor |
||||
|
||||
def main(): |
||||
ap = AP() |
||||
ap.add_argument("--settings", default="baddies.ini") |
||||
|
||||
args = ap.parse_args() |
||||
s = settings.load(args.settings) |
||||
fmax = s.get("thresholds", "max_floodfills_per_ip", fallback=5) |
||||
f = filter.FloodfillFilter(fmax) |
||||
p = processor.BaddieProcessor([f]) |
||||
netdb.inspect(p.hook) |
||||
with open(s.get("output", "file", fallback="baddies.txt"), 'w') as f: |
||||
p.write_blocklist(f) |
||||
|
||||
|
||||
if __name__ == "__main__": |
||||
main() |
@ -0,0 +1,32 @@
@@ -0,0 +1,32 @@
|
||||
|
||||
from . import util |
||||
|
||||
class Filter: |
||||
|
||||
name = "unnamed filter" |
||||
|
||||
def process(self, info): |
||||
""" |
||||
process an info and return True if it should be added to blocklist |
||||
any other return value will cause this info to NOT be added to blocklist |
||||
""" |
||||
|
||||
class FloodfillFilter(Filter): |
||||
|
||||
name = "floodfill sybil detector" |
||||
|
||||
def __init__(self, fmax): |
||||
self._floodfills = dict() |
||||
self.fmax = int(fmax) |
||||
|
||||
def process(self, info): |
||||
caps = util.getcaps(info) |
||||
if not caps: |
||||
return False |
||||
if b'f' not in caps: |
||||
return False |
||||
h = util.getaddress(info) |
||||
if h not in self._floodfills: |
||||
self._floodfills[h] = 0 |
||||
self._floodfills[h] += 1 |
||||
return self._floodfills[h] > self.fmax |
@ -0,0 +1,26 @@
@@ -0,0 +1,26 @@
|
||||
from . import util |
||||
|
||||
import datetime |
||||
|
||||
class BaddieProcessor: |
||||
|
||||
def __init__(self, filters): |
||||
self._filters = filters |
||||
self._baddies = dict() |
||||
|
||||
|
||||
def hook(self, entry): |
||||
for f in self._filters: |
||||
if f.process(entry) is True: |
||||
self.add_baddie(entry, 'detected by {}'.format(f.name)) |
||||
|
||||
def add_baddie(self, entry, reason): |
||||
addr = util.getaddress(entry) |
||||
if addr not in self._baddies: |
||||
self._baddies[addr] = '' |
||||
self._baddies[addr] += reason + ' ' |
||||
|
||||
def write_blocklist(self, f): |
||||
f.write('# baddies blocklist generated on {}'.format(datetime.datetime.now())) |
||||
for k in self._baddies: |
||||
f.write('{}:{}\n'.format(self._baddies[k], k)) |
@ -0,0 +1,11 @@
@@ -0,0 +1,11 @@
|
||||
# |
||||
# baddiefinder settings wrapper |
||||
# |
||||
|
||||
from configparser import ConfigParser |
||||
|
||||
def load(fname): |
||||
c = ConfigParser() |
||||
with open(fname) as f: |
||||
c.read_file(f, fname) |
||||
return c |
@ -0,0 +1,15 @@
@@ -0,0 +1,15 @@
|
||||
def getaddress(info): |
||||
""" |
||||
get ip address from router info dict |
||||
""" |
||||
for addr in info.addrs: |
||||
opts = addr.options |
||||
if b'host' in opts: |
||||
return opts[b'host'] |
||||
|
||||
def getcaps(info): |
||||
""" |
||||
extract router caps |
||||
""" |
||||
if b'caps' in info.options: |
||||
return info.options[b'caps'] |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
[thresholds] |
||||
max_floodfills_per_ip = 2 |
Loading…
Reference in new issue