= ACL list = == Regular Expression ACLs == Some ACLs just try to match simple text, so the have the exactly same behavior. * sender - evaluated at least on smtpd_sender_restrictions * recipient - evaluated at least on smtpd_recipient_restrictions * client_name * helo_name - evaluated at least on smtpd_helo_restrictions * sasl_username - evaluated at least on smtpd_sender_restrictions * sasl_method - evaluated at least on smtpd_sender_restrictions * sasl_sender - evaluated at least on smtpd_sender_restrictions * reverse_client_name {i} sasl_username, sasl_method and sasl_sender require Postfix 2.2 or latter This ACLs supports regular expressions, so you can use the full power of the [[http://docs.python.org/lib/re-syntax.html|Python Regular Expression library]]. Some examples: {{{ acl bad_sender sender foo@foo.com bar@bar.com acl bad_domain sender @foo.com @bar.com acl trap recipient trap@ acl other_trap recipient (sales|contact)@bar.com acl dyn_host client_name (.dynamic.|.dhcp.) acl mycontext policy_context context1 context2 silent }}} In policy_context ACL you don't want to see checking of the ACL. ''silent'' can be specified anywhere as argument. == client_address == This ACL supports IPv4 and IPv6. {{{ acl machine client_address 192.168.0.10 acl net client_address 192.168.1.0/24 acl net client_address 192.168.2.0/255.255.255.0 acl net client_address 192.168.3.0-192.168.3.255 }}} == day == This ACL can be evaluated at any time. Weekdays are not case sensitive {{{ Monday Tuesday Wednesday Thursday Friday Saturday Sunday acl weekend day SATURDAY,Sunday acl notweekend day Monday Tuesday-Friday }}} == time == This ACL can be evaluated at any time. {{{ acl work time 08:00-17:00 }}} == rbl == This ACL will query the RBL host supplied with the client IP address and it can be evaluated at any time. {{{ acl check_rbl rbl zen.spamhaus.org bl.spamcop.net }}} == size == {i} Requires Postfix 2.2 or latter The value of this ACL is specified in bytes and can be evaluated at smtpd_sender_restrictions. Note that it is possible to know the size of a message if the client is using the [[http://tools.ietf.org/html/rfc1870|SIZE]] extension of the [[http://en.wikipedia.org/wiki/SMTP_extension|ESMTP]] protocol. Although, use this ACL as the last verification on your policy, after RBL checks, greylisting, helo and sender verifications, etc, because it is much more probable that a legit server uses [[http://en.wikipedia.org/wiki/SMTP_extension|ESMTP]] and the [[http://tools.ietf.org/html/rfc1870|SIZE]] extension. Refer to this thread on the postfix-users mailing list about this topic, very good information: http://thread.gmane.org/gmane.mail.postfix.user/182300. If you need 100% accuracy when controlling message sizes, then call the policy daemon from [[http://www.postfix.org/postconf.5.html#smtpd_end_of_data_restrictions|smtpd_end_of_data_restrictions]]. {{{ acl 10mb size 10240000 acl 20mb size 20480000 }}} == greylisting == For more information about greylisting, check the links below: * Wikipedia entry about it: http://en.wikipedia.org/wiki/Greylisting * The "official" website: http://www.greylisting.org/ * The Next Step in the Spam Control War: Greylisting, by Evan Harris http://projects.puremagic.com/greylisting/whitepaper.html The value of the ''greylisting'' ACL is a list of parameters separated by spaces and/or commas. This parameters are: * '''time''': the period for not accepting a message, in '''minutes'''. Default: 5 * '''lifetime''': how long should a validated tripled be used, in '''minutes'''. Default: 1440 * '''backend''': the storage type, possible values: '''disk''', '''memory''' and '''memcached'''. Default: memory * '''host''': the IP and port to connect using the '''memcached''' backend. Default: 127.0.0.1:11211 * '''root''': parameter used by the '''disk''' backend, witch corresponds to the root directory to store the greylist database. We use a custom storage system, just using directories and files. Default: /var/cache/apolicy {{{ acl grey_1 greylisting acl grey_2 greylisting time=2,lifetime=14400 backend=disk root=/var/cache/apolicy/ }}} The '''root''' parameter must point to a directory owned by the user '''nobody''', or the user specified by the parameter ''user'' in the ''main.conf'' configuration file. Considering performance, both methods are good for a medium sized server, around 100k requests per day. We don't have any benchmark to measure how far they scale yet. Keeping 100k entries in memory, the process will use around 15 to 18 megabytes, not that much considering how cheap 1 Gb of RAM is today. If you need higher persistence, consider using the disk backend, it can create 30k entries in a few seconds. === memcached backend === {i} Available in apolicy 0.73 and latter ''memcached'' is a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load. Please read more about ''memcached'' on [[http://www.socialtext.net/memcached/index.cgi?faq]]. One of the key advantages of using ''memcached'' is that you can share the greylisting database with many ''apolicy'' servers and keep memory usage under control, avoiding maintaining a relational database and reducing overhead. To use a ''memcached'' daemon, configure a greylisting ACL like this: {{{ acl grey greylisting time=2 lifetime=1440 host=127.0.0.1:11211 backend=memcached }}} Note that the '''host''' parameters is only used with the ''memcached'' backend and the format is IP:PORT. The default value is '''127.0.0.1:11211'''. In case you use a ''memcached'' daemon on another server, specify the IP and port like this: 192.168.1.2:11211. When ''apolicy'' starts it tries to store a test object on the ''memcached'' daemon, if it fails ''apolicy'' will exit immediately and log the error. While ''apolicy'' is running, if it is not possible to store objects in the ''memcached'' daemon, the ACL will return false and an error will be logged. === disk backend === The ''disk'' backend uses just files and directories to store the greylisting triplets (sender, recipient, client IP). Inside the ''root'' directory there is a structure like this: {{{ [root@friends apolicy]# pwd /var/cache/apolicy [root@friends apolicy]# ls -lR ./116/11: total 0 -rw------- 1 nobody nobody 0 Apr 24 11:13 1097c1ccfeb492ce1a3dfe9f3d503d70 -rw------- 1 nobody nobody 0 Apr 26 13:52 93322022115a05a66f4688f3a815fe79 ./140/113: total 0 -rw------- 1 nobody nobody 0 May 6 02:28 74408c779e34b46e929117a410533d18 -rw------- 1 nobody nobody 0 May 5 17:49 d93dbf9d3fbe38a19d1505a9aadeac92 ./138/243: total 0 -rw------- 1 nobody nobody 0 Apr 21 19:23 53efc51cc0d0414bd0b343724804f819 -rw------- 1 nobody nobody 0 Apr 24 05:22 6278c0c068d06b659a8316f5657d40ee }}} Basically we get the first two octets of the client IP address and create two directories. So if the client IP is 138.243.10.40, inside the ''root'' directory given to the greylisting ACL, for example the default ''/var/cache/apolicy'', this path will be created: '''/var/cache/apolicy/138/243'''. Then, inside this directory an empty file is created using as name a MD5 hash of the triplet like md5(sender + recipient + client_ip). Using the file creation time and the current time the difference is calculated and we have a working greylisting. The ''disk'' backend uses very low disk space, read/write performance is very good, avoids the overhead of a relational database and is very simple to setup. An example from a production server: {{{ [root@friends apolicy]# pwd /var/cache/apolicy [root@friends apolicy]# find . -type f | wc -l 729907 [root@friends apolicy]# du . -hc --max-depth=1 | grep total 80M total }}} To store more than 700.000 entries, just 80 Megabytes are needed. There is no need to clean and delete old files. If the ''lifetime'' for an authenticated triplet is set to 5 days and a MD5 hash of a triplet is older then 5 days, the modified time is updated, instead of cleaning up the expired triplets and creating then again. We call this ''lazy expiration''. == spf == If the ''sender'' is authorized, neutral, or softfailed by and SPF record this ACL returns '''False'''. If the ''sender'' is not authorized by an SPF record this ACL returns '''True'''. For more information on how and why use SPF, check the links below: * OpenSPF official site: http://www.openspf.org/ * A summary about SPF: http://old.openspf.org/for-mit-spam-conference.html The value of the ''spf'' ACL is a list of parameters separated by spaces and/or commas. The parameters corresponds to the SPF qualifiers, and you can customize what to do with witch one. The SPF specification states that a ''neutral'' or ''softfail'' qualifier should not result a rejection, but lets say you want that every domain that declares itself neutral or softfail, even if the message is not authorized, must be rejected in case of a not authorized message. Possible parameters, all of them must be '''reject''' or '''pass''': * pass, default pass * fail, default reject * neutral default pass * softfail default pass * none default pass * temperror default pass * permerror default pass {{{ acl restrict_spf spf softfail=reject,neutral=reject }}} Or to use the default behavior: {{{ acl normal_spf spf }}} == protocol_name == {i} Available in apolicy 0.72 and latter This ACL compares the current protocol used by the client, either '''SMTP''', '''ESMTP''' and '''LMTP'''. Any value different from that will result in an error when ''apolicy'' starts. {{{ acl smtp protocol_name SMTP acl esmtp protocol_name esmtp acl smtp protocol_name FOO # invalid value }}} == log == {i} Available in apolicy 0.72 and latter When this ACL is processed it generates a log event with the requested parameters. {{{ acl log_sender_helo log content=sender:helo acl log_rbl log prefix=RBL content=client_address:helo:sender }}} The first line logs the sender and the HELO message used during the SMTP transaction. The second line logs the client IP, the HELO message and the sender, prefixed by the string ''RBL''. The ''prefix'' parameter can help identify the log event in the log files. Possible parameters: * '''prefix''': Adds a message before the requested content logged. Default: LOG: * '''content''': The actual content to be logged separated by colons. The parameters are exactly the same used in the policy protocol. There is a list the possible values: request, protocol_state, protocol_name, helo_name, queue_id, sender, recipient, recipient_count, client_address, client_name, reverse_client_name, instance sasl_method, sasl_username, sasl_sender, size, ccert_subject, ccert_issuer, ccert_fingerprint, encryption_protocol, encryption_cipher, encryption_keysize, etrn_domain, stress. Default: client_address:sender:recipient * '''result''': The default behavior of the ''log'' ACL is to return false to not interfere. But it is possible to change that using the parameter ''result''. Possible values '''true''' or '''false'''. Default: false == country == {i} Available in apolicy 0.73 and latter This ACL will query the hostip.info to geolocate client IP addresses. {{{ acl italy country IT acl sud_america country PE PY UY,BR acl china country CN http_proxy=http://user:password@192.168.10.20:8080,api_url=http://www.bertera.it/country.php?ip=%s,timeout=2 }}} The country must be match with the value returned from hostip.info. Generally it's [[http://www.iso.org/iso/country_codes.htm|ISO3166]]. But there are specific cases where obsolete or invalid codes are used, largely because the source of the information (the various NICs or the netblock owner) don't validate or update it. You can find the complete list of country code at http://www.hostip.info/bulk/countries.html Possible Parameters: * '''api_url''': The alternative URL for HTTP query, must be in the format: http://host.domain.com/foo.bar?var=%s the '''%s''' statement is replaced with client ip address * '''http_proxy''': You can configure proxy for the connection, the optional user and password must be written in the url as in example * '''timeout''': Seconds of timeout for http connections == stress == {i} Available in apolicy 0.73 and latter. Requires Postfix 2.5 or latter This ACL detect server overload. See the [[http://www.postfix.org/STRESS_README.html|STRESS_README]] document for further information. {{{ acl overload stress }}} == message flow control == This option can control how many recipients a sender is allowed to send. Requires a management datasource with given capabilities, SQL for now. It optionally can use a second datasource with custom quotas for senders, tested with LDAP datasource. Each datasource with the same driver must have an unique identifier. The management datasource need to add/remove/query information from the database, so specific information is neeeded in a configuration file. * 'insert' clause to note down recipients per sender. * 'select' clause to count recipients per sender * 'delete' clause to clean old recipients per sender * 'caught' clause to verify if a sender is in the database * 'catch' clause to blacklist a sender The optional custom quota datasource need to query information from the database, so likewise a configuration file is needed. The values, if found, overrides the defaults (the last ACL option). * 'quota_filter' query to select a specific sender information * 'quota_attribute' attribute that can contains custom quota information. The format is : 'mquota:i/is:i/im:i/ih:i/id' i is an integer. For example: ''mail:service:mquota:10/3s:30/2m:40/1h:100:1d'' to limit to a máximun of 10 recipients in 3 seconds, 30 recipients in 2 minutes, etc. To apply sender message quota {{{ acl outer_quota mquota quotas:/etc/apolicy/psql_manager_db.conf limit=10/3s:30/2m:40/1h:100:1d acl users_quota mquota quotas:/etc/apolicy/manager_db.conf ldap:/etc/apolicy/custom_quota.conf limit=30/1m:100/1h:200:1d }}} If the sender exceed the quota then he will be blaclisted in the database. The distribution comes with a detailed example.