9 changed files with 0 additions and 759 deletions
-
13agent.py
-
33agent/db.py
-
52agent/firewall.py
-
72agent/ipfw.sh
-
139agent/main.py
-
159agent/models.py
-
242agent/sslTransmitter.py
-
18install.sql
-
31shaper.sh
@ -1,13 +0,0 @@ |
|||||
#!/bin/env python2 |
|
||||
|
|
||||
import os |
|
||||
|
|
||||
from agent import main |
|
||||
|
|
||||
|
|
||||
if __name__ == "__main__": |
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djing.settings") |
|
||||
|
|
||||
while True: |
|
||||
main(debug=True) |
|
||||
print "Exit from main, reload..." |
|
||||
@ -1,33 +0,0 @@ |
|||||
# -*- coding:utf-8 -*- |
|
||||
from json import loads |
|
||||
|
|
||||
import requests |
|
||||
from requests.exceptions import ConnectionError |
|
||||
|
|
||||
from models import deserialize_tariffs, deserialize_abonents |
|
||||
import settings |
|
||||
|
|
||||
|
|
||||
def load_from_db(): |
|
||||
try: |
|
||||
r = requests.get('%s://%s:%d/abons/api/abons' % ( |
|
||||
'https' if settings.IS_USE_SSL else 'http', |
|
||||
settings.SERVER_IP, |
|
||||
settings.SERVER_PORT |
|
||||
), verify=False) |
|
||||
user_data = loads(r.text) |
|
||||
|
|
||||
# Получаем тарифы |
|
||||
tariffs = deserialize_tariffs(user_data) |
|
||||
|
|
||||
# Получаем пользователей |
|
||||
abons = deserialize_abonents(user_data, tariffs) |
|
||||
|
|
||||
return abons, tariffs |
|
||||
|
|
||||
except ValueError as e: |
|
||||
print('Error:', e, r.text) |
|
||||
|
|
||||
except ConnectionError: |
|
||||
print("Can not connect to server %s:%d..." % (settings.SERVER_IP, settings.SERVER_PORT)) |
|
||||
exit(0) |
|
||||
@ -1,52 +0,0 @@ |
|||||
# -*- coding:utf-8 -*- |
|
||||
from agent.models import Abonent, Tariff |
|
||||
|
|
||||
|
|
||||
class FirewallManager(object): |
|
||||
f = r'/sbin/ipfw -q' |
|
||||
|
|
||||
# вызывает комманду shell |
|
||||
def exec_cmd(self, cmd): |
|
||||
print cmd |
|
||||
# os.execv(cmd, ['']) |
|
||||
|
|
||||
# ставит заглушку на абонента |
|
||||
def set_cap(self, user): |
|
||||
pass |
|
||||
|
|
||||
# Открывает доступ в интернет |
|
||||
def open_inet_door(self, user): |
|
||||
assert isinstance(user, Abonent) |
|
||||
if not user.tariff: |
|
||||
print u'WARNING: User does not have a tariff' |
|
||||
return |
|
||||
cmd = r"%s table 12 add %s/32 %d && %s table 13 add %s/32 %d" % ( |
|
||||
self.f, user.ip_str(), user.tariff.tid, |
|
||||
self.f, user.ip_str(), user.tariff.tid + 1000 |
|
||||
) |
|
||||
self.exec_cmd(cmd) |
|
||||
|
|
||||
# Закрывает доступ в интернет |
|
||||
def close_inet_door(self, user): |
|
||||
assert isinstance(user, Abonent) |
|
||||
cmd = r"%s table 12 del %s/32 && %s table 13 del %s/32" % ( |
|
||||
self.f, user.ip_str(), |
|
||||
self.f, user.ip_str() |
|
||||
) |
|
||||
self.exec_cmd(cmd) |
|
||||
|
|
||||
# Создаёт тариф (пайпы, режущие скорость |
|
||||
def make_tariff(self, tariff): |
|
||||
assert isinstance(tariff, Tariff) |
|
||||
cmd = r"make ipfw tariff :)" |
|
||||
self.exec_cmd(cmd) |
|
||||
|
|
||||
# Убирает тариф из фаервола |
|
||||
def destroy_tariff(self, tariff): |
|
||||
assert isinstance(tariff, Tariff) |
|
||||
cmd = r"destroy ipfw tariff :)" |
|
||||
self.exec_cmd(cmd) |
|
||||
|
|
||||
def reset(self): |
|
||||
cmd = r"%s -f flush && %s table all flush" % (self.f, self.f) |
|
||||
self.exec_cmd(cmd) |
|
||||
@ -1,72 +0,0 @@ |
|||||
#!/bin/sh |
|
||||
|
|
||||
######################################################### |
|
||||
# ВАЖНО! Биллинг пока ограничен количеством тарифных планов |
|
||||
# не больше 1000 |
|
||||
######################################################### |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
f="/sbin/ipfw -q" |
|
||||
|
|
||||
lan=em1 # Clients |
|
||||
wan=em0 # Inet |
|
||||
|
|
||||
|
|
||||
${f} -f flush |
|
||||
${f} table all flush |
|
||||
|
|
||||
sysctl net.inet.ip.fw.one_pass=0 |
|
||||
|
|
||||
# dns |
|
||||
${f} table 100 add 8.8.8.8 # google public dns |
|
||||
${f} table 100 add 8.8.4.4 # google public dns2 |
|
||||
${f} table 100 add 77.88.8.8 # yandex base dns |
|
||||
${f} table 100 add 77.88.8.1 # yandex base dns2 |
|
||||
|
|
||||
|
|
||||
# ssh access |
|
||||
${f} add 50 allow tcp from any to me 22 |
|
||||
${f} add 51 allow tcp from me 22 to any |
|
||||
|
|
||||
|
|
||||
# loopback |
|
||||
${f} add 100 allow ip from any to any via lo0 |
|
||||
|
|
||||
|
|
||||
# в таблице 100 приоритетный траффик. |
|
||||
# это dns, платёжки.. |
|
||||
${f} add 500 allow ip from table\(100\) to any |
|
||||
${f} add 501 allow ip from any to table\(100\) |
|
||||
|
|
||||
|
|
||||
|
|
||||
# в таблице 10 разрешённые пользователи |
|
||||
# блокируем трафик всем кто не в ней |
|
||||
${f} add 1001 deny ip from not table\(10\) to any via $wan |
|
||||
|
|
||||
# если у абонентов есть внешние адреса (не через NAT) |
|
||||
#${f} add 1101 deny ip from any to not table\(10\) via $wan |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
# по 2 пайпа на тарифный план, на вход и выход |
|
||||
#${f} pipe 212 config bw 1152Kbit/s mask src-ip 0xffffffff noerror |
|
||||
#${f} pipe 213 config bw 1152Kbit/s mask dst-ip 0xffffffff noerror |
|
||||
|
|
||||
# добавляем пайпы в таблицу |
|
||||
${f} add 2001 pipe 212 ip from table\(10\) to any via $wan |
|
||||
${f} add 2002 pipe 213 ip from any to table\(11\) via $wan |
|
||||
|
|
||||
#---------------------- |
|
||||
# так добавляем абонентов чтоб резать скорость, надо указать номер их пайпа |
|
||||
#${f} table 10 add 10.0.172.138/32 212 |
|
||||
#${f} table 11 add 10.0.172.138/32 2212 |
|
||||
#---------------------- |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
# тут будем поджимать пользователей когда не хватает канала |
|
||||
@ -1,139 +0,0 @@ |
|||||
# -*- coding:utf-8 -*- |
|
||||
from sys import stdout |
|
||||
from time import sleep |
|
||||
|
|
||||
from db import load_from_db |
|
||||
from firewall import FirewallManager |
|
||||
from sslTransmitter import TransmitServer |
|
||||
from agent.models import Abonent, Tariff |
|
||||
|
|
||||
|
|
||||
def filter_user_by_id(users, uid): |
|
||||
# users = filter(lambda usr: isinstance(usr, Abonent), users) |
|
||||
users = filter(lambda usr: usr.uid == uid, users) |
|
||||
if len(users) > 0: |
|
||||
return users[0] |
|
||||
|
|
||||
|
|
||||
def filter_tariff_by_id(tariffs, tid): |
|
||||
# tariffs = filter(lambda trf: isinstance(trf, Tariff), tariffs) |
|
||||
tariffs = filter(lambda trf: trf.tid == tid, tariffs) |
|
||||
if len(tariffs) > 0: |
|
||||
return tariffs[0] |
|
||||
|
|
||||
|
|
||||
def create_abon(tariffs, users, event, frw): |
|
||||
print('SIGNAL: Create abon') |
|
||||
trf = filter_tariff_by_id(tariffs, int(event.dt['tarif_id'])) |
|
||||
abon = Abonent( |
|
||||
int(event.id), |
|
||||
int(event.dt['ip']), |
|
||||
trf |
|
||||
) |
|
||||
users.append(abon) |
|
||||
if abon.is_access(): |
|
||||
frw.open_inet_door(abon) |
|
||||
|
|
||||
|
|
||||
def main(debug=False): |
|
||||
users, tariffs = load_from_db() |
|
||||
frw = FirewallManager() |
|
||||
frw.reset() |
|
||||
|
|
||||
# Инициализация абонентов |
|
||||
if debug: |
|
||||
print("Инициализация...") |
|
||||
# Открываем доступ в инет тем кто активен и у кого подключён тариф |
|
||||
for usr in filter(lambda usr: usr.is_active, users): |
|
||||
|
|
||||
# даём услуги если можно |
|
||||
if usr.is_access(): |
|
||||
# Открываем доступ в инет |
|
||||
frw.open_inet_door(usr) |
|
||||
if debug: print "Разрешён доступ в инет для:", usr.ip_str() |
|
||||
|
|
||||
# Слушем в отдельном процессе сеть на предмет событий |
|
||||
ts = TransmitServer('127.0.0.1', 2134) |
|
||||
ts.start() |
|
||||
|
|
||||
if debug: print("Загружено %d абонентов" % len(users)) |
|
||||
|
|
||||
while True: |
|
||||
# Загружаем события для абонентов из сети (список объектов EventNAS из models) |
|
||||
events = ts.get_data() |
|
||||
# Проходим по появившимся событиям |
|
||||
for event in events: |
|
||||
# event.toa, event.id, event.dt |
|
||||
|
|
||||
# Смотрим тип события |
|
||||
toa = int(event.toa) |
|
||||
if toa == 0: |
|
||||
continue |
|
||||
|
|
||||
# создаём абонента |
|
||||
elif toa == 1: |
|
||||
create_abon(tariffs, users, event, frw) |
|
||||
|
|
||||
# Сигнал о том что инфа об абоненте изменилась, надо перечитать |
|
||||
elif toa == 2: |
|
||||
print('SIGNAL: Change abon') |
|
||||
usr = filter_user_by_id(users, event.id) |
|
||||
# если есть то меняем инфу о клиенте |
|
||||
if usr: |
|
||||
usr.deserialize(event.dt, tariffs) |
|
||||
# в любом случае сначала очистить всю инфу о клиенте из таблицы фаера |
|
||||
frw.close_inet_door(usr) |
|
||||
# если у абонента есть доступ то можно и в инет |
|
||||
if usr.is_access(): |
|
||||
frw.open_inet_door(usr) |
|
||||
# Иначе создаём клиента |
|
||||
else: |
|
||||
create_abon(tariffs, users, event, frw) |
|
||||
|
|
||||
# Удаляем абонента |
|
||||
elif toa == 3: |
|
||||
print('SIGNAL: Delete abon') |
|
||||
usr = filter_user_by_id(users, event.id) |
|
||||
frw.close_inet_door(usr) |
|
||||
users.remove(usr) |
|
||||
|
|
||||
# Создаём тариф |
|
||||
elif toa == 4: |
|
||||
print('SIGNAL: Create tariff') |
|
||||
trf = Tariff( |
|
||||
int(event.dt['tid']), |
|
||||
float(event.dt['speedIn']), |
|
||||
float(event.dt['speedOut']) |
|
||||
) |
|
||||
tariffs.append(trf) |
|
||||
frw.make_tariff(trf) |
|
||||
|
|
||||
# Обновить тарифф |
|
||||
elif toa == 5: |
|
||||
print('SIGNAL: Change tariff') |
|
||||
trf = filter_tariff_by_id(tariffs, int(event.dt['tarif_id'])) |
|
||||
trf.deserialize(event.dt) |
|
||||
frw.destroy_tariff(trf) |
|
||||
frw.make_tariff(trf) |
|
||||
|
|
||||
# Удалить тарифф |
|
||||
elif toa == 6: |
|
||||
print('SIGNAL: Delete tariff') |
|
||||
ban_users = filter(lambda usr: usr.tariff.tid == usr.tariff.tid, users) |
|
||||
for usr in ban_users: |
|
||||
frw.close_inet_door(usr) |
|
||||
trf = filter_tariff_by_id(tariffs, int(event.dt['tarif_id'])) |
|
||||
tariffs.remove(trf) |
|
||||
|
|
||||
elif toa == 7: |
|
||||
# Сигнал на перезагрузку |
|
||||
# Выходим из main, выше она в цикле запустится ещё раз |
|
||||
return |
|
||||
|
|
||||
# Очищаем очередь событий |
|
||||
ts.clear() |
|
||||
|
|
||||
# ждём время между итерациями проверки 10 сек... |
|
||||
sleep(10) |
|
||||
stdout.write('.') |
|
||||
stdout.flush() |
|
||||
@ -1,159 +0,0 @@ |
|||||
# -*- coding:utf-8 -*- |
|
||||
import socket |
|
||||
import struct |
|
||||
from json import loads, dumps |
|
||||
from abc import ABCMeta, abstractmethod |
|
||||
|
|
||||
|
|
||||
class Serializer(object): |
|
||||
__metaclass__ = ABCMeta |
|
||||
|
|
||||
@abstractmethod |
|
||||
def _serializable_obj(self): |
|
||||
"""Вернуть словарь для сериализации""" |
|
||||
|
|
||||
def serialize(self): |
|
||||
return dumps(self._serializable_obj()) |
|
||||
|
|
||||
@abstractmethod |
|
||||
def deserialize(self, *args): |
|
||||
"""Надо обязательно этот метод реализовать, он много где используется. |
|
||||
Из JSON создать объект класса где реализуется метод""" |
|
||||
|
|
||||
|
|
||||
def serialize_tariffs(tariffs): |
|
||||
dt = map(lambda trf: trf._serializable_obj(), tariffs) |
|
||||
return dumps({'tariffs': dt}) |
|
||||
|
|
||||
|
|
||||
def deserialize_tariffs(dat): |
|
||||
dat = loads(dat) if type(dat) == str else dat |
|
||||
# Распаковываем из JSON массива dat['tariffs'] объекты через метод deserialize |
|
||||
return map(lambda tariff: Tariff().deserialize(tariff), dat['tariffs']) |
|
||||
|
|
||||
|
|
||||
def serialize_abonents(abonents): |
|
||||
dt = map(lambda abn: abn._serializable_obj(), abonents) |
|
||||
return dumps({'subscribers': dt}) |
|
||||
|
|
||||
|
|
||||
def deserialize_abonents(dat, tariffs): |
|
||||
dat = loads(dat) if type(dat) == str else dat |
|
||||
# Распаковываем из JSON массива dat['subscribers'] объекты через метод deserialize |
|
||||
return map(lambda abon: Abonent().deserialize(abon, tariffs), dat['subscribers']) |
|
||||
|
|
||||
|
|
||||
class Tariff(Serializer): |
|
||||
tid = 0 |
|
||||
speedIn = 0.0 |
|
||||
speedOut = 0.0 |
|
||||
|
|
||||
def __init__(self, tariff_id=None, speed_in=None, speed_out=None): |
|
||||
self.tid = tariff_id |
|
||||
self.speedOut = speed_out |
|
||||
self.speedIn = speed_in |
|
||||
|
|
||||
def is_active(self): |
|
||||
"""возвращает активность тарифа. Если он не активен то пропустить""" |
|
||||
return True |
|
||||
|
|
||||
def _serializable_obj(self): |
|
||||
return { |
|
||||
'id': self.tid, |
|
||||
'speedIn': self.speedIn, |
|
||||
'speedOut': self.speedOut |
|
||||
} |
|
||||
|
|
||||
def deserialize(self, dump): |
|
||||
inf = loads(dump) if type(dump) == str else dump |
|
||||
self.speedIn = float(inf['speedIn']) |
|
||||
self.speedOut = float(inf['speedOut']) |
|
||||
self.tid = int(inf['id']) |
|
||||
return self |
|
||||
|
|
||||
|
|
||||
class Abonent(Serializer): |
|
||||
uid = 0 |
|
||||
tariff = Tariff() |
|
||||
ip = 0xffffffff |
|
||||
|
|
||||
# Включён-ли абонент |
|
||||
is_active = True |
|
||||
|
|
||||
def __init__(self, uid=None, ip=None, tariff=None, is_active=True): |
|
||||
# none потому что может инициализироваться пустым, чтоб быть распакованным через deserialize() |
|
||||
if tariff: |
|
||||
assert isinstance(tariff, Tariff) |
|
||||
self.ip = ip |
|
||||
self.uid = uid |
|
||||
self.tariff = tariff |
|
||||
self.is_active = is_active |
|
||||
|
|
||||
def ip_str(self): |
|
||||
return socket.inet_ntoa(struct.pack("!I", self.ip)) |
|
||||
|
|
||||
def _serializable_obj(self): |
|
||||
return { |
|
||||
'id': self.uid, |
|
||||
'is_active': bool(self.is_active), |
|
||||
'ip': self.ip, |
|
||||
'tarif_id': self.tariff.tid if self.tariff else 0 |
|
||||
} |
|
||||
|
|
||||
def deserialize(self, dump, tariffs): |
|
||||
# фильтруем только элементы нужного типа |
|
||||
tariffs = filter(lambda trf: isinstance(trf, Tariff), tariffs) |
|
||||
assert len(tariffs) > 0 |
|
||||
|
|
||||
inf = loads(dump) if type(dump) == str else dump |
|
||||
self.uid = int(inf['id']) |
|
||||
self.is_active = bool(inf['is_active']) |
|
||||
self.ip = int(inf['ip']) |
|
||||
|
|
||||
tarif_id = int(inf['tarif_id']) |
|
||||
dbtrf = filter(lambda trf: trf.tid == tarif_id, tariffs) |
|
||||
if len(dbtrf) > 0: |
|
||||
self.tariff = dbtrf[0] |
|
||||
else: |
|
||||
self.tariff = None |
|
||||
return self |
|
||||
|
|
||||
def is_access(self): |
|
||||
# Доступ в интернет происходит по наличию подключённого тарифа |
|
||||
# если тарифа нет, то и инета нет |
|
||||
if self.is_active and self.tariff is not None: |
|
||||
return True |
|
||||
else: |
|
||||
return False |
|
||||
|
|
||||
|
|
||||
class EventNAS(Serializer): |
|
||||
# Type Of Action |
|
||||
toa = 0 |
|
||||
|
|
||||
# id of object |
|
||||
id = 0 |
|
||||
|
|
||||
# extended data |
|
||||
dt = object() |
|
||||
|
|
||||
def __init__(self, type_action=None, obj_id=None, ext_data=None): |
|
||||
self.toa = type_action |
|
||||
self.id = obj_id |
|
||||
self.dt = ext_data |
|
||||
|
|
||||
def _serializable_obj(self): |
|
||||
if self.dt: |
|
||||
return {'toa': self.toa, 'id': self.id, 'dt': self.dt} |
|
||||
else: |
|
||||
return {'toa': self.toa, 'id': self.id} |
|
||||
|
|
||||
def deserialize(self, dump): |
|
||||
try: |
|
||||
inf = loads(dump) if type(dump) == str else dump |
|
||||
except ValueError: |
|
||||
return |
|
||||
self.toa = int(inf['toa']) |
|
||||
self.id = int(inf['id']) |
|
||||
self.dt = inf.get('dt') |
|
||||
return self |
|
||||
@ -1,242 +0,0 @@ |
|||||
# -*- coding: utf-8 -*- |
|
||||
import ssl |
|
||||
import socket |
|
||||
from multiprocessing import Process, Manager |
|
||||
|
|
||||
import settings |
|
||||
from models import EventNAS, Abonent, Tariff |
|
||||
|
|
||||
|
|
||||
class NetExcept(Exception): |
|
||||
def __init__(self, value): |
|
||||
self.value = value |
|
||||
|
|
||||
def __str__(self): |
|
||||
return repr(self.value) |
|
||||
|
|
||||
|
|
||||
class SSLTransmitterServer(object): |
|
||||
bindsocket = None |
|
||||
|
|
||||
def connect(self, ip, port): |
|
||||
self.bindsocket = socket.socket() |
|
||||
self.bindsocket.bind((ip, port)) |
|
||||
self.bindsocket.listen(5) |
|
||||
|
|
||||
@staticmethod |
|
||||
def _on_data_recive(v, data): |
|
||||
print "do_something:", data |
|
||||
# with lock: |
|
||||
dat = EventNAS().deserialize(data) |
|
||||
if dat is not None: |
|
||||
v.append(dat) |
|
||||
else: |
|
||||
print 'ERROR: bad data:', data |
|
||||
return False |
|
||||
|
|
||||
def _deal_with_client(self, connstream, v): |
|
||||
data = connstream.read() |
|
||||
while data: |
|
||||
if not self._on_data_recive(v, data): |
|
||||
break |
|
||||
data = connstream.read() |
|
||||
|
|
||||
def process(self, v): |
|
||||
while True: |
|
||||
newsocket, fromaddr = self.bindsocket.accept() |
|
||||
connstream = ssl.wrap_socket(newsocket, |
|
||||
server_side=True, |
|
||||
certfile=settings.CERTFILE, |
|
||||
keyfile=settings.KEYFILE) |
|
||||
try: |
|
||||
self._deal_with_client(connstream, v) |
|
||||
finally: |
|
||||
connstream.shutdown(socket.SHUT_RDWR) |
|
||||
connstream.close() |
|
||||
|
|
||||
|
|
||||
class PlainTransmitterServer(SSLTransmitterServer): |
|
||||
def process(self, v): |
|
||||
while True: |
|
||||
newsocket, fromaddr = self.bindsocket.accept() |
|
||||
dat = newsocket.recv(0xffff) |
|
||||
if not dat: |
|
||||
break |
|
||||
self._on_data_recive(v, dat) |
|
||||
|
|
||||
|
|
||||
# Декоратор переводит классы абонента базы к объекту агента если надо. |
|
||||
# abonapp.models.Abon -> agent.Abonent |
|
||||
def agent_abon_typer(fn): |
|
||||
def wrapped(self, abon): |
|
||||
if isinstance(abon, Abonent): |
|
||||
fn(self, abon) |
|
||||
else: |
|
||||
act_tar = abon.active_tariff() |
|
||||
agent_tariff = Tariff(act_tar.id, act_tar.speedIn, act_tar.speedOut) if act_tar else None |
|
||||
abn = Abonent( |
|
||||
abon.id, |
|
||||
abon.ip_address.int_ip() if abon.ip_address else 0, |
|
||||
agent_tariff, |
|
||||
abon.is_active |
|
||||
) |
|
||||
fn(self, abn) |
|
||||
|
|
||||
return wrapped |
|
||||
|
|
||||
|
|
||||
# Декоратор переводит классы тарифа базы к объекту агента если надо. |
|
||||
# tariff_app.models.Tariff -> agent.Tariff |
|
||||
def agent_tariff_typer(fn): |
|
||||
def wrapped(self, tariff): |
|
||||
if isinstance(tariff, Tariff): |
|
||||
fn(self, tariff) |
|
||||
else: |
|
||||
trf = Tariff( |
|
||||
tariff.id, |
|
||||
tariff.speedIn, |
|
||||
tariff.speedOut |
|
||||
) |
|
||||
fn(self, trf) |
|
||||
|
|
||||
return wrapped |
|
||||
|
|
||||
|
|
||||
class SSLTransmitterClient(object): |
|
||||
s = None |
|
||||
|
|
||||
def __init__(self, ip=None, port=None): |
|
||||
try: |
|
||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
||||
# Require a certificate from the server. We used a self-signed certificate |
|
||||
# so here ca_certs must be the server certificate itself. |
|
||||
self.s = ssl.wrap_socket(s, |
|
||||
ca_certs=settings.CERTFILE, |
|
||||
cert_reqs=ssl.CERT_REQUIRED) |
|
||||
self.s.connect(( |
|
||||
ip or settings.SELF_IP, |
|
||||
port or settings.SELF_PORT |
|
||||
)) |
|
||||
except socket.error: |
|
||||
raise NetExcept('Ошибка подключения к NAS агенту %s:%d' % ( |
|
||||
ip or settings.SELF_IP, |
|
||||
port or settings.SELF_PORT |
|
||||
)) |
|
||||
|
|
||||
def write(self, d): |
|
||||
self.s.write(d) |
|
||||
|
|
||||
# Создаём абонента |
|
||||
@agent_abon_typer |
|
||||
def signal_abon_create(self, abon): |
|
||||
self.write( |
|
||||
EventNAS(1, abon.id, abon._serializable_obj()).serialize() |
|
||||
) |
|
||||
|
|
||||
# Обновляем абонента |
|
||||
@agent_abon_typer |
|
||||
def signal_abon_refresh(self, abon): |
|
||||
self.write( |
|
||||
EventNAS(2, abon.uid, abon._serializable_obj()).serialize() |
|
||||
) |
|
||||
|
|
||||
# Удаляем абонента |
|
||||
@agent_abon_typer |
|
||||
def signal_abon_remove(self, abon): |
|
||||
self.write( |
|
||||
EventNAS(3, abon.id).serialize() |
|
||||
) |
|
||||
|
|
||||
# Создаём тариф |
|
||||
@agent_tariff_typer |
|
||||
def signal_tariff_create(self, tariff): |
|
||||
self.write( |
|
||||
EventNAS(4, tariff.tid, tariff._serializable_obj()).serialize() |
|
||||
) |
|
||||
|
|
||||
# Обновляем тариф |
|
||||
@agent_tariff_typer |
|
||||
def signal_tariff_refresh(self, tariff): |
|
||||
self.write( |
|
||||
EventNAS(5, tariff.tid, tariff._serializable_obj()).serialize() |
|
||||
) |
|
||||
|
|
||||
# Удаляем тариф |
|
||||
@agent_tariff_typer |
|
||||
def signal_tariff_remove(self, tariff): |
|
||||
self.write( |
|
||||
EventNAS(6, tariff.tid).serialize() |
|
||||
) |
|
||||
|
|
||||
# Перезагружаем всё |
|
||||
@agent_abon_typer |
|
||||
def signal_agent_reboot(self): |
|
||||
self.write( |
|
||||
EventNAS(7, 0).serialize() |
|
||||
) |
|
||||
|
|
||||
def __del__(self): |
|
||||
if self.s: |
|
||||
self.s.close() |
|
||||
|
|
||||
|
|
||||
class PlainTransmitterClient(SSLTransmitterClient): |
|
||||
def __init__(self, ip=None, port=None): |
|
||||
try: |
|
||||
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
|
||||
self.s.connect(( |
|
||||
ip or settings.SELF_IP, |
|
||||
port or settings.SELF_PORT |
|
||||
)) |
|
||||
except socket.error: |
|
||||
raise NetExcept(u'Ошибка подключения к NAS агенту на %s:%d' % ( |
|
||||
ip or settings.SELF_IP, |
|
||||
port or settings.SELF_PORT |
|
||||
)) |
|
||||
|
|
||||
def write(self, d): |
|
||||
self.s.send(d) |
|
||||
|
|
||||
|
|
||||
# общалка с NAS'ом |
|
||||
def get_TransmitterClientKlass(): |
|
||||
if settings.IS_USE_SSL: |
|
||||
return SSLTransmitterClient |
|
||||
else: |
|
||||
return PlainTransmitterClient |
|
||||
|
|
||||
|
|
||||
def get_TransmitterServerKlass(): |
|
||||
if settings.IS_USE_SSL: |
|
||||
return SSLTransmitterServer |
|
||||
else: |
|
||||
return PlainTransmitterServer |
|
||||
|
|
||||
|
|
||||
def proc_entrypoint(obj, v, lock, ip, port): |
|
||||
srv = get_TransmitterServerKlass()() |
|
||||
srv.connect(ip, port) |
|
||||
srv.process(v) |
|
||||
|
|
||||
|
|
||||
class TransmitServer(object): |
|
||||
def __init__(self, ip, port): |
|
||||
mngr = Manager() |
|
||||
self.v = mngr.list() |
|
||||
# self.lock = Lock() |
|
||||
self.p = Process(target=proc_entrypoint, args=(self, self.v, None, ip, port)) #self.lock)) |
|
||||
|
|
||||
def get_data(self): |
|
||||
if len(self.v) > 0: |
|
||||
return list(self.v) |
|
||||
else: |
|
||||
return [] |
|
||||
|
|
||||
def clear(self): |
|
||||
del self.v[:] |
|
||||
|
|
||||
def start(self): |
|
||||
self.p.start() |
|
||||
|
|
||||
def __del__(self): |
|
||||
self.p.terminate() |
|
||||
@ -1,18 +0,0 @@ |
|||||
CREATE TABLE flowstat ( |
|
||||
`id` INT(10) AUTO_INCREMENT NOT NULL, |
|
||||
`src_ip` CHAR(8) NOT NULL, |
|
||||
`dst_ip` CHAR(8) NOT NULL, |
|
||||
`proto` SMALLINT(2) UNSIGNED NOT NULL DEFAULT 0, |
|
||||
`src_port` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0, |
|
||||
`dst_port` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0, |
|
||||
`octets` INT UNSIGNED NOT NULL DEFAULT 0, |
|
||||
`packets` INT UNSIGNED NOT NULL DEFAULT 0, |
|
||||
PRIMARY KEY (`id`) |
|
||||
) |
|
||||
ENGINE =MyISAM |
|
||||
DEFAULT CHARSET =utf8; |
|
||||
|
|
||||
|
|
||||
INSERT INTO flowstat (`src_ip`, `dst_ip`, `proto`, `src_port`, `dst_port`, `octets`, `packets`) VALUES |
|
||||
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13), |
|
||||
('c0a80201', 'c0a805ba', 6, 49150, 443, 5281, 13) |
|
||||
@ -1,31 +0,0 @@ |
|||||
#!/usr/bin/bash |
|
||||
|
|
||||
IfNet=em0 |
|
||||
IfUsr=em1 |
|
||||
|
|
||||
f=/sbin/ipfw |
|
||||
|
|
||||
${f} -f flush |
|
||||
${f} -f pipe flush |
|
||||
${f} -f table all flush |
|
||||
|
|
||||
|
|
||||
# Разрешаем ICMP |
|
||||
${f} add 50 allow icmp from any to any |
|
||||
|
|
||||
|
|
||||
# список разрешённых пользователей - table15 |
|
||||
${f} add 501 allow ip from "table(15)" to any out recv ${IfUsr} xmit ${IfNet} |
|
||||
|
|
||||
|
|
||||
# На каждый тарифный план по пайпу |
|
||||
${f} pipe 212 config bw 1152Kbit/s mask src-ip 0xffffffff noerror |
|
||||
${f} pipe 213 config bw 1152Kbit/s mask dst-ip 0xffffffff noerror |
|
||||
|
|
||||
# создаём эти пайпы |
|
||||
${f} add 1001 pipe tablearg ip from "table(12)" to any out recv ${IfUsr} xmit ${IfNet} |
|
||||
${f} add 1002 pipe tablearg ip from any to "table(13)" out recv ${IfNet} xmit ${IfUsr} |
|
||||
|
|
||||
# ------- Так добавляются пользователи |
|
||||
${f} table 12 add 10.0.172.138/32 212 |
|
||||
${f} table 13 add 10.0.172.138/32 213 |
|
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue