]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.8-20230312
authorWietse Venema <wietse@porcupine.org>
Sun, 12 Mar 2023 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 13 Mar 2023 12:53:54 +0000 (08:53 -0400)
27 files changed:
postfix/HISTORY
postfix/WISHLIST
postfix/html/postconf.5.html
postfix/html/smtpd.8.html
postfix/man/man5/postconf.5
postfix/man/man8/smtpd.8
postfix/mantools/postlink
postfix/proto/postconf.proto
postfix/proto/stop.double-cc
postfix/proto/stop.double-history
postfix/proto/stop.spell-cc
postfix/proto/stop.spell-history
postfix/src/cleanup/cleanup_milter.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/smtp/smtp_addr.c
postfix/src/smtp/smtp_proto.c
postfix/src/smtpd/Makefile.in
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd.h
postfix/src/smtpd/smtpd_peer.c
postfix/src/tls/tls_fprint.c
postfix/src/util/Makefile.in
postfix/src/util/net_mask_top.c [new file with mode: 0644]
postfix/src/util/net_mask_top.h [new file with mode: 0644]
postfix/src/util/sock_addr.c
postfix/src/util/sock_addr.h

index cd2d89f9f3588822aae787d934aa94bc7cec0506..245645be378634c38cf1ce6f80dd371a0402fa6c 100644 (file)
@@ -26921,3 +26921,31 @@ Apologies for any names omitted.
        example is to capture output from "postmulti -p status" to
        figure out which instances are or are not running. Files:
        postfix/postfix.c, postlog/postlog.c.
+
+20230209
+
+       Cleanup: in smtp_service_addr() refined the loop detection
+       code for SRV lookup. File: smtp/smtp_addr.c.
+
+       Cleanup: renamed macros with invisible side effects and
+       implicit inputs to upper case.  Verified that the compiled
+       code did not change. File: tls_fprint.c.
+
+20230310
+
+       Cleanup: the milter header/body checks logged less text (up
+       to 60 bytes) than the 'original' header/body checks (up to
+       200 bytes). Problem reported by Aleksandr Stankevic. Fixed
+       the same inconsistency in the Postfix SMTP client. Files:
+       cleanup/cleanup_milter.c, smtp/smtp_proto.c.
+
+20230311
+
+       Hardening: the Postfix SMTP server can now aggregate
+       smtpd_client_*_rate and smtpd_client_*_count statistics by
+       network block, as specified with smtpd_client_ipv4_prefix_length
+       (default 32, no aggregation) and smtpd_client_ipv6_prefix_length
+       (default 72, aggregation by /72 network blocks). The latter
+       raises the bar for a memory exhaustion attack. Files:
+       util/net_mask_top.[hc], smtpd/smtpd.c, smtpd/smtpd_peer.c,
+       mantools/postlink, proto/postconf.proto.
index 71b1685caab1d2281f86b7364e94cb8affaecb68..7c891253c67b6330d11ee0b080ce85a29f3c28c7 100644 (file)
@@ -14,6 +14,13 @@ Wish list:
        Multi-recipient support in sender/recipient_bcc_maps and
        always_bcc.
 
