Example #1
0
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)
Example #2
0
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)
Example #3
0
            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
Example #4
0
File: allow.py Project: evbevz/core
            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':