diff --git a/Makefile.in.patch b/Makefile.in.patch deleted file mode 100644 index 2e1e7fc..0000000 --- a/Makefile.in.patch +++ /dev/null @@ -1,55 +0,0 @@ ---- /home/titus/postfix/postfix-2.9.3/src/global/Makefile.in 2012-01-22 21:25:14.000000000 +0530 -+++ /home/titus/postfix/postfix-2.9.3.mod/src/global/Makefile.in 2012-08-08 00:03:15.422066765 +0530 -@@ -3,7 +3,7 @@ - canon_addr.c cfg_parser.c cleanup_strerror.c cleanup_strflags.c \ - clnt_stream.c conv_time.c db_common.c debug_peer.c debug_process.c \ - defer.c deliver_completed.c deliver_flock.c deliver_pass.c \ -- deliver_request.c dict_ldap.c dict_mysql.c dict_pgsql.c \ -+ deliver_request.c dict_ldap.c dict_mysql.c dict_pgsql.c dict_redis.c \ - dict_proxy.c dict_sqlite.c domain_list.c dot_lockfile.c dot_lockfile_as.c \ - dsb_scan.c dsn.c dsn_buf.c dsn_mask.c dsn_print.c dsn_util.c \ - ehlo_mask.c ext_prop.c file_id.c flush_clnt.c header_opts.c \ -@@ -37,7 +37,7 @@ - canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \ - clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \ - defer.o deliver_completed.o deliver_flock.o deliver_pass.o \ -- deliver_request.o dict_ldap.o dict_mysql.o dict_pgsql.o \ -+ deliver_request.o dict_ldap.o dict_mysql.o dict_pgsql.o dict_redis.o \ - dict_proxy.o dict_sqlite.o domain_list.o dot_lockfile.o dot_lockfile_as.o \ - dsb_scan.o dsn.o dsn_buf.o dsn_mask.o dsn_print.o dsn_util.o \ - ehlo_mask.o ext_prop.o file_id.o flush_clnt.o header_opts.o \ -@@ -71,7 +71,7 @@ - canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \ - conv_time.h db_common.h debug_peer.h debug_process.h defer.h \ - deliver_completed.h deliver_flock.h deliver_pass.h deliver_request.h \ -- dict_ldap.h dict_mysql.h dict_pgsql.h dict_proxy.h dict_sqlite.h domain_list.h \ -+ dict_ldap.h dict_mysql.h dict_pgsql.h dict_proxy.h dict_sqlite.h domain_list.h dict_redis.h \ - dot_lockfile.h dot_lockfile_as.h dsb_scan.h dsn.h dsn_buf.h \ - dsn_mask.h dsn_print.h dsn_util.h ehlo_mask.h ext_prop.h \ - file_id.h flush_clnt.h header_opts.h header_token.h input_transp.h \ -@@ -984,6 +984,17 @@ - dict_sqlite.o: dict_sqlite.c - dict_sqlite.o: dict_sqlite.h - dict_sqlite.o: string_list.h -+dict_redis.o: ../../include/dict.h -+dict_redis.o: ../../include/mymalloc.h -+dict_redis.o: ../../include/vbuf.h -+dict_redis.o: ../../include/vstream.h -+dict_redis.o: ../../include/vstring.h -+dict_redis.o: ../../include/stringops.h -+dict_redis.o: ../../include/sys_defs.h -+dict_redis.o: hiredis.h -+dict_redis.o: cfg_parser.h -+dict_redis.o: dict_redis.c -+dict_redis.o: dict_redis.h - domain_list.o: ../../include/argv.h - domain_list.o: ../../include/match_list.h - domain_list.o: ../../include/sys_defs.h -@@ -1372,6 +1383,7 @@ - mail_dict.o: dict_pgsql.h - mail_dict.o: dict_proxy.h - mail_dict.o: dict_sqlite.h -+mail_dict.o: dict_redis.h - mail_dict.o: mail_dict.c - mail_dict.o: mail_dict.h - mail_error.o: ../../include/name_mask.h diff --git a/README.md b/README.md index 3d788aa..c93f1d7 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,95 @@ +### Now availible on Alpine linux +As the `postfix-redis` package, so it can be installed without compiling. + ### Postfix Redis -This is a patch to the postfix 2.9.3 MTA to add a lookup table for redis database. +This is a patch to the postfix 3.4.3+ MTA to add a lookup table for redis database. + This patch depends on hiredis client library. -Apply the patch to a vanilla postfix 2.9.3 source tree +Apply the patch to a vanilla postfix 3.4.3+ source tree + +Copy dict_redis.c and dict_redis.h files to the postfix/src/global directory. + +Copy the postfix-redis.patch to the postfix folder and apply with patch -p2 -i postfix-redis.patch + +### Generate make files +``` +$ make makefiles CCARGS="-DHAS_REDIS $(pkg-config --cflags hiredis)" AUXLIBS_REDIS="$(pkg-config --libs hiredis)" config_directory=/etc/postfix meta_directory=/etc/postfix daemon_directory=/usr/libexec/postfix shlib_directory=/usr/lib/postfix dynamicmaps=yes shared=yes +``` + +### Compile postfix +``` +$ make +``` + +### Install postfix +``` +$ make upgrade +``` -Copy dict_redis.c, dict_redis.h and hiredis.h files to the src/global directory -Patch Makefile.in and mail_dict.c in src/global with the provided diffs +### Example postfix configuration +main.cf: -### Generate make files -% make makefiles CCARGS="-DHAS_REDIS -I/usr/local/include/hiredis" AUXLIBS="-L/usr/local/lib -lhiredis" -Change the include and library location for hiredis client library if required. +``` +virtual_mailbox_domains = redis:/etc/postfix/redis-vdomains.cf +virtual_mailbox_maps = redis:/etc/postfix/redis-vmailbox-maps.cf +virtual_alias_maps = redis:/etc/postfix/redis-valias-maps.cf +``` -### Compile postfix -% make +### Example .cf files +#### Defaults +``` +host = 127.0.0.1 +port = 6379 +prefix = (none) +``` -### Install postfix -% make install +redis-vdomains.cf: +``` +host = 127.0.0.1 +port = 6379 +prefix = VMD: +``` -### Using the lookup table -transport_maps = redis:/etc/postfix/redis_transport_maps.cf +redis-vmailbox-maps.cf: +``` +host = 127.0.0.1 +port = 6379 +prefix = VMM: +``` -redis_transport_maps.cf: -host = localhost +redis-redis-valias-maps.cf: +``` +host = 127.0.0.1 port = 6379 +prefix = VAM: +``` + +Example Redis keys and values: +``` +1) "VMD:example.com" "example.com" +2) "VMM:user@example.com" "user@example.com" +3) "VAM:postmaster@example.com" "user@example.com" +``` + +### Testing Lookup + +To test the lookup table you can postmap the string as follows, and monitor redis with ```redis-cli monitor```. +``` +$ postmap -q "postmaster@example.com" redis:/etc/postfix/redis-valias-maps.cf +``` + +### Creating Redis database +virtual_mailbox_domains +``` +$ redis-cli set VMD:example.com example.com +``` +virtual_mailbox_maps +``` +$ redis-cli set VMM:user@example.com user@example.com +``` +virtual_alias_maps +``` +$ redis-cli set VAM:postmaster@example.com user@example.com +``` diff --git a/REDIS_README.html b/REDIS_README.html new file mode 100644 index 0000000..792227e --- /dev/null +++ b/REDIS_README.html @@ -0,0 +1,105 @@ + + + + + + +Postfix Redis Howto + + + + + + + +