+       mail_conf_xxx supprt for non-negative numbers (i.e. 
+       numbers with a lower bound of zero).
+
+       Log anvil transgressions with their address range (in
+       addition to the offending IP address. We should not disclose
+       to random clients how we aggregate anvil event counters.
+
        Should "postconf -f" pretty-print text inside {}?
 
        Is there any code that calls attr_scan*() and that works
index a83d227f4515a2733ed00e4885dd985fa7704506..10816cb9aaea08350873d811cebb95b596f14b82 100644 (file)
@@ -14639,6 +14639,33 @@ This feature is available in Postfix 2.2 and later.
 </p>
 
 
+</DD>
+
+<DT><b><a name="smtpd_client_ipv4_prefix_length">smtpd_client_ipv4_prefix_length</a>
+(default: 32)</b></DT><DD>
+
+<p> Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+by IPv4 network blocks with the specified network prefix. Aggregation
+reduces the <a href="anvil.8.html">anvil(8)</a> resources needed to maintain counters. By
+default, aggregation is disabled for IPv4. </p>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
+
+
+</DD>
+
+<DT><b><a name="smtpd_client_ipv6_prefix_length">smtpd_client_ipv6_prefix_length</a>
+(default: 72)</b></DT><DD>
+
+<p> Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+by IPv6 network blocks with the specified network prefix. Aggregation
+reduces the <a href="anvil.8.html">anvil(8)</a> resources needed to maintain counters. By
+default, aggregation is enabled for IPv6.
+</p>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="smtpd_client_message_rate_limit">smtpd_client_message_rate_limit</a>
index dca57a0ace46213653dd7bd92f00d334b1f44548..ecf775cf891c895fa16e7b93763bae89c5846f1b 100644 (file)
@@ -962,6 +962,16 @@ SMTPD(8)                                                              SMTPD(8)
        <b><a href="postconf.5.html#header_from_format">header_from_format</a> (standard)</b>
               The format of the Postfix-generated <b>From:</b> header.
 
+       Available in Postfix version 3.8 and later:
+
+       <b><a href="postconf.5.html#smtpd_client_ipv4_prefix_length">smtpd_client_ipv4_prefix_length</a> (32)</b>
+              Aggregate smtpd_client_*_count and  smtpd_client_*_rate  statis-
+              tics by IPv4 network blocks with the specified network prefix.
+
+       <b><a href="postconf.5.html#smtpd_client_ipv6_prefix_length">smtpd_client_ipv6_prefix_length</a> (72)</b>
+              Aggregate  smtpd_client_*_count  and smtpd_client_*_rate statis-
+              tics by IPv6 network blocks with the specified network prefix.
+
 <b>TARPIT CONTROLS</b>
        When a remote SMTP client makes errors, the  Postfix  SMTP  server  can
        insert  delays  before  responding. This can help to slow down run-away
index 38fabbb23bfaa8ce40684d6e962182cb820e9d66..2d84788ba46cd60b88293430f63d9e60169c19ef 100644 (file)
@@ -9956,6 +9956,20 @@ parent_domain_matches_subdomains parameter value (Postfix 3.0 and
 later).
 .PP
 This feature is available in Postfix 2.2 and later.
+.SH smtpd_client_ipv4_prefix_length (default: 32)
+Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+by IPv4 network blocks with the specified network prefix. Aggregation
+reduces the \fBanvil\fR(8) resources needed to maintain counters. By
+default, aggregation is disabled for IPv4.
+.PP
+This feature is available in Postfix 3.8 and later.
+.SH smtpd_client_ipv6_prefix_length (default: 72)
+Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+by IPv6 network blocks with the specified network prefix. Aggregation
+reduces the \fBanvil\fR(8) resources needed to maintain counters. By
+default, aggregation is enabled for IPv6.
+.PP
+This feature is available in Postfix 3.8 and later.
 .SH smtpd_client_message_rate_limit (default: 0)
 The maximal number of message delivery requests that any client is
 allowed to make to this service per time unit, regardless of whether
index 3bfe323c638c4b41d405fa8637937fe828276e67..3062953e3c80e25661320e167e5c2a0bd458bd92 100644 (file)
@@ -841,6 +841,14 @@ DATA and BDAT requests, when deadlines are enabled with
 smtpd_per_request_deadline.
 .IP "\fBheader_from_format (standard)\fR"
 The format of the Postfix\-generated \fBFrom:\fR header.
+.PP
+Available in Postfix version 3.8 and later:
+.IP "\fBsmtpd_client_ipv4_prefix_length (32)\fR"
+Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+by IPv4 network blocks with the specified network prefix.
+.IP "\fBsmtpd_client_ipv6_prefix_length (72)\fR"
+Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+by IPv6 network blocks with the specified network prefix.
 .SH "TARPIT CONTROLS"
 .na
 .nf
index 39057abe5c0bd366f7c610845b7fa8f97afacbd6..7185c757c97c65778ae3bb040a485c61707e30bc 100755 (executable)
@@ -543,6 +543,8 @@ while (<>) {
     s;\bsmtpd_client_port_logging\b;<a href="postconf.5.html#smtpd_client_port_logging">$&</a>;g;
     s;\bsmtpd_client_recipient_rate_limit\b;<a href="postconf.5.html#smtpd_client_recipient_rate_limit">$&</a>;g;
     s;\bsmtpd_client_new_tls_session_rate_limit\b;<a href="postconf.5.html#smtpd_client_new_tls_session_rate_limit">$&</a>;g;
+    s;\bsmtpd_client_ipv4_prefix_length\b;<a href="postconf.5.html#smtpd_client_ipv4_prefix_length">$&</a>;g;
+    s;\bsmtpd_client_ipv6_prefix_length\b;<a href="postconf.5.html#smtpd_client_ipv6_prefix_length">$&</a>;g;
     s;\bsmtpd_client_restrictions\b;<a href="postconf.5.html#smtpd_client_restrictions">$&</a>;g;
     s;\bsmtpd_command_filter\b;<a href="postconf.5.html#smtpd_command_filter">$&</a>;g;
     s;\bsmtpd_data_restrictions\b;<a href="postconf.5.html#smtpd_data_restrictions">$&</a>;g;
index 20a22cfafee31d0f249cf0cb3cffc802f80dff26..d661dda65b21c5d3eaf5cc726fa6a3cf00da39fd 100644 (file)
@@ -18598,3 +18598,22 @@ lookup as if SRV record lookup was not enabled. </p>
 to MX or IP address lookup as if SRV record lookup was not enabled. <p>
 
 <p> This feature is available in Postfix 3.8 and later. </p>
+
+%PARAM smtpd_client_ipv4_prefix_length 32
+
+<p> Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+by IPv4 network blocks with the specified network prefix. Aggregation
+reduces the anvil(8) resources needed to maintain counters. By
+default, aggregation is disabled for IPv4. </p>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
+
+%PARAM smtpd_client_ipv6_prefix_length 72
+
+<p> Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+by IPv6 network blocks with the specified network prefix. Aggregation
+reduces the anvil(8) resources needed to maintain counters. By
+default, aggregation is enabled for IPv6.
+</p>
+
+<p> This feature is available in Postfix 3.8 and later. </p>
index 333b55738ddff56a66a6ae3c68cbc091b504a607..09a32d8748d0572fb3f43a5059571c9a1590d2aa 100644 (file)
@@ -331,3 +331,4 @@ USE_FNV_32BIT  USE_FNV_32BIT
 void  void cleanup_milter_receive state count 
  struct DICT open const char int int dict_xx_open 
  Available in in Postfix version 2 3 3 7 
+length  length of 0 31 0 127 
index ff18887cdb5f05efbf438753152bf25a5ccc26f6..ff1eceaf41e39eddcd5f1c6df280e305c0c4c112 100644 (file)
@@ -35,3 +35,4 @@ proto  proto SASL_README html proto SQLITE_README html
  tls tls_proxy h tlsproxy tlsproxy c 
  postfix postfix c postlog postlog c 
  postfix postfix c postlog postlog c 
+ util net_mask_top hc smtpd smtpd c smtpd smtpd_peer c 
index b1fce0d3b61a550e489d3acb0ab82832395dfb45..ec3df3008b8da23c48118e0ec0915ad488d0bde7 100644 (file)
@@ -1793,3 +1793,6 @@ Korbar
 ign
 noport
 nopref
+ADDRP
+iffalse
+iftrue
index e462649750c2b241e11afc88aa39b43f3e6b85be..9cca6240f3d0fbdc4d48720ad6de9caa6a5c07c6 100644 (file)
@@ -47,3 +47,5 @@ modernisms
 Bordo
 css
 makemanidx
+soho
+soho
index 11510b55959ebf36e3c9d078c8ebc151655f34f8..b71a6dd3afc6d2317851c91b09d868a2e91bd59d 100644 (file)
@@ -244,7 +244,7 @@ static void cleanup_milter_hbc_log(void *context, const char *action,
     const CLEANUP_STATE *state = (CLEANUP_STATE *) context;
     const char *attr;
 
-    vstring_sprintf(state->temp1, "%s: milter-%s-%s: %s %.60s from %s[%s];",
+    vstring_sprintf(state->temp1, "%s: milter-%s-%s: %s %.200s from %s[%s];",
                    state->queue_id, where, action, where, line,
                    state->client_name, state->client_addr);
     if (state->sender)
index ad227e240938294dd6fb2bf3bc907e8e126f184a..d83c9eb506f80457cfb9339ecb0a7fb8b775604e 100644 (file)
@@ -3198,6 +3198,16 @@ extern int var_smtpd_cntls_limit;
 #define DEF_SMTPD_CAUTH_LIMIT          0
 extern int var_smtpd_cauth_limit;
 
+#define VAR_SMTPD_CIPV4_PREFIX         "smtpd_client_ipv4_prefix_length"
+#define DEF_SMTPD_CIPV4_PREFIX         32
+#define MAX_SMTPD_CIPV4_PREFIX         32
+extern int var_smtpd_cipv4_prefix;
+
+#define VAR_SMTPD_CIPV6_PREFIX         "smtpd_client_ipv6_prefix_length"
+#define DEF_SMTPD_CIPV6_PREFIX         72
+#define MAX_SMTPD_CIPV6_PREFIX         128
+extern int var_smtpd_cipv6_prefix;
+
 #define VAR_SMTPD_HOGGERS              "smtpd_client_event_limit_exceptions"
 #define DEF_SMTPD_HOGGERS              "${smtpd_client_connection_limit_exceptions:$" VAR_MYNETWORKS "}"
 extern char *var_smtpd_hoggers;
index 52bc0bdf71eb7e4e6c2926026ea3242d93267cd6..e07da42337537bafa98a54024a000cf44aee0dd1 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20230308"
+#define MAIL_RELEASE_DATE      "20230312"
 #define MAIL_VERSION_NUMBER    "3.8"
 
 #ifdef SNAPSHOT
index a31cb38c1c04cde2e000b85180ac5a6e3cd64a4e..5e23388d69da8b62e159516d03b445de29aff765 100644 (file)
@@ -840,7 +840,6 @@ DNS_RR *smtp_service_addr(const char *name, const char *service, DNS_RR **mxrr,
        dsb_status(why, "5.4.4");
        break;
     }
-    *found_myself |= (self != 0);
 
     /*
      * If permitted, fall back to non-SRV record lookups.
@@ -854,5 +853,12 @@ DNS_RR *smtp_service_addr(const char *name, const char *service, DNS_RR **mxrr,
        else
            addr_list = smtp_host_addr(name, misc_flags, why);
     }
+
+    /*
+     * Only if we're not falling back.
+     */ 
+    else {
+       *found_myself |= (self != 0);
+    }
     return (addr_list);
 }
index 2ceb0f35c1d709e98605d85732b99c2969a369a5..097d51842351f441e09f3ac86e13eb92bb20b6c8 100644 (file)
@@ -1146,10 +1146,10 @@ static void smtp_hbc_logger(void *context, const char *action,
     const SMTP_STATE *state = (SMTP_STATE *) context;
 
     if (*text) {
-       msg_info("%s: %s: %s %.60s: %s",
+       msg_info("%s: %s: %s %.200s: %s",
                 state->request->queue_id, action, where, content, text);
     } else {
-       msg_info("%s: %s: %s %.60s",
+       msg_info("%s: %s: %s %.200s",
                 state->request->queue_id, action, where, content);
     }
 }
index f48d38f026db55e828a6634f5d073af755e9fdfd..422cbac5a7fac37a78c88ae03dfbc2861229ee95 100644 (file)
@@ -492,6 +492,7 @@ smtpd_peer.o: ../../include/myaddrinfo.h
 smtpd_peer.o: ../../include/mymalloc.h
 smtpd_peer.o: ../../include/name_code.h
 smtpd_peer.o: ../../include/name_mask.h
+smtpd_peer.o: ../../include/net_mask_top.h
 smtpd_peer.o: ../../include/nvtable.h
 smtpd_peer.o: ../../include/sock_addr.h
 smtpd_peer.o: ../../include/split_at.h
index 0807387fffeaf3a6a61fefbb9fe9284dec79f28f..7580629a0458bef1e7f9311ab8eaa3c0ac820d3f 100644 (file)
 /*     smtpd_per_request_deadline.
 /* .IP "\fBheader_from_format (standard)\fR"
 /*     The format of the Postfix-generated \fBFrom:\fR header.
+/* .PP
+/*     Available in Postfix version 3.8 and later:
+/* .IP "\fBsmtpd_client_ipv4_prefix_length (32)\fR"
+/*     Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+/*     by IPv4 network blocks with the specified network prefix.
+/* .IP "\fBsmtpd_client_ipv6_prefix_length (72)\fR"
+/*     Aggregate smtpd_client_*_count and smtpd_client_*_rate statistics
+/*     by IPv6 network blocks with the specified network prefix.
 /* TARPIT CONTROLS
 /* .ad
 /* .fi
@@ -1411,6 +1419,8 @@ int     var_smtpd_cmail_limit;
 int     var_smtpd_crcpt_limit;
 int     var_smtpd_cntls_limit;
 int     var_smtpd_cauth_limit;
+int     var_smtpd_cipv4_prefix;
+int     var_smtpd_cipv6_prefix;
 char   *var_smtpd_hoggers;
 char   *var_local_rwr_clients;
 char   *var_smtpd_ehlo_dis_words;
@@ -2054,7 +2064,7 @@ static int smtpd_sasl_auth_cmd_wrapper(SMTPD_STATE *state, int argc,
        && anvil_clnt
        && var_smtpd_cauth_limit > 0
        && !namadr_list_match(hogger_list, state->name, state->addr)
-       && anvil_clnt_auth(anvil_clnt, state->service, state->addr,
+       && anvil_clnt_auth(anvil_clnt, state->service, state->anvil_range,
                           &rate) == ANVIL_STAT_OK
        && rate > var_smtpd_cauth_limit) {
        state->error_mask |= MAIL_ERROR_POLICY;
@@ -2512,7 +2522,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        && anvil_clnt
        && var_smtpd_cmail_limit > 0
        && !namadr_list_match(hogger_list, state->name, state->addr)
-       && anvil_clnt_mail(anvil_clnt, state->service, state->addr,
+       && anvil_clnt_mail(anvil_clnt, state->service, state->anvil_range,
                           &rate) == ANVIL_STAT_OK
        && rate > var_smtpd_cmail_limit) {
        state->error_mask |= MAIL_ERROR_POLICY;
@@ -2906,7 +2916,7 @@ static int rcpt_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        && anvil_clnt
        && var_smtpd_crcpt_limit > 0
        && !namadr_list_match(hogger_list, state->name, state->addr)
-       && anvil_clnt_rcpt(anvil_clnt, state->service, state->addr,
+       && anvil_clnt_rcpt(anvil_clnt, state->service, state->anvil_range,
                           &rate) == ANVIL_STAT_OK
        && rate > var_smtpd_crcpt_limit) {
        state->error_mask |= MAIL_ERROR_POLICY;
@@ -4230,7 +4240,7 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
        && anvil_clnt
        && var_smtpd_crcpt_limit > 0
        && !namadr_list_match(hogger_list, state->name, state->addr)
-       && anvil_clnt_rcpt(anvil_clnt, state->service, state->addr,
+       && anvil_clnt_rcpt(anvil_clnt, state->service, state->anvil_range,
                           &rate) == ANVIL_STAT_OK
        && rate > var_smtpd_crcpt_limit) {
        state->error_mask |= MAIL_ERROR_POLICY;
@@ -5146,7 +5156,7 @@ static void smtpd_start_tls(SMTPD_STATE *state)
        && !xclient_allowed
        && anvil_clnt
        && !namadr_list_match(hogger_list, state->name, state->addr)
-       && anvil_clnt_newtls(anvil_clnt, state->service, state->addr,
+       && anvil_clnt_newtls(anvil_clnt, state->service, state->anvil_range,
                             &rate) == ANVIL_STAT_OK
        && rate > var_smtpd_cntls_limit) {
        state->error_mask |= MAIL_ERROR_POLICY;
@@ -5292,8 +5302,8 @@ static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
        && !xclient_allowed
        && anvil_clnt
        && !namadr_list_match(hogger_list, state->name, state->addr)
-       && anvil_clnt_newtls_stat(anvil_clnt, state->service, state->addr,
-                                 &rate) == ANVIL_STAT_OK
+       && anvil_clnt_newtls_stat(anvil_clnt, state->service,
+                                 state->anvil_range, &rate) == ANVIL_STAT_OK
        && rate > var_smtpd_cntls_limit) {
        state->error_mask |= MAIL_ERROR_POLICY;
        msg_warn("Refusing STARTTLS request from %s for service %s",
@@ -5560,7 +5570,7 @@ static void smtpd_proto(SMTPD_STATE *state)
                && anvil_clnt
                && !namadr_list_match(hogger_list, state->name, state->addr)
                && anvil_clnt_newtls_stat(anvil_clnt, state->service,
-                                   state->addr, &tls_rate) == ANVIL_STAT_OK
+                            state->anvil_range, &tls_rate) == ANVIL_STAT_OK
                && tls_rate > var_smtpd_cntls_limit) {
                state->error_mask |= MAIL_ERROR_POLICY;
                msg_warn("Refusing TLS service request from %s for service %s",
@@ -5586,8 +5596,9 @@ static void smtpd_proto(SMTPD_STATE *state)
            && !xclient_allowed
            && anvil_clnt
            && !namadr_list_match(hogger_list, state->name, state->addr)
-           && anvil_clnt_connect(anvil_clnt, state->service, state->addr,
-                                 &state->conn_count, &state->conn_rate)
+           && anvil_clnt_connect(anvil_clnt, state->service,
+                                 state->anvil_range, &state->conn_count,
+                                 &state->conn_rate)
            == ANVIL_STAT_OK) {
            if (var_smtpd_cconn_limit > 0
                && state->conn_count > var_smtpd_cconn_limit) {
@@ -5845,7 +5856,7 @@ static void smtpd_proto(SMTPD_STATE *state)
        && !xclient_allowed
        && anvil_clnt
        && !namadr_list_match(hogger_list, state->name, state->addr))
-       anvil_clnt_disconnect(anvil_clnt, state->service, state->addr);
+       anvil_clnt_disconnect(anvil_clnt, state->service, state->anvil_range);
 
     /*
      * Log abnormal session termination, in case postmaster notification has
@@ -6427,6 +6438,8 @@ int     main(int argc, char **argv)
        VAR_SMTPD_CRCPT_LIMIT, DEF_SMTPD_CRCPT_LIMIT, &var_smtpd_crcpt_limit, 0, 0,
        VAR_SMTPD_CNTLS_LIMIT, DEF_SMTPD_CNTLS_LIMIT, &var_smtpd_cntls_limit, 0, 0,
        VAR_SMTPD_CAUTH_LIMIT, DEF_SMTPD_CAUTH_LIMIT, &var_smtpd_cauth_limit, 0, 0,
+       VAR_SMTPD_CIPV4_PREFIX, DEF_SMTPD_CIPV4_PREFIX, &var_smtpd_cipv4_prefix, 0, MAX_SMTPD_CIPV4_PREFIX,
+       VAR_SMTPD_CIPV6_PREFIX, DEF_SMTPD_CIPV6_PREFIX, &var_smtpd_cipv6_prefix, 0, MAX_SMTPD_CIPV6_PREFIX,
 #ifdef USE_TLS
        VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0,
 #endif
index 0bb5bbbce026ede819a726baab49e831ecc4d47f..56ebc078da0d0de861d09a30fb397afda3c5c873 100644 (file)
@@ -77,6 +77,7 @@ typedef struct {
     char   *addr;                      /* client host address string */
     char   *port;                      /* port for logging */
     char   *namaddr;                   /* name[address]:port */
+    char   *anvil_range;               /* client address or network/length */
     char   *rfc_addr;                  /* address for RFC 2821 */
     int     addr_family;               /* address family */
     char   *dest_addr;                 /* Dovecot AUTH, Milter {daemon_addr} */
index 3a5c1d46bb3ce87a004c0fecf8e52649033dfb93..f212035440b6042fd0e66cf812247c27082d7f36 100644 (file)
 #include <sock_addr.h>
 #include <inet_proto.h>
 #include <split_at.h>
+#include <net_mask_top.h>
 
 /* Global library. */
 
@@ -250,10 +251,12 @@ static int smtpd_peer_sockaddr_to_hostaddr(SMTPD_STATE *state)
                state->addr = mystrdup(colonp + 1);
                state->rfc_addr = mystrdup(colonp + 1);
                state->addr_family = AF_INET;
-               aierr = hostaddr_to_sockaddr(state->addr, (char *) 0, 0, &res0);
+               aierr =
+                   hostaddr_to_sockaddr(state->addr, state->port, 0, &res0);
                if (aierr)
-                   msg_fatal("%s: cannot convert %s from string to binary: %s",
-                             myname, state->addr, MAI_STRERROR(aierr));
+                   msg_fatal("%s: cannot convert [%s]:%s to binary: %s",
+                             myname, state->addr, state->port,
+                             MAI_STRERROR(aierr));
                sa_length = res0->ai_addrlen;
                if (sa_length > sizeof(state->sockaddr))
                    sa_length = sizeof(state->sockaddr);
@@ -264,10 +267,10 @@ static int smtpd_peer_sockaddr_to_hostaddr(SMTPD_STATE *state)
            /*
             * Following RFC 2821 section 4.1.3, an IPv6 address literal gets
             * a prefix of 'IPv6:'. We do this consistently for all IPv6
-            * addresses that appear in headers or envelopes. The fact
-            * that valid_mailhost_addr() enforces the form helps of course.
-            * We use the form without IPV6: prefix when doing access
-            * control, or when accessing the connection cache.
+            * addresses that appear in headers or envelopes. The fact that
+            * valid_mailhost_addr() enforces the form helps of course. We
+            * use the form without IPV6: prefix when doing access control,
+            * or when accessing the connection cache.
             */
            else {
                state->addr = mystrdup(client_addr.buf);
@@ -581,6 +584,7 @@ static void smtpd_peer_from_proxy(SMTPD_STATE *state)
 
 void    smtpd_peer_init(SMTPD_STATE *state)
 {
+    int     af;
 
     /*
      * Initialize.
@@ -599,6 +603,7 @@ void    smtpd_peer_init(SMTPD_STATE *state)
     state->namaddr = 0;
     state->rfc_addr = 0;
     state->port = 0;
+    state->anvil_range = 0;
     state->dest_addr = 0;
     state->dest_port = 0;
 
@@ -633,6 +638,16 @@ void    smtpd_peer_init(SMTPD_STATE *state)
      */
     state->namaddr = SMTPD_BUILD_NAMADDRPORT(state->name, state->addr,
                                             state->port);
+
+    /*
+     * Generate 'address' or 'net/mask' index for anvil event aggregation.
+     */
+    af = SOCK_ADDR_FAMILY(&(state->sockaddr));
+    state->anvil_range = net_mask_top(af,
+                                     SOCK_ADDR_ADDRP(&(state->sockaddr)),
+                                     af == AF_INET ?
+                                     var_smtpd_cipv4_prefix :
+                                     var_smtpd_cipv6_prefix);
 }
 
 /* smtpd_peer_reset - destroy peer information */
@@ -655,4 +670,6 @@ void    smtpd_peer_reset(SMTPD_STATE *state)
        myfree(state->dest_addr);
     if (state->dest_port)
        myfree(state->dest_port);
+    if (state->anvil_range)
+       myfree(state->anvil_range);
 }
index 802157045be81ef4c118294fba6da256467eaf49..39b5a5219299bbc3a1941ce41bbe0522b57e18a3 100644 (file)
 
 static const char hexcodes[] = "0123456789ABCDEF";
 
-#define checkok(stillok) (ok = ok && (stillok))
-#define digest_object(p) digest_data((unsigned char *)(p), sizeof(*(p)))
-#define digest_data(p, l) checkok(digest_bytes(mdctx, (p), (l)))
-#define digest_string(s) checkok(digest_chars(mdctx, (s)))
-#define digest_dane(tlsa) checkok(tls_digest_tlsa(mdctx, tlsa))
+#define CHECK_OK_AND(stillok) (ok = ok && (stillok))
+#define CHECK_OK_AND_DIGEST_OBJECT(m, p) \
+       CHECK_OK_AND_DIGEST_DATA((m), (unsigned char *)(p), sizeof(*(p)))
+#define CHECK_OK_AND_DIGEST_DATA(m, p, l) CHECK_OK_AND(digest_bytes((m), (p), (l)))
+#define CHECK_OK_AND_DIGEST_CHARS(m, s) CHECK_OK_AND(digest_chars((m), (s)))
 
 /* digest_bytes - hash octet string of given length */
 
@@ -186,13 +186,13 @@ static int tls_digest_tlsa(EVP_MD_CTX *mdctx, TLS_TLSA *tlsa)
        arr[i++] = (void *) p;
     qsort(arr, n, sizeof(arr[0]), tlsa_cmp);
 
-    digest_object(&n);
+    CHECK_OK_AND_DIGEST_OBJECT(mdctx, &n);
     for (i = 0; i < n; ++i) {
-       digest_object(&arr[i]->usage);
-       digest_object(&arr[i]->selector);
-       digest_object(&arr[i]->mtype);
-       digest_object(&arr[i]->length);
-       digest_data(arr[i]->data, arr[i]->length);
+       CHECK_OK_AND_DIGEST_OBJECT(mdctx, &arr[i]->usage);
+       CHECK_OK_AND_DIGEST_OBJECT(mdctx, &arr[i]->selector);
+       CHECK_OK_AND_DIGEST_OBJECT(mdctx, &arr[i]->mtype);
+       CHECK_OK_AND_DIGEST_OBJECT(mdctx, &arr[i]->length);
+       CHECK_OK_AND_DIGEST_DATA(mdctx, arr[i]->data, arr[i]->length);
     }
     myfree((void *) arr);
     return (ok);
@@ -218,15 +218,15 @@ const EVP_MD *tls_digest_byname(const char *mdalg, EVP_MD_CTX **mdctxPtr)
      * Note that EVP_MD_CTX_{create,destroy} were renamed to, respectively,
      * EVP_MD_CTX_{new,free} in OpenSSL 1.1.0.
      */
-    checkok(md = EVP_get_digestbyname(mdalg));
+    CHECK_OK_AND(md = EVP_get_digestbyname(mdalg));
 
     /*
      * Sanity check: Newer shared libraries could (hypothetical ABI break)
      * allow larger digests, we avoid such poison algorithms.
      */
-    checkok(EVP_MD_size(md) <= EVP_MAX_MD_SIZE);
-    checkok(mdctx = EVP_MD_CTX_new());
-    checkok(EVP_DigestInit_ex(mdctx, md, NULL));
+    CHECK_OK_AND(EVP_MD_size(md) <= EVP_MAX_MD_SIZE);
+    CHECK_OK_AND(mdctx = EVP_MD_CTX_new());
+    CHECK_OK_AND(EVP_DigestInit_ex(mdctx, md, NULL));
 
 
     if (ok && mdctxPtr != 0)
@@ -269,10 +269,10 @@ char   *tls_serverid_digest(TLS_SESS_STATE *TLScontext,
     /* Salt the session lookup key with the OpenSSL runtime version. */
     sslversion = OpenSSL_version_num();
 
-    digest_string(props->helo ? props->helo : "");
-    digest_object(&sslversion);
-    digest_string(props->protocols);
-    digest_string(ciphers);
+    CHECK_OK_AND_DIGEST_CHARS(mdctx, props->helo ? props->helo : "");
+    CHECK_OK_AND_DIGEST_OBJECT(mdctx, &sslversion);
+    CHECK_OK_AND_DIGEST_CHARS(mdctx, props->protocols);
+    CHECK_OK_AND_DIGEST_CHARS(mdctx, ciphers);
 
     /*
      * Ensure separation of caches for sessions where DANE trust
@@ -280,7 +280,7 @@ char   *tls_serverid_digest(TLS_SESS_STATE *TLScontext,
      * should always see a certificate validation failure, both on initial
      * handshake and on resumption.
      */
-    digest_object(&TLScontext->must_fail);
+    CHECK_OK_AND_DIGEST_OBJECT(mdctx, &TLScontext->must_fail);
 
     /*
      * DNS-based or synthetic DANE trust settings are potentially used at all
@@ -288,11 +288,11 @@ char   *tls_serverid_digest(TLS_SESS_STATE *TLScontext,
      */
     if (TLScontext->level > TLS_LEV_ENCRYPT
        && props->dane && props->dane->tlsa) {
-       digest_dane(props->dane->tlsa);
+       CHECK_OK_AND(tls_digest_tlsa(mdctx, props->dane->tlsa));
     } else {
        int     none = 0;               /* Record a TLSA RR count of zero */
 
-       digest_object(&none);
+       CHECK_OK_AND_DIGEST_OBJECT(mdctx, &none);
     }
 
     /*
@@ -300,11 +300,11 @@ char   *tls_serverid_digest(TLS_SESS_STATE *TLScontext,
      * selection.
      */
     if (TLScontext->level > TLS_LEV_ENCRYPT && TLScontext->peer_sni)
-       digest_string(TLScontext->peer_sni);
+       CHECK_OK_AND_DIGEST_CHARS(mdctx, TLScontext->peer_sni);
     else
-       digest_string("");
+       CHECK_OK_AND_DIGEST_CHARS(mdctx, "");
 
-    checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
+    CHECK_OK_AND(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
     EVP_MD_CTX_destroy(mdctx);
     if (!ok)
        msg_fatal("error computing %s message digest", mdalg);
@@ -368,8 +368,8 @@ static char *tls_data_fprint(const unsigned char *buf, int len, const char *mdal
     if (tls_digest_byname(mdalg, &mdctx) == 0)
        msg_panic("digest algorithm \"%s\" not found", mdalg);
 
-    digest_data(buf, len);
-    checkok(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
+    CHECK_OK_AND_DIGEST_DATA(mdctx, buf, len);
+    CHECK_OK_AND(EVP_DigestFinal_ex(mdctx, md_buf, &md_len));
     EVP_MD_CTX_destroy(mdctx);
     if (!ok)
        msg_fatal("error computing %s message digest", mdalg);
index cdc671cffb267f761f811ac5b90fedcf66d2be62..4592f6a502e175fb6dcb8ea184aca09edee334f3 100644 (file)
@@ -44,7 +44,7 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        msg_logger.c logwriter.c unix_dgram_connect.c unix_dgram_listen.c \
        byte_mask.c known_tcp_ports.c argv_split_at.c dict_stream.c \
        sane_strtol.c hash_fnv.c ldseed.c mkmap_cdb.c mkmap_db.c mkmap_dbm.c \
-       mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c
+       mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c net_mask_top.c
 OBJS   = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
        attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -90,7 +90,7 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        msg_logger.o logwriter.o unix_dgram_connect.o unix_dgram_listen.o \
        byte_mask.o known_tcp_ports.o argv_split_at.o dict_stream.o \
        sane_strtol.o hash_fnv.o ldseed.o mkmap_db.o mkmap_dbm.o \
-       mkmap_fail.o mkmap_open.o
+       mkmap_fail.o mkmap_open.o net_mask_top.o
 # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
 # When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
 # otherwise it sets the PLUGIN_* macros.
@@ -121,7 +121,8 @@ HDRS        = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        slmdb.h compat_va_copy.h dict_pipe.h dict_random.h \
        valid_utf8_hostname.h midna_domain.h dict_union.h dict_inline.h \
        check_arg.h argv_attr.h msg_logger.h logwriter.h byte_mask.h \
-       known_tcp_ports.h sane_strtol.h hash_fnv.h ldseed.h mkmap.h
+       known_tcp_ports.h sane_strtol.h hash_fnv.h ldseed.h mkmap.h \
+       net_mask_top.h
 TESTSRC        = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
        stream_test.c dup2_pass_on_exec.c
 DEFS   = -I. -D$(SYSTYPE)
@@ -2415,6 +2416,15 @@ nbbio.o: mymalloc.h
 nbbio.o: nbbio.c
 nbbio.o: nbbio.h
 nbbio.o: sys_defs.h
+net_mask_top.o: check_arg.h
+net_mask_top.o: mask_addr.h
+net_mask_top.o: msg.h
+net_mask_top.o: myaddrinfo.h
+net_mask_top.o: net_mask_top.c
+net_mask_top.o: net_mask_top.h
+net_mask_top.o: sys_defs.h
+net_mask_top.o: vbuf.h
+net_mask_top.o: vstring.h
 netstring.o: check_arg.h
 netstring.o: compat_va_copy.h
 netstring.o: msg.h
diff --git a/postfix/src/util/net_mask_top.c b/postfix/src/util/net_mask_top.c
new file mode 100644 (file)
index 0000000..5483fca
--- /dev/null
@@ -0,0 +1,120 @@
+/*++
+/* NAME
+/*     net_mask_top 3
+/* SUMMARY
+/*     convert net/mask to printable string
+/* SYNOPSIS
+/*     #include <mask_addr.h>
+/*
+/*     char    *net_mask_top(
+/*     int     family,
+/*     const void *src,
+/*     int     prefix_len)
+/* DESCRIPTION
+/*     net_mask_top() prints the network portion of the specified
+/*     IPv4 or IPv6 address, null bits for the host portion, and
+/*     the prefix length if it is shorter than the address.
+/*     The result should be passed to myfree(). The code can
+/*     handle addresses of any length, and bytes of any width.
+/*
+/*     Arguments:
+/* .IP af
+/*     The address family, as with inet_ntop().
+/* .IP src
+/*     Pointer to storage for an IPv4 or IPv6 address, as with
+/*     inet_ntop().
+/* .IP prefix_len
+/*     The number of most-significant bits in \fBsrc\fR that should
+/*     not be cleared.
+/* DIAGNOSTICS
+/*     Panic: unexpected protocol family, bad prefix length. Fatal
+/*     errors: address conversion error.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+ /*
+  * Utility library.
+  */
+#include <mask_addr.h>
+#include <msg.h>
+#include <myaddrinfo.h>
+#include <net_mask_top.h>
+#include <vstring.h>
+
+/*
+ * XXX Factor out if we also need this in other places.
+ */
+struct addr_size {
+    int     af;                                /* address family (binary) */
+    char    ipproto_str[5];            /* IP protocol version (string) */
+    int     addr_bitcount;             /* bits per address */
+    int     addr_bytecount;            /* bytes per address */
+    int     addr_strlen;               /* string representation length */
+    int     slashdigs_strlen;          /* length of /0-31, /0-127 */
+};
+static struct addr_size addr_sizes[] = {
+    AF_INET, "IPv4", MAI_V4ADDR_BITS, MAI_V4ADDR_BYTES, INET_ADDRSTRLEN, 3,
+#ifdef HAS_IPV6
+    AF_INET6, "IPv6", MAI_V6ADDR_BITS, MAI_V6ADDR_BYTES, INET6_ADDRSTRLEN, 4,
+#endif
+};
+
+/* get_addr_size - get bit-banging numbers for address family */
+
+static struct addr_size *get_addr_size(int af)
+{
+    struct addr_size *ap;
+
+    for (ap = addr_sizes; /* see below */ ; ap++) {
+       if (ap >= addr_sizes + sizeof(addr_sizes) / sizeof(struct addr_size))
+           return (0);
+       if (ap->af == af)
+           return (ap);
+    }
+}
+
+/* net_mask_top - printable net/mask pattern */
+
+char   *net_mask_top(int af, const void *src, int prefix_len)
+{
+    const char myname[] = "net_mask_top";
+    union {
+       struct in_addr in_addr;
+       struct in6_addr in6_addr;
+    }       u;
+    VSTRING *buf;
+    struct addr_size *ap;
+
+    if ((ap = get_addr_size(af)) == 0)
+       msg_panic("%s: unexpected address family: %d", myname, af);
+    if (prefix_len > ap->addr_bitcount || prefix_len < 0)
+       msg_fatal("%s: bad %s address prefix length: %d",
+                 myname, ap->ipproto_str, prefix_len);
+    memcpy((void *) &u, src, ap->addr_bytecount);
+    if (prefix_len < ap->addr_bitcount) {
+       mask_addr((unsigned char *) &u, ap->addr_bytecount, prefix_len);
+       buf = vstring_alloc(ap->addr_strlen + ap->slashdigs_strlen);
+    } else {
+       buf = vstring_alloc(ap->addr_strlen);
+    }
+    if (inet_ntop(af, &u, vstring_str(buf), vstring_avail(buf)) == 0)
+       msg_fatal("%s: inet_ntop: %m", myname);
+    vstring_set_payload_size(buf, strlen(vstring_str(buf)));
+    if (prefix_len < ap->addr_bitcount)
+       vstring_sprintf_append(buf, "/%d", prefix_len);
+    return (vstring_export(buf));
+}
diff --git a/postfix/src/util/net_mask_top.h b/postfix/src/util/net_mask_top.h
new file mode 100644 (file)
index 0000000..8f043f5
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _NET_MASK_TOP_H_INCLUDED_
+#define _NET_MASK_TOP_H_INCLUDED_
+
+/*++
+/* NAME
+/*     net_mask_top 3h
+/* SUMMARY
+/*     convert net/mask to printable string
+/* SYNOPSIS
+/*     #include <net_mask_top.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * External interface.
+  */
+extern char *net_mask_top(int, const void *, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*--*/
+
+#endif
index dc5c4b146002963ede9dceefcab83d8a17c5bfdd..38ccc9142792272f281c016a6c7bb5ee62eaffd1 100644 (file)
@@ -28,6 +28,7 @@
 /*     struct sockaddr *SOCK_ADDR_PTR(ptr)
 /*     unsigned char SOCK_ADDR_FAMILY(ptr)
 /*     unsigned char SOCK_ADDR_LEN(ptr)
+/*     void *SOCK_ADDR_ADDRP(ptr)
 /*     unsigned short SOCK_ADDR_PORT(ptr)
 /*     unsigned short *SOCK_ADDR_PORTP(ptr)
 /*
@@ -68,7 +69,8 @@
 /*     address family and length of the real structure that hides
 /*     inside a generic sockaddr structure. On systems where struct
 /*     sockaddr has no sa_len member, SOCK_ADDR_LEN() cannot be
-/*     used as lvalue. SOCK_ADDR_PORT() returns the IPv4 or IPv6
+/*     used as lvalue. SOCKADDR_ADDRP() returns a pointer to the 
+/*     IPv4 or IPv6 address. SOCK_ADDR_PORT() returns the IPv4 or IPv6
 /*     port number, in network byte order; it must not be used as
 /*     lvalue. SOCK_ADDR_PORTP() returns a pointer to the same.
 /*
index 1f5407a4be9bcf86b0091fe26775ff8d05ea2a0a..92b6835ccc6fe823efcb3f2e794c70130241ed7e 100644 (file)
@@ -45,6 +45,9 @@ extern int sock_addr_in_loopback(const struct sockaddr *);
      sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in))
 #endif
 
+#define SOCK_ADDR_ADDRP(sa)    \
+    (SOCK_ADDR_FAMILY(sa) == AF_INET ? \
+       (void *) &SOCK_ADDR_IN_ADDR(sa) : (void *) &SOCK_ADDR_IN6_ADDR(sa))
 #define SOCK_ADDR_PORT(sa) \
     (SOCK_ADDR_PTR(sa)->sa_family == AF_INET6 ? \
        SOCK_ADDR_IN6_PORT(sa) : SOCK_ADDR_IN_PORT(sa))
@@ -78,8 +81,9 @@ extern int sock_addr_in_loopback(const struct sockaddr *);
 #define SOCK_ADDR_LEN(sa)      sizeof(struct sockaddr_in)
 #endif
 
-#define SOCK_ADDR_PORT(sa)     SOCK_ADDR_IN_PORT(sa))
-#define SOCK_ADDR_PORTP(sa)    &SOCK_ADDR_IN_PORT(sa))
+#define SOCK_ADDR_ADDRP(sa)    (&SOCK_ADDR_IN_ADDR(sa))
+#define SOCK_ADDR_PORT(sa)     SOCK_ADDR_IN_PORT(sa)
+#define SOCK_ADDR_PORTP(sa)    (&SOCK_ADDR_IN_PORT(sa))
 
 #define SOCK_ADDR_EQ_ADDR(sa, sb) \
     (SOCK_ADDR_FAMILY(sa) == AF_INET && SOCK_ADDR_FAMILY(sb) == AF_INET \