def start_firewall(self): '''Start the firewall''' err_msg = _("problem running") if self.dryrun: msg("> " + _("running ufw-init")) else: (rc, out) = cmd([self.files['init'], 'start']) if rc != 0: debug(out) raise UFWError(err_msg + " ufw-init") if not self.defaults.has_key('loglevel') or \ self.defaults['loglevel'] not in self.loglevels.keys(): # Add the loglevel if not valid try: self.set_loglevel("low") except Exception: err_msg = _("Could not set LOGLEVEL") raise UFWError(err_msg) else: try: self.update_logging(self.defaults['loglevel']) except Exception: err_msg = _("Could not load logging rules") raise UFWError(err_msg)
def stop_firewall(self): '''Stop the firewall''' err_msg = _("problem running") if self.dryrun: msg("> " + _("running ufw-init")) else: (rc, out) = cmd([self.files['init'], 'force-stop']) if rc != 0: debug(out) raise UFWError(err_msg + " ufw-init")
def stop_firewall(self): """Stops the firewall""" err_msg = _("problem running") if self.dryrun: msg("> " + _("running ufw-init")) else: (rc, out) = cmd([self.files["init"], "force-stop"]) if rc != 0: debug(out) raise UFWError(err_msg + " ufw-init")
def _chain_cmd(self, chain, args, fail_ok=False): """Perform command on chain""" exe = self.iptables if chain.startswith("ufw6"): exe = self.ip6tables (rc, out) = cmd([exe] + args) if rc != 0: err_msg = _("Could not perform '%s'") % (args) if fail_ok: debug("FAILOK: " + err_msg) else: raise UFWError(err_msg)
def _chain_cmd(self, chain, args, fail_ok=False): '''Perform command on chain''' exe = self.iptables if chain.startswith("ufw6"): exe = self.ip6tables (rc, out) = cmd([exe] + args) if rc != 0: err_msg = _("Could not perform '%s'") % (args) if fail_ok: debug("FAILOK: " + err_msg) else: raise UFWError(err_msg)
def status(command, replies): """.""" if not verify(command.message): return clear_cmd() x = "active" for c in ("input", "output"): if ufwu.cmd([fw()[1].iptables, "-L", "ufw-user-%s" % (c), "-n"])[0] == 1: x = "inactive" if x == "active": dbot.commands.register(name="/stop", func=status_stop) replies.add( f"š STATUS\nš¹ firewall: 'active'\n\nšŗ /stop\nStopps firewall and disables startup on boot." ) else: dbot.commands.register(name="/start", func=status_start) replies.add( f"š STATUS\nš¹ firewall: 'inactive'\n\nšŗ /start\nStarts firewall and enables startup on boot." )
def _need_reload(self, v6): '''Check if all chains exist''' if self.dryrun: return False prefix = "ufw" exe = self.iptables if v6: prefix = "ufw6" exe = self.ip6tables for chain in [ 'input', 'output', 'forward', 'limit', 'limit-accept' ]: if v6 and (chain == "limit" or chain == "limit-accept"): continue (rc, out) = cmd([exe, '-n', '-L', prefix + "-user-" + chain]) if rc != 0: debug("_need_reload: forcing reload") return True return False
def _need_reload(self, v6): '''Check if all chains exist''' if self.dryrun: return False prefix = "ufw" exe = self.iptables if v6: prefix = "ufw6" exe = self.ip6tables for chain in ['input', 'output', 'forward', 'limit', 'limit-accept']: if v6 and (chain == "limit" or chain == "limit-accept"): continue (rc, out) = cmd([exe, '-n', '-L', prefix + "-user-" + chain]) if rc != 0: debug("_need_reload: forcing reload") return True return False
def _need_reload(self, v6): """Check if all chains exist""" if self.dryrun: return False prefix = "ufw" exe = self.iptables if v6: prefix = "ufw6" exe = self.ip6tables for chain in ["input", "output", "forward", "limit", "limit-accept"]: if v6 and (chain == "limit" or chain == "limit-accept"): continue (rc, out) = cmd([exe, "-n", "-L", prefix + "-user-" + chain]) if rc != 0: debug("_need_reload: forcing reload") return True return False
def get_running_raw(self, rules_type): '''Show current running status of firewall''' if self.dryrun: out = "> " + _("Checking raw iptables\n") out += "> " + _("Checking raw ip6tables\n") return out args = ['-n', '-v', '-x', '-L'] items = [] items6 = [] if rules_type == "raw": args.append('-t') items = ['filter', 'nat', 'mangle', 'raw'] items6 = ['filter', 'mangle', 'raw'] elif rules_type == "builtins": for c in ['INPUT', 'FORWARD', 'OUTPUT']: items.append('filter:%s' % c) items6.append('filter:%s' % c) for c in ['PREROUTING', 'INPUT', 'FORWARD', 'OUTPUT', \ 'POSTROUTING']: items.append('mangle:%s' % c) items6.append('mangle:%s' % c) for c in ['PREROUTING', 'OUTPUT']: items.append('raw:%s' % c) items6.append('raw:%s' % c) for c in ['PREROUTING', 'POSTROUTING', 'OUTPUT']: items.append('nat:%s' % c) elif rules_type == "before": for b in ['input', 'forward', 'output']: items.append('ufw-before-%s' % b) items6.append('ufw6-before-%s' % b) elif rules_type == "user": for b in ['input', 'forward', 'output']: items.append('ufw-user-%s' % b) items6.append('ufw6-user-%s' % b) items.append('ufw-user-limit-accept') items.append('ufw-user-limit') elif rules_type == "after": for b in ['input', 'forward', 'output']: items.append('ufw-after-%s' % b) items6.append('ufw6-after-%s' % b) elif rules_type == "logging": for b in ['input', 'forward', 'output']: items.append('ufw-before-logging-%s' % b) items6.append('ufw6-before-logging-%s' % b) items.append('ufw-user-logging-%s' % b) items6.append('ufw6-user-logging-%s' % b) items.append('ufw-after-logging-%s' % b) items6.append('ufw6-after-logging-%s' % b) items.append('ufw-logging-allow') items.append('ufw-logging-deny') items6.append('ufw6-logging-allow') items6.append('ufw6-logging-deny') out = "IPV4 (%s):\n" % (rules_type) for i in items: if ':' in i: (t, c) = i.split(':') out += "(%s) " % (t) (rc, tmp) = cmd([self.iptables] + args + [c, '-t', t]) else: (rc, tmp) = cmd([self.iptables] + args + [i]) out += tmp if rules_type != "raw": out += "\n" if rc != 0: raise UFWError(out) if rules_type == "raw" or self.use_ipv6(): out += "\n\nIPV6:\n" for i in items6: if ':' in i: (t, c) = i.split(':') out += "(%s) " % (t) (rc, tmp) = cmd([self.iptables] + args + [c, '-t', t]) else: (rc, tmp) = cmd([self.ip6tables] + args + [i]) out += tmp if rules_type != "raw": out += "\n" if rc != 0: raise UFWError(out) return out
def set_rule(self, rule, allow_reload=True): """Updates firewall with rule by: * appending the rule to the chain if new rule and firewall enabled * deleting the rule from the chain if found and firewall enabled * inserting the rule if possible and firewall enabled * updating user rules file * reloading the user rules file if rule is modified """ rstr = "" if rule.v6: if not self.use_ipv6(): err_msg = _("Adding IPv6 rule failed: IPv6 not enabled") raise UFWError(err_msg) if rule.action == "limit": # Netfilter doesn't have ip6t_recent yet, so skip return _("Skipping unsupported IPv6 '%s' rule") % (rule.action) if rule.multi and rule.protocol != "udp" and rule.protocol != "tcp": err_msg = _("Must specify 'tcp' or 'udp' with multiple ports") raise UFWError(err_msg) newrules = [] found = False modified = False delete = False rules = self.rules position = rule.position if rule.v6: if self.iptables_version < "1.4" and (rule.dapp != "" or rule.sapp != ""): return _("Skipping IPv6 application rule. Need at least iptables 1.4") rules = self.rules6 # bail if we have a bad position if position < 0 or position > len(rules): err_msg = _("Invalid position '%d'") % (position) raise UFWError(err_msg) if position > 0 and rule.remove: err_msg = _("Cannot specify insert and delete") raise UFWError(err_msg) if position > len(rules): err_msg = _("Cannot insert rule at position '%d'") % position raise UFWError(err_msg) # First construct the new rules list try: rule.normalize() except Exception: raise count = 1 inserted = False matches = 0 last = ("", "", "", "") for r in rules: try: r.normalize() except Exception: raise current = (r.dst, r.src, r.dapp, r.sapp) if count == position: # insert the rule if: # 1. the last rule was not an application rule # 2. the current rule is not an application rule # 3. the last application rule is different than the current # while the new rule is different than the current one if ( (last[2] == "" and last[3] == "" and count > 1) or (current[2] == "" and current[3] == "") or last != current ): inserted = True newrules.append(rule.dup_rule()) last = ("", "", "", "") else: position += 1 last = current count += 1 ret = UFWRule.match(r, rule) if ret < 1: matches += 1 if ret == 0 and not found and not inserted: # If find the rule, add it if it's not to be removed, otherwise # skip it. found = True if not rule.remove: newrules.append(rule.dup_rule()) elif ret < 0 and not rule.remove and not inserted: # If only the action is different, replace the rule if it's not # to be removed. found = True modified = True newrules.append(rule.dup_rule()) else: newrules.append(r) if inserted: if matches > 0: rstr = _("Skipping inserting existing rule") if rule.v6: rstr += " (v6)" return rstr else: # Add rule to the end if it was not already added. if not found and not rule.remove: newrules.append(rule.dup_rule()) # Don't process non-existing or unchanged pre-exisiting rules if not found and rule.remove and not self.dryrun: rstr = _("Could not delete non-existent rule") if rule.v6: rstr += " (v6)" return rstr elif found and not rule.remove and not modified: rstr = _("Skipping adding existing rule") if rule.v6: rstr += " (v6)" return rstr if rule.v6: self.rules6 = newrules else: self.rules = newrules # Update the user rules file try: self._write_rules(rule.v6) except UFWError: raise except Exception: err_msg = _("Couldn't update rules file") UFWError(err_msg) # We wrote out the rules, so set reasonable string. We will change # this below when operating on the live firewall. rstr = _("Rules updated") if rule.v6: rstr = _("Rules updated (v6)") # Operate on the chains if self._is_enabled() and not self.dryrun: flag = "" if modified or self._need_reload(rule.v6) or inserted: rstr = "" if inserted: rstr += _("Rule inserted") else: rstr += _("Rule updated") if rule.v6: rstr += " (v6)" if allow_reload: # Reload the chain try: self._reload_user_rules() except Exception: raise else: rstr += _(" (skipped reloading firewall)") elif found and rule.remove: flag = "-D" rstr = _("Rule deleted") elif not found and not modified and not rule.remove: flag = "-A" rstr = _("Rule added") if flag != "": exe = self.iptables chain_prefix = "ufw" if rule.v6: exe = self.ip6tables chain_prefix = "ufw6" rstr += " (v6)" chain_suffix = "input" if rule.direction == "out": chain_suffix = "output" chain = "%s-user-%s" % (chain_prefix, chain_suffix) # Is the firewall running? err_msg = _("Could not update running firewall") (rc, out) = cmd([exe, "-L", chain, "-n"]) if rc != 0: raise UFWError(err_msg) rule_str = "%s %s %s" % (flag, chain, rule.format_rule()) pat_log = re.compile(r"(-A +)(ufw6?-user-[a-z\-]+)(.*)") for s in self._get_lists_from_formatted(rule_str, chain_prefix, chain_suffix): (rc, out) = cmd([exe] + s) if rc != 0: msg(out, sys.stderr) UFWError(err_msg) # delete any lingering RETURN rules (needed for upgrades) if flag == "-A" and pat_log.search(" ".join(s)): c = pat_log.sub(r"\2", " ".join(s)) (rc, out) = cmd([exe, "-D", c, "-j", "RETURN"]) if rc != 0: debug("FAILOK: -D %s -j RETURN" % (c)) return rstr
def get_status(self, verbose=False, show_count=False): """Show ufw managed rules""" out = "" out6 = "" if self.dryrun: out = "> " + _("Checking iptables\n") if self.use_ipv6(): out += "> " + _("Checking ip6tables\n") return out err_msg = _("problem running") for direction in ["input", "output"]: # Is the firewall loaded at all? (rc, out) = cmd([self.iptables, "-L", "ufw-user-%s" % (direction), "-n"]) if rc == 1: return _("Status: inactive") elif rc != 0: raise UFWError(err_msg + " iptables: %s\n" % (out)) if self.use_ipv6(): (rc, out6) = cmd([self.ip6tables, "-L", "ufw6-user-%s" % (direction), "-n"]) if rc != 0: raise UFWError(err_msg + " ip6tables") s = "" str_out = "" rules = self.rules + self.rules6 count = 1 app_rules = {} for r in rules: tmp_str = "" location = {} tupl = "" show_proto = True if not verbose and (r.dapp != "" or r.sapp != ""): show_proto = False tupl = r.get_app_tuple() if app_rules.has_key(tupl): debug("Skipping found tuple '%s'" % (tupl)) continue else: app_rules[tupl] = True for loc in ["dst", "src"]: location[loc] = "" port = "" tmp = "" if loc == "dst": tmp = r.dst if not verbose and r.dapp != "": port = r.dapp if r.v6 and tmp == "::/0": port += " (v6)" else: port = r.dport else: tmp = r.src if not verbose and r.sapp != "": port = r.sapp if r.v6 and tmp == "::/0": port += " (v6)" else: port = r.sport if tmp != "0.0.0.0/0" and tmp != "::/0": location[loc] = tmp if port != "any": if location[loc] == "": location[loc] = port else: location[loc] += " " + port if show_proto and r.protocol != "any": location[loc] += "/" + r.protocol if verbose: if loc == "dst" and r.dapp != "": location[loc] += " (%s" % (r.dapp) if r.v6 and tmp == "::/0": location[loc] += " (v6)" location[loc] += ")" if loc == "src" and r.sapp != "": location[loc] += " (%s" % (r.sapp) if r.v6 and tmp == "::/0": location[loc] += " (v6)" location[loc] += ")" if port == "any": if tmp == "0.0.0.0/0" or tmp == "::/0": location[loc] = "Anywhere" # Show the protocol if Anywhere to Anwhere, have # protocol and source and dest ports are any if show_proto and r.protocol != "any" and r.dst == r.src and r.dport == r.sport: location[loc] += "/" + r.protocol if tmp == "::/0": location[loc] += " (v6)" else: # Show the protocol if have protocol, and source # and dest ports are any if show_proto and r.protocol != "any" and r.dport == r.sport: location[loc] += "/" + r.protocol if loc == "dst" and r.interface_in != "": location[loc] += " on %s" % (r.interface_in) if loc == "src" and r.interface_out != "": location[loc] += " on %s" % (r.interface_out) attribs = [] attrib_str = "" if r.logtype or r.direction.lower() == "out": if r.logtype: attribs.append(r.logtype.lower()) if show_count and r.direction == "out": attribs.append(r.direction) if len(attribs) > 0: attrib_str = " (%s)" % (", ".join(attribs)) # now construct the rule output string if show_count: tmp_str += "[%2d] " % (count) dir_str = r.direction.upper() if r.direction == "in" and not verbose and not show_count: dir_str = "" tmp_str += "%-26s %-12s%s%s\n" % ( location["dst"], " ".join([r.action.upper(), dir_str]), location["src"], attrib_str, ) # Show the list in the order given if a numbered list, otherwise # split incoming and outgoing rules if show_count: s += tmp_str else: if r.direction == "out": str_out += tmp_str else: s += tmp_str count += 1 if s != "" or str_out != "": full_str = "\n\n" if show_count: full_str += " " str_to = _("To") str_from = _("From") str_action = _("Action") rules_header = "%-26s %-12s%s\n" % ( str_to.decode("utf-8", "ignore"), str_action.decode("utf-8", "ignore"), str_from.decode("utf-8", "ignore"), ) if show_count: rules_header += " " rules_header += "%-26s %-12s%s\n" % ( "-" * len(str_to.decode("utf-8", "ignore")), "-" * len(str_action.decode("utf-8", "ignore")), "-" * len(str_from.decode("utf-8", "ignore")), ) full_str += rules_header.encode("utf-8", "ignore") if s != "": full_str += s if s != "" and str_out != "": full_str += _("\n") if str_out != "": full_str += str_out s = full_str if verbose: (level, logging_str) = self.get_loglevel() policy_str = _("Default: %(in)s (incoming), %(out)s (outgoing)") % ( {"in": self.get_default_policy(), "out": self.get_default_policy("output")} ) app_policy_str = self.get_default_application_policy() return _("Status: active\n%(log)s\n%(pol)s\n%(app)s%(status)s") % ( {"log": logging_str, "pol": policy_str, "app": app_policy_str, "status": s} ) else: return _("Status: active%s") % (s)
def get_running_raw(self, set): """Show current running status of firewall""" if self.dryrun: out = "> " + _("Checking raw iptables\n") out += "> " + _("Checking raw ip6tables\n") return out err_msg = _("problem running") args = ["-n", "-v", "-x", "-L"] items = [] items6 = [] if set == "raw": args.append("-t") items = ["filter", "nat", "mangle", "raw"] items6 = ["filter", "mangle", "raw"] elif set == "builtins": for c in ["INPUT", "FORWARD", "OUTPUT"]: items.append("filter:%s" % c) items6.append("filter:%s" % c) for c in ["PREROUTING", "INPUT", "FORWARD", "OUTPUT", "POSTROUTING"]: items.append("mangle:%s" % c) items6.append("mangle:%s" % c) for c in ["PREROUTING", "OUTPUT"]: items.append("raw:%s" % c) items6.append("raw:%s" % c) for c in ["PREROUTING", "POSTROUTING", "OUTPUT"]: items.append("nat:%s" % c) elif set == "before": for b in ["input", "forward", "output"]: items.append("ufw-before-%s" % b) items6.append("ufw6-before-%s" % b) elif set == "user": for b in ["input", "forward", "output"]: items.append("ufw-user-%s" % b) items6.append("ufw6-user-%s" % b) items.append("ufw-user-limit-accept") items.append("ufw-user-limit") elif set == "after": for b in ["input", "forward", "output"]: items.append("ufw-after-%s" % b) items6.append("ufw6-after-%s" % b) elif set == "logging": for b in ["input", "forward", "output"]: items.append("ufw-before-logging-%s" % b) items6.append("ufw6-before-logging-%s" % b) items.append("ufw-user-logging-%s" % b) items6.append("ufw6-user-logging-%s" % b) items.append("ufw-after-logging-%s" % b) items6.append("ufw6-after-logging-%s" % b) items.append("ufw-logging-allow") items.append("ufw-logging-deny") items6.append("ufw6-logging-allow") items6.append("ufw6-logging-deny") out = "IPV4 (%s):\n" % (set) for i in items: if ":" in i: (t, c) = i.split(":") out += "(%s) " % (t) (rc, tmp) = cmd([self.iptables] + args + [c, "-t", t]) else: (rc, tmp) = cmd([self.iptables] + args + [i]) out += tmp if set != "raw": out += "\n" if rc != 0: raise UFWError(out) if set == "raw" or self.use_ipv6(): out += "\n\nIPV6:\n" for i in items6: if ":" in i: (t, c) = i.split(":") out += "(%s) " % (t) (rc, tmp) = cmd([self.iptables] + args + [c, "-t", t]) else: (rc, tmp) = cmd([self.ip6tables] + args + [i]) out += tmp if set != "raw": out += "\n" if rc != 0: raise UFWError(out) return out
def get_status(self, verbose=False, show_count=False): '''Show ufw managed rules''' out = "" if self.dryrun: out = "> " + _("Checking iptables\n") if self.use_ipv6(): out += "> " + _("Checking ip6tables\n") return out err_msg = _("problem running") for direction in ["input", "output"]: # Is the firewall loaded at all? (rc, out) = cmd([self.iptables, '-L', \ 'ufw-user-%s' % (direction), '-n']) if rc == 1: return _("Status: inactive") elif rc != 0: raise UFWError(err_msg + " iptables: %s\n" % (out)) if self.use_ipv6(): (rc, out6) = cmd([self.ip6tables, '-L', \ 'ufw6-user-%s' % (direction), '-n']) if rc != 0: raise UFWError(err_msg + " ip6tables") s = "" str_out = "" rules = self.rules + self.rules6 count = 1 app_rules = {} for r in rules: tmp_str = "" location = {} tupl = "" show_proto = True if not verbose and (r.dapp != "" or r.sapp != ""): show_proto = False tupl = r.get_app_tuple() if app_rules.has_key(tupl): debug("Skipping found tuple '%s'" % (tupl)) continue else: app_rules[tupl] = True for loc in ['dst', 'src']: location[loc] = "" port = "" tmp = "" if loc == "dst": tmp = r.dst if not verbose and r.dapp != "": port = r.dapp if r.v6 and tmp == "::/0": port += " (v6)" else: port = r.dport else: tmp = r.src if not verbose and r.sapp != "": port = r.sapp if r.v6 and tmp == "::/0": port += " (v6)" else: port = r.sport if tmp != "0.0.0.0/0" and tmp != "::/0": location[loc] = tmp if port != "any": if location[loc] == "": location[loc] = port else: location[loc] += " " + port if show_proto and r.protocol != "any": location[loc] += "/" + r.protocol if verbose: if loc == "dst" and r.dapp != "": location[loc] += " (%s" % (r.dapp) if r.v6 and tmp == "::/0": location[loc] += " (v6)" location[loc] += ")" if loc == "src" and r.sapp != "": location[loc] += " (%s" % (r.sapp) if r.v6 and tmp == "::/0": location[loc] += " (v6)" location[loc] += ")" if port == "any": if tmp == "0.0.0.0/0" or tmp == "::/0": location[loc] = "Anywhere" # Show the protocol if Anywhere to Anwhere, have # protocol and source and dest ports are any if show_proto and r.protocol != "any" and \ r.dst == r.src and r.dport == r.sport: location[loc] += "/" + r.protocol if tmp == "::/0": location[loc] += " (v6)" else: # Show the protocol if have protocol, and source # and dest ports are any if show_proto and r.protocol != "any" and \ r.dport == r.sport: location[loc] += "/" + r.protocol if loc == 'dst' and r.interface_in != "": location[loc] += " on %s" % (r.interface_in) if loc == 'src' and r.interface_out != "": location[loc] += " on %s" % (r.interface_out) attribs = [] attrib_str = "" if r.logtype or r.direction.lower() == "out": if r.logtype: attribs.append(r.logtype.lower()) if show_count and r.direction == "out": attribs.append(r.direction) if len(attribs) > 0: attrib_str = " (%s)" % (', '.join(attribs)) # now construct the rule output string if show_count: tmp_str += "[%2d] " % (count) dir_str = r.direction.upper() if r.direction == "in" and not verbose and not show_count: dir_str = "" tmp_str += "%-26s %-12s%s%s\n" % (location['dst'], \ " ".join([r.action.upper(), \ dir_str]), \ location['src'], attrib_str) # Show the list in the order given if a numbered list, otherwise # split incoming and outgoing rules if show_count: s += tmp_str else: if r.direction == "out": str_out += tmp_str else: s += tmp_str count += 1 if s != "" or str_out != "": full_str = "\n\n" if show_count: full_str += " " str_to = _("To") str_from = _("From") str_action = _("Action") rules_header = "%-26s %-12s%s\n" % \ (str_to.decode("utf-8", 'ignore'), \ str_action.decode("utf-8", 'ignore'), \ str_from.decode("utf-8", 'ignore')) if show_count: rules_header += " " rules_header += "%-26s %-12s%s\n" % \ ("-" * len(str_to.decode("utf-8", 'ignore')), \ "-" * len(str_action.decode("utf-8", 'ignore')), \ "-" * len(str_from.decode("utf-8", 'ignore'))) full_str += rules_header.encode('utf-8', 'ignore') if s != "": full_str += s if s != "" and str_out != "": full_str += _("\n") if str_out != "": full_str += str_out s = full_str if verbose: (level, logging_str) = self.get_loglevel() policy_str = _("Default: %(in)s (incoming), %(out)s (outgoing)") \ % ({'in': self._get_default_policy(), \ 'out': self._get_default_policy("output")}) app_policy_str = self.get_default_application_policy() return _("Status: active\n%(log)s\n%(pol)s\n%(app)s%(status)s") % \ ({'log': logging_str, 'pol': policy_str, \ 'app': app_policy_str, 'status': s}) else: return _("Status: active%s") % (s)
def set_rule(self, rule, allow_reload=True): '''Updates firewall with rule by: * appending the rule to the chain if new rule and firewall enabled * deleting the rule from the chain if found and firewall enabled * inserting the rule if possible and firewall enabled * updating user rules file * reloading the user rules file if rule is modified ''' rstr = "" if rule.v6: if not self.use_ipv6(): err_msg = _("Adding IPv6 rule failed: IPv6 not enabled") raise UFWError(err_msg) if rule.action == 'limit': # Netfilter doesn't have ip6t_recent yet, so skip return _("Skipping unsupported IPv6 '%s' rule") % (rule.action) if rule.multi and rule.protocol != "udp" and rule.protocol != "tcp": err_msg = _("Must specify 'tcp' or 'udp' with multiple ports") raise UFWError(err_msg) newrules = [] found = False modified = False rules = self.rules position = rule.position if rule.v6: if self.iptables_version < "1.4" and (rule.dapp != "" or \ rule.sapp != ""): return _( "Skipping IPv6 application rule. Need at least iptables 1.4" ) rules = self.rules6 # bail if we have a bad position if position < 0 or position > len(rules): err_msg = _("Invalid position '%d'") % (position) raise UFWError(err_msg) if position > 0 and rule.remove: err_msg = _("Cannot specify insert and delete") raise UFWError(err_msg) if position > len(rules): err_msg = _("Cannot insert rule at position '%d'") % position raise UFWError(err_msg) # First construct the new rules list try: rule.normalize() except Exception: raise count = 1 inserted = False matches = 0 last = ('', '', '', '') for r in rules: try: r.normalize() except Exception: raise current = (r.dst, r.src, r.dapp, r.sapp) if count == position: # insert the rule if: # 1. the last rule was not an application rule # 2. the current rule is not an application rule # 3. the last application rule is different than the current # while the new rule is different than the current one if (last[2] == '' and last[3] == '' and count > 1) or \ (current[2] == '' and current[3] == '') or \ last != current: inserted = True newrules.append(rule.dup_rule()) last = ('', '', '', '') else: position += 1 last = current count += 1 ret = UFWRule.match(r, rule) if ret < 1: matches += 1 if ret == 0 and not found and not inserted: # If find the rule, add it if it's not to be removed, otherwise # skip it. found = True if not rule.remove: newrules.append(rule.dup_rule()) elif ret < 0 and not rule.remove and not inserted: # If only the action is different, replace the rule if it's not # to be removed. found = True modified = True newrules.append(rule.dup_rule()) else: newrules.append(r) if inserted: if matches > 0: rstr = _("Skipping inserting existing rule") if rule.v6: rstr += " (v6)" return rstr else: # Add rule to the end if it was not already added. if not found and not rule.remove: newrules.append(rule.dup_rule()) # Don't process non-existing or unchanged pre-exisiting rules if not found and rule.remove and not self.dryrun: rstr = _("Could not delete non-existent rule") if rule.v6: rstr += " (v6)" return rstr elif found and not rule.remove and not modified: rstr = _("Skipping adding existing rule") if rule.v6: rstr += " (v6)" return rstr if rule.v6: self.rules6 = newrules else: self.rules = newrules # Update the user rules file try: self._write_rules(rule.v6) except UFWError: raise except Exception: err_msg = _("Couldn't update rules file") UFWError(err_msg) # We wrote out the rules, so set reasonable string. We will change # this below when operating on the live firewall. rstr = _("Rules updated") if rule.v6: rstr = _("Rules updated (v6)") # Operate on the chains if self.is_enabled() and not self.dryrun: flag = "" if modified or self._need_reload(rule.v6) or inserted: rstr = "" if inserted: rstr += _("Rule inserted") else: rstr += _("Rule updated") if rule.v6: rstr += " (v6)" if allow_reload: # Reload the chain try: self._reload_user_rules() except Exception: raise else: rstr += _(" (skipped reloading firewall)") elif found and rule.remove: flag = '-D' rstr = _("Rule deleted") elif not found and not modified and not rule.remove: flag = '-A' rstr = _("Rule added") if flag != "": exe = self.iptables chain_prefix = "ufw" if rule.v6: exe = self.ip6tables chain_prefix = "ufw6" rstr += " (v6)" chain_suffix = "input" if rule.direction == "out": chain_suffix = "output" chain = "%s-user-%s" % (chain_prefix, chain_suffix) # Is the firewall running? err_msg = _("Could not update running firewall") (rc, out) = cmd([exe, '-L', chain, '-n']) if rc != 0: raise UFWError(err_msg) rule_str = "%s %s %s" % (flag, chain, rule.format_rule()) pat_log = re.compile(r'(-A +)(ufw6?-user-[a-z\-]+)(.*)') for s in self._get_lists_from_formatted(rule_str, \ chain_prefix, \ chain_suffix): (rc, out) = cmd([exe] + s) if rc != 0: msg(out, sys.stderr) UFWError(err_msg) # delete any lingering RETURN rules (needed for upgrades) if flag == "-A" and pat_log.search(" ".join(s)): c = pat_log.sub(r'\2', " ".join(s)) (rc, out) = cmd([exe, '-D', c, '-j', 'RETURN']) if rc != 0: debug("FAILOK: -D %s -j RETURN" % (c)) return rstr