Postfix Redis Howto

+ +
+ +

Introduction

+ +

The Postfix redis map type allows you to hook up Postfix to a +Redis database.

+ +

Building Postfix with Redis support

+ +

These instructions assume that you build Postfix from source +code as described in the INSTALL document. Some modification may +be required if you build Postfix from a vendor-specific source +package.

+ +

In order to build Postfix with redis map support, you specify +-DHAS_REDIS, the directory with the hiredis header files, and +the location of the hiredis library file.

+ +

For example:

+ +
+
+% make tidy
+% make -f Makefile.init makefiles \
+        'CCARGS=-DHAS_REDIS $(pkg-config --cflags hiredis)' \
+        'AUXLIBS_REDIS=$(pkg-config --libs hiredis)'
+
+
+ +
+ +

Failure to use the AUXLIBS_REDIS variable will defeat the purpose +of dynamic database client loading. Every Postfix executable file +will have Redis database library dependencies. And that was exactly +what dynamic database client loading was meant to avoid.

+ +
+ +

Then just run 'make'.

+ +

Configuring Redis lookup tables

+ +

Once Postfix is built with redis support, you can specify a +map type in main.cf like this:

+ +
+
+/etc/postfix/main.cf:
+    alias_maps = redis:/etc/postfix/redis-aliases.cf
+
+
+ +

The file /etc/postfix/redis-aliases.cf specifies how to reach the redis database. +For a complete description, see the redis_table(5) manual page.

+ +

Example: virtual mailbox domain

+ +
+#
+# redis config file for virtual(8) lookups
+#
+
+#
+# The hosts that Postfix will try to connect to
+host = 127.0.0.1
+
+# The prefix added to the query to check with redis
+prefix = VDOM:
+
+ +

Using mirrored databases

+ +

Sites that have a need for multiple mail exchangers can setup a redis cluster +if needed, for fallover capability.

+ +

Credits

