Merge lp:~bertrand-goareguer/ufw/ufw-qos into lp:~jdstrand/ufw/trunk
- ufw-qos
- Merge into trunk
Proposed by
Jonathan Davies
Status: | Rejected | ||||
---|---|---|---|---|---|
Rejected by: | Jamie Strandboge | ||||
Proposed branch: | lp:~bertrand-goareguer/ufw/ufw-qos | ||||
Merge into: | lp:~jdstrand/ufw/trunk | ||||
Diff against target: |
634 lines (+347/-3) 6 files modified
setup.py (+1/-1) src/backend_iptables.py (+81/-0) src/common.py (+40/-0) src/frontend.py (+52/-2) src/tc_functions.py (+150/-0) src/ufw-init-functions (+23/-0) |
||||
To merge this branch: | bzr merge lp:~bertrand-goareguer/ufw/ufw-qos | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jamie Strandboge | Pending | ||
Review via email: mp+15907@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Unmerged revisions
- 371. By Bertrand Goareguer <beber@beber-laptop>
-
added creation of the TC filters when firewall is enabled
- 370. By Bertrand Goareguer <beber@beber-laptop>
-
implemented the deletion of the tc filters (when deleting the rule)
- 369. By Bertrand Goareguer <beber@beber-laptop>
-
added creation of tc filters (deletion is not implemente yet)
- 368. By Bertrand Goareguer <beber@beber-laptop>
-
added creation/deletion of tc qdiscs on firewall startup/shutdown
- 367. By Bertrand Goareguer <beber@beber-laptop>
-
- rules now have a rate clause
- the rate is expressed in kbps (kilo bits per second)
- the rate can only be specified with the "allow" action
- if no rate is specified or if action != "allow", the rate is set to "unlimited"
- writing the 2 same rules with different rates updates the rule (similar to writing same rules with different actions)
- both short and full rule formats are supported
- rate must be the last parameter for short rule format
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'setup.py' | |||
2 | --- setup.py 2009-11-30 16:03:43 +0000 | |||
3 | +++ setup.py 2009-12-09 23:28:13 +0000 | |||
4 | @@ -253,7 +253,7 @@ | |||
5 | 253 | license='GPL-3', | 253 | license='GPL-3', |
6 | 254 | cmdclass={'install': Install}, | 254 | cmdclass={'install': Install}, |
7 | 255 | package_dir={'ufw': 'staging'}, | 255 | package_dir={'ufw': 'staging'}, |
9 | 256 | py_modules=['ufw.backend', 'ufw.backend_iptables', 'ufw.common', 'ufw.frontend', 'ufw.util', 'ufw.applications'] | 256 | py_modules=['ufw.backend', 'ufw.backend_iptables', 'ufw.common', 'ufw.frontend', 'ufw.util', 'ufw.applications', 'ufw.tc_functions'] |
10 | 257 | ) | 257 | ) |
11 | 258 | 258 | ||
12 | 259 | shutil.rmtree('staging') | 259 | shutil.rmtree('staging') |
13 | 260 | 260 | ||
14 | === modified file 'src/backend_iptables.py' | |||
15 | --- src/backend_iptables.py 2009-11-11 18:05:16 +0000 | |||
16 | +++ src/backend_iptables.py 2009-12-09 23:28:13 +0000 | |||
17 | @@ -20,9 +20,11 @@ | |||
18 | 20 | import re | 20 | import re |
19 | 21 | import sys | 21 | import sys |
20 | 22 | import tempfile | 22 | import tempfile |
21 | 23 | import ufw.tc_functions | ||
22 | 23 | 24 | ||
23 | 24 | from ufw.common import UFWError, UFWRule, config_dir, state_dir, prefix_dir | 25 | from ufw.common import UFWError, UFWRule, config_dir, state_dir, prefix_dir |
24 | 25 | from ufw.util import warn, debug, msg, cmd, cmd_pipe | 26 | from ufw.util import warn, debug, msg, cmd, cmd_pipe |
25 | 27 | from ufw.tc_functions import add_filter, delete_filter | ||
26 | 26 | import ufw.backend | 28 | import ufw.backend |
27 | 27 | 29 | ||
28 | 28 | 30 | ||
29 | @@ -388,6 +390,9 @@ | |||
30 | 388 | (rc, out) = cmd([self.files['init'], 'start']) | 390 | (rc, out) = cmd([self.files['init'], 'start']) |
31 | 389 | if rc != 0: | 391 | if rc != 0: |
32 | 390 | raise UFWError(err_msg + " ufw-init") | 392 | raise UFWError(err_msg + " ufw-init") |
33 | 393 | else: | ||
34 | 394 | # if firewall has been started successfully, apply the TC rules | ||
35 | 395 | self._reload_user_filters() | ||
36 | 391 | 396 | ||
37 | 392 | if not self.defaults.has_key('loglevel') or \ | 397 | if not self.defaults.has_key('loglevel') or \ |
38 | 393 | self.defaults['loglevel'] not in self.loglevels.keys(): | 398 | self.defaults['loglevel'] not in self.loglevels.keys(): |
39 | @@ -454,7 +459,19 @@ | |||
40 | 454 | if rc != 0: | 459 | if rc != 0: |
41 | 455 | raise UFWError(err_msg + " ip6tables") | 460 | raise UFWError(err_msg + " ip6tables") |
42 | 456 | 461 | ||
43 | 462 | <<<<<<< TREE | ||
44 | 457 | def _get_rules_from_formatted(self, frule, prefix, suffix): | 463 | def _get_rules_from_formatted(self, frule, prefix, suffix): |
45 | 464 | ======= | ||
46 | 465 | def _reload_user_filters(self): | ||
47 | 466 | '''Reload TC filters''' | ||
48 | 467 | for rule in self.rules: | ||
49 | 468 | if rule.rate != "unlimited": | ||
50 | 469 | if rule.action == "allow": | ||
51 | 470 | add_filter(rule.src, rule.dst, rule.sport, rule.dport, rule.rate, rule.filter_id) | ||
52 | 471 | |||
53 | 472 | |||
54 | 473 | def _get_rules_from_formatted(self, frule, prefix): | ||
55 | 474 | >>>>>>> MERGE-SOURCE | ||
56 | 458 | '''Return list of iptables rules appropriate for sending''' | 475 | '''Return list of iptables rules appropriate for sending''' |
57 | 459 | snippets = [] | 476 | snippets = [] |
58 | 460 | 477 | ||
59 | @@ -558,7 +575,11 @@ | |||
60 | 558 | if pat_tuple.match(line): | 575 | if pat_tuple.match(line): |
61 | 559 | tuple = pat_tuple.sub('', line) | 576 | tuple = pat_tuple.sub('', line) |
62 | 560 | tmp = re.split(r'\s+', tuple.strip()) | 577 | tmp = re.split(r'\s+', tuple.strip()) |
63 | 578 | <<<<<<< TREE | ||
64 | 561 | if len(tmp) < 6 or len(tmp) > 9: | 579 | if len(tmp) < 6 or len(tmp) > 9: |
65 | 580 | ======= | ||
66 | 581 | if len(tmp) != 8 and len(tmp) != 10: | ||
67 | 582 | >>>>>>> MERGE-SOURCE | ||
68 | 562 | warn_msg = _("Skipping malformed tuple (bad length): %s") % (tuple) | 583 | warn_msg = _("Skipping malformed tuple (bad length): %s") % (tuple) |
69 | 563 | warn(warn_msg) | 584 | warn(warn_msg) |
70 | 564 | continue | 585 | continue |
71 | @@ -573,12 +594,24 @@ | |||
72 | 573 | else: | 594 | else: |
73 | 574 | type = tmp[-1] | 595 | type = tmp[-1] |
74 | 575 | try: | 596 | try: |
75 | 597 | <<<<<<< TREE | ||
76 | 576 | if len(tmp) < 8: | 598 | if len(tmp) < 8: |
77 | 599 | ======= | ||
78 | 600 | if len(tmp) == 8: | ||
79 | 601 | >>>>>>> MERGE-SOURCE | ||
80 | 577 | rule = UFWRule(tmp[0], tmp[1], tmp[2], tmp[3], | 602 | rule = UFWRule(tmp[0], tmp[1], tmp[2], tmp[3], |
81 | 603 | <<<<<<< TREE | ||
82 | 578 | tmp[4], tmp[5], type) | 604 | tmp[4], tmp[5], type) |
83 | 605 | ======= | ||
84 | 606 | tmp[4], tmp[5], tmp[6], tmp[7]) | ||
85 | 607 | >>>>>>> MERGE-SOURCE | ||
86 | 579 | else: | 608 | else: |
87 | 580 | rule = UFWRule(tmp[0], tmp[1], tmp[2], tmp[3], | 609 | rule = UFWRule(tmp[0], tmp[1], tmp[2], tmp[3], |
88 | 610 | <<<<<<< TREE | ||
89 | 581 | tmp[4], tmp[5], type) | 611 | tmp[4], tmp[5], type) |
90 | 612 | ======= | ||
91 | 613 | tmp[4], tmp[5], tmp[8], tmp[9]) | ||
92 | 614 | >>>>>>> MERGE-SOURCE | ||
93 | 582 | # Removed leading [sd]app_ and unescape spaces | 615 | # Removed leading [sd]app_ and unescape spaces |
94 | 583 | pat_space = re.compile('%20') | 616 | pat_space = re.compile('%20') |
95 | 584 | if tmp[6] != "-": | 617 | if tmp[6] != "-": |
96 | @@ -662,6 +695,7 @@ | |||
97 | 662 | action += "_" + r.logtype | 695 | action += "_" + r.logtype |
98 | 663 | 696 | ||
99 | 664 | if r.dapp == "" and r.sapp == "": | 697 | if r.dapp == "" and r.sapp == "": |
100 | 698 | <<<<<<< TREE | ||
101 | 665 | tstr = "\n### tuple ### %s %s %s %s %s %s %s" % \ | 699 | tstr = "\n### tuple ### %s %s %s %s %s %s %s" % \ |
102 | 666 | (action, r.protocol, r.dport, r.dst, r.sport, r.src, \ | 700 | (action, r.protocol, r.dport, r.dst, r.sport, r.src, \ |
103 | 667 | r.direction) | 701 | r.direction) |
104 | @@ -670,6 +704,10 @@ | |||
105 | 670 | if r.interface_out != "": | 704 | if r.interface_out != "": |
106 | 671 | tstr += "_%s" % (r.interface_out) | 705 | tstr += "_%s" % (r.interface_out) |
107 | 672 | ufw.util.write_to_file(fd, tstr + "\n") | 706 | ufw.util.write_to_file(fd, tstr + "\n") |
108 | 707 | ======= | ||
109 | 708 | os.write(fd, "\n### tuple ### %s %s %s %s %s %s %s %s\n" % \ | ||
110 | 709 | (r.action, r.protocol, r.dport, r.dst, r.sport, r.src, r.rate, r.filter_id)) | ||
111 | 710 | >>>>>>> MERGE-SOURCE | ||
112 | 673 | else: | 711 | else: |
113 | 674 | pat_space = re.compile(' ') | 712 | pat_space = re.compile(' ') |
114 | 675 | dapp = "-" | 713 | dapp = "-" |
115 | @@ -678,6 +716,7 @@ | |||
116 | 678 | sapp = "-" | 716 | sapp = "-" |
117 | 679 | if r.sapp: | 717 | if r.sapp: |
118 | 680 | sapp = pat_space.sub('%20', r.sapp) | 718 | sapp = pat_space.sub('%20', r.sapp) |
119 | 719 | <<<<<<< TREE | ||
120 | 681 | tstr = "\n### tuple ### %s %s %s %s %s %s %s %s %s" % \ | 720 | tstr = "\n### tuple ### %s %s %s %s %s %s %s %s %s" % \ |
121 | 682 | (action, r.protocol, r.dport, r.dst, r.sport, r.src, \ | 721 | (action, r.protocol, r.dport, r.dst, r.sport, r.src, \ |
122 | 683 | dapp, sapp, r.direction) | 722 | dapp, sapp, r.direction) |
123 | @@ -697,6 +736,14 @@ | |||
124 | 697 | for s in self._get_rules_from_formatted(rule_str, chain_prefix, \ | 736 | for s in self._get_rules_from_formatted(rule_str, chain_prefix, \ |
125 | 698 | chain_suffix): | 737 | chain_suffix): |
126 | 699 | ufw.util.write_to_file(fd, s) | 738 | ufw.util.write_to_file(fd, s) |
127 | 739 | ======= | ||
128 | 740 | os.write(fd, "\n### tuple ### %s %s %s %s %s %s %s %s %s %s\n" \ | ||
129 | 741 | % (r.action, r.protocol, r.dport, r.dst, r.sport, r.src, \ | ||
130 | 742 | dapp, sapp, r.rate, r.filter_id)) | ||
131 | 743 | |||
132 | 744 | for s in self._get_rules_from_formatted(rule_str, chain_prefix): | ||
133 | 745 | os.write(fd, s) | ||
134 | 746 | >>>>>>> MERGE-SOURCE | ||
135 | 700 | 747 | ||
136 | 701 | # Write footer | 748 | # Write footer |
137 | 702 | ufw.util.write_to_file(fd, "\n### END RULES ###\n") | 749 | ufw.util.write_to_file(fd, "\n### END RULES ###\n") |
138 | @@ -825,9 +872,17 @@ | |||
139 | 825 | # skip it. | 872 | # skip it. |
140 | 826 | found = True | 873 | found = True |
141 | 827 | if not rule.remove: | 874 | if not rule.remove: |
142 | 875 | <<<<<<< TREE | ||
143 | 828 | newrules.append(rule.dup_rule()) | 876 | newrules.append(rule.dup_rule()) |
144 | 829 | elif ret < 0 and not rule.remove and not inserted: | 877 | elif ret < 0 and not rule.remove and not inserted: |
145 | 830 | # If only the action is different, replace the rule if it's not | 878 | # If only the action is different, replace the rule if it's not |
146 | 879 | ======= | ||
147 | 880 | newrules.append(rule) | ||
148 | 881 | else: | ||
149 | 882 | rule.filter_id = r.filter_id | ||
150 | 883 | elif ret < 0 and not rule.remove: | ||
151 | 884 | # If only the action or the rate is different, replace the rule if it's not | ||
152 | 885 | >>>>>>> MERGE-SOURCE | ||
153 | 831 | # to be removed. | 886 | # to be removed. |
154 | 832 | found = True | 887 | found = True |
155 | 833 | modified = True | 888 | modified = True |
156 | @@ -932,13 +987,39 @@ | |||
157 | 932 | msg(out, sys.stderr) | 987 | msg(out, sys.stderr) |
158 | 933 | UFWError(err_msg) | 988 | UFWError(err_msg) |
159 | 934 | 989 | ||
160 | 990 | <<<<<<< TREE | ||
161 | 935 | # delete any lingering RETURN rules (needed for upgrades) | 991 | # delete any lingering RETURN rules (needed for upgrades) |
162 | 936 | if flag == "-A" and pat_log.search(" ".join(s)): | 992 | if flag == "-A" and pat_log.search(" ".join(s)): |
163 | 937 | c = pat_log.sub(r'\2', " ".join(s)) | 993 | c = pat_log.sub(r'\2', " ".join(s)) |
164 | 938 | (rc, out) = cmd([exe, '-D', c, '-j', 'RETURN']) | 994 | (rc, out) = cmd([exe, '-D', c, '-j', 'RETURN']) |
165 | 995 | ======= | ||
166 | 996 | # add/remove the TC filter if needed | ||
167 | 997 | if rule.rate != "unlimited": | ||
168 | 998 | if not rule.remove: | ||
169 | 999 | add_filter(rule.src, rule.dst, rule.sport, rule.dport, rule.rate, rule.filter_id) | ||
170 | 1000 | else: | ||
171 | 1001 | delete_filter(rule.src, rule.dst, rule.sport, rule.dport, rule.filter_id) | ||
172 | 1002 | |||
173 | 1003 | # delete the RETURN rule then add it back, so it is at the | ||
174 | 1004 | # end | ||
175 | 1005 | if flag == "-A": | ||
176 | 1006 | (rc, out) = cmd([exe, '-D', chain, '-j', 'RETURN']) | ||
177 | 1007 | >>>>>>> MERGE-SOURCE | ||
178 | 939 | if rc != 0: | 1008 | if rc != 0: |
179 | 940 | debug("FAILOK: -D %s -j RETURN" % (c)) | 1009 | debug("FAILOK: -D %s -j RETURN" % (c)) |
180 | 941 | 1010 | ||
181 | 1011 | <<<<<<< TREE | ||
182 | 1012 | ======= | ||
183 | 1013 | (rc, out) = cmd([exe, '-A', chain, '-j', 'RETURN']) | ||
184 | 1014 | if rc != 0: | ||
185 | 1015 | msg(out, sys.stderr) | ||
186 | 1016 | |||
187 | 1017 | else: | ||
188 | 1018 | # the rule has been updated: remove the old filter (an error occurs if there was none) and add the new one (if it exists) | ||
189 | 1019 | delete_filter(rule.src, rule.dst, rule.sport, rule.dport, rule.filter_id) | ||
190 | 1020 | if rule.rate != "unlimited": | ||
191 | 1021 | add_filter(rule.src, rule.dst, rule.sport, rule.dport, rule.rate, rule.filter_id) | ||
192 | 1022 | >>>>>>> MERGE-SOURCE | ||
193 | 942 | return rstr | 1023 | return rstr |
194 | 943 | 1024 | ||
195 | 944 | def get_app_rules_from_system(self, template, v6): | 1025 | def get_app_rules_from_system(self, template, v6): |
196 | 945 | 1026 | ||
197 | === modified file 'src/common.py' | |||
198 | --- src/common.py 2009-08-26 20:18:30 +0000 | |||
199 | +++ src/common.py 2009-12-09 23:28:13 +0000 | |||
200 | @@ -40,7 +40,11 @@ | |||
201 | 40 | class UFWRule: | 40 | class UFWRule: |
202 | 41 | '''This class represents firewall rules''' | 41 | '''This class represents firewall rules''' |
203 | 42 | def __init__(self, action, protocol, dport="any", dst="0.0.0.0/0", | 42 | def __init__(self, action, protocol, dport="any", dst="0.0.0.0/0", |
204 | 43 | <<<<<<< TREE | ||
205 | 43 | sport="any", src="0.0.0.0/0", direction="in"): | 44 | sport="any", src="0.0.0.0/0", direction="in"): |
206 | 45 | ======= | ||
207 | 46 | sport="any", src="0.0.0.0/0", rate="unlimited", filter_id="0"): | ||
208 | 47 | >>>>>>> MERGE-SOURCE | ||
209 | 44 | # Be sure to update dup_rule accordingly... | 48 | # Be sure to update dup_rule accordingly... |
210 | 45 | self.remove = False | 49 | self.remove = False |
211 | 46 | self.updated = False | 50 | self.updated = False |
212 | @@ -54,10 +58,15 @@ | |||
213 | 54 | self.dapp = "" | 58 | self.dapp = "" |
214 | 55 | self.sapp = "" | 59 | self.sapp = "" |
215 | 56 | self.action = "" | 60 | self.action = "" |
216 | 61 | <<<<<<< TREE | ||
217 | 57 | self.position = 0 | 62 | self.position = 0 |
218 | 58 | self.logtype = "" | 63 | self.logtype = "" |
219 | 59 | self.interface_in = "" | 64 | self.interface_in = "" |
220 | 60 | self.interface_out = "" | 65 | self.interface_out = "" |
221 | 66 | ======= | ||
222 | 67 | self.rate ="" | ||
223 | 68 | self.filter_id ="" | ||
224 | 69 | >>>>>>> MERGE-SOURCE | ||
225 | 61 | try: | 70 | try: |
226 | 62 | self.set_action(action) | 71 | self.set_action(action) |
227 | 63 | self.set_protocol(protocol) | 72 | self.set_protocol(protocol) |
228 | @@ -65,7 +74,12 @@ | |||
229 | 65 | self.set_port(sport, "src") | 74 | self.set_port(sport, "src") |
230 | 66 | self.set_src(src) | 75 | self.set_src(src) |
231 | 67 | self.set_dst(dst) | 76 | self.set_dst(dst) |
232 | 77 | <<<<<<< TREE | ||
233 | 68 | self.set_direction(direction) | 78 | self.set_direction(direction) |
234 | 79 | ======= | ||
235 | 80 | self.set_rate(rate) | ||
236 | 81 | self.set_filter_id(filter_id) | ||
237 | 82 | >>>>>>> MERGE-SOURCE | ||
238 | 69 | except UFWError: | 83 | except UFWError: |
239 | 70 | raise | 84 | raise |
240 | 71 | 85 | ||
241 | @@ -85,11 +99,16 @@ | |||
242 | 85 | rule.multi = self.multi | 99 | rule.multi = self.multi |
243 | 86 | rule.dapp = self.dapp | 100 | rule.dapp = self.dapp |
244 | 87 | rule.sapp = self.sapp | 101 | rule.sapp = self.sapp |
245 | 102 | <<<<<<< TREE | ||
246 | 88 | rule.position = self.position | 103 | rule.position = self.position |
247 | 89 | rule.logtype = self.logtype | 104 | rule.logtype = self.logtype |
248 | 90 | rule.interface_in = self.interface_in | 105 | rule.interface_in = self.interface_in |
249 | 91 | rule.interface_out = self.interface_out | 106 | rule.interface_out = self.interface_out |
250 | 92 | rule.direction = self.direction | 107 | rule.direction = self.direction |
251 | 108 | ======= | ||
252 | 109 | rule.rate = self.rate | ||
253 | 110 | rule.filter_id = self.filter_id | ||
254 | 111 | >>>>>>> MERGE-SOURCE | ||
255 | 93 | 112 | ||
256 | 94 | return rule | 113 | return rule |
257 | 95 | 114 | ||
258 | @@ -278,6 +297,7 @@ | |||
259 | 278 | self.dst = tmp | 297 | self.dst = tmp |
260 | 279 | self._fix_anywhere() | 298 | self._fix_anywhere() |
261 | 280 | 299 | ||
262 | 300 | <<<<<<< TREE | ||
263 | 281 | def set_interface(self, type, name): | 301 | def set_interface(self, type, name): |
264 | 282 | '''Sets an interface for rule''' | 302 | '''Sets an interface for rule''' |
265 | 283 | if type != "in" and type != "out": | 303 | if type != "in" and type != "out": |
266 | @@ -321,6 +341,18 @@ | |||
267 | 321 | err_msg = _("Unsupported direction '%s'") % (direction) | 341 | err_msg = _("Unsupported direction '%s'") % (direction) |
268 | 322 | raise UFWError(err_msg) | 342 | raise UFWError(err_msg) |
269 | 323 | 343 | ||
270 | 344 | ======= | ||
271 | 345 | def set_rate(self, rate): | ||
272 | 346 | '''Sets rate for the rule''' | ||
273 | 347 | self.rate = rate | ||
274 | 348 | self._fix_anywhere() | ||
275 | 349 | |||
276 | 350 | def set_filter_id(self, filter_id): | ||
277 | 351 | '''Sets the if of the filter associated to the rule''' | ||
278 | 352 | self.filter_id = filter_id | ||
279 | 353 | self._fix_anywhere() | ||
280 | 354 | |||
281 | 355 | >>>>>>> MERGE-SOURCE | ||
282 | 324 | def normalize(self): | 356 | def normalize(self): |
283 | 325 | '''Normalize src and dst to standard form''' | 357 | '''Normalize src and dst to standard form''' |
284 | 326 | changed = False | 358 | changed = False |
285 | @@ -391,6 +423,7 @@ | |||
286 | 391 | if x.sapp != y.sapp: | 423 | if x.sapp != y.sapp: |
287 | 392 | debug(dbg_msg) | 424 | debug(dbg_msg) |
288 | 393 | return 1 | 425 | return 1 |
289 | 426 | <<<<<<< TREE | ||
290 | 394 | if x.interface_in != y.interface_in: | 427 | if x.interface_in != y.interface_in: |
291 | 395 | return 1 | 428 | return 1 |
292 | 396 | if x.interface_out != y.interface_out: | 429 | if x.interface_out != y.interface_out: |
293 | @@ -398,13 +431,20 @@ | |||
294 | 398 | if x.direction != y.direction: | 431 | if x.direction != y.direction: |
295 | 399 | return 1 | 432 | return 1 |
296 | 400 | if x.action == y.action and x.logtype == y.logtype: | 433 | if x.action == y.action and x.logtype == y.logtype: |
297 | 434 | ======= | ||
298 | 435 | if x.action == y.action and x.rate == y.rate: | ||
299 | 436 | >>>>>>> MERGE-SOURCE | ||
300 | 401 | dbg_msg = _("Found exact match") | 437 | dbg_msg = _("Found exact match") |
301 | 402 | debug(dbg_msg) | 438 | debug(dbg_msg) |
302 | 403 | return 0 | 439 | return 0 |
303 | 440 | <<<<<<< TREE | ||
304 | 404 | dbg_msg = _("Found non-action/non-logtype match " \ | 441 | dbg_msg = _("Found non-action/non-logtype match " \ |
305 | 405 | "(%(xa)s/%(ya)s %(xl)s/%(yl)s)") % \ | 442 | "(%(xa)s/%(ya)s %(xl)s/%(yl)s)") % \ |
306 | 406 | ({'xa': x.action, 'ya': y.action, \ | 443 | ({'xa': x.action, 'ya': y.action, \ |
307 | 407 | 'xl': x.logtype, 'yl': y.logtype}) | 444 | 'xl': x.logtype, 'yl': y.logtype}) |
308 | 445 | ======= | ||
309 | 446 | dbg_msg = _("Found non-action or non-rate match") | ||
310 | 447 | >>>>>>> MERGE-SOURCE | ||
311 | 408 | debug(dbg_msg) | 448 | debug(dbg_msg) |
312 | 409 | return -1 | 449 | return -1 |
313 | 410 | 450 | ||
314 | 411 | 451 | ||
315 | === modified file 'src/frontend.py' | |||
316 | --- src/frontend.py 2009-09-21 14:33:28 +0000 | |||
317 | +++ src/frontend.py 2009-12-09 23:28:13 +0000 | |||
318 | @@ -25,6 +25,7 @@ | |||
319 | 25 | import ufw.util | 25 | import ufw.util |
320 | 26 | from ufw.util import error, warn | 26 | from ufw.util import error, warn |
321 | 27 | from ufw.backend_iptables import UFWBackendIptables | 27 | from ufw.backend_iptables import UFWBackendIptables |
322 | 28 | from ufw.tc_functions import get_next_filter_id | ||
323 | 28 | 29 | ||
324 | 29 | def allowed_command(cmd): | 30 | def allowed_command(cmd): |
325 | 30 | '''Return command if it is allowed, otherwise raise an exception''' | 31 | '''Return command if it is allowed, otherwise raise an exception''' |
326 | @@ -204,6 +205,7 @@ | |||
327 | 204 | direction=rule_direction) | 205 | direction=rule_direction) |
328 | 205 | if remove: | 206 | if remove: |
329 | 206 | rule.remove = remove | 207 | rule.remove = remove |
330 | 208 | <<<<<<< TREE | ||
331 | 207 | elif insert_pos != "": | 209 | elif insert_pos != "": |
332 | 208 | try: | 210 | try: |
333 | 209 | rule.set_position(insert_pos) | 211 | rule.set_position(insert_pos) |
334 | @@ -211,6 +213,10 @@ | |||
335 | 211 | raise | 213 | raise |
336 | 212 | if nargs == 3: | 214 | if nargs == 3: |
337 | 213 | # Short form where only app or port/proto is given | 215 | # Short form where only app or port/proto is given |
338 | 216 | ======= | ||
339 | 217 | if nargs == 3 or nargs == 5: | ||
340 | 218 | # Short form where only app + rate? or port/proto + rate? is given | ||
341 | 219 | >>>>>>> MERGE-SOURCE | ||
342 | 214 | if ufw.applications.valid_profile_name(argv[2]): | 220 | if ufw.applications.valid_profile_name(argv[2]): |
343 | 215 | # Check if name collision with /etc/services. If so, use | 221 | # Check if name collision with /etc/services. If so, use |
344 | 216 | # /etc/services instead of application profile | 222 | # /etc/services instead of application profile |
345 | @@ -233,9 +239,21 @@ | |||
346 | 233 | raise UFWError(err_msg) | 239 | raise UFWError(err_msg) |
347 | 234 | to_service = port | 240 | to_service = port |
348 | 235 | 241 | ||
349 | 242 | if nargs == 5 and argv[3] == "rate" and action == "allow": | ||
350 | 243 | if not re.match('^\d([0-9]*\d+)*$', argv[4]): | ||
351 | 244 | err_msg = ("Rates must be numeric") | ||
352 | 245 | raise UFWError(err_msg) | ||
353 | 246 | rate = argv[4] | ||
354 | 247 | filter_id = "undefined" | ||
355 | 248 | else: | ||
356 | 249 | rate = "unlimited" | ||
357 | 250 | filter_id = "0" | ||
358 | 251 | |||
359 | 236 | try: | 252 | try: |
360 | 237 | rule.set_protocol(proto) | 253 | rule.set_protocol(proto) |
361 | 238 | rule.set_port(port, "dst") | 254 | rule.set_port(port, "dst") |
362 | 255 | rule.set_rate(rate) | ||
363 | 256 | rule.set_filter_id(filter_id) | ||
364 | 239 | type = "both" | 257 | type = "both" |
365 | 240 | except UFWError: | 258 | except UFWError: |
366 | 241 | err_msg = _("Bad port") | 259 | err_msg = _("Bad port") |
367 | @@ -249,7 +267,11 @@ | |||
368 | 249 | raise UFWError(err_msg) | 267 | raise UFWError(err_msg) |
369 | 250 | else: | 268 | else: |
370 | 251 | # Full form with PF-style syntax | 269 | # Full form with PF-style syntax |
371 | 270 | <<<<<<< TREE | ||
372 | 252 | keys = [ 'proto', 'from', 'to', 'port', 'app', 'in', 'out' ] | 271 | keys = [ 'proto', 'from', 'to', 'port', 'app', 'in', 'out' ] |
373 | 272 | ======= | ||
374 | 273 | keys = [ 'proto', 'from', 'to', 'port', 'app', 'rate' ] | ||
375 | 274 | >>>>>>> MERGE-SOURCE | ||
376 | 253 | 275 | ||
377 | 254 | # quick check | 276 | # quick check |
378 | 255 | if argv.count("to") > 1 or \ | 277 | if argv.count("to") > 1 or \ |
379 | @@ -259,7 +281,8 @@ | |||
380 | 259 | argv.count("in") > 1 or \ | 281 | argv.count("in") > 1 or \ |
381 | 260 | argv.count("out") > 1 or \ | 282 | argv.count("out") > 1 or \ |
382 | 261 | argv.count("app") > 2 or \ | 283 | argv.count("app") > 2 or \ |
384 | 262 | argv.count("app") > 0 and argv.count("proto") > 0: | 284 | argv.count("app") > 0 and argv.count("proto") > 0 or \ |
385 | 285 | argv.count("rate") > 1: | ||
386 | 263 | err_msg = _("Improper rule syntax") | 286 | err_msg = _("Improper rule syntax") |
387 | 264 | raise UFWError(err_msg) | 287 | raise UFWError(err_msg) |
388 | 265 | 288 | ||
389 | @@ -269,7 +292,26 @@ | |||
390 | 269 | if i % 2 == 0 and argv[i] not in keys: | 292 | if i % 2 == 0 and argv[i] not in keys: |
391 | 270 | err_msg = _("Invalid token '%s'") % (argv[i]) | 293 | err_msg = _("Invalid token '%s'") % (argv[i]) |
392 | 271 | raise UFWError(err_msg) | 294 | raise UFWError(err_msg) |
394 | 272 | if arg == "proto": | 295 | if arg == "rate": |
395 | 296 | if i+1 < nargs: | ||
396 | 297 | if action != "allow": | ||
397 | 298 | err_msg = ("Rates can only be specified with the 'allow' action") | ||
398 | 299 | raise UFWError(err_msg) | ||
399 | 300 | try: | ||
400 | 301 | rate = argv[i+1] | ||
401 | 302 | if not re.match('^\d([0-9]*\d+)*$', rate): | ||
402 | 303 | err_msg = _("Rates must be numeric") | ||
403 | 304 | raise UFWError(err_msg) | ||
404 | 305 | |||
405 | 306 | rule.set_rate(rate) | ||
406 | 307 | filter_id = "undefined" | ||
407 | 308 | rule.set_filter_id(filter_id) | ||
408 | 309 | except Exception: | ||
409 | 310 | raise | ||
410 | 311 | else: | ||
411 | 312 | err_msg = ("Invalid 'rate' clause") | ||
412 | 313 | raise UFWError(err_msg) | ||
413 | 314 | elif arg == "proto": | ||
414 | 273 | if i+1 < nargs: | 315 | if i+1 < nargs: |
415 | 274 | try: | 316 | try: |
416 | 275 | rule.set_protocol(argv[i+1]) | 317 | rule.set_protocol(argv[i+1]) |
417 | @@ -900,6 +942,7 @@ | |||
418 | 900 | tmp = self.backend.find_application_name(rule.sapp) | 942 | tmp = self.backend.find_application_name(rule.sapp) |
419 | 901 | if tmp != rule.sapp: | 943 | if tmp != rule.sapp: |
420 | 902 | rule.sapp = tmp | 944 | rule.sapp = tmp |
421 | 945 | <<<<<<< TREE | ||
422 | 903 | rule.set_port(tmp, "dst") | 946 | rule.set_port(tmp, "dst") |
423 | 904 | except UFWError, e: | 947 | except UFWError, e: |
424 | 905 | # allow for the profile being deleted (LP: #407810) | 948 | # allow for the profile being deleted (LP: #407810) |
425 | @@ -909,6 +952,13 @@ | |||
426 | 909 | err_msg = _("Invalid profile name") | 952 | err_msg = _("Invalid profile name") |
427 | 910 | raise UFWError(err_msg) | 953 | raise UFWError(err_msg) |
428 | 911 | 954 | ||
429 | 955 | ======= | ||
430 | 956 | rule.set_port(tmp, "src") | ||
431 | 957 | if not rule.remove and rule.rate != "undefined": | ||
432 | 958 | rule.filter_id = get_next_filter_id(self.backend.rules) | ||
433 | 959 | except UFWError, e: | ||
434 | 960 | error(e.value) | ||
435 | 961 | >>>>>>> MERGE-SOURCE | ||
436 | 912 | res = self.set_rule(rule, ip_version) | 962 | res = self.set_rule(rule, ip_version) |
437 | 913 | else: | 963 | else: |
438 | 914 | err_msg = _("Unsupported action '%s'") % (action) | 964 | err_msg = _("Unsupported action '%s'") % (action) |
439 | 915 | 965 | ||
440 | === added file 'src/tc_functions.py' | |||
441 | --- src/tc_functions.py 1970-01-01 00:00:00 +0000 | |||
442 | +++ src/tc_functions.py 2009-12-09 23:28:13 +0000 | |||
443 | @@ -0,0 +1,150 @@ | |||
444 | 1 | # | ||
445 | 2 | # tc_functions.py: tc related functions for ufw | ||
446 | 3 | # | ||
447 | 4 | # Copyright (C) 2008-2009 Canonical Ltd. | ||
448 | 5 | # | ||
449 | 6 | # This program is free software: you can redistribute it and/or modify | ||
450 | 7 | # it under the terms of the GNU General Public License version 3, | ||
451 | 8 | # as published by the Free Software Foundation. | ||
452 | 9 | # | ||
453 | 10 | # This program is distributed in the hope that it will be useful, | ||
454 | 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
455 | 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
456 | 13 | # GNU General Public License for more details. | ||
457 | 14 | # | ||
458 | 15 | # You should have received a copy of the GNU General Public License | ||
459 | 16 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
460 | 17 | # | ||
461 | 18 | |||
462 | 19 | import os | ||
463 | 20 | import re | ||
464 | 21 | import sys | ||
465 | 22 | import subprocess | ||
466 | 23 | |||
467 | 24 | from ufw.common import UFWError, UFWRule, config_dir, state_dir, prefix_dir | ||
468 | 25 | from ufw.util import warn, debug, msg, cmd, cmd_pipe | ||
469 | 26 | |||
470 | 27 | def get_interface_list(): | ||
471 | 28 | '''Get a list of all the available network interfaces''' | ||
472 | 29 | list = [] | ||
473 | 30 | |||
474 | 31 | sp1 = subprocess.Popen("/sbin/ifconfig", stdout=subprocess.PIPE) | ||
475 | 32 | sp2 = subprocess.Popen(["cut", '-d ', "-f1"], stdin=sp1.stdout, stdout=subprocess.PIPE) | ||
476 | 33 | sp3 = subprocess.Popen(["sort", '-u'], stdin=sp2.stdout, stdout=subprocess.PIPE) | ||
477 | 34 | sp4 = subprocess.Popen(["grep", '-v', "^$"], stdin=sp3.stdout, stdout=subprocess.PIPE) | ||
478 | 35 | sp5 = subprocess.Popen("xargs", stdin=sp4.stdout, stdout=subprocess.PIPE) | ||
479 | 36 | |||
480 | 37 | out = sp5.communicate()[0] | ||
481 | 38 | |||
482 | 39 | list = out.split() | ||
483 | 40 | |||
484 | 41 | return list | ||
485 | 42 | |||
486 | 43 | |||
487 | 44 | def is_local_ip_address(addr): | ||
488 | 45 | '''Checks whether the given IP address is a local IP addresse''' | ||
489 | 46 | sp1 = subprocess.Popen("/sbin/ifconfig", stdout=subprocess.PIPE) | ||
490 | 47 | sp2 = subprocess.Popen(["grep", addr], stdin=sp1.stdout, stdout=subprocess.PIPE) | ||
491 | 48 | sp3 = subprocess.Popen(["grep", "-ci", "inet"], stdin=sp2.stdout, stdout=subprocess.PIPE) | ||
492 | 49 | |||
493 | 50 | out = sp3.communicate()[0] | ||
494 | 51 | |||
495 | 52 | return int(out) | ||
496 | 53 | |||
497 | 54 | |||
498 | 55 | def add_filter(src, dst, sport, dport, rate, filter_id): | ||
499 | 56 | interface_list = get_interface_list() | ||
500 | 57 | |||
501 | 58 | # if src and/or dst are IP addresses (instead of network addresses, add the all 1s netmask | ||
502 | 59 | if not re.match(r'.*/.*', src): | ||
503 | 60 | tc_src = src + "/32" | ||
504 | 61 | else: | ||
505 | 62 | tc_src = src | ||
506 | 63 | if not re.match(r'.*/.*', dst): | ||
507 | 64 | tc_dst = dst + "/32" | ||
508 | 65 | else: | ||
509 | 66 | tc_dst = dst | ||
510 | 67 | |||
511 | 68 | |||
512 | 69 | # build the u32 filter | ||
513 | 70 | u32_match="match ip src " + tc_src + " match ip dst " + tc_dst | ||
514 | 71 | if sport != "any": | ||
515 | 72 | u32_match = u32_match + " match ip sport " + sport + " 0xffff" | ||
516 | 73 | if dport != "any": | ||
517 | 74 | u32_match = u32_match + " match ip dport " + dport + " 0xffff" | ||
518 | 75 | |||
519 | 76 | # add the filter to the proper qdiscs (ingress or egress) | ||
520 | 77 | if is_local_ip_address(src): | ||
521 | 78 | #msg("add to egress qdisc: "+tc_src+" "+tc_dst+" "+sport+" "+dport+" "+rate) | ||
522 | 79 | for i in interface_list: | ||
523 | 80 | command = ["/sbin/tc", "filter", "add", "dev", i, "parent", "1:", "protocol", "ip", "prio", "1", "handle", "::"+str(filter_id), "u32", u32_match, "police", "rate", rate + "kbit", "burst", "100kbit", "drop", "flowid", ':1'] | ||
524 | 81 | command = ' '.join(command) | ||
525 | 82 | command = command.split(' ') | ||
526 | 83 | cmd(command) | ||
527 | 84 | else: | ||
528 | 85 | |||
529 | 86 | #msg("add to ingress qdisc: "+tc_src+" "+tc_dst+" "+sport+" "+dport+" "+rate) | ||
530 | 87 | for i in interface_list: | ||
531 | 88 | command=["/sbin/tc", "filter", "add", "dev", i, "parent", "ffff:", "protocol", "ip", "prio", "1", "handle", "::"+str(filter_id), "u32", u32_match, "police", "rate", rate + "kbit", "burst", "100kbit", "drop", "flowid", ':1'] | ||
532 | 89 | command = ' '.join(command) | ||
533 | 90 | command = command.split(' ') | ||
534 | 91 | cmd(command) | ||
535 | 92 | |||
536 | 93 | |||
537 | 94 | def delete_filter(src, dst, sport, dport, filter_id): | ||
538 | 95 | interface_list = get_interface_list() | ||
539 | 96 | |||
540 | 97 | # if src and/or dst are IP addresses (instead of network addresses, add the all 1s netmask | ||
541 | 98 | if not re.match(r'.*/.*', src): | ||
542 | 99 | tc_src = src + "/32" | ||
543 | 100 | else: | ||
544 | 101 | tc_src = src | ||
545 | 102 | if not re.match(r'.*/.*', dst): | ||
546 | 103 | tc_dst = dst + "/32" | ||
547 | 104 | else: | ||
548 | 105 | tc_dst = dst | ||
549 | 106 | |||
550 | 107 | # remove the filter from the proper qdiscs (ingres or egress) | ||
551 | 108 | if is_local_ip_address(src): | ||
552 | 109 | #msg("delete from egress qdisc: "+tc_src+" "+tc_dst+" "+sport+" "+dport) | ||
553 | 110 | for i in interface_list: | ||
554 | 111 | command=["/sbin/tc", "filter", "del", "dev", i, "parent", "1:", "protocol", "ip", "prio", "1", "handle", "::"+str(filter_id), "u32"] | ||
555 | 112 | command = ' '.join(command) | ||
556 | 113 | command = command.split(' ') | ||
557 | 114 | cmd(command) | ||
558 | 115 | else: | ||
559 | 116 | #msg("delete from ingress qdisc: "+tc_src+" "+tc_dst+" "+sport+" "+dport) | ||
560 | 117 | for i in interface_list: | ||
561 | 118 | command=["/sbin/tc", "filter", "del", "dev", i, "parent", "ffff:", "protocol", "ip", "prio", "1", "handle", "800::"+str(filter_id), "u32"] | ||
562 | 119 | command = ' '.join(command) | ||
563 | 120 | command = command.split(' ') | ||
564 | 121 | cmd(command) | ||
565 | 122 | |||
566 | 123 | |||
567 | 124 | def get_next_filter_id(rules): | ||
568 | 125 | id_list = [] | ||
569 | 126 | for r in rules: | ||
570 | 127 | id_list.append(r.filter_id) | ||
571 | 128 | |||
572 | 129 | id_list.sort() | ||
573 | 130 | |||
574 | 131 | idx = 1 | ||
575 | 132 | for id in id_list: | ||
576 | 133 | if(int(id) != idx): | ||
577 | 134 | return idx | ||
578 | 135 | idx = idx + 1 | ||
579 | 136 | |||
580 | 137 | return idx | ||
581 | 138 | |||
582 | 139 | def my_main(): | ||
583 | 140 | msg("hello") | ||
584 | 141 | list = get_interface_list() | ||
585 | 142 | msg("Found interfaces : %s" % list) | ||
586 | 143 | |||
587 | 144 | if is_local_ip_address("127.0.0.1"): | ||
588 | 145 | msg("OK") | ||
589 | 146 | else: | ||
590 | 147 | msg("KO") | ||
591 | 148 | |||
592 | 149 | |||
593 | 150 | |||
594 | 0 | 151 | ||
595 | === modified file 'src/ufw-init-functions' | |||
596 | --- src/ufw-init-functions 2009-08-24 15:09:18 +0000 | |||
597 | +++ src/ufw-init-functions 2009-12-09 23:28:13 +0000 | |||
598 | @@ -122,6 +122,18 @@ | |||
599 | 122 | flush_builtins | 122 | flush_builtins |
600 | 123 | fi | 123 | fi |
601 | 124 | 124 | ||
602 | 125 | |||
603 | 126 | interface_list=`/sbin/ifconfig | cut -d' ' -f 1 | sort -u | grep -v "^$" | xargs` | ||
604 | 127 | |||
605 | 128 | for i in $interface_list | ||
606 | 129 | do | ||
607 | 130 | # create incoming qdiscs | ||
608 | 131 | /sbin/tc qdisc add dev $i handle ffff: ingress | ||
609 | 132 | /sbin/tc qdisc add dev $i parent root handle 1: prio bands 3 | ||
610 | 133 | done | ||
611 | 134 | |||
612 | 135 | |||
613 | 136 | |||
614 | 125 | execs="iptables" | 137 | execs="iptables" |
615 | 126 | 138 | ||
616 | 127 | # IPv6 setup | 139 | # IPv6 setup |
617 | @@ -347,6 +359,17 @@ | |||
618 | 347 | return 0 | 359 | return 0 |
619 | 348 | fi | 360 | fi |
620 | 349 | 361 | ||
621 | 362 | |||
622 | 363 | interface_list=`/sbin/ifconfig | cut -d' ' -f 1 | sort -u | grep -v "^$" | xargs` | ||
623 | 364 | |||
624 | 365 | for i in $interface_list | ||
625 | 366 | do | ||
626 | 367 | # delete incoming qdiscs | ||
627 | 368 | /sbin/tc qdisc del dev $i ingress | ||
628 | 369 | /sbin/tc qdisc del dev $i parent root | ||
629 | 370 | done | ||
630 | 371 | |||
631 | 372 | |||
632 | 350 | error="" | 373 | error="" |
633 | 351 | execs="iptables" | 374 | execs="iptables" |
634 | 352 | if ip6tables -L INPUT -n >/dev/null 2>&1; then | 375 | if ip6tables -L INPUT -n >/dev/null 2>&1; then |