~bilalakhtar/ubuntu/natty/ufw/fix-682811

« back to all changes in this revision

Viewing changes to src/backend_iptables.py

  • Committer: Bazaar Package Importer
  • Author(s): Jamie Strandboge
  • Date: 2009-11-11 14:26:56 UTC
  • mfrom: (0.2.3 upstream)
  • mto: (0.1.10 sid) (30.1.10 upstream)
  • mto: This revision was merged to the branch mainline in revision 48.
  • Revision ID: james.westby@ubuntu.com-20091111142656-elu1gdohgz1muifz
Tags: upstream-0.29.1
ImportĀ upstreamĀ versionĀ 0.29.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
106
106
            old_log_str = ''
107
107
            new_log_str = ''
108
108
            if policy == "allow":
109
 
                self.set_default(self.files['defaults'], \
 
109
                try:
 
110
                    self.set_default(self.files['defaults'], \
110
111
                                            "DEFAULT_%s_POLICY" % (chain), \
111
112
                                            "\"ACCEPT\"")
 
113
                except Exception:
 
114
                    raise
112
115
                old_log_str = 'UFW BLOCK'
113
116
                new_log_str = 'UFW ALLOW'
114
117
            elif policy == "reject":
115
 
                self.set_default(self.files['defaults'], \
 
118
                try:
 
119
                    self.set_default(self.files['defaults'], \
116
120
                                            "DEFAULT_%s_POLICY" % (chain), \
117
121
                                            "\"REJECT\"")
 
122
                except Exception:
 
123
                    raise
118
124
                old_log_str = 'UFW ALLOW'
119
125
                new_log_str = 'UFW BLOCK'
120
126
            else:
121
 
                self.set_default(self.files['defaults'], \
 
127
                try:
 
128
                    self.set_default(self.files['defaults'], \
122
129
                                            "DEFAULT_%s_POLICY" % (chain), \
123
130
                                            "\"DROP\"")
 
131
                except Exception:
 
132
                    raise
124
133
                old_log_str = 'UFW ALLOW'
125
134
                new_log_str = 'UFW BLOCK'
126
135
 
135
144
 
136
145
                for line in fns['orig']:
137
146
                    if pat.search(line):
138
 
                        os.write(fd, pat.sub(new_log_str, line))
 
147
                        ufw.util.write_to_file(fd, pat.sub(new_log_str, line))
139
148
                    else:
140
 
                        os.write(fd, line)
 
149
                        ufw.util.write_to_file(fd, line)
141
150
 
142
 
                ufw.util.close_files(fns)
 
151
                try:
 
152
                    ufw.util.close_files(fns)
 
153
                except Exception:
 
154
                    raise
143
155
 
144
156
        rstr = _("Default %(direction)s policy changed to '%(policy)s'\n") % \
145
157
                 ({'direction': direction, 'policy': policy})
596
608
        if v6:
597
609
            rules_file = self.files['rules6']
598
610
 
 
611
        # Perform this here so we can present a nice error to the user rather
 
612
        # than a traceback
 
613
        if not os.access(rules_file, os.W_OK):
 
614
            err_msg = _("'%s' is not writable" % (rules_file))
 
615
            raise UFWError(err_msg)
 
616
 
599
617
        try:
600
618
            fns = ufw.util.open_files(rules_file)
601
619
        except Exception:
613
631
            fd = fns['tmp']
614
632
 
615
633
        # Write header
616
 
        os.write(fd, "*filter\n")
617
 
        os.write(fd, ":" + chain_prefix + "-user-input - [0:0]\n")
618
 
        os.write(fd, ":" + chain_prefix + "-user-output - [0:0]\n")
619
 
        os.write(fd, ":" + chain_prefix + "-user-forward - [0:0]\n")
 
634
        ufw.util.write_to_file(fd, "*filter\n")
 
635
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-user-input - [0:0]\n")
 
636
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-user-output - [0:0]\n")
 
637
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-user-forward - [0:0]\n")
 
638
 
 
639
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-before-logging-input - [0:0]\n")
 
640
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-before-logging-output - [0:0]\n")
 
641
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-before-logging-forward - [0:0]\n")
 
642
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-user-logging-input - [0:0]\n")
 
643
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-user-logging-output - [0:0]\n")
 
644
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-user-logging-forward - [0:0]\n")
 
645
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-after-logging-input - [0:0]\n")
 
646
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-after-logging-output - [0:0]\n")
 
647
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-after-logging-forward - [0:0]\n")
 
648
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-logging-deny - [0:0]\n")
 
649
        ufw.util.write_to_file(fd, ":" + chain_prefix + "-logging-allow - [0:0]\n")
620
650
 
621
651
        if chain_prefix == "ufw":
622
652
            # Rate limiting only supported with IPv4
623
 
            os.write(fd, ":" + chain_prefix + "-user-limit - [0:0]\n")
624
 
            os.write(fd, ":" + chain_prefix + "-user-limit-accept - [0:0]\n")
 
653
            ufw.util.write_to_file(fd, ":" + chain_prefix + "-user-limit - [0:0]\n")
 
654
            ufw.util.write_to_file(fd, ":" + chain_prefix + "-user-limit-accept - [0:0]\n")
625
655
 
626
 
        os.write(fd, "### RULES ###\n")
 
656
        ufw.util.write_to_file(fd, "### RULES ###\n")
627
657
 
628
658
        # Write rules
629
659
        for r in rules:
639
669
                    tstr += "_%s" % (r.interface_in)
640
670
                if r.interface_out != "":
641
671
                    tstr += "_%s" % (r.interface_out)
642
 
                os.write(fd, tstr + "\n")
 
672
                ufw.util.write_to_file(fd, tstr + "\n")
643
673
            else:
644
674
                pat_space = re.compile(' ')
645
675
                dapp = "-"
656
686
                    tstr += "_%s" % (r.interface_in)
657
687
                if r.interface_out != "":
658
688
                    tstr += "_%s" % (r.interface_out)
659
 
                os.write(fd, tstr + "\n")
 
689
                ufw.util.write_to_file(fd, tstr + "\n")
660
690
 
661
691
            chain_suffix = "input"
662
692
            if r.direction == "out":
666
696
 
667
697
            for s in self._get_rules_from_formatted(rule_str, chain_prefix, \
668
698
                                                    chain_suffix):
669
 
                os.write(fd, s)
 
699
                ufw.util.write_to_file(fd, s)
670
700
 
671
701
        # Write footer
672
 
        os.write(fd, "\n### END RULES ###\n")
 
702
        ufw.util.write_to_file(fd, "\n### END RULES ###\n")
 
703
 
 
704
        # Add logging rules, skipping any delete ('-D') rules
 
705
        ufw.util.write_to_file(fd, "\n### LOGGING ###\n")
 
706
        try:
 
707
            lrules_t = self._get_logging_rules(self.defaults['loglevel'])
 
708
        except Exception:
 
709
            raise
 
710
        for c, r, q in lrules_t:
 
711
            if len(r) > 0 and r[0] == '-D':
 
712
                continue
 
713
            if c.startswith(chain_prefix + "-"):
 
714
                ufw.util.write_to_file(fd,
 
715
                    " ".join(r).replace('[', '"[').replace('] ', '] "') + \
 
716
                    "\n")
 
717
        ufw.util.write_to_file(fd, "### END LOGGING ###\n")
673
718
 
674
719
        if chain_prefix == "ufw":
 
720
            ufw.util.write_to_file(fd, "\n### RATE LIMITING ###\n")
675
721
            # Rate limiting only supported with IPv4
676
 
            os.write(fd, "-A " + chain_prefix + "-user-limit -m limit " + \
 
722
            ufw.util.write_to_file(fd, "-A " + chain_prefix + "-user-limit -m limit " + \
677
723
                         "--limit 3/minute -j LOG --log-prefix " + \
678
724
                         "\"[UFW LIMIT BLOCK] \"\n")
679
 
            os.write(fd, "-A " + chain_prefix + "-user-limit -j REJECT\n")
680
 
            os.write(fd, "-A " + chain_prefix + "-user-limit-accept -j ACCEPT\n")
681
 
 
682
 
        os.write(fd, "COMMIT\n")
683
 
 
684
 
        if self.dryrun:
685
 
            ufw.util.close_files(fns, False)
686
 
        else:
687
 
            ufw.util.close_files(fns)
 
725
            ufw.util.write_to_file(fd, "-A " + chain_prefix + "-user-limit -j REJECT\n")
 
726
            ufw.util.write_to_file(fd, "-A " + chain_prefix + "-user-limit-accept -j ACCEPT\n")
 
727
            ufw.util.write_to_file(fd, "### END RATE LIMITING ###\n")
 
728
 
 
729
        ufw.util.write_to_file(fd, "COMMIT\n")
 
730
 
 
731
        try:
 
732
            if self.dryrun:
 
733
                ufw.util.close_files(fns, False)
 
734
            else:
 
735
                ufw.util.close_files(fns)
 
736
        except Exception:
 
737
            raise
688
738
 
689
739
    def set_rule(self, rule, allow_reload=True):
690
740
        '''Updates firewall with rule by:
816
866
        # Update the user rules file
817
867
        try:
818
868
            self._write_rules(rule.v6)
 
869
        except UFWError:
 
870
            raise
819
871
        except Exception:
820
872
            err_msg = _("Couldn't update rules file")
821
873
            UFWError(err_msg)
863
915
                if rule.direction == "out":
864
916
                    chain_suffix = "output"
865
917
                chain = "%s-user-%s" % (chain_prefix, chain_suffix)
866
 
          
867
918
 
868
919
                # Is the firewall running?
869
920
                err_msg = _("Could not update running firewall")
932
983
        if not self._is_enabled():
933
984
            return
934
985
 
935
 
        if level not in self.loglevels.keys():
936
 
            err_msg = _("Invalid log level '%s'") % (level)
937
 
            raise UFWError(err_msg)
 
986
        rules_t = []
 
987
        try:
 
988
            rules_t = self._get_logging_rules(level)
 
989
        except Exception:
 
990
            raise
 
991
 
 
992
        # Update the user rules file
 
993
        try:
 
994
            self._write_rules(v6=False)
 
995
            self._write_rules(v6=True)
 
996
        except UFWError:
 
997
            raise
 
998
        except Exception:
 
999
            err_msg = _("Couldn't update rules file for logging")
 
1000
            UFWError(err_msg)
938
1001
 
939
1002
        # make sure all the chains are here, it's redundant but helps make
940
1003
        # sure the chains are in a consistent state
955
1018
        except:
956
1019
            raise UFWError(err_msg)
957
1020
 
 
1021
        # Add logging rules to running firewall
 
1022
        for c, r, q in rules_t:
 
1023
            fail_ok = False
 
1024
            if len(r) > 0 and r[0] == '-D':
 
1025
                fail_ok = True
 
1026
            try:
 
1027
                if q == 'delete_first' and len(r) > 1:
 
1028
                    self._chain_cmd(c, ['-D'] + r[1:], fail_ok=True)
 
1029
                self._chain_cmd(c, r, fail_ok)
 
1030
            except Exception:
 
1031
                raise UFWError(err_msg)
 
1032
 
 
1033
    def _get_logging_rules(self, level):
 
1034
        '''Get rules for specified logging level'''
 
1035
        rules_t = []
 
1036
 
 
1037
        if level not in self.loglevels.keys():
 
1038
            err_msg = _("Invalid log level '%s'") % (level)
 
1039
            raise UFWError(err_msg)
 
1040
 
958
1041
        if level == "off":
959
1042
            # when off, insert a RETURN rule at the top of user rules, thus
960
1043
            # preserving the rules
961
1044
            for c in self.chains['user']:
962
 
                self._chain_cmd(c, ['-D', c, '-j', 'RETURN'], fail_ok=True)
963
 
                self._chain_cmd(c, ['-I', c, '-j', 'RETURN'])
964
 
            return
 
1045
                rules_t.append([c, ['-I', c, '-j', 'RETURN'], 'delete_first'])
 
1046
            return rules_t
965
1047
        else:
966
1048
            # when on, remove the RETURN rule at the top of user rules, thus
967
1049
            # honoring the log rules
968
1050
            for c in self.chains['user']:
969
 
                self._chain_cmd(c, ['-D', c, '-j', 'RETURN'], fail_ok=True)
 
1051
                rules_t.append([c, ['-D', c, '-j', 'RETURN'], ''])
970
1052
 
971
1053
        limit_args = ['-m', 'limit', '--limit', '3/min', '--limit-burst', '10']
972
1054
 
983
1065
                        if self.get_default_policy(t) == "reject" or \
984
1066
                           self.get_default_policy(t) == "deny":
985
1067
                            msg = "[UFW BLOCK] "
986
 
                            try:
987
 
                                self._chain_cmd(c, ['-A', c, '-j', 'LOG', \
988
 
                                                    '--log-prefix', msg] + largs)
989
 
                            except:
990
 
                                raise
 
1068
                            rules_t.append([c, ['-A', c, '-j', 'LOG', \
 
1069
                                                '--log-prefix', msg] +
 
1070
                                                largs, ''])
991
1071
                        elif self.loglevels[level] >= self.loglevels["medium"]:
992
1072
                            msg = "[UFW ALLOW] "
993
 
                            try:
994
 
                                self._chain_cmd(c, ['-A', c, '-j', 'LOG', \
995
 
                                                    '--log-prefix', msg] + largs)
996
 
                            except:
997
 
                                raise
 
1073
                            rules_t.append([c, ['-A', c, '-j', 'LOG', \
 
1074
                                                '--log-prefix', msg] + largs, ''])
998
1075
 
999
1076
            # Setup the miscellaneous logging chains
1000
1077
            largs = []
1007
1084
                    msg = "[UFW ALLOW] "
1008
1085
                elif c.endswith("deny"):
1009
1086
                    msg = "[UFW BLOCK] "
1010
 
                    if self.loglevels[level] >= self.loglevels["medium"]:
 
1087
                    if self.loglevels[level] < self.loglevels["medium"]:
1011
1088
                        # only log INVALID in medium and higher
1012
 
                        try:
1013
 
                            self._chain_cmd(c, ['-I', c, '-m', 'state', \
1014
 
                                                '--state', 'INVALID', \
1015
 
                                                '-j', 'RETURN'] + largs)
1016
 
                        except:
1017
 
                            raise
1018
 
                try:
1019
 
                    self._chain_cmd(c, ['-A', c, '-j', 'LOG', \
1020
 
                                        '--log-prefix', msg] + largs)
1021
 
                except:
1022
 
                    raise
 
1089
                        rules_t.append([c, ['-I', c, '-m', 'state', \
 
1090
                                            '--state', 'INVALID', \
 
1091
                                            '-j', 'RETURN'] + largs, ''])
 
1092
                rules_t.append([c, ['-A', c, '-j', 'LOG', \
 
1093
                                    '--log-prefix', msg] + largs, ''])
1023
1094
 
1024
1095
        # Setup the audit logging chains
1025
1096
        if self.loglevels[level] >= self.loglevels["medium"]:
1036
1107
 
1037
1108
            msg = "[UFW AUDIT] "
1038
1109
            for c in self.chains['before']:
1039
 
                try:
1040
 
                    self._chain_cmd(c, ['-I', c, '-j', 'LOG', \
1041
 
                                        '--log-prefix', msg] + largs)
1042
 
                except:
1043
 
                    raise UFWError(err_msg)
1044
 
 
1045
 
 
 
1110
                rules_t.append([c, ['-I', c, '-j', 'LOG', \
 
1111
                                    '--log-prefix', msg] + largs, ''])
 
1112
 
 
1113
        return rules_t