Mercurial > prosody-modules
comparison mod_firewall/actions.lib.lua @ 947:c91cac3b823f
mod_firewall: General stanza filtering plugin with a declarative rule-based syntax
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Wed, 03 Apr 2013 16:11:20 +0100 |
parents | |
children | b729414b4bf1 |
comparison
equal
deleted
inserted
replaced
946:2c5430ff1c11 | 947:c91cac3b823f |
---|---|
1 local action_handlers = {}; | |
2 | |
3 -- Takes an XML string and returns a code string that builds that stanza | |
4 -- using st.stanza() | |
5 local function compile_xml(data) | |
6 local code = {}; | |
7 local first, short_close = true, nil; | |
8 for tagline, text in data:gmatch("<([^>]+)>([^<]*)") do | |
9 if tagline:sub(-1,-1) == "/" then | |
10 tagline = tagline:sub(1, -2); | |
11 short_close = true; | |
12 end | |
13 if tagline:sub(1,1) == "/" then | |
14 code[#code+1] = (":up()"); | |
15 else | |
16 local name, attr = tagline:match("^(%S*)%s*(.*)$"); | |
17 local attr_str = {}; | |
18 for k, _, v in attr:gmatch("(%S+)=([\"'])([^%2]-)%2") do | |
19 if #attr_str == 0 then | |
20 table.insert(attr_str, ", { "); | |
21 else | |
22 table.insert(attr_str, ", "); | |
23 end | |
24 if k:match("^%a%w*$") then | |
25 table.insert(attr_str, string.format("%s = %q", k, v)); | |
26 else | |
27 table.insert(attr_str, string.format("[%q] = %q", k, v)); | |
28 end | |
29 end | |
30 if #attr_str > 0 then | |
31 table.insert(attr_str, " }"); | |
32 end | |
33 if first then | |
34 code[#code+1] = (string.format("st.stanza(%q %s)", name, #attr_str>0 and table.concat(attr_str) or ", nil")); | |
35 first = nil; | |
36 else | |
37 code[#code+1] = (string.format(":tag(%q%s)", name, table.concat(attr_str))); | |
38 end | |
39 end | |
40 if text and text:match("%S") then | |
41 code[#code+1] = (string.format(":text(%q)", text)); | |
42 elseif short_close then | |
43 short_close = nil; | |
44 code[#code+1] = (":up()"); | |
45 end | |
46 end | |
47 return table.concat(code, ""); | |
48 end | |
49 | |
50 | |
51 function action_handlers.DROP() | |
52 return "log('debug', 'Firewall dropping stanza: %s', tostring(stanza)); return true;"; | |
53 end | |
54 | |
55 function action_handlers.STRIP(tag_desc) | |
56 local code = {}; | |
57 local name, xmlns = tag_desc:match("^(%S+) (.+)$"); | |
58 if not name then | |
59 name, xmlns = tag_desc, nil; | |
60 end | |
61 if name == "*" then | |
62 name = nil; | |
63 end | |
64 code[#code+1] = ("local stanza_xmlns = stanza.attr.xmlns; "); | |
65 code[#code+1] = "stanza:maptags(function (tag) if "; | |
66 if name then | |
67 code[#code+1] = ("tag.name == %q and "):format(name); | |
68 end | |
69 if xmlns then | |
70 code[#code+1] = ("(tag.attr.xmlns or stanza_xmlns) == %q "):format(xmlns); | |
71 else | |
72 code[#code+1] = ("tag.attr.xmlns == stanza_xmlns "); | |
73 end | |
74 code[#code+1] = "then return nil; end return tag; end );"; | |
75 return table.concat(code); | |
76 end | |
77 | |
78 function action_handlers.INJECT(tag) | |
79 return "stanza:add_child("..compile_xml(tag)..")", { "st" }; | |
80 end | |
81 | |
82 local error_types = { | |
83 ["bad-request"] = "modify"; | |
84 ["conflict"] = "cancel"; | |
85 ["feature-not-implemented"] = "cancel"; | |
86 ["forbidden"] = "auth"; | |
87 ["gone"] = "cancel"; | |
88 ["internal-server-error"] = "cancel"; | |
89 ["item-not-found"] = "cancel"; | |
90 ["jid-malformed"] = "modify"; | |
91 ["not-acceptable"] = "modify"; | |
92 ["not-allowed"] = "cancel"; | |
93 ["not-authorized"] = "auth"; | |
94 ["payment-required"] = "auth"; | |
95 ["policy-violation"] = "modify"; | |
96 ["recipient-unavailable"] = "wait"; | |
97 ["redirect"] = "modify"; | |
98 ["registration-required"] = "auth"; | |
99 ["remote-server-not-found"] = "cancel"; | |
100 ["remote-server-timeout"] = "wait"; | |
101 ["resource-constraint"] = "wait"; | |
102 ["service-unavailable"] = "cancel"; | |
103 ["subscription-required"] = "auth"; | |
104 ["undefined-condition"] = "cancel"; | |
105 ["unexpected-request"] = "wait"; | |
106 }; | |
107 | |
108 | |
109 local function route_modify(make_new, to, drop) | |
110 local reroute, deps = "session.send(newstanza)", { "st" }; | |
111 if to then | |
112 reroute = ("newstanza.attr.to = %q; core_post_stanza(session, newstanza)"):format(to); | |
113 deps[#deps+1] = "core_post_stanza"; | |
114 end | |
115 return ([[local newstanza = st.%s; %s; %s; ]]) | |
116 :format(make_new, reroute, drop and "return true" or ""), deps; | |
117 end | |
118 | |
119 function action_handlers.BOUNCE(with) | |
120 local error = with and with:match("^%S+") or "service-unavailable"; | |
121 local error_type = error:match(":(%S+)"); | |
122 if not error_type then | |
123 error_type = error_types[error] or "cancel"; | |
124 else | |
125 error = error:match("^[^:]+"); | |
126 end | |
127 error, error_type = string.format("%q", error), string.format("%q", error_type); | |
128 local text = with and with:match(" %((.+)%)$"); | |
129 if text then | |
130 text = string.format("%q", text); | |
131 else | |
132 text = "nil"; | |
133 end | |
134 return route_modify(("error_reply(stanza, %s, %s, %s)"):format(error_type, error, text), nil, true); | |
135 end | |
136 | |
137 function action_handlers.REDIRECT(where) | |
138 return route_modify("clone(stanza)", where, true, true); | |
139 end | |
140 | |
141 function action_handlers.COPY(where) | |
142 return route_modify("clone(stanza)", where, true, false); | |
143 end | |
144 | |
145 function action_handlers.LOG(string) | |
146 local level = string:match("^%[(%a+)%]") or "info"; | |
147 string = string:gsub("^%[%a+%] ?", ""); | |
148 return (("log(%q, %q)"):format(level, string) | |
149 :gsub("$top", [["..stanza:top_tag().."]]) | |
150 :gsub("$stanza", [["..stanza.."]]) | |
151 :gsub("$(%b())", [["..%1.."]])); | |
152 end | |
153 | |
154 function action_handlers.RULEDEP(dep) | |
155 return "", { dep }; | |
156 end | |
157 | |
158 return action_handlers; |