Jeff Becker
8 years ago
8 changed files with 126 additions and 5 deletions
@ -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 @@ |
|||||||
|
|
||||||
|
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 @@ |
|||||||
|
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 @@ |
|||||||
|
# |
||||||
|
# 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 @@ |
|||||||
|
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 @@ |
|||||||
|
[thresholds] |
||||||
|
max_floodfills_per_ip = 2 |
Loading…
Reference in new issue