class CPBackgroundProcess(object): """ background process helper class """ def __init__(self): # open syslog and notice startup syslog.openlog('captiveportal', logoption=syslog.LOG_DAEMON) syslog.syslog(syslog.LOG_NOTICE, 'starting captiveportal background process') # handles to ipfw, arp the config and the internal administration self.ipfw = IPFW() self.arp = ARP() self.cnf = Config() self.db = DB() self._conf_zone_info = self.cnf.get_zones() def list_zone_ids(self): """ return zone numbers """ return self._conf_zone_info.keys() def initialize_fixed(self): """ initialize fixed ip / hosts per zone """ cpzones = self._conf_zone_info for zoneid in cpzones: for conf_section in ['allowedaddresses', 'allowedmacaddresses']: for address in cpzones[zoneid][conf_section]: if conf_section.find('mac') == -1: sessions = self.db.sessions_per_address(zoneid, ip_address=address) ip_address = address mac_address = None else: sessions = self.db.sessions_per_address(zoneid, mac_address=address) ip_address = None mac_address = address sessions_deleted = 0 for session in sessions: if session['authenticated_via'] not in ('---ip---', '---mac---'): sessions_deleted += 1 self.db.del_client(zoneid, session['sessionId']) if sessions_deleted == len(sessions) or len(sessions) == 0: # when there's no session active, add a new one # (only administrative, the sync process will add it if neccesary) if ip_address is not None: self.db.add_client(zoneid, "---ip---", "", ip_address, "") else: self.db.add_client(zoneid, "---mac---", "", "", mac_address) # cleanup removed static sessions for dbclient in self.db.list_clients(zoneid): if dbclient['authenticated_via'] == '---ip---' \ and dbclient['ipAddress'] not in cpzones[zoneid]['allowedaddresses']: self.ipfw.delete(zoneid, dbclient['ipAddress']) self.db.del_client(zoneid, dbclient['sessionId']) elif dbclient['authenticated_via'] == '---mac---' \ and dbclient['macAddress'] not in cpzones[zoneid]['allowedmacaddresses']: if dbclient['ipAddress'] != '': self.ipfw.delete(zoneid, dbclient['ipAddress']) self.db.del_client(zoneid, dbclient['sessionId']) def sync_zone(self, zoneid): """ Synchronize captiveportal zone. Handles timeouts and administrative changes to this zones sessions """ if zoneid in self._conf_zone_info: # fetch data for this zone cpzone_info = self._conf_zone_info[zoneid] registered_addresses = self.ipfw.list_table(zoneid) registered_addr_accounting = self.ipfw.list_accounting_info() expected_clients = self.db.list_clients(zoneid) concurrent_users = self.db.find_concurrent_user_sessions(zoneid) # handle connected clients, timeouts, address changes, etc. for db_client in expected_clients: # fetch ip address (or network) from database cpnet = db_client['ipAddress'].strip() # there are different reasons why a session should be removed, check for all reasons and # use the same method for the actual removal drop_session_reason = None # session cleanups, only for users not for static hosts/ranges. if db_client['authenticated_via'] not in ('---ip---', '---mac---'): # check if hardtimeout is set and overrun for this session if 'hardtimeout' in cpzone_info and str(cpzone_info['hardtimeout']).isdigit(): # hardtimeout should be set and we should have collected some session data from the client if int(cpzone_info['hardtimeout']) > 0 and float(db_client['startTime']) > 0: if (time.time() - float(db_client['startTime'])) / 60 > int(cpzone_info['hardtimeout']): drop_session_reason = "session %s hit hardtimeout" % db_client['sessionId'] # check if idletimeout is set and overrun for this session if 'idletimeout' in cpzone_info and str(cpzone_info['idletimeout']).isdigit(): # idletimeout should be set and we should have collected some session data from the client if int(cpzone_info['idletimeout']) > 0 and float(db_client['last_accessed']) > 0: if (time.time() - float(db_client['last_accessed'])) / 60 > int(cpzone_info['idletimeout']): drop_session_reason = "session %s hit idletimeout" % db_client['sessionId'] # cleanup concurrent users if 'concurrentlogins' in cpzone_info and int(cpzone_info['concurrentlogins']) == 0: if db_client['sessionId'] in concurrent_users: drop_session_reason = "remove concurrent session %s" % db_client['sessionId'] # if mac address changes, drop session. it's not the same client current_arp = self.arp.get_by_ipaddress(cpnet) if current_arp is not None and current_arp['mac'] != db_client['macAddress']: drop_session_reason = "mac address changed for session %s" % db_client['sessionId'] elif db_client['authenticated_via'] == '---mac---': # detect mac changes current_ip = self.arp.get_address_by_mac(db_client['macAddress']) if current_ip != None: if db_client['ipAddress'] != '': # remove old ip self.ipfw.delete(zoneid, db_client['ipAddress']) self.db.update_client_ip(zoneid, db_client['sessionId'], current_ip) self.ipfw.add_to_table(zoneid, current_ip) self.ipfw.add_accounting(current_ip) # check session, if it should be active, validate its properties if drop_session_reason is None: # registered client, but not active according to ipfw (after reboot) if cpnet not in registered_addresses: self.ipfw.add_to_table(zoneid, cpnet) # is accounting rule still available? need to reapply after reload / reboot if cpnet not in registered_addr_accounting: self.ipfw.add_accounting(cpnet) else: # remove session syslog.syslog(syslog.LOG_NOTICE, drop_session_reason) self.ipfw.delete(zoneid, cpnet) self.db.del_client(zoneid, db_client['sessionId']) # if there are addresses/networks in the underlying ipfw table which are not in our administration, # remove them from ipfw. for registered_address in registered_addresses: address_active = False for db_client in expected_clients: if registered_address == db_client['ipAddress']: address_active = True break if not address_active: self.ipfw.delete(zoneid, registered_address)
class CPBackgroundProcess(object): """ background process helper class """ def __init__(self): # open syslog and notice startup syslog.openlog('captiveportal', logoption=syslog.LOG_DAEMON, facility=syslog.LOG_LOCAL4) syslog.syslog(syslog.LOG_NOTICE, 'starting captiveportal background process') # handles to ipfw, arp the config and the internal administration self.ipfw = IPFW() self.arp = ARP() self.cnf = Config() self.db = DB() self._conf_zone_info = self.cnf.get_zones() def list_zone_ids(self): """ return zone numbers """ return self._conf_zone_info.keys() def initialize_fixed(self): """ initialize fixed ip / hosts per zone """ cpzones = self._conf_zone_info for zoneid in cpzones: for conf_section in ['allowedaddresses', 'allowedmacaddresses']: for address in cpzones[zoneid][conf_section]: if conf_section.find('mac') == -1: sessions = self.db.sessions_per_address(zoneid, ip_address=address) ip_address = address mac_address = None else: sessions = self.db.sessions_per_address(zoneid, mac_address=address) ip_address = None mac_address = address sessions_deleted = 0 for session in sessions: if session['authenticated_via'] not in ('---ip---', '---mac---'): sessions_deleted += 1 self.db.del_client(zoneid, session['sessionId']) if sessions_deleted == len(sessions) or len(sessions) == 0: # when there's no session active, add a new one # (only administrative, the sync process will add it if neccesary) if ip_address is not None: self.db.add_client(zoneid, "---ip---", "", ip_address, "") else: self.db.add_client(zoneid, "---mac---", "", "", mac_address) # cleanup removed static sessions for dbclient in self.db.list_clients(zoneid): if dbclient['authenticated_via'] == '---ip---' \ and dbclient['ipAddress'] not in cpzones[zoneid]['allowedaddresses']: self.ipfw.delete(zoneid, dbclient['ipAddress']) self.db.del_client(zoneid, dbclient['sessionId']) elif dbclient['authenticated_via'] == '---mac---' \ and dbclient['macAddress'] not in cpzones[zoneid]['allowedmacaddresses']: if dbclient['ipAddress'] != '': self.ipfw.delete(zoneid, dbclient['ipAddress']) self.db.del_client(zoneid, dbclient['sessionId']) def sync_zone(self, zoneid): """ Synchronize captiveportal zone. Handles timeouts and administrative changes to this zones sessions """ if zoneid in self._conf_zone_info: # fetch data for this zone cpzone_info = self._conf_zone_info[zoneid] registered_addresses = self.ipfw.list_table(zoneid) registered_addr_accounting = self.ipfw.list_accounting_info() expected_clients = self.db.list_clients(zoneid) concurrent_users = self.db.find_concurrent_user_sessions(zoneid) # handle connected clients, timeouts, address changes, etc. for db_client in expected_clients: # fetch ip address (or network) from database cpnet = db_client['ipAddress'].strip() # there are different reasons why a session should be removed, check for all reasons and # use the same method for the actual removal drop_session_reason = None # session cleanups, only for users not for static hosts/ranges. if db_client['authenticated_via'] not in ('---ip---', '---mac---'): # check if hardtimeout is set and overrun for this session if 'hardtimeout' in cpzone_info and str(cpzone_info['hardtimeout']).isdigit(): # hardtimeout should be set and we should have collected some session data from the client if int(cpzone_info['hardtimeout']) > 0 and float(db_client['startTime']) > 0: if (time.time() - float(db_client['startTime'])) / 60 > int(cpzone_info['hardtimeout']): drop_session_reason = "session %s hit hardtimeout" % db_client['sessionId'] # check if idletimeout is set and overrun for this session if 'idletimeout' in cpzone_info and str(cpzone_info['idletimeout']).isdigit(): # idletimeout should be set and we should have collected some session data from the client if int(cpzone_info['idletimeout']) > 0 and float(db_client['last_accessed']) > 0: if (time.time() - float(db_client['last_accessed'])) / 60 > int(cpzone_info['idletimeout']): drop_session_reason = "session %s hit idletimeout" % db_client['sessionId'] # cleanup concurrent users if 'concurrentlogins' in cpzone_info and int(cpzone_info['concurrentlogins']) == 0: if db_client['sessionId'] in concurrent_users: drop_session_reason = "remove concurrent session %s" % db_client['sessionId'] # if mac address changes, drop session. it's not the same client current_arp = self.arp.get_by_ipaddress(cpnet) if current_arp is not None and current_arp['mac'] != db_client['macAddress']: drop_session_reason = "mac address changed for session %s" % db_client['sessionId'] # session accounting if db_client['acc_session_timeout'] is not None \ and time.time() - float(db_client['startTime']) > db_client['acc_session_timeout']: drop_session_reason = "accounting limit reached for session %s" % db_client['sessionId'] elif db_client['authenticated_via'] == '---mac---': # detect mac changes current_ip = self.arp.get_address_by_mac(db_client['macAddress']) if current_ip is not None: if db_client['ipAddress'] != '': # remove old ip self.ipfw.delete(zoneid, db_client['ipAddress']) self.db.update_client_ip(zoneid, db_client['sessionId'], current_ip) self.ipfw.add_to_table(zoneid, current_ip) self.ipfw.add_accounting(current_ip) # check session, if it should be active, validate its properties if drop_session_reason is None: # registered client, but not active according to ipfw (after reboot) if cpnet not in registered_addresses: self.ipfw.add_to_table(zoneid, cpnet) # is accounting rule still available? need to reapply after reload / reboot if cpnet not in registered_addr_accounting: self.ipfw.add_accounting(cpnet) else: # remove session syslog.syslog(syslog.LOG_NOTICE, drop_session_reason) self.ipfw.delete(zoneid, cpnet) self.db.del_client(zoneid, db_client['sessionId']) # if there are addresses/networks in the underlying ipfw table which are not in our administration, # remove them from ipfw. for registered_address in registered_addresses: address_active = False for db_client in expected_clients: if registered_address == db_client['ipAddress']: address_active = True break if not address_active: self.ipfw.delete(zoneid, registered_address)
parameters[current_param] = param.strip() current_param = None # create new session if parameters['ip_address'] is not None and parameters['zoneid'] is not None: cpDB = DB() cpIPFW = IPFW() arp_entry = ARP().get_by_ipaddress(parameters['ip_address']) if arp_entry is not None: mac_address = arp_entry['mac'] else: mac_address = None response = cpDB.add_client( zoneid=parameters['zoneid'], authenticated_via=parameters['authenticated_via'], username=parameters['username'], ip_address=parameters['ip_address'], mac_address=mac_address) # check if address is not already registered before adding it to the ipfw table if not cpIPFW.ip_or_net_in_table(table_number=parameters['zoneid'], address=parameters['ip_address']): cpIPFW.add_to_table(table_number=parameters['zoneid'], address=parameters['ip_address']) # add accounting for this ip address cpIPFW.add_accounting(parameters['ip_address']) response['clientState'] = 'AUTHORIZED' else: response = {'clientState': 'UNKNOWN'} # output result as plain text or json
parameters[current_param] = param.strip() current_param = None # create new session if parameters['ip_address'] is not None and parameters['zoneid'] is not None: cpDB = DB() cpIPFW = IPFW() arp_entry = ARP().get_by_ipaddress(parameters['ip_address']) if arp_entry is not None: mac_address = arp_entry['mac'] else: mac_address = None response = cpDB.add_client(zoneid=parameters['zoneid'], authenticated_via=parameters['authenticated_via'], username=parameters['username'], ip_address=parameters['ip_address'], mac_address=mac_address ) # check if address is not already registered before adding it to the ipfw table if not cpIPFW.ip_or_net_in_table(table_number=parameters['zoneid'], address=parameters['ip_address']): cpIPFW.add_to_table(table_number=parameters['zoneid'], address=parameters['ip_address']) # add accounting for this ip address cpIPFW.add_accounting(parameters['ip_address']) response['clientState'] = 'AUTHORIZED' else: response = {'clientState': 'UNKNOWN'} # output result as plain text or json if parameters['output_type'] != 'json':