diff --git a/postfix/HISTORY b/postfix/HISTORY
index bd9f61782..0a42ce0b6 100644
--- a/postfix/HISTORY
+++ b/postfix/HISTORY
@@ -5358,26 +5358,43 @@ Apologies for any names omitted.
token when it adds mail to the incoming queue. If no token
is available the cleanup server pauses for $in_flow_delay
seconds and proceeds anyway. The delay allows mail sending
- process to catch up and access the disk. Valid delays are
- 0..10 seconds.
+ process to catch up and access the disk while not blocking
+ inbound mail. Valid delays are 0..10 seconds.
20010727
Bugfix: updated LDAP client module from LaMont Jones, HP.
+ This also introduces new LDAP query filter patterns: %u
+ (address localpart) and %d (domain part). Files:
+ conf/sample-ldap.cf, util/dict_ldap.c.
20010729
- Bugfix: recursive restrictions could clobber non-reentrant
- address resolving results. Problem found by Victor Duchovni,
- morganstanley.com. In order to fix, introduced address
- resolving caching, which shouls speed up UCE processing.
+ Bugfix: recursive smtpd_whatever_restrictions clobbered
+ intermediate results when switching between sender and
+ recipient address restrictions. Problem found by Victor
+ Duchovni, morganstanley.com. In order to fix, introduced
+ address resolver result caching, which should also help to
+ speed up sender/recipient address restriction processing.
- Bugfix: the not yet published DUNNO table lookup result
- did not prevent further partial key lookups in the same
- table. Problem found by Victor Duchovni, morganstanley.com.
+ Bugfix: the not yet announced DUNNO access table lookup
+ result did not prevent lookups with substrings of the same
+ lookup key. Found by Victor Duchovni, morganstanley.com.
-20010729
+20010730
Robustness: trim trailing whitespace from regexp and pcre
right-hand sides, for consistency with DB/DBM tables.
Files: util/dict_pcre.c, util/dict_regexp.c.
+
+20010731
+
+ Robustness: eliminate duplicate IP addresses after expansion
+ of hostnames in $inet_interfaces, so that Postfix does not
+ suddenly refuse to start up after someone changes the DNS.
+ Files: util/inet_addr_list.c global/own_inet_addr.c.
+
+ Feature: specify "disable_verp_bounces = yes" to have
+ Postfix send one RFC-standard, non-VERP, bounce report for
+ multi-recipient mail, even when VERP style delivery is
+ requested.
diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES
index bc9f2771e..721d02f59 100644
--- a/postfix/RELEASE_NOTES
+++ b/postfix/RELEASE_NOTES
@@ -1,3 +1,36 @@
+Incompatible changes with snapshot-20010731
+===========================================
+
+The protocol between Postfix master and child processes has changed.
+You must stop and start Postfix in order to switch between Snapshot
+20010731 and releases that implement the older protocol.
+
+Major changes with snapshot-20010731
+====================================
+
+Specify "disable_verp_bounces = yes" to have Postfix send one
+RFC-standard, non-VERP, bounce report for multi-recipient mail,
+even when VERP style delivery is requested.
+
+Variable coupling between message receiving rates and message
+delivery rates. When the message receiving rate exceeds the message
+delivery rate, an SMTP server will pause for $in_flow_delay seconds
+(default: 1) before accepting a message. This delay gives Postfix
+a chance catch up and access the disk, while still allowing new
+mail to arrive.
+
+The in_flow_delay feature has effect mainly when your system is
+being flooded port through a limited number of SMTP connections.
+This is also useful for mass-mailing applications, because it avoids
+the need to hand-tune the rate at which mail is sent into Postfix.
+
+The in_flow_delay feature has negligible effect when mail arrives
+via many different SMTP connections. With the default limit of 50
+SMTP server processes and with the default $in_flow_delay of 1
+second, total mail inflow is limited to 50 messages per second more
+than the number of messages that are delivered per second. Many
+systems saturate at values much smaller than 50 messages per second.
+
Incompatible changes with snapshot-20010714
===========================================
diff --git a/postfix/conf/main.cf b/postfix/conf/main.cf
index 8807373a4..5e6b2c4c8 100644
--- a/postfix/conf/main.cf
+++ b/postfix/conf/main.cf
@@ -44,9 +44,10 @@ daemon_directory = /usr/libexec/postfix
#
# The mail_owner parameter specifies the owner of the Postfix queue
# and of most Postfix daemon processes. Specify the name of a user
-# account THAT DOES NOT SHARE A GROUP WITH OTHER ACCOUNTS AND THAT
-# OWNS NO OTHER FILES OR PROCESSES ON THE SYSTEM. In particular,
-# don't specify nobody or daemon. PLEASE USE A DEDICATED USER.
+# account THAT DOES NOT SHARE ITS USER OR GROUP ID WITH OTHER ACCOUNTS
+# AND THAT OWNS NO OTHER FILES OR PROCESSES ON THE SYSTEM. In
+# particular, don't specify nobody or daemon. PLEASE USE A DEDICATED
+# USER.
#
mail_owner = postfix
@@ -238,6 +239,19 @@ mail_owner = postfix
#
#local_recipient_maps = $alias_maps unix:passwd.byname
+# INPUT RATE CONTROL
+#
+# The in_flow_delay configuration parameter implements mail input
+# flow control. By default, a Postfix process will pause for one
+# second before accepting a new message, when the message arrival
+# rate exceeds the message delivery rate. With the default 50 SMTP
+# server process limit, this limits the mail inflow to 50 messages
+# a second more than the number of messages delivered per second.
+#
+# Specify 0 to disable the feature. Valid delays are 0..10.
+#
+#in_flow_delay = 1
+
# ADDRESS REWRITING
#
# Insert text from sample-rewrite.cf if you need to do address
diff --git a/postfix/html/cleanup.8.html b/postfix/html/cleanup.8.html
index 3f55c1de4..48ab1db87 100644
--- a/postfix/html/cleanup.8.html
+++ b/postfix/html/cleanup.8.html
@@ -133,6 +133,11 @@ CLEANUP(8) CLEANUP(8)
Limit the amount of memory in bytes used to process
a message header.
+ in_flow_delay
+ Amount of time to pause before accepting a message,
+ when the message arrival rate exceeds the message
+ delivery rate.
+
extract_recipient_limit
Limit the amount of recipients extracted from mes-
sage headers.
diff --git a/postfix/html/postalias.1.html b/postfix/html/postalias.1.html
index c1f00012b..8fbe2ce8c 100644
--- a/postfix/html/postalias.1.html
+++ b/postfix/html/postalias.1.html
@@ -109,10 +109,6 @@ POSTALIAS(1) POSTALIAS(1)
cess (including successful postmap -q lookup) and termi-
nates with non-zero exit status in case of failure.
-BUGS
- The "delete key" support is limited to one delete opera-
- tion per command invocation.
-
ENVIRONMENT
MAIL_CONFIG
Directory with Postfix configuration files.
@@ -121,12 +117,12 @@ POSTALIAS(1) POSTALIAS(1)
Enable verbose logging for debugging purposes.
CONFIGURATION PARAMETERS
- The following main.cf parameters are especially relevant
- to this program. See the Postfix main.cf file for syntax
+ The following main.cf parameters are especially relevant
+ to this program. See the Postfix main.cf file for syntax
details and for default values.
database_type
- Default alias database type. On many UNIX systems,
+ Default alias database type. On many UNIX systems,
the default type is either dbm or hash.
STANDARDS
@@ -137,7 +133,7 @@ POSTALIAS(1) POSTALIAS(1)
sendmail(1) mail posting and compatibility interface.
LICENSE
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
AUTHOR(S)
diff --git a/postfix/html/postmap.1.html b/postfix/html/postmap.1.html
index eff9ea79a..9a43c2bbe 100644
--- a/postfix/html/postmap.1.html
+++ b/postfix/html/postmap.1.html
@@ -127,10 +127,6 @@ POSTMAP(1) POSTMAP(1)
cess (including successful postmap -q lookup) and termi-
nates with non-zero exit status in case of failure.
-BUGS
- The "delete key" support is limited to one delete opera-
- tion per command invocation.
-
ENVIRONMENT
MAIL_CONFIG
Directory with Postfix configuration files.
@@ -140,12 +136,12 @@ POSTMAP(1) POSTMAP(1)
CONFIGURATION PARAMETERS
database_type
- Default output database type. On many UNIX sys-
- tems, the default database type is either hash or
+ Default output database type. On many UNIX sys-
+ tems, the default database type is either hash or
dbm.
LICENSE
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
AUTHOR(S)
diff --git a/postfix/man/man1/postalias.1 b/postfix/man/man1/postalias.1
index 1e8b32833..ac7da6d2e 100644
--- a/postfix/man/man1/postalias.1
+++ b/postfix/man/man1/postalias.1
@@ -98,11 +98,6 @@ flagged with a warning.
\fBpostalias\fR terminates with zero exit status in case of success
(including successful \fBpostmap -q\fR lookup) and terminates
with non-zero exit status in case of failure.
-.SH BUGS
-.ad
-.fi
-The "delete key" support is limited to one delete operation
-per command invocation.
.SH ENVIRONMENT
.na
.nf
diff --git a/postfix/man/man1/postmap.1 b/postfix/man/man1/postmap.1
index 2f0b9c6c1..83f8cd424 100644
--- a/postfix/man/man1/postmap.1
+++ b/postfix/man/man1/postmap.1
@@ -115,11 +115,6 @@ skipped and are flagged with a warning.
\fBpostmap\fR terminates with zero exit status in case of success
(including successful \fBpostmap -q\fR lookup) and terminates
with non-zero exit status in case of failure.
-.SH BUGS
-.ad
-.fi
-The "delete key" support is limited to one delete operation
-per command invocation.
.SH ENVIRONMENT
.na
.nf
diff --git a/postfix/man/man8/cleanup.8 b/postfix/man/man8/cleanup.8
index 2cbdb5a3a..098cc2942 100644
--- a/postfix/man/man8/cleanup.8
+++ b/postfix/man/man8/cleanup.8
@@ -121,6 +121,9 @@ Address mapping lookup table for envelope recipient addresses.
Limit the number of envelope recipients that are remembered.
.IP \fBheader_size_limit\fR
Limit the amount of memory in bytes used to process a message header.
+.IP \fBin_flow_delay\fR
+Amount of time to pause before accepting a message, when the
+message arrival rate exceeds the message delivery rate.
.IP \fBextract_recipient_limit\fR
Limit the amount of recipients extracted from message headers.
.SH SEE ALSO
diff --git a/postfix/src/cleanup/cleanup.c b/postfix/src/cleanup/cleanup.c
index 1d457753d..7e7b369ad 100644
--- a/postfix/src/cleanup/cleanup.c
+++ b/postfix/src/cleanup/cleanup.c
@@ -107,6 +107,9 @@
/* Limit the number of envelope recipients that are remembered.
/* .IP \fBheader_size_limit\fR
/* Limit the amount of memory in bytes used to process a message header.
+/* .IP \fBin_flow_delay\fR
+/* Amount of time to pause before accepting a message, when the
+/* message arrival rate exceeds the message delivery rate.
/* .IP \fBextract_recipient_limit\fR
/* Limit the amount of recipients extracted from message headers.
/* SEE ALSO
diff --git a/postfix/src/global/mail_params.h b/postfix/src/global/mail_params.h
index 45eaecaa4..bf273b250 100644
--- a/postfix/src/global/mail_params.h
+++ b/postfix/src/global/mail_params.h
@@ -1283,6 +1283,10 @@ extern char *var_verp_delims;
#define DEF_VERP_FILTER "-=+"
extern char *var_verp_filter;
+#define VAR_VERP_BOUNCE_OFF "disable_verp_bounces"
+#define DEF_VERP_BOUNCE_OFF 0
+extern bool var_verp_bounce_off;
+
/*
* Inbound mail flow control. This allows for a stiffer coupling between
* receiving mail and sending mail. A sending process produces one token for
diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h
index 3079cb8ea..234a54fe4 100644
--- a/postfix/src/global/mail_version.h
+++ b/postfix/src/global/mail_version.h
@@ -15,7 +15,7 @@
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20010730"
+#define DEF_MAIL_VERSION "Snapshot-20010731"
extern char *var_mail_version;
/* LICENSE
diff --git a/postfix/src/global/own_inet_addr.c b/postfix/src/global/own_inet_addr.c
index f06232989..1dc8aaf4f 100644
--- a/postfix/src/global/own_inet_addr.c
+++ b/postfix/src/global/own_inet_addr.c
@@ -107,6 +107,14 @@ static void own_inet_addr_init(INET_ADDR_LIST *addr_list,
VAR_INET_INTERFACES, host);
myfree(hosts);
+ /*
+ * Weed out duplicate IP addresses. Duplicates happen when the same
+ * IP address is listed under multiple hostnames. If we don't weed
+ * out duplicates, Postfix can suddenly stop working after the DNS is
+ * changed.
+ */
+ inet_addr_list_uniq(addr_list);
+
inet_addr_list_init(&local_addrs);
inet_addr_list_init(&local_masks);
if (inet_addr_local(&local_addrs, &local_masks) == 0)
diff --git a/postfix/src/master/mail_flow.c b/postfix/src/master/mail_flow.c
index 3a42df080..292e84a4c 100644
--- a/postfix/src/master/mail_flow.c
+++ b/postfix/src/master/mail_flow.c
@@ -106,9 +106,11 @@ int mail_flow_put(int len)
/*
* Write or discard N bytes.
*/
+ memset(buf, 0, len > BUFFER_SIZE ? BUFFER_SIZE : len);
+
for (count = len; count > 0; count -= n)
if ((n = write(MASTER_FLOW_WRITE, buf, count > BUFFER_SIZE ?
- BUFFER_SIZE : count)) < 0)
+ BUFFER_SIZE : count)) < 0)
return (-1);
if (msg_verbose)
msg_info("%s: %d %d", myname, len, len - count);
diff --git a/postfix/src/nqmgr/qmgr.c b/postfix/src/nqmgr/qmgr.c
index 6185a0be9..438691b50 100644
--- a/postfix/src/nqmgr/qmgr.c
+++ b/postfix/src/nqmgr/qmgr.c
@@ -336,6 +336,7 @@ bool var_allow_min_user;
int var_local_con_lim;
int var_local_rcpt_lim;
int var_proc_limit;
+bool var_verp_bounce_off;
static QMGR_SCAN *qmgr_incoming;
static QMGR_SCAN *qmgr_deferred;
@@ -514,7 +515,7 @@ static void qmgr_post_init(char *unused_name, char **unused_argv)
qmgr_incoming = qmgr_scan_create(MAIL_QUEUE_INCOMING);
qmgr_deferred = qmgr_scan_create(MAIL_QUEUE_DEFERRED);
qmgr_scan_request(qmgr_incoming, QMGR_SCAN_START);
- qmgr_deferred_run_event(0, (char *)0);
+ qmgr_deferred_run_event(0, (char *) 0);
}
/* main - the main program */
@@ -555,6 +556,7 @@ int main(int argc, char **argv)
};
static CONFIG_BOOL_TABLE bool_table[] = {
VAR_ALLOW_MIN_USER, DEF_ALLOW_MIN_USER, &var_allow_min_user,
+ VAR_VERP_BOUNCE_OFF, DEF_VERP_BOUNCE_OFF, &var_verp_bounce_off,
0,
};
diff --git a/postfix/src/nqmgr/qmgr_active.c b/postfix/src/nqmgr/qmgr_active.c
index 6d22e806a..8f28b0686 100644
--- a/postfix/src/nqmgr/qmgr_active.c
+++ b/postfix/src/nqmgr/qmgr_active.c
@@ -275,7 +275,7 @@ void qmgr_active_done(QMGR_MESSAGE *message)
} else {
if (msg_verbose)
msg_info("%s: bounce %s", myname, message->queue_id);
- if (message->verp_delims == 0)
+ if (message->verp_delims == 0 || var_verp_bounce_off)
abounce_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
@@ -362,7 +362,7 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
if (event_time() > message->arrival_time + var_max_queue_time) {
msg_info("%s: from=<%s>, status=expired, returned to sender",
message->queue_id, message->sender);
- if (message->verp_delims == 0)
+ if (message->verp_delims == 0 || var_verp_bounce_off)
adefer_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
diff --git a/postfix/src/qmgr/qmgr.c b/postfix/src/qmgr/qmgr.c
index a705aadc4..95a4e092a 100644
--- a/postfix/src/qmgr/qmgr.c
+++ b/postfix/src/qmgr/qmgr.c
@@ -295,6 +295,7 @@ int var_qmgr_hog;
int var_local_rcpt_lim; /* XXX */
int var_local_con_lim; /* XXX */
int var_proc_limit;
+bool var_verp_bounce_off;
static QMGR_SCAN *qmgr_incoming;
static QMGR_SCAN *qmgr_deferred;
@@ -512,6 +513,7 @@ int main(int argc, char **argv)
};
static CONFIG_BOOL_TABLE bool_table[] = {
VAR_ALLOW_MIN_USER, DEF_ALLOW_MIN_USER, &var_allow_min_user,
+ VAR_VERP_BOUNCE_OFF, DEF_VERP_BOUNCE_OFF, &var_verp_bounce_off,
0,
};
diff --git a/postfix/src/qmgr/qmgr_active.c b/postfix/src/qmgr/qmgr_active.c
index 6d22e806a..8f28b0686 100644
--- a/postfix/src/qmgr/qmgr_active.c
+++ b/postfix/src/qmgr/qmgr_active.c
@@ -275,7 +275,7 @@ void qmgr_active_done(QMGR_MESSAGE *message)
} else {
if (msg_verbose)
msg_info("%s: bounce %s", myname, message->queue_id);
- if (message->verp_delims == 0)
+ if (message->verp_delims == 0 || var_verp_bounce_off)
abounce_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
@@ -362,7 +362,7 @@ static void qmgr_active_done_2_generic(QMGR_MESSAGE *message)
if (event_time() > message->arrival_time + var_max_queue_time) {
msg_info("%s: from=<%s>, status=expired, returned to sender",
message->queue_id, message->sender);
- if (message->verp_delims == 0)
+ if (message->verp_delims == 0 || var_verp_bounce_off)
adefer_flush(BOUNCE_FLAG_KEEP,
message->queue_name,
message->queue_id,
diff --git a/postfix/src/smtpd/Makefile.in b/postfix/src/smtpd/Makefile.in
index 2031632ee..73a262306 100644
--- a/postfix/src/smtpd/Makefile.in
+++ b/postfix/src/smtpd/Makefile.in
@@ -171,6 +171,7 @@ smtpd_check.o: ../../include/mymalloc.h
smtpd_check.o: ../../include/dict.h
smtpd_check.o: ../../include/vstream.h
smtpd_check.o: ../../include/htable.h
+smtpd_check.o: ../../include/ctable.h
smtpd_check.o: ../../include/dns.h
smtpd_check.o: ../../include/namadr_list.h
smtpd_check.o: ../../include/domain_list.h
diff --git a/postfix/src/smtpd/smtpd.h b/postfix/src/smtpd/smtpd.h
index feedc8020..29fb3d2d7 100644
--- a/postfix/src/smtpd/smtpd.h
+++ b/postfix/src/smtpd/smtpd.h
@@ -67,7 +67,6 @@ typedef struct SMTPD_STATE {
int recursion;
off_t msg_size;
int junk_cmds;
- VSTRING *error_text;
#ifdef USE_SASL_AUTH
char *sasl_mechanism_list;
char *sasl_method;
diff --git a/postfix/src/smtpd/smtpd_state.c b/postfix/src/smtpd/smtpd_state.c
index c22ebd5c8..ca4929634 100644
--- a/postfix/src/smtpd/smtpd_state.c
+++ b/postfix/src/smtpd/smtpd_state.c
@@ -91,7 +91,6 @@ void smtpd_state_init(SMTPD_STATE *state, VSTREAM *stream)
state->recursion = 0;
state->msg_size = 0;
state->junk_cmds = 0;
- state->error_text = vstring_alloc(100);
#ifdef USE_SASL_AUTH
if (SMTPD_STAND_ALONE(state))
@@ -124,7 +123,6 @@ void smtpd_state_reset(SMTPD_STATE *state)
if (state->buffer)
vstring_free(state->buffer);
smtpd_peer_reset(state);
- vstring_free(state->error_text);
#ifdef USE_SASL_AUTH
if (var_smtpd_sasl_enable)
diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in
index d7e85a063..04fa8037a 100644
--- a/postfix/src/util/Makefile.in
+++ b/postfix/src/util/Makefile.in
@@ -80,7 +80,8 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \
mystrtok sigdelay translit valid_hostname vstream_popen \
vstring vstring_vstream doze select_bug stream_test mac_expand \
- watchdog unescape hex_quote name_mask rand_sleep sane_time ctable
+ watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \
+ inet_addr_list
LIB_DIR = ../../lib
INC_DIR = ../../include
@@ -279,6 +280,11 @@ ctable: $(LIB)
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
+inet_addr_list: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
@@ -291,7 +297,7 @@ stream_test: stream_test.c $(LIB)
$(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS)
tests: valid_hostname_test mac_expand_test dict_test unescape_test \
- hex_quote_test cache_test
+ hex_quote_test ctable_test inet_addr_list_test
valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
./valid_hostname valid_hostname.tmp
@@ -319,6 +325,11 @@ ctable_test: ctable
diff ctable.ref ctable.tmp
rm -f ctable.tmp
+inet_addr_list_test: inet_addr_list
+ ./inet_addr_list `cat inet_addr_list.in` >inet_addr_list.tmp 2>&1
+ diff inet_addr_list.ref inet_addr_list.tmp
+ rm -f inet_addr_list.tmp
+
DB_TYPE = `../postconf/postconf -h default_database_type`
dict_test: dict_open testdb dict_test.in dict_test.ref
diff --git a/postfix/src/util/inet_addr_list.c b/postfix/src/util/inet_addr_list.c
index d449e76c7..fa1cbd399 100644
--- a/postfix/src/util/inet_addr_list.c
+++ b/postfix/src/util/inet_addr_list.c
@@ -13,6 +13,9 @@
/* INET_ADDR_LIST *list;
/* struct in_addr *addr;
/*
+/* void inet_addr_list_uniq(list)
+/* INET_ADDR_LIST *list;
+/*
/* void inet_addr_list_free(list)
/* INET_ADDR_LIST *list;
/* DESCRIPTION
@@ -25,6 +28,9 @@
/* inet_addr_list_append() appends the specified address to
/* the specified list, extending the list on the fly.
/*
+/* inet_addr_list_uniq() sorts the specified address list and
+/* eliminates duplicates.
+/*
/* inet_addr_list_free() reclaims memory used for the
/* specified address list.
/* LICENSE
@@ -43,6 +49,7 @@
#include
#include
#include
+#include
/* Utility library. */
@@ -77,9 +84,81 @@ void inet_addr_list_append(INET_ADDR_LIST *list, struct in_addr * addr)
list->addrs[list->used++] = *addr;
}
+/* inet_addr_list_comp - compare addresses */
+
+static int inet_addr_list_comp(const void *a, const void *b)
+{
+ const struct in_addr *a_addr = (const struct in_addr *) a;
+ const struct in_addr *b_addr = (const struct in_addr *) b;
+
+ return (a_addr->s_addr - b_addr->s_addr);
+}
+
+/* inet_addr_list_uniq - weed out duplicates */
+
+void inet_addr_list_uniq(INET_ADDR_LIST *list)
+{
+ int n;
+ int m;
+
+ /*
+ * Put the identical members right next to each other.
+ */
+ qsort((void *) list->addrs, list->used,
+ sizeof(list->addrs[0]), inet_addr_list_comp);
+
+ /*
+ * Nuke the duplicates. Postcondition after while loop: m is the largest
+ * index for which list->addrs[n] == list->addrs[m].
+ */
+ for (m = n = 0; m < list->used; m++, n++) {
+ if (m != n)
+ list->addrs[n] = list->addrs[m];
+ while (m + 1 < list->used
+ && inet_addr_list_comp((void *) &(list->addrs[n]),
+ (void *) &(list->addrs[m + 1])) == 0)
+ m += 1;
+ }
+ list->used = n;
+}
+
/* inet_addr_list_free - destroy internet address list */
void inet_addr_list_free(INET_ADDR_LIST *list)
{
myfree((char *) list->addrs);
}
+
+#ifdef TEST
+
+ /*
+ * Duplicate elimination needs to be tested.
+ */
+#include
+
+static void inet_addr_list_print(INET_ADDR_LIST *list)
+{
+ int n;
+
+ for (n = 0; n < list->used; n++)
+ msg_info("%s", inet_ntoa(list->addrs[n]));
+}
+
+int main(int argc, char **argv)
+{
+ INET_ADDR_LIST list;
+
+ inet_addr_list_init(&list);
+ while (--argc && *++argv)
+ if (inet_addr_host(&list, *argv) == 0)
+ msg_fatal("host not found: %s", *argv);
+ msg_info("list before sort/uniq");
+ inet_addr_list_print(&list);
+ inet_addr_list_uniq(&list);
+ msg_info("list after sort/uniq");
+ inet_addr_list_print(&list);
+ inet_addr_list_free(&list);
+ return (0);
+}
+
+#endif
diff --git a/postfix/src/util/inet_addr_list.h b/postfix/src/util/inet_addr_list.h
index 48a4c9712..372b3ccb7 100644
--- a/postfix/src/util/inet_addr_list.h
+++ b/postfix/src/util/inet_addr_list.h
@@ -27,6 +27,7 @@ typedef struct INET_ADDR_LIST {
extern void inet_addr_list_init(INET_ADDR_LIST *);
extern void inet_addr_list_free(INET_ADDR_LIST *);
+extern void inet_addr_list_uniq(INET_ADDR_LIST *);
extern void inet_addr_list_append(INET_ADDR_LIST *, struct in_addr *);
/* LICENSE
diff --git a/postfix/src/util/inet_addr_list.in b/postfix/src/util/inet_addr_list.in
new file mode 100644
index 000000000..742281fae
--- /dev/null
+++ b/postfix/src/util/inet_addr_list.in
@@ -0,0 +1,9 @@
+168.100.189.2
+168.100.189.2
+168.100.189.1
+168.100.189.3
+168.100.189.3
+168.100.189.3
+168.100.189.4
+168.100.189.1
+168.100.189.4
diff --git a/postfix/src/util/inet_addr_list.ref b/postfix/src/util/inet_addr_list.ref
new file mode 100644
index 000000000..0a8a56e1a
--- /dev/null
+++ b/postfix/src/util/inet_addr_list.ref
@@ -0,0 +1,15 @@
+unknown: list before sort/uniq
+unknown: 168.100.189.2
+unknown: 168.100.189.2
+unknown: 168.100.189.1
+unknown: 168.100.189.3
+unknown: 168.100.189.3
+unknown: 168.100.189.3
+unknown: 168.100.189.4
+unknown: 168.100.189.1
+unknown: 168.100.189.4
+unknown: list after sort/uniq
+unknown: 168.100.189.1
+unknown: 168.100.189.2
+unknown: 168.100.189.3
+unknown: 168.100.189.4