started writing better tools
This commit is contained in:
parent
5ed68bced4
commit
b79d0f631d
|
@ -1,4 +1,6 @@
|
||||||
# Captiveportal web application using Bottle.py
|
# Captiveportal
|
||||||
|
# This is the web API the portal website speaks to and requests new clients
|
||||||
|
# to be added by running jobs in rq.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from pprint import pprint as pp
|
from pprint import pprint as pp
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Client tools
|
||||||
|
|
||||||
|
These tools deal with clients in IPtables backed by a PostgreSQL database.
|
||||||
|
|
||||||
|
A class is defined in client.py that handles creating and looking up clients.
|
|
@ -2,31 +2,43 @@
|
||||||
# Python helper tool to add IPtables rule using the iptc library. This must
|
# Python helper tool to add IPtables rule using the iptc library. This must
|
||||||
# of course run as root for iptc to work.
|
# of course run as root for iptc to work.
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser, FileType
|
||||||
from pprint import pprint as pp
|
from pprint import pprint as pp
|
||||||
|
from configparser import RawConfigParser
|
||||||
|
|
||||||
import iptc
|
from storage import StorageRedis
|
||||||
|
from client import Client
|
||||||
|
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
|
|
||||||
parser.add_argument('--chain', required=True)
|
parser.add_argument(
|
||||||
parser.add_argument('--protocol', required=True)
|
'--protocol',
|
||||||
parser.add_argument('--src-ip', required=True)
|
required=True,
|
||||||
|
choices=['tcp', 'udp'],
|
||||||
|
help='Protocol for client'
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'--config',
|
||||||
|
type=FileType('r'),
|
||||||
|
required=True,
|
||||||
|
help='Configuration file'
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
'src_ip',
|
||||||
|
help='Client source IP to add'
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
table = iptc.Table(iptc.Table.MANGLE)
|
config = RawConfigParser()
|
||||||
chain = iptc.Chain(table, args.chain)
|
config.readfp(args.config)
|
||||||
|
|
||||||
# Check if rule exists
|
sr = StorageRedis(config=config)
|
||||||
for rule in chain.rules:
|
client = Client(
|
||||||
src_ip = rule.src
|
storage=sr,
|
||||||
if src_ip.startswith(args.src_ip) and rule.protocol == args.protocol:
|
client_id=args.src_ip,
|
||||||
print('Rule exists')
|
protocol=args.protocol,
|
||||||
break
|
chain=config.get('iptables', 'chain')
|
||||||
else:
|
)
|
||||||
rule = iptc.Rule()
|
|
||||||
rule.src = args.src_ip
|
|
||||||
rule.protocol = args.protocol
|
|
||||||
rule.target = iptc.Target(rule, 'RETURN')
|
|
||||||
chain.insert_rule(rule)
|
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
"""
|
||||||
|
Handles "clients" in IPtables for captive portal.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
#import iptc
|
||||||
|
|
||||||
|
|
||||||
|
class Client(object):
|
||||||
|
|
||||||
|
def __init__(self, **kw):
|
||||||
|
self.storage = kw.pop('storage')
|
||||||
|
self.client_id = kw.pop('client_id')
|
||||||
|
self.protocol = kw.pop('protocol')
|
||||||
|
self.chain = kw.pop('chain')
|
||||||
|
|
||||||
|
# Default values for client data
|
||||||
|
self.data = {
|
||||||
|
'client_id': self.client_id,
|
||||||
|
'protocol': self.protocol,
|
||||||
|
'created': datetime.now(),
|
||||||
|
'bytes': 0,
|
||||||
|
'packets': 0,
|
||||||
|
'last_activity': None
|
||||||
|
}
|
||||||
|
|
||||||
|
self.client_exists = False
|
||||||
|
|
||||||
|
# Attempt to fetch client from storage
|
||||||
|
client_data = self.storage.get_client(self.client_id)
|
||||||
|
if client_data:
|
||||||
|
self.data = client_data
|
||||||
|
self.exists = True
|
||||||
|
|
||||||
|
|
||||||
|
def commit(self):
|
||||||
|
self.commit_client()
|
||||||
|
#self.commit_rule()
|
||||||
|
|
||||||
|
|
||||||
|
def commit_client(self):
|
||||||
|
if self.exists:
|
||||||
|
self.storage.update_client(
|
||||||
|
self.client_id,
|
||||||
|
**self.data
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.storage.add_client(
|
||||||
|
self.client_id,
|
||||||
|
**self.data
|
||||||
|
)
|
||||||
|
|
||||||
|
def commit_rule(self):
|
||||||
|
table = iptc.Table(iptc.Table.MANGLE)
|
||||||
|
chain = iptc.Chain(table, self.chain)
|
||||||
|
|
||||||
|
# Check if rule exists
|
||||||
|
for rule in chain.rules:
|
||||||
|
src_ip = rule.src
|
||||||
|
if src_ip.startswith(self.client_id) and rule.protocol == self.protocol:
|
||||||
|
print('Rule exists')
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
rule = iptc.Rule()
|
||||||
|
rule.src = self.client_id
|
||||||
|
rule.protocol = self.protocol
|
||||||
|
rule.target = iptc.Target(rule, 'RETURN')
|
||||||
|
chain.insert_rule(rule)
|
|
@ -0,0 +1,10 @@
|
||||||
|
[pgsql]
|
||||||
|
hostname=localhost
|
||||||
|
username=captiveportal
|
||||||
|
password=secret.
|
||||||
|
database=captiveportal
|
||||||
|
|
||||||
|
[redis]
|
||||||
|
hostname=localhost
|
||||||
|
port=6379
|
||||||
|
db=0
|
|
@ -0,0 +1,35 @@
|
||||||
|
"""
|
||||||
|
Database storage backends for client.py.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from redis import Redis
|
||||||
|
|
||||||
|
|
||||||
|
class DateTimeEncoder(json.JSONEncoder):
|
||||||
|
"""
|
||||||
|
json.JSONEncoder sub-class that converts all datetime objects to
|
||||||
|
epoch timestamp integer values.
|
||||||
|
"""
|
||||||
|
def default(self, o):
|
||||||
|
if isinstance(o, datetime):
|
||||||
|
return int(o.strftime('%s'))
|
||||||
|
return json.JSONEncoder.default(self, o)
|
||||||
|
|
||||||
|
|
||||||
|
class StorageRedis(object):
|
||||||
|
|
||||||
|
def __init__(self, **kw):
|
||||||
|
config = kw.pop('config')
|
||||||
|
|
||||||
|
self.r = Redis(
|
||||||
|
host=config.get('redis', 'hostname'),
|
||||||
|
port=config.getint('redis', 'port'),
|
||||||
|
db=config.getint('redis', 'db')
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def add_client(self, client_id, **kw):
|
||||||
|
pass
|
Loading…
Reference in New Issue