Пример #1
0
 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()
Пример #2
0
 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()
Пример #3
0
 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 job')
     # handles to ipfw, arp the config and the internal administration
     self.ipfw = IPFW()
     self.db = DB()
Пример #4
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)
Пример #5
0
# parse input parameters
parameters = {"sessionid": None, "zoneid": None, "output_type": "plain"}
current_param = None
for param in sys.argv[1:]:
    if len(param) > 1 and param[0] == "/":
        current_param = param[1:].lower()
    elif current_param is not None:
        if current_param in parameters:
            parameters[current_param] = param.strip()
        current_param = None

# disconnect client
response = {"terminateCause": "UNKNOWN"}
if parameters["sessionid"] is not None and parameters["zoneid"] is not None:
    cp_db = DB()
    # remove client
    client_session_info = cp_db.del_client(parameters["zoneid"], parameters["sessionid"])
    if client_session_info is not None:
        cpIPFW = IPFW()
        cpIPFW.delete_from_table(parameters["zoneid"], client_session_info["ip_address"])
        client_session_info["terminateCause"] = "User-Request"
        response = client_session_info

# output result as plain text or json
if parameters["output_type"] != "json":
    for item in response:
        print "%20s %s" % (item, response[item])
else:
    print (ujson.dumps(response))
Пример #6
0
parameters = {'sessionid': None, 'zoneid': None, 'output_type': 'plain'}
current_param = None
for param in sys.argv[1:]:
    if len(param) > 1 and param[0] == '/':
        current_param = param[1:].lower()
    elif current_param is not None:
        if current_param in parameters:
            parameters[current_param] = param.strip()
        current_param = None

# disconnect client
response = {'terminateCause': 'UNKNOWN'}
if parameters['sessionid'] is not None and parameters['zoneid'] is not None:
    cp_db = DB()
    # remove client
    client_session_info = cp_db.del_client(parameters['zoneid'],
                                           parameters['sessionid'])
    if client_session_info is not None:
        cpIPFW = IPFW()
        cpIPFW.delete_from_table(parameters['zoneid'],
                                 client_session_info['ip_address'])
        client_session_info['terminateCause'] = 'User-Request'
        response = client_session_info

# output result as plain text or json
if parameters['output_type'] != 'json':
    for item in response:
        print '%20s %s' % (item, response[item])
else:
    print(ujson.dumps(response))
Пример #7
0
    'authenticated_via': None,
    'output_type': 'plain'
}
current_param = None
for param in sys.argv[1:]:
    if len(param) > 1 and param[0] == '/':
        current_param = param[1:].lower()
    elif current_param is not None:
        if current_param in parameters:
            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']):
Пример #8
0
from lib.db import DB
from lib.ipfw import IPFW

# parse input parameters
parameters = {'sessionid': None, 'zoneid': None, 'output_type': 'plain'}
current_param = None
for param in sys.argv[1:]:
    if len(param) > 1 and param[0] == '/' and param[1:] in parameters:
        current_param = param[1:].lower()
    elif current_param is not None:
        parameters[current_param] = param.strip()
        current_param = None

# disconnect client
response = {'terminateCause': 'UNKNOWN'}
if parameters['sessionid'] is not None and parameters['zoneid'] is not None:
    # remove client
    client_session_info = DB().del_client(parameters['zoneid'],
                                          parameters['sessionid'])
    if client_session_info is not None:
        IPFW().delete(parameters['zoneid'], client_session_info['ip_address'])
        client_session_info['terminateCause'] = 'User-Request'
        response = client_session_info

# output result as plain text or json
if parameters['output_type'] != 'json':
    for item in response:
        print('%20s %s' % (item, response[item]))
else:
    print(ujson.dumps(response))
Пример #9
0
    'authenticated_via': None,
    'output_type': 'plain'
}
current_param = None
for param in sys.argv[1:]:
    if len(param) > 1 and param[0] == '/':
        current_param = param[1:].lower()
    elif current_param is not None:
        if current_param in parameters:
            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)
    cpIPFW.add_to_table(table_number=parameters['zoneid'],
                        address=parameters['ip_address'])
    response['clientState'] = 'AUTHORIZED'