+ + + + + + diff --git a/dict_redis.c b/dict_redis.c index fe59abb..eae2471 100644 --- a/dict_redis.c +++ b/dict_redis.c @@ -1,30 +1,100 @@ - -#include "sys_defs.h" +/*++ +/* NAME +/* dict_redis 3 +/* SUMMARY +/* dictionary manager interface to Redis databases +/* SYNOPSIS +/* #include +/* +/* DICT *dict_redis_open(name, open_flags, dict_flags) +/* const char *name; +/* int open_flags; +/* int dict_flags; +/* DESCRIPTION +/* dict_redis_open() creates a dictionary of type 'redis'. This +/* dictionary is an interface for the postfix key->value mappings +/* to redis. The result is a pointer to the installed dictionary, +/* or a null pointer in case of problems. +/* .PP +/* Arguments: +/* .IP name +/* Either the path to the Redis configuration file (if it +/* starts with '/' or '.'), or the prefix which will be used to +/* obtain main.cf configuration parameters for this search. +/* +/* In the first case, the configuration parameters below are +/* specified in the file as \fIname\fR=\fIvalue\fR pairs. +/* +/* In the second case, the configuration parameters are +/* prefixed with the value of \fIname\fR and an underscore, +/* and they are specified in main.cf. For example, if this +/* value is \fIredisDB\fR, the parameters would look like +/* \fIredisDB_host\fR, \fIpredisDB_prefix\fR, and so on. +/* .IP other_name +/* reference for outside use. +/* .IP open_flags +/* unused. +/* .IP dict_flags +/* See dict_open(3). +/* +/* .PP +/* Configuration parameters: +/* .IP host +/* IP address of the redis server hosting the database. +/* .IP port +/* Port number to connect to the above. +/* .IP prefix +/* Prefix to add to the key when looking it up. +/* .PP +/* For example, if you want the map to reference databases on +/* redis host "127.0.0.1" and prefix the query with VDOM: +/* Then the configuration file +/* should read: +/* .PP +/* host = 127.0.0.1 +/* .br +/* port = 6379 +/* .br +/* prefix = VDOM: +/* .PP +/* SEE ALSO +/* dict(3) generic dictionary manager +/* HISTORY +/* .ad +/* .fi +/* This feature was introduced with Postfix 3.7. +/* AUTHOR(S) +/* Titus Jose +/* titus.nitt@gmail.com +/* +/* Updated by: +/* Duncan Bellamy +/* dunk@denkimushi.com +/*--*/ + +#include #ifdef HAS_REDIS #include #include #include -#ifdef STRCASECMP_IN_STRINGS_H -#include -#endif - /* Utility library. */ -#include "dict.h" -#include "mymalloc.h" -#include "vstring.h" -#include "stringops.h" +#include +#include +#include +#include +#include /* Global library. */ -#include "cfg_parser.h" +#include /* Application-specific. */ -#include "dict_redis.h" -#include "hiredis.h" +#include +#include typedef struct { DICT dict; @@ -32,6 +102,8 @@ typedef struct { redisContext *c; char *host; int port; + char *prefix; + VSTRING *result; } DICT_REDIS; /* internal function declarations */ @@ -47,12 +119,13 @@ static const char *dict_redis_lookup(DICT *dict, const char *name) DICT_REDIS *dict_redis = (DICT_REDIS *) dict; redisReply *reply; const char *r; - VSTRING *result; + int error; + dict->error = 0; - - result = vstring_alloc(10); - VSTRING_RESET(result); - VSTRING_TERMINATE(result); + + if (msg_verbose) + msg_info("%s: Requesting key %s%s", dict_redis->host, dict_redis->prefix, name); + /* * Optionally fold the key. */ @@ -62,33 +135,42 @@ static const char *dict_redis_lookup(DICT *dict, const char *name) vstring_strcpy(dict->fold_buf, name); name = lowercase(vstring_str(dict->fold_buf)); } - - if(dict_redis->c) { - reply = redisCommand(dict_redis->c,"GET %s",name); - } - else { - dict->error = DICT_ERR_CONFIG; - } - if(reply->str) { - vstring_strcpy(result,reply->str); - r = vstring_str(result); - freeReplyObject(reply); - } - else { - dict->error = DICT_ERR_RETRY; + + /* + * TODO(wietse) domain match, substring query, and key format support as in + * memcache_table. + */ + reply = redisCommand(dict_redis->c, "GET %s%s", dict_redis->prefix, name); + error = dict->error; + if (reply->str) { + vstring_strcpy(dict_redis->result, reply->str); + r = vstring_str(dict_redis->result); + } else { + error = 1; } - return ((dict->error == 0 && *r) ? r : 0); + freeReplyObject(reply); + return ((error == 0 && *r) ? r : 0); } /* redis_parse_config - parse redis configuration file */ static void redis_parse_config(DICT_REDIS *dict_redis, const char *rediscf) { - const char *myname = "redisname_parse"; + const char *myname = "redis_parse_config"; CFG_PARSER *p = dict_redis->parser; +#if 0 + + /* + * TODO(wietse) substring query and key format support as in + * memcache_table. + */ + dict_redis->key_format = cfg_get_str(p, "key_format", "%s", 0, 0); +#endif dict_redis->port = cfg_get_int(p, "port", 6379, 0, 0); dict_redis->host = cfg_get_str(p, "host", "127.0.0.1", 1, 0); + dict_redis->prefix = cfg_get_str(p, "prefix", "", 0, 0); + dict_redis->result = vstring_alloc(10); } /* dict_redis_open - open redis data base */ @@ -97,7 +179,14 @@ DICT *dict_redis_open(const char *name, int open_flags, int dict_flags) { DICT_REDIS *dict_redis; CFG_PARSER *parser; - redisContext *c; + + /* + * Sanity check. + */ + if (open_flags != O_RDONLY) + return (dict_surrogate(DICT_TYPE_REDIS, name, open_flags, dict_flags, + "%s:%s map requires O_RDONLY access mode", + DICT_TYPE_REDIS, name)); /* * Open the configuration file. @@ -114,13 +203,30 @@ DICT *dict_redis_open(const char *name, int open_flags, int dict_flags) dict_redis->parser = parser; redis_parse_config(dict_redis, name); dict_redis->dict.owner = cfg_get_owner(dict_redis->parser); - c = redisConnect(dict_redis->host,dict_redis->port); - if(c->err) { - dict_redis->c = NULL; - } else { - dict_redis->c = c; + dict_redis->c = redisConnect(dict_redis->host, dict_redis->port); + if (dict_redis->c == 0 || dict_redis->c->err) { + msg_warn("%s:%s: Cannot connect to Redis server %s", + DICT_TYPE_REDIS, name, dict_redis->host); + dict_redis->dict.close((DICT *) dict_redis); + return (dict_surrogate(DICT_TYPE_REDIS, name, open_flags, dict_flags, + "open %s: %m", name)); } - +#if 0 + + /* + * TODO(wietse) domain match, substring query, and key format support as in + * memcache_table. + */ + dict_redis->dbc_ctxt = 0; + db_common_parse(&dict_redis->dict, &dict_redis->dbc_ctxt, + dict_redis->key_format, 1); + db_common_parse_domain(dict_redis->parser, dict_redis->dbc_ctxt); + if (db_common_dict_partial(dict_redis->dbc_ctxt)) + /* Breaks recipient delimiters */ + dict_redis->dict.flags |= DICT_FLAG_PATTERN; + else + dict_redis->dict.flags |= DICT_FLAG_FIXED; +#endif return (DICT_DEBUG (&dict_redis->dict)); } @@ -130,8 +236,12 @@ static void dict_redis_close(DICT *dict) { DICT_REDIS *dict_redis = (DICT_REDIS *) dict; + if (dict_redis->c) + redisFree(dict_redis->c); cfg_parser_free(dict_redis->parser); myfree(dict_redis->host); + myfree(dict_redis->prefix); + vstring_free(dict_redis->result); if (dict->fold_buf) vstring_free(dict->fold_buf); dict_free(dict); diff --git a/dict_redis.h b/dict_redis.h index dfd6499..b078c4e 100644 --- a/dict_redis.h +++ b/dict_redis.h @@ -1,10 +1,39 @@ #ifndef _DICT_REDIS_H_INCLUDED_ #define _DICT_REDIS_H_INCLUDED_ +/*++ +/* NAME +/* dict_redis 3h +/* SUMMARY +/* dictionary manager interface to redis databases +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ #include + /* + * External interface. + */ #define DICT_TYPE_REDIS "redis" extern DICT *dict_redis_open(const char *, int, int); +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Titus Jose +/* titus.nitt@gmail.com +/* +/* Updated by: +/* Duncan Bellamy +/* dunk@denkimushi.com +/*--*/ + #endif diff --git a/hiredis.h b/hiredis.h deleted file mode 100644 index 7c04b62..0000000 --- a/hiredis.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_H -#define __HIREDIS_H -#include /* for size_t */ -#include /* for va_list */ -#include /* for struct timeval */ - -#define HIREDIS_MAJOR 0 -#define HIREDIS_MINOR 10 -#define HIREDIS_PATCH 1 - -#define REDIS_ERR -1 -#define REDIS_OK 0 - -/* When an error occurs, the err flag in a context is set to hold the type of - * error that occured. REDIS_ERR_IO means there was an I/O error and you - * should use the "errno" variable to find out what is wrong. - * For other values, the "errstr" field will hold a description. */ -#define REDIS_ERR_IO 1 /* Error in read or write */ -#define REDIS_ERR_EOF 3 /* End of file */ -#define REDIS_ERR_PROTOCOL 4 /* Protocol error */ -#define REDIS_ERR_OOM 5 /* Out of memory */ -#define REDIS_ERR_OTHER 2 /* Everything else... */ - -/* Connection type can be blocking or non-blocking and is set in the - * least significant bit of the flags field in redisContext. */ -#define REDIS_BLOCK 0x1 - -/* Connection may be disconnected before being free'd. The second bit - * in the flags field is set when the context is connected. */ -#define REDIS_CONNECTED 0x2 - -/* The async API might try to disconnect cleanly and flush the output - * buffer and read all subsequent replies before disconnecting. - * This flag means no new commands can come in and the connection - * should be terminated once all replies have been read. */ -#define REDIS_DISCONNECTING 0x4 - -/* Flag specific to the async API which means that the context should be clean - * up as soon as possible. */ -#define REDIS_FREEING 0x8 - -/* Flag that is set when an async callback is executed. */ -#define REDIS_IN_CALLBACK 0x10 - -/* Flag that is set when the async context has one or more subscriptions. */ -#define REDIS_SUBSCRIBED 0x20 - -/* Flag that is set when monitor mode is active */ -#define REDIS_MONITORING 0x40 - -#define REDIS_REPLY_STRING 1 -#define REDIS_REPLY_ARRAY 2 -#define REDIS_REPLY_INTEGER 3 -#define REDIS_REPLY_NIL 4 -#define REDIS_REPLY_STATUS 5 -#define REDIS_REPLY_ERROR 6 - -#ifdef __cplusplus -extern "C" { -#endif - -/* This is the reply object returned by redisCommand() */ -typedef struct redisReply { - int type; /* REDIS_REPLY_* */ - long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ - int len; /* Length of string */ - char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ - size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ - struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ -} redisReply; - -typedef struct redisReadTask { - int type; - int elements; /* number of elements in multibulk container */ - int idx; /* index in parent (array) object */ - void *obj; /* holds user-generated value for a read task */ - struct redisReadTask *parent; /* parent task */ - void *privdata; /* user-settable arbitrary field */ -} redisReadTask; - -typedef struct redisReplyObjectFunctions { - void *(*createString)(const redisReadTask*, char*, size_t); - void *(*createArray)(const redisReadTask*, int); - void *(*createInteger)(const redisReadTask*, long long); - void *(*createNil)(const redisReadTask*); - void (*freeObject)(void*); -} redisReplyObjectFunctions; - -/* State for the protocol parser */ -typedef struct redisReader { - int err; /* Error flags, 0 when there is no error */ - char errstr[128]; /* String representation of error when applicable */ - - char *buf; /* Read buffer */ - size_t pos; /* Buffer cursor */ - size_t len; /* Buffer length */ - - redisReadTask rstack[4]; - int ridx; /* Index of current read task */ - void *reply; /* Temporary reply pointer */ - - redisReplyObjectFunctions *fn; - void *privdata; -} redisReader; - -/* Public API for the protocol parser. */ -redisReader *redisReaderCreate(void); -void redisReaderFree(redisReader *r); -int redisReaderFeed(redisReader *r, const char *buf, size_t len); -int redisReaderGetReply(redisReader *r, void **reply); - -/* Backwards compatibility, can be removed on big version bump. */ -#define redisReplyReaderCreate redisReaderCreate -#define redisReplyReaderFree redisReaderFree -#define redisReplyReaderFeed redisReaderFeed -#define redisReplyReaderGetReply redisReaderGetReply -#define redisReplyReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) -#define redisReplyReaderGetObject(_r) (((redisReader*)(_r))->reply) -#define redisReplyReaderGetError(_r) (((redisReader*)(_r))->errstr) - -/* Function to free the reply objects hiredis returns by default. */ -void freeReplyObject(void *reply); - -/* Functions to format a command according to the protocol. */ -int redisvFormatCommand(char **target, const char *format, va_list ap); -int redisFormatCommand(char **target, const char *format, ...); -int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); - -/* Context for a connection to Redis */ -typedef struct redisContext { - int err; /* Error flags, 0 when there is no error */ - char errstr[128]; /* String representation of error when applicable */ - int fd; - int flags; - char *obuf; /* Write buffer */ - redisReader *reader; /* Protocol reader */ -} redisContext; - -redisContext *redisConnect(const char *ip, int port); -redisContext *redisConnectWithTimeout(const char *ip, int port, struct timeval tv); -redisContext *redisConnectNonBlock(const char *ip, int port); -redisContext *redisConnectUnix(const char *path); -redisContext *redisConnectUnixWithTimeout(const char *path, struct timeval tv); -redisContext *redisConnectUnixNonBlock(const char *path); -int redisSetTimeout(redisContext *c, struct timeval tv); -void redisFree(redisContext *c); -int redisBufferRead(redisContext *c); -int redisBufferWrite(redisContext *c, int *done); - -/* In a blocking context, this function first checks if there are unconsumed - * replies to return and returns one if so. Otherwise, it flushes the output - * buffer to the socket and reads until it has a reply. In a non-blocking - * context, it will return unconsumed replies until there are no more. */ -int redisGetReply(redisContext *c, void **reply); -int redisGetReplyFromReader(redisContext *c, void **reply); - -/* Write a command to the output buffer. Use these functions in blocking mode - * to get a pipeline of commands. */ -int redisvAppendCommand(redisContext *c, const char *format, va_list ap); -int redisAppendCommand(redisContext *c, const char *format, ...); -int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); - -/* Issue a command to Redis. In a blocking context, it is identical to calling - * redisAppendCommand, followed by redisGetReply. The function will return - * NULL if there was an error in performing the request, otherwise it will - * return the reply. In a non-blocking context, it is identical to calling - * only redisAppendCommand and will always return NULL. */ -void *redisvCommand(redisContext *c, const char *format, va_list ap); -void *redisCommand(redisContext *c, const char *format, ...); -void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/mail_dict.c.patch b/mail_dict.c.patch deleted file mode 100644 index dedc900..0000000 --- a/mail_dict.c.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- /home/titus/postfix/postfix-2.9.3/src/global/mail_dict.c 2011-12-20 01:25:38.000000000 +0530 -+++ /home/titus/postfix/postfix-2.9.3.mod/src/global/mail_dict.c 2012-08-08 00:04:12.252776279 +0530 -@@ -38,6 +38,7 @@ - #include - #include - #include -+#include - #include - - typedef struct { -@@ -59,6 +60,9 @@ - #ifdef HAS_SQLITE - DICT_TYPE_SQLITE, dict_sqlite_open, - #endif -+#ifdef HAS_REDIS -+ DICT_TYPE_REDIS, dict_redis_open, -+#endif - DICT_TYPE_MEMCACHE, dict_memcache_open, - 0, - }; diff --git a/patches/postfix-redis.patch b/patches/postfix-redis.patch new file mode 100644 index 0000000..28e8d84 --- /dev/null +++ b/patches/postfix-redis.patch @@ -0,0 +1,136 @@ +diff -Nurp a/conf/dynamicmaps.cf b/conf/dynamicmaps.cf +--- a/conf/dynamicmaps.cf 2014-05-30 12:38:33.000000000 +0100 ++++ b/conf/dynamicmaps.cf 2020-08-15 08:59:29.358727776 +0100 +@@ -5,5 +5,6 @@ lmdb ${LIB_PREFIX}lmdb${LIB_SUFFIX} dict + mysql ${LIB_PREFIX}mysql${LIB_SUFFIX} dict_mysql_open + pcre ${LIB_PREFIX}pcre${LIB_SUFFIX} dict_pcre_open + pgsql ${LIB_PREFIX}pgsql${LIB_SUFFIX} dict_pgsql_open ++redis ${LIB_PREFIX}redis${LIB_SUFFIX} dict_redis_open + sdbm ${LIB_PREFIX}sdbm${LIB_SUFFIX} dict_sdbm_open mkmap_sdbm_open + sqlite ${LIB_PREFIX}sqlite${LIB_SUFFIX} dict_sqlite_open +diff -Nurp a/conf/postfix-files b/conf/postfix-files +--- a/conf/postfix-files 2019-01-29 22:24:42.000000000 +0000 ++++ b/conf/postfix-files 2020-08-15 08:59:59.590574025 +0100 +@@ -78,6 +78,7 @@ $shlib_directory/${LIB_PREFIX}lmdb${LIB_ + $shlib_directory/${LIB_PREFIX}mysql${LIB_SUFFIX}:f:root:-:755 + $shlib_directory/${LIB_PREFIX}pcre${LIB_SUFFIX}:f:root:-:755 + $shlib_directory/${LIB_PREFIX}pgsql${LIB_SUFFIX}:f:root:-:755 ++$shlib_directory/${LIB_PREFIX}redis${LIB_SUFFIX}:f:root:-:755 + $shlib_directory/${LIB_PREFIX}sdbm${LIB_SUFFIX}:f:root:-:755 + $shlib_directory/${LIB_PREFIX}sqlite${LIB_SUFFIX}:f:root:-:755 + $meta_directory/dynamicmaps.cf.d:d:root:-:755 +diff -Nurp a/makedefs b/makedefs +--- a/makedefs 2020-05-06 15:10:47.000000000 +0100 ++++ b/makedefs 2020-08-15 09:02:11.765901819 +0100 +@@ -1167,7 +1167,7 @@ DEFINED_MAP_TYPES=` + + # Propagate AUXLIBS_FOO or merge them into global AUXLIBS (i.e. SYSLIBS). + +-PLUGGABLE_MAPS="CDB LDAP LMDB MYSQL PCRE PGSQL SDBM SQLITE" ++PLUGGABLE_MAPS="CDB LDAP LMDB MYSQL PCRE PGSQL REDIS SDBM SQLITE" + + case "$dynamicmaps" in + yes) for name in $PLUGGABLE_MAPS +diff -Nurp a/src/global/mail_dict.c b/src/global/mail_dict.c +--- a/src/global/mail_dict.c 2014-06-22 01:42:55.000000000 +0100 ++++ b/src/global/mail_dict.c 2020-08-15 09:03:33.445486419 +0100 +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -68,6 +69,9 @@ static const DICT_OPEN_INFO dict_open_in + #ifdef HAS_PGSQL + DICT_TYPE_PGSQL, dict_pgsql_open, + #endif ++#ifdef HAS_REDIS ++ DICT_TYPE_REDIS, dict_redis_open, ++#endif + #ifdef HAS_SQLITE + DICT_TYPE_SQLITE, dict_sqlite_open, + #endif +diff -Nurp a/src/global/Makefile.in b/src/global/Makefile.in +--- a/src/global/Makefile.in 2020-01-12 13:50:56.000000000 +0000 ++++ b/src/global/Makefile.in 2020-08-15 09:12:53.593101032 +0100 +@@ -3,7 +3,7 @@ SRCS = abounce.c anvil_clnt.c been_here. + canon_addr.c cfg_parser.c cleanup_strerror.c cleanup_strflags.c \ + clnt_stream.c conv_time.c db_common.c debug_peer.c debug_process.c \ + defer.c deliver_completed.c deliver_flock.c deliver_pass.c \ +- deliver_request.c dict_ldap.c dict_mysql.c dict_pgsql.c \ ++ deliver_request.c dict_ldap.c dict_mysql.c dict_pgsql.c dict_redis.c \ + dict_proxy.c dict_sqlite.c domain_list.c dot_lockfile.c dot_lockfile_as.c \ + dsb_scan.c dsn.c dsn_buf.c dsn_mask.c dsn_print.c dsn_util.c \ + ehlo_mask.c ext_prop.c file_id.c flush_clnt.c header_opts.c \ +@@ -78,13 +78,13 @@ OBJS = abounce.o anvil_clnt.o been_here. + # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf. + # When hard-linking these maps, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ), + # otherwise it sets the PLUGIN_* macros. +-MAP_OBJ = dict_ldap.o dict_mysql.o dict_pgsql.o dict_sqlite.o mkmap_cdb.o \ ++MAP_OBJ = dict_ldap.o dict_mysql.o dict_pgsql.o dict_redis.o dict_sqlite.o mkmap_cdb.o \ + mkmap_lmdb.o mkmap_sdbm.o + HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \ + canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \ + conv_time.h db_common.h debug_peer.h debug_process.h defer.h \ + deliver_completed.h deliver_flock.h deliver_pass.h deliver_request.h \ +- dict_ldap.h dict_mysql.h dict_pgsql.h dict_proxy.h dict_sqlite.h domain_list.h \ ++ dict_ldap.h dict_mysql.h dict_pgsql.h dict_redis.h dict_proxy.h dict_sqlite.h domain_list.h \ + dot_lockfile.h dot_lockfile_as.h dsb_scan.h dsn.h dsn_buf.h \ + dsn_mask.h dsn_print.h dsn_util.h ehlo_mask.h ext_prop.h \ + file_id.h flush_clnt.h header_opts.h header_token.h input_transp.h \ +@@ -131,7 +131,7 @@ LIBS = ../../lib/lib$(LIB_PREFIX)util$(L + LIB_DIR = ../../lib + INC_DIR = ../../include + PLUGIN_MAP_SO = $(LIB_PREFIX)ldap$(LIB_SUFFIX) $(LIB_PREFIX)mysql$(LIB_SUFFIX) \ +- $(LIB_PREFIX)pgsql$(LIB_SUFFIX) $(LIB_PREFIX)sqlite$(LIB_SUFFIX) \ ++ $(LIB_PREFIX)pgsql$(LIB_SUFFIX) $(LIB_PREFIX)redis$(LIB_SUFFIX) $(LIB_PREFIX)sqlite$(LIB_SUFFIX) \ + $(LIB_PREFIX)lmdb$(LIB_SUFFIX) $(LIB_PREFIX)cdb$(LIB_SUFFIX) \ + $(LIB_PREFIX)sdbm$(LIB_SUFFIX) + MAKES = +@@ -167,6 +167,9 @@ $(LIB_PREFIX)mysql$(LIB_SUFFIX): dict_my + $(LIB_PREFIX)pgsql$(LIB_SUFFIX): dict_pgsql.o + $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_pgsql.o $(AUXLIBS_PGSQL) + ++$(LIB_PREFIX)redis$(LIB_SUFFIX): dict_redis.o ++ $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_redis.o $(AUXLIBS_REDIS) ++ + $(LIB_PREFIX)sqlite$(LIB_SUFFIX): dict_sqlite.o + $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_sqlite.o $(AUXLIBS_SQLITE) + +@@ -521,6 +524,8 @@ surrogate_test: mail_dict surrogate.ref + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict mysql:/xx read >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict pgsql:/xx write >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict pgsql:/xx read >>surrogate.tmp 2>&1 ++ echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict redis:/xx write >>surrogate.tmp 2>&1 ++ echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict redis:/xx read >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict sqlite:/xx write >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict sqlite:/xx read >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict memcache:/xx read >>surrogate.tmp 2>&1 +@@ -1183,6 +1188,17 @@ dict_pgsql.o: db_common.h + dict_pgsql.o: dict_pgsql.c + dict_pgsql.o: dict_pgsql.h + dict_pgsql.o: string_list.h ++dict_redis.o: ../../include/dict.h ++dict_redis.o: ../../include/msg.h ++dict_redis.o: ../../include/mymalloc.h ++dict_redis.o: ../../include/vbuf.h ++dict_redis.o: ../../include/vstream.h ++dict_redis.o: ../../include/vstring.h ++dict_redis.o: ../../include/stringops.h ++dict_redis.o: ../../include/sys_defs.h ++dict_redis.o: cfg_parser.h ++dict_redis.o: dict_redis.c ++dict_redis.o: dict_redis.h + dict_proxy.o: ../../include/argv.h + dict_proxy.o: ../../include/attr.h + dict_proxy.o: ../../include/check_arg.h +@@ -1768,6 +1784,7 @@ mail_dict.o: dict_ldap.h + mail_dict.o: dict_memcache.h + mail_dict.o: dict_mysql.h + mail_dict.o: dict_pgsql.h ++mail_dict.o: dict_redis.h + mail_dict.o: dict_proxy.h + mail_dict.o: dict_sqlite.h + mail_dict.o: dynamicmaps.h diff --git a/patches/postfix3.6-musl.patch b/patches/postfix3.6-musl.patch new file mode 100644 index 0000000..e6b31f1 --- /dev/null +++ b/patches/postfix3.6-musl.patch @@ -0,0 +1,30 @@ +diff -Nurp a/src/dns/dns_lookup.c aa/src/dns/dns_lookup.c +--- a/src/dns/dns_lookup.c 2020-05-23 17:38:26.000000000 +0100 ++++ aa/src/dns/dns_lookup.c 2020-09-24 19:42:10.782442351 +0100 +@@ -394,8 +394,10 @@ static int dns_neg_query(const char *nam + if (msg_verbose) + msg_info("res_nmkquery() failed"); + return (len); +- } else if ((len = DNS_RES_NSEND(&dns_res_state, +- msg_buf, len, answer, anslen)) < 0) { ++ } ++ msg_buf[3] |= 32; // AD flag ++ if ((len = DNS_RES_NSEND(&dns_res_state, ++ msg_buf, len, answer, anslen)) < 0) { + DNS_SET_H_ERRNO(&dns_res_state, TRY_AGAIN); + if (msg_verbose) + msg_info("res_nsend() failed"); +@@ -538,11 +540,12 @@ static int dns_query(const char *name, i + for (;;) { + dns_res_state.options &= ~saved_options; + dns_res_state.options |= flags; +- if (keep_notfound && var_dns_ncache_ttl_fix) { ++ if (1) { + #ifdef HAVE_RES_SEND + len = dns_neg_query((char *) name, C_IN, type, reply->buf, + reply->buf_len); + #else ++#error HAVE_RES_SEND not defined + var_dns_ncache_ttl_fix = 0; + msg_warn("system library does not support %s=yes" + " -- ignoring this setting", VAR_DNS_NCACHE_TTL_FIX); diff --git a/patches/postfix3.6-redis.patch b/patches/postfix3.6-redis.patch new file mode 100644 index 0000000..42ff912 --- /dev/null +++ b/patches/postfix3.6-redis.patch @@ -0,0 +1,196 @@ +--- /var/tmp/postfix-3.6-20210224/conf/dynamicmaps.cf 2014-05-30 07:38:33.000000000 -0400 ++++ ./conf/dynamicmaps.cf 2021-03-11 18:07:16.529195712 -0500 +@@ -5,5 +5,6 @@ + mysql ${LIB_PREFIX}mysql${LIB_SUFFIX} dict_mysql_open + pcre ${LIB_PREFIX}pcre${LIB_SUFFIX} dict_pcre_open + pgsql ${LIB_PREFIX}pgsql${LIB_SUFFIX} dict_pgsql_open ++redis ${LIB_PREFIX}redis${LIB_SUFFIX} dict_redis_open + sdbm ${LIB_PREFIX}sdbm${LIB_SUFFIX} dict_sdbm_open mkmap_sdbm_open + sqlite ${LIB_PREFIX}sqlite${LIB_SUFFIX} dict_sqlite_open +diff '--exclude=man' '--exclude=html' '--exclude=README_FILES' '--exclude=INSTALL' '--exclude=.indent.pro' -r -ur --new-file /var/tmp/postfix-3.6-20210224/conf/postfix-files ./conf/postfix-files +--- /var/tmp/postfix-3.6-20210224/conf/postfix-files 2019-01-29 17:24:42.000000000 -0500 ++++ ./conf/postfix-files 2021-03-11 18:07:16.530195726 -0500 +@@ -78,6 +78,7 @@ + $shlib_directory/${LIB_PREFIX}mysql${LIB_SUFFIX}:f:root:-:755 + $shlib_directory/${LIB_PREFIX}pcre${LIB_SUFFIX}:f:root:-:755 + $shlib_directory/${LIB_PREFIX}pgsql${LIB_SUFFIX}:f:root:-:755 ++$shlib_directory/${LIB_PREFIX}redis${LIB_SUFFIX}:f:root:-:755 + $shlib_directory/${LIB_PREFIX}sdbm${LIB_SUFFIX}:f:root:-:755 + $shlib_directory/${LIB_PREFIX}sqlite${LIB_SUFFIX}:f:root:-:755 + $meta_directory/dynamicmaps.cf.d:d:root:-:755 +@@ -200,6 +201,7 @@ + $manpage_directory/man5/nisplus_table.5:f:root:-:644 + $manpage_directory/man5/pcre_table.5:f:root:-:644 + $manpage_directory/man5/pgsql_table.5:f:root:-:644 ++$manpage_directory/man5/redis_table.5:f:root:-:644 + $manpage_directory/man5/postconf.5:f:root:-:644 + $manpage_directory/man5/postfix-wrapper.5:f:root:-:644 + $manpage_directory/man5/regexp_table.5:f:root:-:644 +@@ -307,6 +309,7 @@ + $readme_directory/PACKAGE_README:f:root:-:644 + $readme_directory/PCRE_README:f:root:-:644 + $readme_directory/PGSQL_README:f:root:-:644 ++$readme_directory/REDIS_README:f:root:-:644 + $readme_directory/POSTSCREEN_README:f:root:-:644 + $readme_directory/QMQP_README:f:root:-:644:o + $readme_directory/QSHAPE_README:f:root:-:644 +@@ -363,6 +366,7 @@ + $html_directory/PACKAGE_README.html:f:root:-:644 + $html_directory/PCRE_README.html:f:root:-:644 + $html_directory/PGSQL_README.html:f:root:-:644 ++$html_directory/REDIS_README.html:f:root:-:644 + $html_directory/POSTSCREEN_README.html:f:root:-:644 + $html_directory/QMQP_README.html:f:root:-:644:o + $html_directory/QSHAPE_README.html:f:root:-:644 +@@ -414,6 +418,7 @@ + $html_directory/oqmgr.8.html:f:root:-:644 + $html_directory/pcre_table.5.html:f:root:-:644 + $html_directory/pgsql_table.5.html:f:root:-:644 ++$html_directory/redis_table.5.html:f:root:-:644 + $html_directory/pickup.8.html:f:root:-:644 + $html_directory/pipe.8.html:f:root:-:644 + $html_directory/postalias.1.html:f:root:-:644 +diff '--exclude=man' '--exclude=html' '--exclude=README_FILES' '--exclude=INSTALL' '--exclude=.indent.pro' -r -ur --new-file /var/tmp/postfix-3.6-20210224/makedefs ./makedefs +--- /var/tmp/postfix-3.6-20210224/makedefs 2020-09-30 17:22:49.000000000 -0400 ++++ ./makedefs 2021-03-11 18:07:16.531195739 -0500 +@@ -1165,7 +1165,7 @@ + + # Propagate AUXLIBS_FOO or merge them into global AUXLIBS (i.e. SYSLIBS). + +-PLUGGABLE_MAPS="CDB LDAP LMDB MYSQL PCRE PGSQL SDBM SQLITE" ++PLUGGABLE_MAPS="CDB LDAP LMDB MYSQL PCRE PGSQL REDIS SDBM SQLITE" + + case "$dynamicmaps" in + yes) for name in $PLUGGABLE_MAPS +diff '--exclude=man' '--exclude=html' '--exclude=README_FILES' '--exclude=INSTALL' '--exclude=.indent.pro' -r -ur --new-file /var/tmp/postfix-3.6-20210224/proto/DATABASE_README.html ./proto/DATABASE_README.html +--- /var/tmp/postfix-3.6-20210224/proto/DATABASE_README.html 2020-08-29 13:51:42.000000000 -0400 ++++ ./proto/DATABASE_README.html 2021-03-13 17:14:36.642652892 -0500 +@@ -421,6 +421,11 @@ + as used in "sdbm:table" is the database file name without the ".dir" + or ".pag" suffix. + ++
redis (read-only)
++ ++
Redis database. Configuration details are given in redis_table(5). ++
++ +
socketmap (read-only)
+ +
Sendmail-style socketmap client. The name of the table is +diff '--exclude=man' '--exclude=html' '--exclude=README_FILES' '--exclude=INSTALL' '--exclude=.indent.pro' -r -ur --new-file /var/tmp/postfix-3.6-20210224/proto/redis_table ./proto/redis_table +--- /var/tmp/postfix-3.6-20210224/src/global/mail_dict.c 2014-06-21 20:42:55.000000000 -0400 ++++ ./src/global/mail_dict.c 2021-03-11 18:07:16.532195753 -0500 +@@ -45,6 +45,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -68,6 +69,9 @@ + #ifdef HAS_PGSQL + DICT_TYPE_PGSQL, dict_pgsql_open, + #endif ++#ifdef HAS_REDIS ++ DICT_TYPE_REDIS, dict_redis_open, ++#endif + #ifdef HAS_SQLITE + DICT_TYPE_SQLITE, dict_sqlite_open, + #endif +diff '--exclude=man' '--exclude=html' '--exclude=README_FILES' '--exclude=INSTALL' '--exclude=.indent.pro' -r -ur --new-file /var/tmp/postfix-3.6-20210224/src/global/Makefile.in ./src/global/Makefile.in +--- /var/tmp/postfix-3.6-20210224/src/global/Makefile.in 2021-01-09 16:24:11.000000000 -0500 ++++ ./src/global/Makefile.in 2021-03-11 18:07:16.535195793 -0500 +@@ -3,7 +3,7 @@ + canon_addr.c cfg_parser.c cleanup_strerror.c cleanup_strflags.c \ + clnt_stream.c conv_time.c db_common.c debug_peer.c debug_process.c \ + defer.c deliver_completed.c deliver_flock.c deliver_pass.c \ +- deliver_request.c dict_ldap.c dict_mysql.c dict_pgsql.c \ ++ deliver_request.c dict_ldap.c dict_mysql.c dict_pgsql.c dict_redis.c \ + dict_proxy.c dict_sqlite.c domain_list.c dot_lockfile.c dot_lockfile_as.c \ + dsb_scan.c dsn.c dsn_buf.c dsn_mask.c dsn_print.c dsn_util.c \ + ehlo_mask.c ext_prop.c file_id.c flush_clnt.c header_opts.c \ +@@ -80,13 +80,13 @@ + # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf. + # When hard-linking these maps, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ), + # otherwise it sets the PLUGIN_* macros. +-MAP_OBJ = dict_ldap.o dict_mysql.o dict_pgsql.o dict_sqlite.o mkmap_cdb.o \ ++MAP_OBJ = dict_ldap.o dict_mysql.o dict_pgsql.o dict_redis.o dict_sqlite.o mkmap_cdb.o \ + mkmap_lmdb.o mkmap_sdbm.o + HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \ + canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \ + conv_time.h db_common.h debug_peer.h debug_process.h defer.h \ + deliver_completed.h deliver_flock.h deliver_pass.h deliver_request.h \ +- dict_ldap.h dict_mysql.h dict_pgsql.h dict_proxy.h dict_sqlite.h domain_list.h \ ++ dict_ldap.h dict_mysql.h dict_pgsql.h dict_redis.h dict_proxy.h dict_sqlite.h domain_list.h \ + dot_lockfile.h dot_lockfile_as.h dsb_scan.h dsn.h dsn_buf.h \ + dsn_mask.h dsn_print.h dsn_util.h ehlo_mask.h ext_prop.h \ + file_id.h flush_clnt.h header_opts.h header_token.h input_transp.h \ +@@ -135,7 +135,7 @@ + LIB_DIR = ../../lib + INC_DIR = ../../include + PLUGIN_MAP_SO = $(LIB_PREFIX)ldap$(LIB_SUFFIX) $(LIB_PREFIX)mysql$(LIB_SUFFIX) \ +- $(LIB_PREFIX)pgsql$(LIB_SUFFIX) $(LIB_PREFIX)sqlite$(LIB_SUFFIX) \ ++ $(LIB_PREFIX)pgsql$(LIB_SUFFIX) $(LIB_PREFIX)redis$(LIB_SUFFIX) $(LIB_PREFIX)sqlite$(LIB_SUFFIX) \ + $(LIB_PREFIX)lmdb$(LIB_SUFFIX) $(LIB_PREFIX)cdb$(LIB_SUFFIX) \ + $(LIB_PREFIX)sdbm$(LIB_SUFFIX) + MAKES = +@@ -171,6 +171,9 @@ + $(LIB_PREFIX)pgsql$(LIB_SUFFIX): dict_pgsql.o + $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_pgsql.o $(AUXLIBS_PGSQL) + ++$(LIB_PREFIX)redis$(LIB_SUFFIX): dict_redis.o ++ $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_redis.o $(AUXLIBS_REDIS) ++ + $(LIB_PREFIX)sqlite$(LIB_SUFFIX): dict_sqlite.o + $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_sqlite.o $(AUXLIBS_SQLITE) + +@@ -535,6 +538,8 @@ + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict mysql:/xx read >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict pgsql:/xx write >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict pgsql:/xx read >>surrogate.tmp 2>&1 ++ echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict redis:/xx write >>surrogate.tmp 2>&1 ++ echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict redis:/xx read >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict sqlite:/xx write >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict sqlite:/xx read >>surrogate.tmp 2>&1 + echo get foo| $(SHLIB_ENV) $(VALGRIND) ./mail_dict memcache:/xx read >>surrogate.tmp 2>&1 +@@ -1231,6 +1236,17 @@ + dict_pgsql.o: dict_pgsql.c + dict_pgsql.o: dict_pgsql.h + dict_pgsql.o: string_list.h ++dict_redis.o: ../../include/dict.h ++dict_redis.o: ../../include/msg.h ++dict_redis.o: ../../include/mymalloc.h ++dict_redis.o: ../../include/vbuf.h ++dict_redis.o: ../../include/vstream.h ++dict_redis.o: ../../include/vstring.h ++dict_redis.o: ../../include/stringops.h ++dict_redis.o: ../../include/sys_defs.h ++dict_redis.o: cfg_parser.h ++dict_redis.o: dict_redis.c ++dict_redis.o: dict_redis.h + dict_proxy.o: ../../include/argv.h + dict_proxy.o: ../../include/attr.h + dict_proxy.o: ../../include/check_arg.h +@@ -1835,6 +1851,7 @@ + mail_dict.o: dict_memcache.h + mail_dict.o: dict_mysql.h + mail_dict.o: dict_pgsql.h ++mail_dict.o: dict_redis.h + mail_dict.o: dict_proxy.h + mail_dict.o: dict_sqlite.h + mail_dict.o: dynamicmaps.h +diff '--exclude=man' '--exclude=html' '--exclude=README_FILES' '--exclude=INSTALL' '--exclude=.indent.pro' -r -ur --new-file /var/tmp/postfix-3.6-20210224/src/postconf/postconf.c ./src/postconf/postconf.c +--- /var/tmp/postfix-3.6-20210224/src/postconf/postconf.c 2021-01-03 12:08:51.000000000 -0500 ++++ ./src/postconf/postconf.c 2021-03-13 16:50:27.846333680 -0500 +@@ -339,6 +339,10 @@ + /* with support for SDBM databases. + /* + /* This feature is available with Postfix 2.2 and later. ++/* .IP "\fBredis\fR (read-only)" ++/* Redis database. This is described in \fBredis_table\fR(5). ++/* ++/* This feature is available with Postfix 3.7 and later. + /* .IP "\fBsocketmap\fR (read-only)" + /* Sendmail-style socketmap client. The table name is + /* \fBinet\fR:\fIhost\fR:\fIport\fR:\fIname\fR for a TCP/IP diff --git a/redis_table b/redis_table new file mode 100644 index 0000000..ce5547a --- /dev/null +++ b/redis_table @@ -0,0 +1,81 @@ +#++ +# NAME +# redis_table 5 +# SUMMARY +# Postfix Redis client configuration +# SYNOPSIS +# \fBpostmap -q "\fIprefix:string\fB" redis:/etc/postfix/\fIfilename\fR +# +# \fBpostmap -q - redis:/etc/postfix/\fIfilename\fB <\fIinputfile\fR +# DESCRIPTION +# The Postfix mail system uses optional tables for address +# rewriting or mail routing. These tables are usually in +# \fBdbm\fR or \fBdb\fR format. +# +# Alternatively, lookup tables can be specified as Redis +# databases. In order to use Redis lookups, define a Redis +# source as a lookup table in main.cf, for example: +# .nf +# virtual_alias_maps = redis:/etc/postfix/redis-valias-maps.cf +# .fi +# +# The file /etc/postfix/redis-valias-maps.cf has the same +# format as the Postfix main.cf file, and can specify the +# parameters described below. +# .IP "\fBhost\fR" +# The IP address of the host that Postfix will try to connect +# to and query from. +# .sp +# Example: +# .nf +# host = 127.0.0.1 +# .fi +# .IP "\fBport\fR" +# The TCP port that Postfix will connect to and query from. +# If not specified the default of \fB6379\fR will be used. +# .sp +# Example: +# .nf +# port = 6379 +# .fi +# .IP "\fBprefix\fR" +# This is the prefix that is added to the query from Postfix +# before it is passed to Redis for a lookup, allowing postfix +# to use simple key:value lookups from Redis. +# .sp +# Examples: +# .nf +# prefix = VALI +# prefix = LOCAL +# prefix = REV +# prefix = HELO +# .fi +# SEE ALSO +# .na +# .nf +# postmap(1), Postfix lookup table manager +# postconf(5), configuration parameters +# ldap_table(5), LDAP lookup tables +# mysql_table(5), MySQL lookup tables +# sqlite_table(5), SQLite lookup tables +# README FILES +# .ad +# .fi +# Use "\fBpostconf readme_directory\fR" or +# "\fBpostconf html_directory\fR" to locate this information. +# .na +# .nf +# DATABASE_README, Postfix lookup table overview +# REDIS_README, Postfix Redis client support +# LICENSE +# The Secure Mailer license must be distributed with this software. +# HISTORY +# Redis support was introduced with Postfix version 3.7. +# AUTHOR(S) +# Titus Jose +# titus.nitt@gmail.com +# +# Updated by: +# Duncan Bellamy +# dunk@denkimushi.com +#--