def sokect_handler(self, socket, address): if self.debug and logger.is_debug(): logger.get_logger().debug('%s: accept connection', address) # send welcome socket.sendall(Messager.data_for_welcome()) conn_inbox = Queue() answer_thread = gevent.spawn(self.answer_fiber, socket, address, conn_inbox) while self._running: try: message = Messager.receive_msg(socket) if not message: if self.debug and logger.is_debug(): logger.get_logger().debug('%s: connection has been closed by client.', address) break; if isinstance(message, Answer): logger.get_logger().error('%s: unexpected message received: %s', address, message) continue elif isinstance(message, Query): if self.debug and logger.is_debug(): logger.get_logger().debug('%s: message received: %s', address, message) message.inbox = conn_inbox self._query_queue.put(message) except gevent.socket.error as ex: logger.get_logger().error('%s: socket error: %s', address, repr(ex)) break except: logger.get_logger().error('%s: exception: %s', address, traceback.format_exc()) break if self.debug and logger.is_debug(): logger.get_logger().debug('%s: close connection', address) socket.close() # stop answer thread conn_inbox.put(StopIteration)
def answer_fiber(self, socket, address, inbox): for answer in inbox: if not isinstance(answer, Answer): logger.get_logger().error('invalid answer %s', answer) continue if self.debug and logger.is_debug(): logger.get_logger().debug('%s: reply answer: %s', address, answer) socket.sendall(answer.get_data()) if self.debug and logger.is_debug(): logger.get_logger().debug('%s: answer fiber stop', address)
def get_passwd(self): try: return self.PwDecrypt(self.get(2)[0]) except: if is_debug(): debug('Exception while trying to get password') return None
def receive_next_msg(self): if self.protocol == 'tcp': message = Messager.receive_msg(self._socket) elif self.protocol == 'udp': pkt, address = self.unitive_recvfrom(65535) message = Messager.message_from_data(pkt) if self.debug and logger.is_debug(): if isinstance(message, Query): logger.get_logger().debug('SQ:%d method=%s', message.qid, message.method) elif isinstance(message, Answer): logger.get_logger().debug('SA:%d status=%d', message.qid, message.status) if not message: raise Exception('Recieved Unknown packet') if isinstance(message, Answer): qid = message.qid if self.pending.get(qid): del self.pending[qid] status = message.status if status: raise ProxyError(qid, status, message.data) return message;
def send_accept(self, req, radiusnas, time_available, speed_ul, speed_dl, data_limit): reply = req.CreateReply() reply.source = req.source reply.code = packet.AccessAccept reply.set_session_timeout(time_available) reply.set_idle_timeout(time_available) reply.set_intrim_update() if speed_dl: reply.set_special_int(radiusnas.vendor_id, "speed_dl", int(speed_dl)) if speed_ul: reply.set_special_int(radiusnas.vendor_id, "speed_ul", int(speed_ul)) #setting data limits is a bit tricky, some routers accept single value for total data. #some accept different for dl/ul reply.set_special_int(radiusnas.vendor_id, "data_limit", int(data_limit)) reply.set_special_int(radiusnas.vendor_id, "dl_data_limit", int(data_limit)) reply.set_special_int(radiusnas.vendor_id, "ul_data_limit", int(data_limit)) req.sock.sendto(reply.ReplyPacket(), reply.source) if is_debug(): debug("[Auth] send an authentication accept,user[%s]"\ %(req.get_username()))
def get_username(self): try: return tools.DecodeString(self.get(1)[0]) except: if is_debug(): exception('Exception while trying to get username') return None
def get_nasid(self): try: return self.get(32)[0] except: if is_debug(): exception('Exception while trying to get nas id') return None
def get_acctstatustype(self): try: return tools.DecodeInteger(self.get(40)[0]) except: if is_debug(): exception( 'Exception while trying to get nas accounting status') return None
def __init__(self, setting): self.setting = setting self.debug = setting.get('debug', False) self._running = True self._adapters = {} self._proxies = {} if self.debug and logger.is_debug(): logger.get_logger().debug("application setting %s", setting)
def get_accnt_sessionid(self): try: return self.get(44)[0] except: if is_debug(): exception( 'Exception while trying to get accounting session id') return None
def connect(self): if self.protocol == 'tcp': self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) elif self.protocol == 'udp': self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._socket.connect((self.host, self.port)) if self.debug and logger.is_debug(): ip, port = self._socket.getsockname() logger.get_logger().debug('address = %s:%d' % (ip, port)) if self.welcome: type = Messager.receive_msg_type(self._socket) if type != MESSAGE_TYPE_WELCOME: raise Exception('Imcomplete message') if self.debug and logger.is_debug(): logger.get_logger().debug('S.WELCOME')
def send_quest(self, qid, method, params, twoway=True): if qid: self.pending[qid] = time.time() if self.debug and logger.is_debug(): logger.get_logger().debug('CQ:%d service=%s method=%s', qid, self.service, method) self.unitive_send(Messager.data_for_query(qid, self.service, method, params)) return qid
def process(self, req): attr_keys = list(req.keys()) if is_debug(): log_ctx.base_info(ip=req.source[0], msgtype='ACCOUNTING PKT') #for attr in attr_keys: debug_info = '\t\t'.join("%s: %s" % (attr, req[attr]) for attr in attr_keys) debug("Accounting packet from :%s [%s]" % (req.source[0], debug_info)) username = req.get_username() if not username: debug('ERROR no username provided') return self.send_response(req) radiususer = db.get_radiususer_from_name(username) if not radiususer: debug('ERROR radius user not found in DB') return self.send_response(req) if not radiususer.active: debug('ERROR radius user is not active') return self.send_response(req) radiusnas_id = radiususer.nas_id radiusnas = db.get_nas_from_id(radiusnas_id) if not radiusnas: debug('ERROR no radiusnas') return self.send_response(req) log_ctx.add_nas_info(nasid=radiusnas_id, siteid=radiusnas.siteid) req.secret = radiusnas.secret reply = req.CreateReply() reply.source = req.source acct_status_type = req.get_acctstatustype() if acct_status_type == STATUS_TYPE_START: log_ctx.update_packet_type('Accounting Start') return self.start_accounting(req, radiusnas) elif acct_status_type == STATUS_TYPE_STOP: log_ctx.update_packet_type('Accounting Stop') return self.stop_accounting(req, radiusnas) elif acct_status_type == STATUS_TYPE_UPDATE: log_ctx.update_packet_type('Accounting Status') return self.update_accounting(req, radiusnas) elif acct_status_type == STATUS_TYPE_NAS_ON or \ acct_status_type == STATUS_TYPE_NAS_OFF : log_ctx.update_packet_type('Accounting NAS On/Off') return self.nasonoff_accounting(req, radiusnas, acct_status_type) else: return self.send_response(req)
def stop_accounting(self, req, radiusnas): username = req.get_username() if not username: if is_debug(): debug('Got empty username') return self.send_response(req) sessionid = req.get_accnt_sessionid() if not sessionid: if is_debug(): debug('Got empty sessionid') return self.send_response(req) radiususer = db.get_radiususer(radiusnas.id, username) if not radiususer: if is_debug(): debug('Got unknown username :%s' % username) return self.send_response(req) radiussession = db.get_radiussession(radiusnas, radiususer, sessionid) if not radiussession: if is_debug(): debug('No session found ') return self.send_response(req) data_used = req.get_totaldatausage() time_used = round(req.get_acctsessiontime() / 60, 0) db.update_radiussession(radiussession.id, data_used=data_used, time_used=time_used, disassoc=True) send_accounting_stop_signal(username) if is_debug(): debug( '[Acct] User[%s] Session-ID[%s] Used[%s Mb] in [%s mins] STOP' % (radiususer.radiususer, radiussession.accnt_sessionid, data_used, time_used)) return self.send_response(req)
def _handle_wildcard_servant(self, query): if self.debug and logger.is_debug(): logger.get_logger().debug('handle_wildcard_servant: %s', query) try: result = self._wildcard_servant(query.service, query.method, query.params) if query.qid: query.inbox.put(Answer(query.qid, 0, result)) except proxy.ProxyError as ex: if query.qid: query.inbox.put(Answer(ex.qid, ex.status, ex.params)) except: if query.qid: query.inbox.put(Answer(query.qid, 1, self._make_exception_params(query)))
def activate(self): for i in range(self._servant_worker_num): gevent.spawn(self.servant_worker) self._pool = Pool(self._accept_pool_num) endpoint = self._endpoint try: service, proto, host, port = proxy.parse_endpoint(endpoint) if proto != 'tcp': raise proxy.ProxyError(1, 'only tcp server supported now') server = StreamServer((host, int(port)), self.sokect_handler, spawn=self._pool) if self.debug and logger.is_debug(): logger.get_logger().debug('adapter start %s', endpoint) self._servers.append(server) server.start() except: logger.get_logger().error('start adapter fail %s', endpoint, exc_info = 1)
def _handle_normal_servant(self, query): called_method = query.method if self.debug and logger.is_debug(): logger.get_logger().debug('handle_normal_servant: %s', query) servant = self._servants.get(query.service) if not servant: #build exception at params exdict = {} exdict['exception'] = 'ServantNotFound' exdict['code'] = 1 exdict['message'] = "servant %s not found in adapter %s" % (query.service, self._endpoint) exdict['raiser'] = self._endpoint if query.qid: query.inbox.put(Answer(query.qid, 1, exdict)) else: logger.get_logger().warning("%s.%s %s", query.service, called_method, exdict) return if called_method[0] == '\0': callback = servant._special_callback(query) else: callback = servant.find_method(called_method) if not callback: self._method_not_found(called_method, query) return try: time_start = time.time() servant.before_method_call(called_method, time_start) result = callback(Params(query.params)) servant.after_method_call(called_method, time_start, (time.time() - time_start) * 1000) if query.qid: result = dict(result) query.inbox.put(Answer(query.qid, 0, result)) except proxy.ProxyError as ex: if query.qid: query.inbox.put(Answer(query.qid, ex.status, ex.params)) else: logger.get_logger().warning("%s.%s %d %s", query.service, called_method, ex.status, ex.params) except: logger.get_logger().error("query %d handle fail", query.qid, exc_info = 1) if query.qid: query.inbox.put(Answer(query.qid, 1, self._make_exception_params(query)))
def start_accounting(self, req, radiusnas): username = req.get_username() if not username: if is_debug(): debug('Got empty username') return self.send_response(req) sessionid = req.get_accnt_sessionid() if not sessionid: if is_debug(): debug('Got empty sessionid') return self.send_response(req) radiususer = db.get_radiususer(radiusnas.id, username) if not radiususer: if is_debug(): debug('Got unknown username :%s' % username) return self.send_response(req) framed_ip_address = req.get_framed_ip() if not framed_ip_address: if is_debug(): debug('ERROR no Framed-IP provided') return self.send_response(req) send_accounting_start_signal(username) radiussession = db.create_radius_session(radiusnas, radiususer, sessionid, framed_ip_address) if not radiussession: if is_debug(): debug( 'Something went wrong while accounting session creation ') return self.send_response(req) if is_debug(): debug('[Acct] User[%s],Nas[%s] billing starting' % (radiususer.radiususer, radiusnas.id)) return self.send_response(req)
def send_answer(self, qid, status, data): if self.debug and logger.is_debug(): logger.get_logger().debug('CA:%d %d %s', qid, status, data) self.unitive_send(Messager.data_for_answer(qid, status, data))
def process(self, req): attr_keys = list(req.keys()) if is_debug(): # for attr in attr_keys: log_ctx.base_info(ip=req.source[0], msgtype='AUTH PKT') debug_info = '\t\t'.join("%s: %s" % (attr, req[attr]) for attr in attr_keys) debug("Received [%s]" % (debug_info)) username = req.get_username() if not username: debug('ERROR no username provided') return self.send_reject(req, 'ERROR no username provided') radiususer = db.get_radiususer_from_name(username) if not radiususer: debug('ERROR radius user not found in DB') return self.send_reject( req, 'ERROR no radiususer found with given username or radiususer not active' ) if not radiususer.active: debug('ERROR radius user is inactive') return self.send_reject( req, 'ERROR no radiususer found with given username or radiususer not active' ) radiusnas_id = radiususer.nas_id radiusnas = db.get_nas_from_id(radiusnas_id) if not radiusnas: return self.send_reject(req, 'ERROR unknown NAS ID') log_ctx.add_nas_info(nasid=radiusnas_id, siteid=radiusnas.siteid) #set secret req.secret = radiusnas.secret if not req.is_valid_pwd(radiususer.radiuspass): if is_debug(): debug('Got unknown password ') return self.send_reject(req, 'ERROR Incorrect password') session_expiry = arrow.get(radiususer.stoptime) time_available = session_expiry.timestamp - arrow.utcnow().timestamp if not time_available > 0: if is_debug(): debug('Guestsession:%s expired at :%s ' % (radiususer.stoptime, session_expiry.humanize())) return self.send_reject(req, 'ERROR expired user credentials') rcvd_mac = req.get_macaddr() if not rcvd_mac: return self.send_reject(req, 'ERROR no Calling-Station-Id provided') if not rcvd_mac.lower() == radiususer.mac.lower(): if is_debug(): debug('Expected MAC :%s got ;%s ' % (radiususer.mac, rcvd_mac)) return self.send_reject( req, 'ERROR Invalid credentials for this device') return self.send_accept( req, radiusnas, time_available=time_available, speed_ul=int(radiususer.speed_ul), #convert to bps speed_dl=int(radiususer.speed_dl), data_limit=radiususer.data_limit) #convert to bytes