/*++
/* NAME
/* rewrite_clnt 3
/* SUMMARY
/* address rewrite service client
/* SYNOPSIS
/* #include <vstring.h>
/* #include <rewrite_clnt.h>
/*
/* VSTRING *rewrite_clnt(ruleset, address, result)
/* const char *ruleset;
/* const char *address;
/*
/* VSTRING *rewrite_clnt_internal(ruleset, address, result)
/* const char *ruleset;
/* const char *address;
/* VSTRING *result;
/* DESCRIPTION
/* This module implements a mail address rewriting client.
/*
/* rewrite_clnt() sends a rule set name and external-form address to the
/* rewriting service and returns the resulting external-form address.
/* In case of communication failure the program keeps trying until the
/* mail system shuts down.
/*
/* rewrite_clnt_internal() performs the same functionality but takes
/* input in internal (unquoted) form, and produces output in internal
/* (unquoted) form.
/* DIAGNOSTICS
/* Warnings: communication failure. Fatal error: mail system is down.
/* SEE ALSO
/* mail_proto(3h) low-level mail component glue.
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/
/* System library. */
#include <sys_defs.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
/* Utility library. */
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <vstring_vstream.h>
#include <events.h>
#include <iostuff.h>
#include <quote_822_local.h>
/* Global library. */
#include "mail_proto.h"
#include "mail_params.h"
#include "clnt_stream.h"
#include "rewrite_clnt.h"
/* Application-specific. */
/*
* XXX this is shared with the resolver client to save a file descriptor .
*/
CLNT_STREAM *rewrite_clnt_stream = 0 ;
static time_t last_expire;
static VSTRING *last_rule;
static VSTRING *last_addr;
static VSTRING *last_result;
/* rewrite_clnt_handshake - receive server protocol announcement */
static int rewrite_clnt_handshake(VSTREAM *stream)
{
return (attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_STREQ(MAIL_ATTR_PROTO, MAIL_ATTR_PROTO_TRIVIAL),
ATTR_TYPE_END));
}
/* rewrite_clnt - rewrite address to (transport, next hop, recipient) */
VSTRING *rewrite_clnt(const char *rule, const char *addr, VSTRING *result)
{
VSTREAM *stream;
int server_flags;
int count = 0 ;
/*
* One - entry cache .
*/
if (last_addr == 0 ) {
last_rule = vstring_alloc(10 );
last_addr = vstring_alloc(100 );
last_result = vstring_alloc(100 );
}
/*
* Sanity check . An address must be in externalized form . The result must
* not clobber the input , because we may have to retransmit the query .
*/
#define STR vstring_str
if (*addr == 0 )
addr = "" ;
if (addr == STR(result))
msg_panic("rewrite_clnt: result clobbers input" );
/*
* Peek at the cache .
*/
if (time((time_t *) 0 ) < last_expire
&& strcmp(addr, STR(last_addr)) == 0
&& strcmp(rule, STR(last_rule)) == 0 ) {
vstring_strcpy(result, STR(last_result));
if (msg_verbose)
msg_info("rewrite_clnt: cached: %s: %s -> %s" ,
rule, addr, vstring_str(result));
return (result);
}
/*
* Keep trying until we get a complete response . The rewrite service is
* CPU bound and making the client asynchronous would just complicate the
* code .
*/
if (rewrite_clnt_stream == 0 )
rewrite_clnt_stream = clnt_stream_create(MAIL_CLASS_PRIVATE,
var_rewrite_service,
var_ipc_idle_limit,
var_ipc_ttl_limit,
rewrite_clnt_handshake);
for (;;) {
stream = clnt_stream_access(rewrite_clnt_stream);
errno = 0 ;
count += 1 ;
if (stream == 0
|| attr_print(stream, ATTR_FLAG_NONE,
SEND_ATTR_STR(MAIL_ATTR_REQ, REWRITE_ADDR),
SEND_ATTR_STR(MAIL_ATTR_RULE, rule),
SEND_ATTR_STR(MAIL_ATTR_ADDR, addr),
ATTR_TYPE_END) != 0
|| vstream_fflush(stream)
|| attr_scan(stream, ATTR_FLAG_STRICT,
RECV_ATTR_INT(MAIL_ATTR_FLAGS, &server_flags),
RECV_ATTR_STR(MAIL_ATTR_ADDR, result),
ATTR_TYPE_END) != 2 ) {
if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
msg_warn("problem talking to service %s: %m" ,
var_rewrite_service);
} else {
if (msg_verbose)
msg_info("rewrite_clnt: %s: %s -> %s" ,
rule, addr, vstring_str(result));
/* Server-requested disconnect. */
if (server_flags != 0 )
clnt_stream_recover(rewrite_clnt_stream);
break ;
}
sleep(1 ); /* XXX make configurable */
clnt_stream_recover(rewrite_clnt_stream);
}
/*
* Update the cache .
*/
vstring_strcpy(last_rule, rule);
vstring_strcpy(last_addr, addr);
vstring_strcpy(last_result, STR(result));
last_expire = time((time_t *) 0 ) + 30 ; /* XXX make configurable */
return (result);
}
/* rewrite_clnt_internal - rewrite from/to internal form */
VSTRING *rewrite_clnt_internal(const char *ruleset, const char *addr, VSTRING *result)
{
VSTRING *src = vstring_alloc(100 );
VSTRING *dst = vstring_alloc(100 );
/*
* Convert the address from internal address form to external RFC822
* form , then rewrite it . After rewriting , convert to internal form .
*/
quote_822_local(src, addr);
rewrite_clnt(ruleset, STR(src), dst);
unquote_822_local(result, STR(dst));
vstring_free(src);
vstring_free(dst);
return (result);
}
#ifdef TEST
#include <stdlib.h>
#include <string.h>
#include <msg_vstream.h>
#include <split_at.h>
#include <vstring_vstream.h>
#include <mail_conf.h>
#include <mail_params.h>
static NORETURN usage(char *myname)
{
msg_fatal("usage: %s [-v] [rule address...]" , myname);
}
static void rewrite(char *rule, char *addr, VSTRING *reply)
{
rewrite_clnt(rule, addr, reply);
vstream_printf("%-10s %s\n" , "rule" , rule);
vstream_printf("%-10s %s\n" , "address" , addr);
vstream_printf("%-10s %s\n\n" , "result" , STR(reply));
vstream_fflush(VSTREAM_OUT);
}
int main(int argc, char **argv)
{
VSTRING *reply;
int ch;
char *rule;
char *addr;
msg_vstream_init(argv[0 ], VSTREAM_ERR);
mail_conf_read();
msg_info("using config files in %s" , var_config_dir);
if (chdir(var_queue_dir) < 0 )
msg_fatal("chdir %s: %m" , var_queue_dir);
while ((ch = GETOPT(argc, argv, "v" )) > 0 ) {
switch (ch) {
case 'v' :
msg_verbose++;
break ;
default :
usage(argv[0 ]);
}
}
reply = vstring_alloc(1 );
if (argc > optind) {
for (;;) {
if ((rule = argv[optind++]) == 0 )
break ;
if ((addr = argv[optind++]) == 0 )
usage(argv[0 ]);
rewrite(rule, addr, reply);
}
} else {
VSTRING *buffer = vstring_alloc(1 );
while (vstring_fgets_nonl(buffer, VSTREAM_IN)) {
if ((addr = split_at(STR(buffer), ' ' )) == 0
|| *(rule = STR(buffer)) == 0 )
usage(argv[0 ]);
rewrite(rule, addr, reply);
}
vstring_free(buffer);
}
vstring_free(reply);
exit (0 );
}
#endif
Messung V0.5 in Prozent C=74 H=95 G=84
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet am 2026-08-08)
¤
*© Formatika GbR, Deutschland