def process(self, *args, **kwargs): with make_db(self.db) as db: try: nodes = db.query(models.TrNode) for node in nodes: r = db.query( func.sum( models.TrOnline.input_total).label("input_total"), func.sum(models.TrOnline.output_total).label( "output_total")).filter( models.TrOnline.account_number == models.TrAccount.account_number, models.TrAccount.customer_id == models.TrCustomer.customer_id, models.TrCustomer.node_id == node.id).first() if r and all([r.input_total, r.output_total]): stat = models.TrFlowStat() stat.node_id = node.id stat.stat_time = int(time.time()) stat.input_total = r.input_total stat.output_total = r.output_total db.add(stat) db.commit() logger.info("flow stat task done") except Exception as err: db.rollback() logger.error('flow_stat_job err,%s' % (str(err))) return 120.0
def acctounting(self): if not self.account: return logger.error( "[Acct] Received an accounting update request but user[%s] not exists" % self.request.account_number) ticket = Storage(**self.request) online = self.get_online(ticket.nas_addr, ticket.acct_session_id) if not online: sessiontime = ticket.acct_session_time updatetime = datetime.datetime.now() _starttime = updatetime - datetime.timedelta(seconds=sessiontime) online = Storage( account_number=self.account.account_number, nas_addr=ticket.nas_addr, acct_session_id=ticket.acct_session_id, acct_start_time=_starttime.strftime("%Y-%m-%d %H:%M:%S"), framed_ipaddr=ticket.framed_ipaddr, mac_addr=ticket.mac_addr, nas_port_id=ticket.nas_port_id, billing_times=ticket.acct_session_time, input_total=self.get_input_total(), output_total=self.get_output_total(), start_source=STATUS_TYPE_UPDATE) self.add_online(online) self.billing(online) logger.info('%s Accounting update request, update online' % self.account.account_number)
def bill_botimes(self,online, product): #买断时长 logger.info('%s > Buyout long time billing ' % self.account.account_number) time_length = self.get_user_time_length() sessiontime = self.request.acct_session_time billing_times = online.billing_times acct_times = sessiontime - billing_times user_time_length = time_length - acct_times if user_time_length < 0 : user_time_length = 0 self.update_billing(Storage( account_number = online.account_number, nas_addr = online.nas_addr, acct_session_id = online.acct_session_id, acct_start_time = online.acct_start_time, acct_session_time = self.request.acct_session_time, input_total = self.get_input_total(), output_total = self.get_output_total(), acct_times = acct_times, acct_flows = 0, acct_fee = 0, actual_fee = 0, balance = 0, time_length = user_time_length, flow_length = 0, is_deduct = 1, create_time = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S") )) if user_time_length == 0 : self.disconnect(online)
def acctounting(self): if not self.account: return logger.error( "[Acct] Received an accounting update request but user[%s] not exists"% self.request.account_number) ticket = Storage(**self.request) _datetime = datetime.datetime.now() online = self.get_online(ticket.nas_addr,ticket.acct_session_id) if not online: session_time = ticket.acct_session_time stop_time = _datetime.strftime( "%Y-%m-%d %H:%M:%S") start_time = (_datetime - datetime.timedelta(seconds=int(session_time))).strftime( "%Y-%m-%d %H:%M:%S") ticket.acct_start_time = start_time ticket.acct_stop_time = stop_time ticket.start_source= STATUS_TYPE_STOP ticket.stop_source = STATUS_TYPE_STOP self.add_ticket(ticket) else: self.del_online(ticket.nas_addr,ticket.acct_session_id) ticket.acct_start_time = online.acct_start_time ticket.acct_stop_time= _datetime.strftime( "%Y-%m-%d %H:%M:%S") ticket.start_source = online.start_source ticket.stop_source = STATUS_TYPE_STOP self.add_ticket(ticket) self.billing(online) logger.info('%s Accounting stop request, remove online'% self.account.account_number)
def process(self, message): datagram, host, port = msgpack.unpackb(message[0]) reply = self.processAuth(datagram, host, port) if not reply: return self.do_stat(reply.code) logger.info("[Radiusd] :: Send radius response: %s" % repr(reply)) if self.config.system.debug: logger.debug(reply.format_str()) self.pusher.push(msgpack.packb([reply.ReplyPacket(), host, port]))
def __init__(self, config, service='auth'): self.config = config self.service = service self.pusher = ZmqPushConnection( ZmqFactory(), ZmqEndpoint('bind', 'ipc:///tmp/radiusd-%s-message' % service)) self.puller = ZmqPullConnection( ZmqFactory(), ZmqEndpoint('bind', 'ipc:///tmp/radiusd-%s-result' % service)) self.puller.onPull = self.reply logger.info("init %s master pusher : %s " % (self.service, self.pusher)) logger.info("init %s master puller : %s " % (self.service, self.puller))
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.do_stat(req.code, req.get_acct_status_type()) logger.info("[Radiusd] :: Received radius request: %s" % (repr(req))) if self.config.system.debug: logger.debug(req.format_str()) if req.code != packet.AccountingRequest: raise PacketError( 'non-AccountingRequest packet on authentication socket') if not req.VerifyAcctRequest(): raise PacketError('VerifyAcctRequest error') reply = req.CreateReply() self.pusher.push(msgpack.packb([reply.ReplyPacket(), host, port])) self.do_stat(reply.code) logger.info("[Radiusd] :: Send radius response: %s" % repr(reply)) if self.config.system.debug: logger.debug(reply.format_str()) status_type = req.get_acct_status_type() if status_type in self.acct_class: acct_func = self.acct_class[status_type]( self.db_engine, self.mcache, None, req.get_ticket()).acctounting reactor.callLater(0.1, acct_func) else: logger.error('status_type <%s> not support' % status_type) except Exception as err: self.do_stat(0) errstr = 'RadiusError:Dropping invalid acct packet from {0} {1},{2}'.format( host, port, utils.safeunicode(err)) logger.error(errstr) import traceback traceback.print_exc()
def process(self, *args, **kwargs): logger.info("start process expire_notify task") _enable = int(self.get_param_value("expire_notify_enable", 0)) if not _enable: return 120.0 _ndays = self.get_param_value("expire_notify_days") notify_tpl = self.get_param_value("expire_notify_tpl") notify_url = self.get_param_value("expire_notify_url") with make_db(self.db) as db: _now = datetime.datetime.now() _date = (datetime.datetime.now() + datetime.timedelta(days=int(_ndays))).strftime("%Y-%m-%d") expire_query = db.query( models.TrAccount.account_number, models.TrAccount.expire_date, models.TrCustomer.email, models.TrCustomer.mobile).filter( models.TrAccount.customer_id == models.TrCustomer.customer_id, models.TrAccount.expire_date <= _date, models.TrAccount.expire_date >= _now.strftime("%Y-%m-%d"), models.TrAccount.status == 1) logger.info('expire_notify total: %s' % expire_query.count()) for account, expire, email, mobile in expire_query: dispatch.pub('account_expire', account, async=False) ctx = notify_tpl.replace('#account#', account) ctx = ctx.replace('#expire#', expire) topic = ctx[:ctx.find('\n')] if email: self.send_mail(email, topic, ctx).addCallbacks(logger.info, logger.error) url = notify_url.replace('{account}', account) url = url.replace('{expire}', expire) url = url.replace('{email}', email) url = url.replace('{mobile}', mobile) url = url.encode('utf-8') url = quote(url, ":?=/&") httpclient.get(url).addCallbacks(lambda r: logger.info(r.code), logger.error) return self.get_notify_interval()
def __init__(self, config, dbengine): self.config = config self.dict = dictionary.Dictionary( os.path.join(os.path.dirname(toughradius.__file__), 'dictionarys/dictionary')) self.db_engine = dbengine or get_engine(config) self.mcache = mcache.Mcache() self.pusher = ZmqPushConnection( ZmqFactory(), ZmqEndpoint('connect', 'ipc:///tmp/radiusd-acct-result')) self.stat_pusher = ZmqPushConnection( ZmqFactory(), ZmqEndpoint('connect', 'ipc:///tmp/radiusd-stat-task')) self.puller = ZmqPullConnection( ZmqFactory(), ZmqEndpoint('connect', 'ipc:///tmp/radiusd-acct-message')) self.puller.onPull = self.process logger.info("init acct worker pusher : %s " % (self.pusher)) logger.info("init acct worker puller : %s " % (self.puller)) logger.info("init auth stat pusher : %s " % (self.stat_pusher)) 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 }
def process(self, *args, **kwargs): with make_db(self.db) as db: try: nas_list = db.query(models.TrBas) for nas in nas_list: if not nas.dns_name: continue results, _, _ = yield client.lookupAddress(nas.dns_name) if not results: logger.info("domain {0} resolver empty".format( nas.dns_name)) if results[0].type == dns.A: ipaddr = ".".join( str(i) for i in struct.unpack( "BBBB", results[0].payload.address)) if ipaddr: nas.ip_addr = ipaddr db.commit() logger.info( "domain {0} resolver {1} success".format( nas.dns_name, ipaddr)) else: logger.info("domain {0} no ip address,{1}".format( nas.dns_name, repr(results))) except Exception as err: logger.error('ddns process error %s' % utils.safeunicode(err.message)) defer.returnValue(60)
def process(self, *args, **kwargs): with make_db(self.db) as db: try: nodes = db.query(models.TrNode) for node in nodes: online_count = db.query(models.TrOnline.id).filter( models.TrOnline.account_number == models.TrAccount.account_number, models.TrAccount.customer_id == models.TrCustomer.customer_id, models.TrCustomer.node_id == node.id).count() stat = models.TrOnlineStat() stat.node_id = node.id stat.stat_time = int(time.time()) stat.total = online_count db.add(stat) db.commit() logger.info("online stat task done") except Exception as err: db.rollback() logger.error('online_stat_job err,%s' % (str(err))) return 120.0
def bill_pptimes(self,online,product): # 预付费时长 logger.info('%s > Prepaid long time billing ' % self.account.account_number) user_balance = self.get_user_balance() sessiontime = decimal.Decimal(self.request.acct_session_time) billing_times = decimal.Decimal(online.billing_times) acct_times = sessiontime - billing_times fee_price = decimal.Decimal(product['fee_price']) usedfee = acct_times/decimal.Decimal(3600) * fee_price usedfee = actual_fee = int(usedfee.to_integral_value()) balance = user_balance - usedfee if balance < 0 : balance = 0 actual_fee = user_balance self.update_billing(Storage( account_number = online.account_number, nas_addr = online.nas_addr, acct_session_id = online.acct_session_id, acct_start_time = online.acct_start_time, acct_session_time = self.request.acct_session_time, input_total = self.get_input_total(), output_total = self.get_output_total(), acct_times = int(acct_times.to_integral_value()), acct_flows = 0, acct_fee = usedfee, actual_fee = actual_fee, balance = balance, time_length = 0, flow_length = 0, is_deduct = 1, create_time = datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S") )) if balance == 0 : self.disconnect(online)
def acctounting(self): if self.is_online(self.request.nas_addr, self.request.acct_session_id): return logger.error('online %s is exists' % self.request.acct_session_id) if not self.account: return logger.error('user %s not exists' % self.request.account_number) online = Storage(account_number=self.request.account_number, nas_addr=self.request.nas_addr, acct_session_id=self.request.acct_session_id, acct_start_time=datetime.datetime.now().strftime( "%Y-%m-%d %H:%M:%S"), framed_ipaddr=self.request.framed_ipaddr, mac_addr=self.request.mac_addr, nas_port_id=self.request.nas_port_id, billing_times=0, input_total=0, output_total=0, start_source=STATUS_TYPE_START) self.add_online(online) logger.info('%s Accounting start request, add new online' % online.account_number)
def __init__(self, config, dbengine): self.config = config self.dict = dictionary.Dictionary( os.path.join(os.path.dirname(toughradius.__file__), 'dictionarys/dictionary')) self.db_engine = dbengine or get_engine(config) self.aes = utils.AESCipher(key=self.config.system.secret) self.mcache = mcache.Mcache() self.pusher = ZmqPushConnection( ZmqFactory(), ZmqEndpoint('connect', 'ipc:///tmp/radiusd-auth-result')) self.stat_pusher = ZmqPushConnection( ZmqFactory(), ZmqEndpoint('connect', 'ipc:///tmp/radiusd-stat-task')) self.puller = ZmqPullConnection( ZmqFactory(), ZmqEndpoint('connect', 'ipc:///tmp/radiusd-auth-message')) self.puller.onPull = self.process logger.info("init auth worker pusher : %s " % (self.pusher)) logger.info("init auth worker puller : %s " % (self.puller)) logger.info("init auth stat pusher : %s " % (self.stat_pusher))
def __init__(self,taskd, **kwargs): TaseBasic.__init__(self,taskd, **kwargs) self.statdata = statistics.MessageStat() self.puller = ZmqPullConnection(ZmqFactory(), ZmqEndpoint('bind', 'ipc:///tmp/radiusd-stat-task')) self.puller.onPull = self.update_stat logger.info("init Radius stat puller : %s " % ( self.puller))
def acctounting(self): self.unlock_online(self.request.nas_addr, None) logger.info('bas accounting onoff success')
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) self.do_stat(req.code) logger.info("[Radiusd] :: Received radius request: %s" % (repr(req))) if self.config.system.debug: logger.debug(req.format_str()) if req.code != packet.AccessRequest: raise PacketError( 'non-AccessRequest packet on authentication socket') reply = req.CreateReply() reply.vendor_id = req.vendor_id aaa_request = dict(account_number=req.get_user_name(), domain=req.get_domain(), macaddr=req.client_mac, nasaddr=req.get_nas_addr(), vlanid1=req.vlanid1, vlanid2=req.vlanid2) auth_resp = RadiusAuth(self.db_engine, self.mcache, self.aes, aaa_request).authorize() if auth_resp['code'] > 0: reply['Reply-Message'] = auth_resp['msg'] reply.code = packet.AccessReject return reply if 'bypass' in auth_resp and int(auth_resp['bypass']) == 0: is_pwd_ok = True else: is_pwd_ok = req.is_valid_pwd(auth_resp.get('passwd')) if not is_pwd_ok: reply['Reply-Message'] = "password not match" reply.code = packet.AccessReject return reply else: if u"input_rate" in auth_resp and u"output_rate" in auth_resp: reply = rate_process.process( reply, input_rate=auth_resp['input_rate'], output_rate=auth_resp['output_rate']) attrs = auth_resp.get("attrs") or {} for attr_name in attrs: try: # todo: May have a type matching problem reply.AddAttribute(utils.safestr(attr_name), attrs[attr_name]) except Exception as err: errstr = "RadiusError:current radius cannot support attribute {0},{1}".format( attr_name, utils.safestr(err.message)) logger.error(errstr) for attr, attr_val in req.resp_attrs.iteritems(): reply[attr] = attr_val reply['Reply-Message'] = 'success!' reply.code = packet.AccessAccept if not req.VerifyReply(reply): raise PacketError('VerifyReply error') return reply except Exception as err: self.do_stat(0) errstr = 'RadiusError:Dropping invalid auth packet from {0} {1},{2}'.format( host, port, utils.safeunicode(err)) logger.error(errstr) import traceback traceback.print_exc()
def run_worker(config, dbengine): logger.info('start radius worker: %s' % RADIUSAuthWorker(config, dbengine)) logger.info('start radius worker: %s' % RADIUSAcctWorker(config, dbengine))
def add_handler(self, handle_cls, path, handle_params={}): logger.info("add handler [%s:%s]" % (path, repr(handle_cls))) self.handlers[path]= (path, handle_cls, handle_params)
def add_handler(self, handle_cls, path, handle_params={}): logger.info("add handler [%s:%s]" % (path, repr(handle_cls))) self.handlers[path] = (path, handle_cls, handle_params)