def __init__(self, port, zmq_factory, data_manager): self.data_manager = data_manager endpoint = ZmqEndpoint(ZmqEndpointType.bind, "tcp://*:%d" % port) ZmqREPConnection.__init__(self, zmq_factory, endpoint)
def __init__(self, config, dbengine, **kwargs): self.config = config self.que = deque() self.db_engine = dbengine or get_engine(config, pool_size=30) self.cache = CacheManager(redis_conf(config), cache_name='SyncdCache-%s' % os.getpid()) self.metadata = models.get_metadata(self.db_engine) self.tables = { _name: _table for _name, _table in self.metadata.tables.items() } self.master_bind = ZmqREPConnection( ZmqFactory(), ZmqEndpoint('bind', config.ha.master)) self.master_bind.gotMessage = self.dataReceived self.sync_task = HaSyncTask(config, self.db_engine, self.cache) self.ops = { 'add': self.do_add, 'update': self.do_update, 'delete': self.do_delete } self.process() logger.info(u'启动HA同步服务: [Master] {} ~ [Slave] {}'.format( self.config.ha.master, self.config.ha.slave)) if not kwargs.get('standalone'): self.logtrace = log_trace.LogTrace(redis_conf(config)) if 'elasticsearch' in config: dispatch.register(eslogapi.EslogApi(config.elasticsearch))
class ZAcctAgent: def __init__(self, app): self.app = app self.config = app.config self.cache = app.mcache self.db = app.db self.syslog = app.syslog self.secret = app.config.system.secret zfactory = ZmqFactory() self.listen = "tcp://*:{0}".format(int(self.config.admin.zacct_port)) endpoint = ZmqEndpoint('bind', self.listen) self.agent = ZmqREPConnection(zfactory, endpoint) self.agent.gotMessage = self.process self.register() self.syslog.info('zmq acctounting agent running %s' % self.listen) def register(self): conn = self.db() try: node = conn.query(models.TrRadAgent).filter_by( endpoint=self.listen, protocol='zeromq', radius_type='acctounting' ).first() if not node: node = models.TrRadAgent() node.radius_type = 'acctounting' node.protocol = 'zeromq' node.endpoint = self.listen node.create_time = utils.get_currtime() node.last_check = utils.get_currtime() conn.add(node) conn.commit() else: node.last_check = utils.get_currtime() conn.commit() except Exception as err: self.syslog.error(u"register acctounting agent error %s" % utils.safeunicode(err.message)) finally: conn.close() reactor.callLater(10.0, self.register, ) @timecast def process(self, msgid, message): self.syslog.info("accept acct message @ %s : %r" % (self.listen, utils.safeunicode(message))) try: req_msg = apiutils.parse_request(self.secret, message) if req_msg.get("action") == 'ping': return self.agent.reply(msgid, apiutils.make_message(self.secret,code=0)) except Exception as err: resp = apiutils.make_message(self.secret, code=1, msg=utils.safestr(err.message)) self.agent.reply(msgid, resp) return
class ZAcctAgent: def __init__(self, app): self.app = app self.config = app.config self.cache = app.cache self.db = app.db self.syslog = app.syslog self.secret = app.config.defaults.secret zfactory = ZmqFactory() self.listen = "tcp://{0}:{1}".format(self.config.admin.agent_addr, int(self.config.admin.port)+97) endpoint = ZmqEndpoint('bind', self.listen) self.agent = ZmqREPConnection(zfactory, endpoint) self.agent.gotMessage = self.process self.register() self.syslog.info('zmq acctounting agent running %s' % self.listen) def register(self): conn = self.db() try: node = conn.query(models.TrRadAgent).filter_by( endpoint=self.listen, protocol='zeromq', radius_type='acctounting' ).first() if not node: node = models.TrRadAgent() node.radius_type = 'acctounting' node.protocol = 'zeromq' node.endpoint = self.listen node.create_time = utils.get_currtime() node.last_check = utils.get_currtime() conn.add(node) conn.commit() else: node.last_check = utils.get_currtime() conn.commit() except Exception as err: self.syslog.error(u"register acctounting agent error %s" % utils.safeunicode(err.message)) finally: conn.close() reactor.callLater(10.0, self.register, ) def process(self, msgid, message): print "Replying to %s, %r" % (msgid, message) self.agent.reply(msgid, "%s %r " % (msgid, message))
def __init__(self, app): self.app = app self.config = app.config self.cache = app.mcache self.db = app.db self.syslog = app.syslog self.secret = app.config.system.secret zfactory = ZmqFactory() self.listen = "tcp://*:{0}".format(int(self.config.admin.zauth_port)) endpoint = ZmqEndpoint('bind', self.listen) self.agent = ZmqREPConnection(zfactory, endpoint) self.agent.gotMessage = self.process self.register() self.syslog.info('zmq authorize agent running %s' % self.listen)
def __init__(self, config, dbengine, radcache = None): self.config = config self.load_plugins(load_types=['radius_auth_req', 'radius_accept']) self.dict = dictionary.Dictionary(os.path.join(os.path.dirname(taurusxradius.__file__), 'dictionarys/dictionary')) self.db_engine = dbengine or get_engine(config) self.aes = utils.AESCipher(key=self.config.system.secret) self.mcache = radcache self.stat_pusher = ZmqPushConnection(ZmqFactory()) self.zmqrep = ZmqREPConnection(ZmqFactory()) self.stat_pusher.tcpKeepalive = 1 self.zmqrep.tcpKeepalive = 1 self.stat_pusher.addEndpoints([ZmqEndpoint('connect', config.mqproxy.task_connect)]) self.zmqrep.addEndpoints([ZmqEndpoint('connect', config.mqproxy.auth_connect)]) self.zmqrep.gotMessage = self.process self.reject_debug = int(self.get_param_value('radius_reject_debug', 0)) == 1 logger.info('radius auth worker %s start' % os.getpid()) logger.info('init auth worker : %s ' % self.zmqrep) logger.info('init auth stat pusher : %s ' % self.stat_pusher)
def router_share_async(obj, address): """ :param obj: :param address: :returns: AsyncRouterExport """ socket = ZmqREPConnection(ZmqFactory(), ZmqEndpoint("bind", address)) return AsyncRouterExport(obj, socket)
def add_rep(self, endpoint, callBack=onPrint): ''' 设置 rep 对象 :param endpoint: :param callBack: :return: ''' if endpoint: logger.debug("开始运行 REP 服务器,监听地址为:{}...".format(endpoint)) self.rep_ = ZmqREPConnection(ZmqFactory(), ZmqEndpoint('bind', endpoint)) self.rep_.gotMessage = callBack
def __init__(self, config, dbengine, radcache = None): self.config = config self.load_plugins(load_types=['radius_acct_req']) self.db_engine = dbengine or get_engine(config) self.mcache = radcache self.dict = dictionary.Dictionary(os.path.join(os.path.dirname(taurusxradius.__file__), 'dictionarys/dictionary')) self.stat_pusher = ZmqPushConnection(ZmqFactory()) self.zmqrep = ZmqREPConnection(ZmqFactory()) self.stat_pusher.tcpKeepalive = 1 self.zmqrep.tcpKeepalive = 1 self.stat_pusher.addEndpoints([ZmqEndpoint('connect', config.mqproxy.task_connect)]) self.zmqrep.addEndpoints([ZmqEndpoint('connect', config.mqproxy.acct_connect)]) self.zmqrep.gotMessage = self.process self.acct_class = {STATUS_TYPE_START: RadiusAcctStart, STATUS_TYPE_STOP: RadiusAcctStop, STATUS_TYPE_UPDATE: RadiusAcctUpdate, STATUS_TYPE_ACCT_ON: RadiusAcctOnoff, STATUS_TYPE_ACCT_OFF: RadiusAcctOnoff} logger.info('radius acct worker %s start' % os.getpid()) logger.info('init acct worker : %s ' % self.zmqrep) logger.info('init acct stat pusher : %s ' % self.stat_pusher)
def __init__(self, app): self.app = app self.config = app.config self.cache = app.cache self.db = app.db self.syslog = app.syslog self.secret = app.config.defaults.secret zfactory = ZmqFactory() self.listen = "tcp://{0}:{1}".format(self.config.admin.agent_addr, int(self.config.admin.port)+97) endpoint = ZmqEndpoint('bind', self.listen) self.agent = ZmqREPConnection(zfactory, endpoint) self.agent.gotMessage = self.process self.register() self.syslog.info('zmq acctounting agent running %s' % self.listen)
def add_rep(self, endpoint, callBack=None): ''' 设置 rep 对象 :param endpoint: :param callBack: :return: ''' if endpoint: logger.debug("开始运行 REP 服务器,监听地址为:{}...".format(endpoint)) self._rep = ZmqREPConnection(ZmqFactory(), ZmqEndpoint('bind', endpoint)) if callBack: self._rep.gotMessage = callBack else: self._rep.gotMessage = self.doDataReceived
class DBSyncServer(object): """ 同步服务进程,接受其他服务器发送的同步数据,更新数据库 """ def __init__(self, config, dbengine, **kwargs): self.config = config self.que = deque() self.db_engine = dbengine or get_engine(config, pool_size=30) self.cache = CacheManager(redis_conf(config), cache_name='SyncdCache-%s' % os.getpid()) self.metadata = models.get_metadata(self.db_engine) self.tables = { _name: _table for _name, _table in self.metadata.tables.items() } self.master_bind = ZmqREPConnection( ZmqFactory(), ZmqEndpoint('bind', config.ha.master)) self.master_bind.gotMessage = self.dataReceived self.sync_task = HaSyncTask(config, self.db_engine, self.cache) self.ops = { 'add': self.do_add, 'update': self.do_update, 'delete': self.do_delete } self.process() logger.info(u'启动HA同步服务: [Master] {} ~ [Slave] {}'.format( self.config.ha.master, self.config.ha.slave)) if not kwargs.get('standalone'): self.logtrace = log_trace.LogTrace(redis_conf(config)) if 'elasticsearch' in config: dispatch.register(eslogapi.EslogApi(config.elasticsearch)) def key_where(self, objdata): """ 组装主键查询条件,只有同步的版本大于数据库的版本时才会更新 """ key_where = ' and '.join( ("%s='%s'" % (k, v) for k, v in objdata.pkeys.items())) key_where = _sql(key_where) return key_where def do_add(self, objdata): """ 同步新增 """ if not objdata.pkeys or not isinstance(objdata.pkeys, dict): raise ValueError('pkeys error') dbtable = self.tables[objdata.table_name] key_where_sql = self.key_where(objdata) with self.db_engine.begin() as db: ret = db.execute( _sql('select count(*) from %s where %s' % (objdata.table_name, key_where_sql))) if ret.scalar() == 1: db.execute(dbtable.delete().where(key_where_sql)) db.execute(dbtable.insert().values(objdata.content)) def do_update(self, objdata): """ 同步更新,查询已经存在的数据并删除,重新插入 """ if not objdata.pkeys or not isinstance(objdata.pkeys, dict): return else: dbtable = self.tables[objdata.table_name] key_where_sql = self.key_where(objdata) with self.db_engine.begin() as db: ret = db.execute( _sql('select sync_ver from %s where %s' % (objdata.table_name, key_where_sql))) oldver = ret.scalar() if oldver is None: db.execute(dbtable.insert().values(objdata.content)) elif int(oldver) < int(objdata.sync_ver): db.execute(dbtable.delete().where(key_where_sql)) db.execute(dbtable.insert().values(objdata.content)) return def do_delete(self, objdata): """ 同步更新,查询已经存在的数据并删除 """ if not objdata.pkeys or not isinstance(objdata.pkeys, dict): return dbtable = self.tables[objdata.table_name] key_where_sql = self.key_where(objdata) with self.db_engine.begin() as db: db.execute(dbtable.delete().where(key_where_sql)) def dataReceived(self, msgid, request): if 'HASYNC_DISABLE' in os.environ: return try: message = msgpack.unpackb(request) self.que.appendleft([msgid, Storage(message)]) except: logger.error(traceback.print_exc()) def process(self): try: msgid, objdata = self.que.pop() if objdata.action == 'ping': self.master_bind.reply(msgid, 'ping ok') reactor.callLater(0.005, self.process) return except: reactor.callLater(1, self.process) return try: table_name = objdata.table_name if table_name not in self.tables: self.reply(msgid, 1, u'数据库表 %s 不存在') else: opfunc = self.ops.get(objdata.action) if opfunc: opfunc(objdata) self.reply(msgid, 0, 'ok') else: self.reply(msgid, 1, u'不支持的同步操作') except Exception as err: logger.exception(err) self.reply(msgid, 1, traceback.format_exc()) finally: reactor.callLater(0.005, self.process) def reply(self, msgid, code, msg): try: data = msgpack.packb(dict(code=code, msg=msg)) self.master_bind.reply(msgid, data) except Exception as e: logger.error(traceback.print_exc())
class ZAuthAgent: def __init__(self, app): self.app = app self.config = app.config self.cache = app.mcache self.db = app.db self.syslog = app.syslog self.secret = app.config.system.secret zfactory = ZmqFactory() self.listen = "tcp://*:{0}".format(int(self.config.admin.zauth_port)) endpoint = ZmqEndpoint('bind', self.listen) self.agent = ZmqREPConnection(zfactory, endpoint) self.agent.gotMessage = self.process self.register() self.syslog.info('zmq authorize agent running %s' % self.listen) def register(self): conn = self.db() try: node = conn.query(models.TrRadAgent).filter_by( endpoint=self.listen, protocol='zeromq', radius_type='authorize').first() if not node: node = models.TrRadAgent() node.radius_type = 'authorize' node.protocol = 'zeromq' node.endpoint = self.listen node.create_time = utils.get_currtime() node.last_check = utils.get_currtime() conn.add(node) conn.commit() except Exception as err: self.syslog.error(u"register authorize agent error %s" % utils.safeunicode(err.message)) finally: conn.close() reactor.callLater( 10.0, self.register, ) @timecast def process(self, msgid, message): self.syslog.info("accept auth message @ %s : %r" % (self.listen, utils.safeunicode(message))) @self.cache.cache(expire=600) def get_account_by_username(username): return self.db.query( models.TrAccount).filter_by(account_number=username).first() @self.cache.cache(expire=600) def get_product_by_id(product_id): return self.db.query( models.TrProduct).filter_by(id=product_id).first() try: req_msg = apiutils.parse_request(self.secret, message) if req_msg.get("action") == 'ping': return self.agent.reply( msgid, apiutils.make_message(self.secret, code=0)) if 'username' not in req_msg: raise ValueError('username is empty') except Exception as err: resp = apiutils.make_message(self.secret, code=1, msg=utils.safestr(err.message)) self.agent.reply(msgid, resp) return try: username = req_msg['username'] account = get_account_by_username(username) if not account: apiutils.make_message(self.secret, code=1, msg=u'user {0} not exists'.format( utils.safeunicode(username))) self.agent.reply(msgid, resp) return passwd = self.app.aes.decrypt(account.password) product = get_product_by_id(account.product_id) result = dict(code=0, msg='success', username=username, passwd=passwd, input_rate=product.input_max_limit, output_rate=product.output_max_limit, attrs={ "Session-Timeout": 86400, "Acct-Interim-Interval": 300 }) resp = apiutils.make_message(self.secret, **result) self.agent.reply(msgid, resp) self.syslog.info("send auth response %r" % (utils.safeunicode(resp))) except Exception as err: self.syslog.error(u"api authorize error %s" % utils.safeunicode(err.message)) resp = apiutils.make_message(self.secret, code=1, msg=utils.safestr(err.message)) return self.agent.reply(msgid, resp)
class ZAcctAgent: def __init__(self, app): self.app = app self.config = app.config self.cache = app.mcache self.db = app.db self.syslog = app.syslog self.secret = app.config.system.secret zfactory = ZmqFactory() self.listen = "tcp://*:{0}".format(int(self.config.admin.zacct_port)) endpoint = ZmqEndpoint('bind', self.listen) self.agent = ZmqREPConnection(zfactory, endpoint) self.agent.gotMessage = self.process self.register() self.syslog.info('zmq acctounting agent running %s' % self.listen) def register(self): conn = self.db() try: node = conn.query(models.TrRadAgent).filter_by( endpoint=self.listen, protocol='zeromq', radius_type='acctounting').first() if not node: node = models.TrRadAgent() node.radius_type = 'acctounting' node.protocol = 'zeromq' node.endpoint = self.listen node.create_time = utils.get_currtime() node.last_check = utils.get_currtime() conn.add(node) conn.commit() else: node.last_check = utils.get_currtime() conn.commit() except Exception as err: self.syslog.error(u"register acctounting agent error %s" % utils.safeunicode(err.message)) finally: conn.close() reactor.callLater( 10.0, self.register, ) @timecast def process(self, msgid, message): self.syslog.info("accept acct message @ %s : %r" % (self.listen, utils.safeunicode(message))) try: req_msg = apiutils.parse_request(self.secret, message) if req_msg.get("action") == 'ping': return self.agent.reply( msgid, apiutils.make_message(self.secret, code=0)) except Exception as err: resp = apiutils.make_message(self.secret, code=1, msg=utils.safestr(err.message)) self.agent.reply(msgid, resp) return
class ZAuthAgent: def __init__(self, app): self.app = app self.config = app.config self.cache = app.mcache self.db = app.db self.syslog = app.syslog self.secret = app.config.system.secret zfactory = ZmqFactory() self.listen = "tcp://*:{0}".format(int(self.config.admin.zauth_port)) endpoint = ZmqEndpoint('bind', self.listen) self.agent = ZmqREPConnection(zfactory, endpoint) self.agent.gotMessage = self.process self.register() self.syslog.info('zmq authorize agent running %s' % self.listen) def register(self): conn = self.db() try: node = conn.query(models.TrRadAgent).filter_by( endpoint=self.listen, protocol='zeromq', radius_type='authorize' ).first() if not node: node = models.TrRadAgent() node.radius_type = 'authorize' node.protocol = 'zeromq' node.endpoint = self.listen node.create_time = utils.get_currtime() node.last_check = utils.get_currtime() conn.add(node) conn.commit() except Exception as err: self.syslog.error(u"register authorize agent error %s" % utils.safeunicode(err.message)) finally: conn.close() reactor.callLater(10.0, self.register, ) @timecast def process(self, msgid, message): self.syslog.info("accept auth message @ %s : %r" % (self.listen, utils.safeunicode(message))) @self.cache.cache(expire=600) def get_account_by_username(username): return self.db.query(models.TrAccount).filter_by(account_number=username).first() @self.cache.cache(expire=600) def get_product_by_id(product_id): return self.db.query(models.TrProduct).filter_by(id=product_id).first() try: req_msg = apiutils.parse_request(self.secret, message) if req_msg.get("action") == 'ping': return self.agent.reply(msgid, apiutils.make_message(self.secret,code=0)) if 'username' not in req_msg: raise ValueError('username is empty') except Exception as err: resp = apiutils.make_message(self.secret, code=1, msg=utils.safestr(err.message)) self.agent.reply(msgid, resp) return try: username = req_msg['username'] account = get_account_by_username(username) if not account: apiutils.make_message(self.secret, code=1, msg=u'user {0} not exists'.format(utils.safeunicode(username))) self.agent.reply(msgid, resp) return passwd = self.app.aes.decrypt(account.password) product = get_product_by_id(account.product_id) result = dict( code=0, msg='success', username=username, passwd=passwd, input_rate=product.input_max_limit, output_rate=product.output_max_limit, attrs={ "Session-Timeout" : 86400, "Acct-Interim-Interval": 300 } ) resp = apiutils.make_message(self.secret, **result) self.agent.reply(msgid, resp) self.syslog.info("send auth response %r" % (utils.safeunicode(resp))) except Exception as err: self.syslog.error(u"api authorize error %s" % utils.safeunicode(err.message)) resp = apiutils.make_message(self.secret, code=1, msg=utils.safestr(err.message)) return self.agent.reply(msgid, resp)
import sys from twisted.internet import reactor rootdir = os.path.realpath(os.path.join(os.path.dirname(sys.argv[0]), '..')) sys.path.insert(0, rootdir) os.chdir(rootdir) from txzmq import ZmqEndpoint, ZmqFactory, ZmqREQConnection, ZmqREPConnection zf = ZmqFactory() endpoint = "ipc:///tmp/txzmq-test" req = ZmqREQConnection(zf, ZmqEndpoint("connect", endpoint)) rep = ZmqREPConnection(zf, ZmqEndpoint("bind", endpoint)) def gotMessage(messageId, message): rep.reply(messageId, b"REP: " + message) rep.gotMessage = gotMessage exitCode = 0 def start(): def gotReply(reply): if reply != [b"REP: REQ1"]: print("Unexpected reply: %r" % (reply, )) global exitCode
def __init__(self, factory, endpoint, client): ZmqREPConnection.__init__(self, factory, endpoint=endpoint) self.client = client
def __init__(self, zmqfactory, zmqendpoint): ZmqREPConnection.__init__(self, zmqfactory, zmqendpoint)
def __init__(self, factory, endpoint): ZmqREPConnection.__init__(self, factory, endpoint=endpoint)
def __init__(self, zf, e, core): ZmqREPConnection.__init__(self, zf, e) self.core = core
def produce(): # data = [str(time.time()), socket.gethostname()] data = str(time.time()) print "Requesting %r" % data try: d = s.sendMsg(data) def doPrint(reply): print("Got reply: %s" % (reply)) d.addCallback(doPrint) except zmq.error.Again: print "Skipping, no pull consumers..." reactor.callLater(1, produce) reactor.callWhenRunning(reactor.callLater, 1, produce) else: s = ZmqREPConnection(zf, e) def doPrint(messageId, message): print "Replying to %s, %r" % (messageId, message) s.reply(messageId, "%s %r " % (messageId, message)) s.gotMessage = doPrint reactor.run()
def __init__(self, zf, e, core): ZmqREPConnection.__init__(self, zf, e) self.dispatcher = CommandDispatcher(core)
import os import sys from twisted.internet import reactor rootdir = os.path.realpath(os.path.join(os.path.dirname(sys.argv[0]), '..')) sys.path.insert(0, rootdir) os.chdir(rootdir) from txzmq import ZmqEndpoint, ZmqFactory, ZmqREQConnection, ZmqREPConnection zf = ZmqFactory() endpoint = "ipc:///tmp/txzmq-test" req = ZmqREQConnection(zf, ZmqEndpoint("connect", endpoint)) rep = ZmqREPConnection(zf, ZmqEndpoint("bind", endpoint)) def gotMessage(messageId, message): rep.reply(messageId, b"REP: " + message) rep.gotMessage = gotMessage exitCode = 0 def start(): def gotReply(reply): if reply != [b"REP: REQ1"]: print("Unexpected reply: %r" % (reply, ))
class RADIUSAuthWorker(TraceMix): """ 认证子进程,处理认证授权逻辑,把结果推送个 radius 协议处理主进程 """ def __init__(self, config, dbengine, radcache = None): self.config = config self.load_plugins(load_types=['radius_auth_req', 'radius_accept']) self.dict = dictionary.Dictionary(os.path.join(os.path.dirname(taurusxradius.__file__), 'dictionarys/dictionary')) self.db_engine = dbengine or get_engine(config) self.aes = utils.AESCipher(key=self.config.system.secret) self.mcache = radcache self.stat_pusher = ZmqPushConnection(ZmqFactory()) self.zmqrep = ZmqREPConnection(ZmqFactory()) self.stat_pusher.tcpKeepalive = 1 self.zmqrep.tcpKeepalive = 1 self.stat_pusher.addEndpoints([ZmqEndpoint('connect', config.mqproxy.task_connect)]) self.zmqrep.addEndpoints([ZmqEndpoint('connect', config.mqproxy.auth_connect)]) self.zmqrep.gotMessage = self.process self.reject_debug = int(self.get_param_value('radius_reject_debug', 0)) == 1 logger.info('radius auth worker %s start' % os.getpid()) logger.info('init auth worker : %s ' % self.zmqrep) logger.info('init auth stat pusher : %s ' % self.stat_pusher) def get_account_bind_nas(self, account_number): def fetch_result(): with self.db_engine.begin() as conn: sql = '\n select bas.ip_addr \n from tr_bas as bas,tr_customer as cus,tr_account as usr,tr_bas_node as bn\n where cus.customer_id = usr.customer_id\n and cus.node_id = bn.node_id\n and bn.bas_id = bas.id\n and usr.account_number = :account_number\n ' cur = conn.execute(_sql(sql), account_number=account_number) ipaddrs = [ addr['ip_addr'] for addr in cur ] return ipaddrs return self.mcache.aget(account_bind_basip_key(account_number), fetch_result, expire=600) def do_stat(self, code): try: stat_msg = {'statattrs': [], 'raddata': {}} if code == packet.AccessRequest: stat_msg['statattrs'].append('auth_req') elif code == packet.AccessAccept: stat_msg['statattrs'].append('auth_accept') elif code == packet.AccessReject: stat_msg['statattrs'].append('auth_reject') else: stat_msg['statattrs'] = ['auth_drop'] self.stat_pusher.push(msgpack.packb(stat_msg)) except: pass def process(self, msgid, message): datagram, host, port = msgpack.unpackb(message) reply = self.processAuth(datagram, host, port) if not reply: return if reply.code == packet.AccessReject: logger.error(u'[Radiusd] :: Send Radius Reject %s' % repr(reply), tag='radius_auth_reject') else: logger.info(u'[Radiusd] :: Send radius response: %s' % repr(reply)) if self.config.system.debug: logger.debug(reply.format_str()) self.zmqrep.reply(msgid, msgpack.packb([reply.ReplyPacket(), host, port])) self.do_stat(reply.code) def createAuthPacket(self, **kwargs): vendor_id = kwargs.pop('vendor_id', 0) auth_message = message.AuthMessage(**kwargs) auth_message.vendor_id = vendor_id for plugin in self.auth_req_plugins: auth_message = plugin.plugin_func(auth_message) return auth_message def freeReply(self, req): reply = req.CreateReply() reply.vendor_id = req.vendor_id reply['Reply-Message'] = 'user:%s auth success' % req.get_user_name() reply.code = packet.AccessAccept reply_attrs = {'attrs': {}} reply_attrs['input_rate'] = int(self.get_param_value('radius_free_input_rate', 1048576)) reply_attrs['output_rate'] = int(self.get_param_value('radius_free_output_rate', 4194304)) reply_attrs['rate_code'] = self.get_param_value('radius_free_rate_code', 'freerate') reply_attrs['domain'] = self.get_param_value('radius_free_domain', 'freedomain') reply_attrs['attrs']['Session-Timeout'] = int(self.get_param_value('radius_max_session_timeout', 86400)) for plugin in self.auth_accept_plugins: reply = plugin.plugin_func(reply, reply_attrs) return reply def rejectReply(self, req, errmsg = ''): reply = req.CreateReply() reply.vendor_id = req.vendor_id reply['Reply-Message'] = errmsg reply.code = packet.AccessReject return reply def processAuth(self, datagram, host, port): try: bas = self.find_nas(host) if not bas: raise PacketError('[Radiusd] :: Dropping packet from unknown host %s' % host) secret, vendor_id = bas['bas_secret'], bas['vendor_id'] req = self.createAuthPacket(packet=datagram, dict=self.dict, secret=six.b(str(secret)), vendor_id=vendor_id) username = req.get_user_name() bypass = int(self.get_param_value('radius_bypass', 1)) if req.code != packet.AccessRequest: raise PacketError('non-AccessRequest packet on authentication socket') self.log_trace(host, port, req) self.do_stat(req.code) if self.config.system.debug: logger.debug('[Radiusd] :: Received radius request: %s' % req.format_str()) else: logger.info('[Radiusd] :: Received radius request: %s' % repr(req)) if bypass == 2: reply = self.freeReply(req) self.log_trace(host, port, req, reply) return reply if not self.user_exists(username): errmsg = u'[Radiusd] :: user:%s not exists' % username reply = self.rejectReply(req, errmsg) self.log_trace(host, port, req, reply) return reply bind_nas_list = self.get_account_bind_nas(username) if not bind_nas_list or host not in bind_nas_list: errmsg = u'[Radiusd] :: nas_addr:%s not bind for user:%s node' % (host, username) reply = self.rejectReply(req, errmsg) self.log_trace(host, port, req, reply) return reply aaa_request = dict(account_number=username, domain=req.get_domain(), macaddr=req.client_mac, nasaddr=req.get_nas_addr(), vlanid1=req.vlanid1, vlanid2=req.vlanid2, bypass=bypass, radreq=req) auth_resp = RadiusAuth(self.db_engine, self.mcache, self.aes, aaa_request).authorize() if auth_resp['code'] > 0: reply = self.rejectReply(req, auth_resp['msg']) self.log_trace(host, port, req, reply) return reply reply = req.CreateReply() reply.code = packet.AccessAccept reply.vendor_id = req.vendor_id reply['Reply-Message'] = 'user:%s auth success' % username reply_attrs = {} reply_attrs.update(auth_resp) reply_attrs.update(req.resp_attrs) for plugin in self.auth_accept_plugins: reply = plugin.plugin_func(reply, reply_attrs) if not req.VerifyReply(reply): raise PacketError('[Radiusd] :: user:%s auth verify reply error' % username) self.log_trace(host, port, req, reply) return reply except Exception as err: if not self.reject_debug: self.do_stat(0) logger.exception(err, tag='radius_auth_error') else: reply = self.rejectReply(req, repr(err)) self.log_trace(host, port, req, reply) return reply
class RADIUSAcctWorker(TraceMix): """ 记账子进程,处理计费逻辑,把结果推送个 radius 协议处理主进程, 记账是异步处理的,即每次收到记账消息时,立即推送响应,然后在后台异步处理计费逻辑。 """ def __init__(self, config, dbengine, radcache = None): self.config = config self.load_plugins(load_types=['radius_acct_req']) self.db_engine = dbengine or get_engine(config) self.mcache = radcache self.dict = dictionary.Dictionary(os.path.join(os.path.dirname(taurusxradius.__file__), 'dictionarys/dictionary')) self.stat_pusher = ZmqPushConnection(ZmqFactory()) self.zmqrep = ZmqREPConnection(ZmqFactory()) self.stat_pusher.tcpKeepalive = 1 self.zmqrep.tcpKeepalive = 1 self.stat_pusher.addEndpoints([ZmqEndpoint('connect', config.mqproxy.task_connect)]) self.zmqrep.addEndpoints([ZmqEndpoint('connect', config.mqproxy.acct_connect)]) self.zmqrep.gotMessage = self.process self.acct_class = {STATUS_TYPE_START: RadiusAcctStart, STATUS_TYPE_STOP: RadiusAcctStop, STATUS_TYPE_UPDATE: RadiusAcctUpdate, STATUS_TYPE_ACCT_ON: RadiusAcctOnoff, STATUS_TYPE_ACCT_OFF: RadiusAcctOnoff} logger.info('radius acct worker %s start' % os.getpid()) logger.info('init acct worker : %s ' % self.zmqrep) logger.info('init acct stat pusher : %s ' % self.stat_pusher) def do_stat(self, code, status_type = 0, req = None): try: stat_msg = {'statattrs': ['acct_drop'], 'raddata': {}} if code in (4, 5): stat_msg['statattrs'] = [] if code == packet.AccountingRequest: stat_msg['statattrs'].append('acct_req') elif code == packet.AccountingResponse: stat_msg['statattrs'].append('acct_resp') if status_type == 1: stat_msg['statattrs'].append('acct_start') elif status_type == 2: stat_msg['statattrs'].append('acct_stop') elif status_type == 3: stat_msg['statattrs'].append('acct_update') stat_msg['raddata']['input_total'] = req.get_input_total() stat_msg['raddata']['output_total'] = req.get_output_total() elif status_type == 7: stat_msg['statattrs'].append('acct_on') elif status_type == 8: stat_msg['statattrs'].append('acct_off') self.stat_pusher.push(msgpack.packb(stat_msg)) except: pass def process(self, msgid, message): datagram, host, port = msgpack.unpackb(message) reply = self.processAcct(datagram, host, port) self.zmqrep.reply(msgid, msgpack.packb([reply.ReplyPacket(), host, port])) def createAcctPacket(self, **kwargs): vendor_id = kwargs.pop('vendor_id', 0) acct_message = message.AcctMessage(**kwargs) acct_message.vendor_id = vendor_id for plugin in self.acct_req_plugins: acct_message = plugin.plugin_func(acct_message) return acct_message def processAcct(self, datagram, host, port): try: bas = self.find_nas(host) if not bas: raise PacketError('[Radiusd] :: Dropping packet from unknown host %s' % host) secret, vendor_id = bas['bas_secret'], bas['vendor_id'] req = self.createAcctPacket(packet=datagram, dict=self.dict, secret=six.b(str(secret)), vendor_id=vendor_id) self.log_trace(host, port, req) self.do_stat(req.code, req.get_acct_status_type(), req=req) if self.config.system.debug: logger.debug('[Radiusd] :: Received radius request: %s' % req.format_str()) else: logger.info('[Radiusd] :: Received radius request: %s' % repr(req)) if req.code != packet.AccountingRequest: raise PacketError('non-AccountingRequest packet on authentication socket') if not req.VerifyAcctRequest(): raise PacketError('VerifyAcctRequest error') status_type = req.get_acct_status_type() if status_type in self.acct_class: ticket = req.get_ticket() if not ticket.get('nas_addr'): ticket['nas_addr'] = host acct_func = self.acct_class[status_type](self.db_engine, self.mcache, None, ticket).acctounting reactor.callLater(0.05, acct_func) else: raise ValueError('status_type <%s> not support' % status_type) reply = req.CreateReply() reactor.callLater(0.05, self.log_trace, host, port, req, reply) reactor.callLater(0.05, self.do_stat, reply.code) if self.config.system.debug: logger.debug('[Radiusd] :: Send radius response: %s' % reply.format_str()) else: logger.info('[Radiusd] :: Send radius response: %s' % repr(reply)) return reply except Exception as err: self.do_stat(0) logger.exception(err, tag='radius_acct_drop') return