Software / code / prosody-modules
Comparison
mod_firewall/README.markdown @ 1803:4d73a1a6ba68
Convert all wiki pages to Markdown
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Fri, 28 Aug 2015 18:03:58 +0200 |
| parent | 1782:mod_firewall/README.wiki@29f3d6b7ad16 |
| child | 2002:ce991c678370 |
comparison
equal
deleted
inserted
replaced
| 1802:0ab737feada6 | 1803:4d73a1a6ba68 |
|---|---|
| 1 --- | |
| 2 labels: | |
| 3 - 'Stage-Alpha' | |
| 4 summary: 'A rule-based stanza filtering module' | |
| 5 ... | |
| 6 | |
| 7 ------------------------------------------------------------------------ | |
| 8 | |
| 9 **Note:** mod\_firewall is in its very early stages. This documentation | |
| 10 is liable to change, and some described functionality may be missing, | |
| 11 incomplete or contain bugs. Feedback is welcome in the comments section | |
| 12 at the bottom of this page. | |
| 13 | |
| 14 ------------------------------------------------------------------------ | |
| 15 | |
| 16 Introduction | |
| 17 ============ | |
| 18 | |
| 19 A firewall is an invaluable tool in the sysadmin's toolbox. However | |
| 20 while low-level firewalls such as iptables and pf are incredibly good at | |
| 21 what they do, they are generally not able to handle application-layer | |
| 22 rules. | |
| 23 | |
| 24 The goal of mod\_firewall is to provide similar services at the XMPP | |
| 25 layer. Based on rule scripts it can efficiently block, bounce, drop, | |
| 26 forward, copy, redirect stanzas and more! Furthermore all rules can be | |
| 27 applied and updated dynamically at runtime without restarting the | |
| 28 server. | |
| 29 | |
| 30 Details | |
| 31 ======= | |
| 32 | |
| 33 mod\_firewall loads one or more scripts, and compiles these to Lua code | |
| 34 that reacts to stanzas flowing through Prosody. The firewall script | |
| 35 syntax is unusual, but straightforward. | |
| 36 | |
| 37 A firewall script is dominated by rules. Each rule has two parts: | |
| 38 conditions, and actions. When a stanza matches all of the conditions, | |
| 39 all of the actions are executed in order. | |
| 40 | |
| 41 Here is a simple example to block stanzas from spammer@example.com: | |
| 42 | |
| 43 FROM: spammer@example.com | |
| 44 DROP. | |
| 45 | |
| 46 FROM is a condition, and DROP is an action. This is about as simple as | |
| 47 it gets. How about heading to the other extreme? Let's demonstrate | |
| 48 something more complex that mod\_firewall can do for you: | |
| 49 | |
| 50 %ZONE myorganisation: staff.myorg.example, support.myorg.example | |
| 51 | |
| 52 ENTERING: myorganisation | |
| 53 KIND: message | |
| 54 TIME: 12am-9am, 5pm-12am, Saturday, Sunday | |
| 55 REPLY=Sorry, I am afraid our office is closed at the moment. If you need assistance, please call our 24-hour support line on 123-456-789. | |
| 56 | |
| 57 This rule will reply with a short message whenever someone tries to send | |
| 58 a message to someone at any of the hosts defined in the 'myorganisation' | |
| 59 outside of office hours. | |
| 60 | |
| 61 Firewall rules should be written to a `ruleset.pfw` file. Multiple such | |
| 62 rule files can be specified in the configuration using: | |
| 63 | |
| 64 firewall_scripts = { "path/to/ruleset.pfw" } | |
| 65 | |
| 66 Conditions | |
| 67 ---------- | |
| 68 | |
| 69 All conditions must come before any action in a rule block. The | |
| 70 condition name is followed by a colon (':'), and the value to test for. | |
| 71 | |
| 72 A condition can be preceded or followed by `NOT` to negate its match. | |
| 73 For example: | |
| 74 | |
| 75 NOT FROM: user@example.com | |
| 76 KIND NOT: message | |
| 77 | |
| 78 ### Zones | |
| 79 | |
| 80 A 'zone' is one or more hosts or JIDs. It is possible to match when a | |
| 81 stanza is entering or leaving a zone, while at the same time not | |
| 82 matching traffic passing between JIDs in the same zone. | |
| 83 | |
| 84 Zones are defined at the top of a script with the following syntax (they | |
| 85 are not part of a rule block): | |
| 86 | |
| 87 %ZONE myzone: host1, host2, user@host3, foo.bar.example | |
| 88 | |
| 89 A host listed in a zone also matches all users on that host (but not | |
| 90 subdomains). | |
| 91 | |
| 92 The following zone-matching conditions are supported: | |
| 93 | |
| 94 Condition Matches | |
| 95 ------------ ------------------------------------------ | |
| 96 `ENTERING` When a stanza is entering the named zone | |
| 97 `LEAVING` When a stanza is leaving the named zone | |
| 98 | |
| 99 ### Stanza matching | |
| 100 | |
| 101 Condition Matches | |
| 102 ----------- ------------------------------------------------------------------------------------------------------------------------------------------------------------ | |
| 103 `KIND` The kind of stanza. May be 'message', 'presence' or 'iq' | |
| 104 `TYPE` The type of stanza. This varies depending on the kind of stanza. See 'Stanza types' below for more information. | |
| 105 `PAYLOAD` The stanza contains a child with the given namespace. Useful for determining the type of an iq request, or whether a message contains a certain extension. | |
| 106 `INSPECT` The node at the specified path exists or matches a given string. This allows you to look anywhere inside a stanza. See below for examples and more. | |
| 107 | |
| 108 #### Stanza types | |
| 109 | |
| 110 Stanza Valid types | |
| 111 ---------- ------------------------------------------------------------------------------------------ | |
| 112 iq get, set, result, error | |
| 113 presence *available*, unavailable, probe, subscribe, subscribed, unsubscribe, unsubscribed, error | |
| 114 message normal, chat, groupchat, headline, error | |
| 115 | |
| 116 **Note:** The type 'available' for presence does not actually appear in | |
| 117 the protocol. Available presence is signalled by the omission of a type. | |
| 118 Similarly, a message stanza with no type is equivalent to one of type | |
| 119 'normal'. mod\_firewall handles these cases for you automatically. | |
| 120 | |
| 121 #### INSPECT | |
| 122 | |
| 123 INSPECT takes a 'path' through the stanza to get a string (an attribute | |
| 124 value or text content). An example is the best way to explain. Let's | |
| 125 check that a user is not trying to register an account with the username | |
| 126 'admin'. This stanza comes from [XEP-0077: In-band | |
| 127 Registration](http://xmpp.org/extensions/xep-0077.html#example-4): | |
| 128 | |
| 129 <iq type='set' id='reg2'> | |
| 130 <query xmlns='jabber:iq:register'> | |
| 131 <username>bill</username> | |
| 132 <password>Calliope</password> | |
| 133 <email>bard@shakespeare.lit</email> | |
| 134 </query> | |
| 135 </iq> | |
| 136 | |
| 137 KIND: iq | |
| 138 TYPE: set | |
| 139 PAYLOAD: jabber:iq:register | |
| 140 INSPECT: {jabber:iq:register}query/username#=admin | |
| 141 BOUNCE=not-allowed The username 'admin' is reserved. | |
| 142 | |
| 143 That weird string deserves some explanation. It is a path, divided into | |
| 144 segments by '/'. Each segment describes an element by its name, | |
| 145 optionally prefixed by its namespace in curly braces ('{...}'). If the | |
| 146 path ends with a '\#' then the text content of the last element will be | |
| 147 returned. If the path ends with '@name' then the value of the attribute | |
| 148 'name' will be returned. | |
| 149 | |
| 150 INSPECT is somewhat slower than the other stanza matching conditions. To | |
| 151 minimise performance impact, always place it below other faster | |
| 152 condition checks where possible (e.g. above we first checked KIND, TYPE | |
| 153 and PAYLOAD matched before INSPECT). | |
| 154 | |
| 155 ### Sender/recipient matching | |
| 156 | |
| 157 Condition Matches | |
| 158 ----------- ------------------------------------------------------- | |
| 159 `FROM` The JID in the 'from' attribute matches the given JID | |
| 160 `TO` The JID in the 'to' attribute matches the given JID | |
| 161 | |
| 162 These conditions both accept wildcards in the JID when the wildcard | |
| 163 expression is enclosed in angle brackets ('\<...\>'). For example: | |
| 164 | |
| 165 # All users at example.com | |
| 166 FROM: <*>@example.com | |
| 167 | |
| 168 # The user 'admin' on any subdomain of example.com | |
| 169 FROM: admin@<*.example.com> | |
| 170 | |
| 171 You can also use [Lua's pattern | |
| 172 matching](http://www.lua.org/manual/5.1/manual.html#5.4.1) for more | |
| 173 powerful matching abilities. Patterns are a lightweight | |
| 174 regular-expression alternative. Simply contain the pattern in double | |
| 175 angle brackets. The pattern is automatically anchored at the start and | |
| 176 end (so it must match the entire portion of the JID). | |
| 177 | |
| 178 # Match admin@example.com, and admin1@example.com, etc. | |
| 179 FROM: <<admin%d*>>@example.com | |
| 180 | |
| 181 **Note:** It is important to know that 'example.com' is a valid JID on | |
| 182 its own, and does **not** match 'user@example.com'. To perform domain | |
| 183 whitelists or blacklists, use Zones. | |
| 184 | |
| 185 **Note:** Some chains execute before Prosody has performed any | |
| 186 normalisation or validity checks on the to/from JIDs on an incoming | |
| 187 stanza. It is not advisable to perform access control or similar rules | |
| 188 on JIDs in these chains (see the chain documentation for more info). | |
| 189 | |
| 190 ### Time and date | |
| 191 | |
| 192 #### TIME | |
| 193 | |
| 194 Matches stanzas sent during certain time periods. | |
| 195 | |
| 196 Condition Matches | |
| 197 ----------- ------------------------------------------------------------------------------------------- | |
| 198 TIME When the current server local time is within one of the comma-separated time ranges given | |
| 199 | |
| 200 TIME: 10pm-6am, 14:00-15:00 | |
| 201 REPLY=Zzzz. | |
| 202 | |
| 203 #### DAY | |
| 204 | |
| 205 It is also possible to match only on certain days of the week. | |
| 206 | |
| 207 Condition Matches | |
| 208 ----------- ----------------------------------------------------------------------------------------------------- | |
| 209 DAY When the current day matches one, or falls within a rage, in the given comma-separated list of days | |
| 210 | |
| 211 Example: | |
| 212 | |
| 213 DAY: Sat-Sun, Wednesday | |
| 214 REPLY=Sorry, I'm out enjoying life! | |
| 215 | |
| 216 ### Rate-limiting | |
| 217 | |
| 218 It is possible to selectively rate-limit stanzas, and use rules to | |
| 219 decide what to do with stanzas when over the limit. | |
| 220 | |
| 221 First, you must define any rate limits that you are going to use in your | |
| 222 script. Here we create a limiter called 'normal' that will allow 2 | |
| 223 stanzas per second, and then we define a rule to bounce messages when | |
| 224 over this limit. Note that the `RATE` definition is not part of a rule | |
| 225 (multiple rules can share the same limiter). | |
| 226 | |
| 227 %RATE normal: 2 (burst 3) | |
| 228 | |
| 229 KIND: message | |
| 230 LIMIT: normal | |
| 231 BOUNCE=policy-violation (Sending too fast!) | |
| 232 | |
| 233 The 'burst' parameter on the rate limit allows you to spread the limit | |
| 234 check over a given time period. For example the definition shown above | |
| 235 will allow the limit to be temporarily surpassed, as long as it is | |
| 236 within the limit after 3 seconds. You will almost always want to specify | |
| 237 a burst factor. | |
| 238 | |
| 239 Both the rate and the burst can be fractional values. For example a rate | |
| 240 of 0.1 means only one event is allowed every 10 seconds. | |
| 241 | |
| 242 The LIMIT condition actually does two things; first it counts against | |
| 243 the given limiter, and then it checks to see if the limiter over its | |
| 244 limit yet. If it is, the condition matches, otherwise it will not. | |
| 245 | |
| 246 Condition Matches | |
| 247 ----------- -------------------------------------------------------------------------------------------------- | |
| 248 `LIMIT` When the named limit is 'used up'. Using this condition automatically counts against that limit. | |
| 249 | |
| 250 **Note:** Reloading mod\_firewall resets the current state of any | |
| 251 limiters. | |
| 252 | |
| 253 Actions | |
| 254 ------- | |
| 255 | |
| 256 Actions come after all conditions in a rule block. There must be at | |
| 257 least one action, though conditions are optional. | |
| 258 | |
| 259 An action without parameters ends with a full-stop/period ('.'), and one | |
| 260 with parameters uses an equals sign ('='): | |
| 261 | |
| 262 # An action with no parameters: | |
| 263 DROP. | |
| 264 | |
| 265 # An action with a parameter: | |
| 266 REPLY=Hello, this is a reply. | |
| 267 | |
| 268 ### Route modification | |
| 269 | |
| 270 The most common actions modify the stanza's route in some way. Currently | |
| 271 the first matching rule to do so will halt further processing of actions | |
| 272 and rules (this may change in the future). | |
| 273 | |
| 274 Action Description | |
| 275 ----------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------- | |
| 276 `PASS.` Stop executing actions and rules on this stanza, and let it through this chain. | |
| 277 `DROP.` Stop executing actions and rules on this stanza, and discard it. | |
| 278 `REDIRECT=jid` Redirect the stanza to the given JID. | |
| 279 `REPLY=text` Reply to the stanza (assumed to be a message) with the given text. | |
| 280 `BOUNCE.` Bounce the stanza with the default error (usually service-unavailable) | |
| 281 `BOUNCE=error` Bounce the stanza with the given error (MUST be a defined XMPP stanza error, see [RFC6120](http://xmpp.org/rfcs/rfc6120.html#stanzas-error-conditions). | |
| 282 `BOUNCE=error (text)` As above, but include the supplied human-readable text with a description of the error | |
| 283 `COPY=jid` Make a copy of the stanza and send the copy to the specified JID. | |
| 284 | |
| 285 ### Stanza modification | |
| 286 | |
| 287 These actions make it possible to modify the content and structure of a | |
| 288 stanza. | |
| 289 | |
| 290 Action Description | |
| 291 ------------------------ ------------------------------------------------------------------------ | |
| 292 `STRIP=name` Remove any child elements with the given name in the default namespace | |
| 293 `STRIP=name namespace` Remove any child elements with the given name and the given namespace | |
| 294 `INJECT=xml` Inject the given XML into the stanza as a child element | |
| 295 | |
| 296 ### Informational | |
| 297 | |
| 298 Action Description | |
| 299 --------------- ------------------------------------------------------------------------------------------------------------------------ | |
| 300 `LOG=message` Logs the given message to Prosody's log file. Optionally prefix it with a log level in square brackets, e.g. `[debug]` |