Пример #10
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)
Пример #11
0
# parse input parameters
parameters = {'username': '', 'ip_address': None, 'zoneid': None, 'authenticated_via': None, 'output_type': 'plain'}
current_param = None
for param in sys.argv[1:]:
    if len(param) > 1 and param[0] == '/':
        current_param = param[1:].lower()
    elif current_param is not None:
        if current_param in parameters:
            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'])
Пример #12
0
from lib.ipfw import IPFW

# parse input parameters
parameters = {'sessionid': None, 'zoneid': None, 'output_type': 'plain'}
current_param = None
for param in sys.argv[1:]:
    if len(param) > 1 and param[0] == '/' and param[1:] in parameters:
        current_param = param[1:].lower()
    elif current_param is not None:
        parameters[current_param] = param.strip()
        current_param = None

# disconnect client
response = {'terminateCause': 'UNKNOWN'}
if parameters['sessionid'] is not None and parameters['zoneid'] is not None:
    cp_db = DB()
    # remove client
    client_session_info = cp_db.del_client(parameters['zoneid'], parameters['sessionid'])
    if client_session_info is not None:
        cpIPFW = IPFW()
        cpIPFW.delete(parameters['zoneid'], client_session_info['ip_address'])
        client_session_info['terminateCause'] = 'User-Request'
        response = client_session_info

# output result as plain text or json
if parameters['output_type'] != 'json':
    for item in response:
        print '%20s %s' % (item, response[item])
else:
    print(ujson.dumps(response))
Пример #13
0
def main():
    syslog.syslog(syslog.LOG_ERR, 'starting captiveportal background process')
    # handle to ipfw, arp and the config
    ipfw = IPFW()
    arp = ARP()
    cnf = Config()
    while True:
        try:
            # construct objects
            db = DB()

            # update accounting info
            db.update_accounting_info(ipfw.list_accounting_info())

            # process sessions per zone
            arp.reload()
            cpzones = cnf.get_zones()
            for zoneid in cpzones:
                registered_addresses = ipfw.list_table(zoneid)
                registered_add_accounting = ipfw.list_accounting_info()
                expected_clients = db.list_clients(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 = False

                    # todo, static ip and addresses shouldn't be affected by the timeout rules below.
                    # check if hardtimeout is set and overrun for this session
                    if 'hardtimeout' in cpzones[zoneid] and str(cpzones[zoneid]['hardtimeout']).isdigit():
                        # hardtimeout should be set and we should have collected some session data from the client
                        if int(cpzones[zoneid]['hardtimeout']) > 0  and float(db_client['startTime']) > 0:
                            if (time.time() - float(db_client['startTime'])) / 60 > int(cpzones[zoneid]['hardtimeout']):
                                drop_session = True

                    # check if idletimeout is set and overrun for this session
                    if 'idletimeout' in cpzones[zoneid] and str(cpzones[zoneid]['idletimeout']).isdigit():
                        # idletimeout should be set and we should have collected some session data from the client
                        if int(cpzones[zoneid]['idletimeout']) > 0 and float(db_client['last_accessed']) > 0:
                            if (time.time() - float(db_client['last_accessed'])) / 60 > int(cpzones[zoneid]['idletimeout']):
                                drop_session = True

                    # check session, if it should be active, validate its properties
                    if not drop_session:
                        # registered client, but not active according to ipfw (after reboot)
                        if cpnet not in registered_addresses:
                            ipfw.add_to_table(zoneid, cpnet)

                        # is accounting rule still available? need to reapply after reload / reboot
                        if cpnet not in registered_add_accounting and db_client['ipAddress'] not in registered_add_accounting:
                            ipfw.add_accounting(cpnet)
                    else:
                        # remove session
                        db.del_client(zoneid, db_client['sessionId'])
                        ipfw.delete_from_table(zoneid, cpnet)
                        ipfw.del_accounting(cpnet)

            # cleanup, destruct
            del db

            # sleep
            time.sleep(5)
        except KeyboardInterrupt:
            break
        except SystemExit:
            break
        except:
            syslog.syslog(syslog.LOG_ERR, traceback.format_exc())