Beispiel #1
0
    def setupCaptiveNat(self):
        # TODO
        captive_port = 9000
        self.forwarding_was_enabled = False

        # Check if forwarding is enabled to restore it after program end
        with open("/proc/sys/net/ipv4/ip_forward", 'r') as f:
            self.forwarding_was_enabled = (f.read(1) == '1')

        self.initNftables()

        # Devices are classified into 3 sets:
        #  - cp_auth_ok: devices which have passed the captive portal auth
        #  - cp_whitelisted: devices manually set as "pass" from the gui (or "capture")
        #  - cp_blacklisted: devices manually set as "block" from the gui
        # NOTE: Could use ether_addr sets with "ether saddr" match but the captive_portal
        # does not know MAC addresses
        nft.run(
            "add rule nat nw_prerouting iif %s tcp dport { 80 } ip saddr %s ip saddr != @cp_auth_ok ether saddr != @cp_whitelisted ether saddr != @cp_blacklisted counter dnat %s:%d"
            % (self.options["interface"], self.lan_network, self.iface_ip,
               captive_port))

        # Masquerade outgoing traffic
        nft.run(
            "add rule nat nw_postrouting oif %s ip saddr %s counter masquerade"
            % (self.options["interface"], self.lan_network))

        # Only allow DNS traffic to pass (otherwise captive portal detection on the device won't work)
        nft.run(
            "add rule filter nw_forward ether saddr @cp_blacklisted counter drop"
        )
        nft.run(
            "add rule filter nw_forward iif %s ip saddr %s udp dport { 53 } counter accept"
            % (self.options["interface"], self.lan_network))
        nft.run(
            "add rule filter nw_forward iif %s ct state new ip saddr %s ip saddr != @cp_auth_ok ether saddr != @cp_whitelisted counter drop"
            % (self.options["interface"], self.lan_network))

        if not self.forwarding_was_enabled:
            self.setForwarding(True)
Beispiel #2
0
    def POST_LoginOk(self):
        username = request.form.get("username")
        password = request.form.get("password")
        success = False

        if username and password:
            log.info("Login: ip='%s' username='******' password='******'" %
                     (request.remote_addr, username, password))
            # TODO
            success = True
            self.cp_eventsqueue[0].send(("auth_ok", request.remote_addr))

        if success:
            # Need to add the expection immediately, before redirecting the device
            # TODO: IP should be harvested when DHCP requests are seen, otherwill
            # the IP will be allowed forever
            nft.run("add element ip nat cp_auth_ok { %s }" %
                    (request.remote_addr, ))
            nft.run("add element ip filter cp_auth_ok { %s }" %
                    (request.remote_addr, ))

            return (self.GET_LoginOk())
        else:
            return redirect(self.get_login_url(url), code=303)
Beispiel #3
0
    def termNftables(self):
        # NOTE: don't delete tables as rules from other programs may be present
        nft.run("delete chain ip nat nw_prerouting")
        nft.run("delete chain ip nat nw_postrouting")
        nft.run("delete chain ip filter nw_forward")

        nft.run("delete set ip nat cp_auth_ok")
        nft.run("delete set ip nat cp_whitelisted")
        nft.run("delete set ip nat cp_blacklisted")

        nft.run("delete set ip filter cp_auth_ok")
        nft.run("delete set ip filter cp_whitelisted")
        nft.run("delete set ip filter cp_blacklisted")
Beispiel #4
0
    def initNftables(self):
        nft.run("add table ip nat")
        nft.run("add table ip filter")

        # Chains are marked with the "nw_" prefix to identify them
        nft.run(
            "add chain ip nat nw_prerouting { type nat hook prerouting priority -100; }"
        )
        nft.run(
            "add chain ip nat nw_postrouting { type nat hook postrouting priority -100; }"
        )
        nft.run(
            "add chain ip filter nw_forward { type filter hook forward priority 0; }"
        )

        nft.run("add set ip nat cp_auth_ok { type ipv4_addr;}")
        nft.run("add set ip nat cp_whitelisted { type ether_addr;}")
        nft.run("add set ip nat cp_blacklisted { type ether_addr;}")

        nft.run("add set ip filter cp_auth_ok { type ipv4_addr;}")
        nft.run("add set ip filter cp_whitelisted { type ether_addr;}")
        nft.run("add set ip filter cp_blacklisted { type ether_addr;}")
Beispiel #5
0
    def reloadExceptions(self):
        if self.passive_mode:
            return

        devices = config.getConfiguredDevices()
        now = time.time()

        nft.run("flush set ip filter cp_whitelisted")
        nft.run("flush set ip filter cp_blacklisted")
        nft.run("flush set ip nat cp_whitelisted")
        nft.run("flush set ip nat cp_blacklisted")

        for mac, mac_info in devices.items():
            policy = mac_info.get("policy", "default")
            rearp_mac = False
            spoof_mac = False

            if ((policy == "pass") or (policy == "capture")):
                nft.run("add element ip nat cp_whitelisted { %s }" % (mac, ))
                nft.run("add element ip filter cp_whitelisted { %s }" %
                        (mac, ))

                if (policy == "pass"):
                    rearp_mac = True
            elif policy == "block":
                nft.run("add element ip nat cp_blacklisted { %s }" % (mac, ))
                nft.run("add element ip filter cp_blacklisted { %s }" %
                        (mac, ))
                spoof_mac = True
            elif policy == "default":
                applied_policy = getDevicePolicy(mac)

                if applied_policy == "pass":
                    rearp_mac = True

            if rearp_mac:
                spoofed_mac = self.macs_to_spoof.pop(mac, None)

                if spoofed_mac:
                    # The MAC was spoofed, rearp it
                    pkt_reader.arp_rearp(self.handle, mac, spoofed_mac["ip"])
            elif spoof_mac and (not self.macs_to_spoof.get(mac)):
                # Try to find the MAC IP to start blocking it
                found_ip = None

                for ip, m in self.ip_to_mac.items():
                    if m == mac:
                        found_ip = ip
                        break

                if found_ip:
                    self.macs_to_spoof[mac] = {
                        "last_seen": now,
                        "ip": found_ip
                    }