Bug Summary

File:src/usr.sbin/smtpd/smtpd/../mta.c
Warning:line 1383, column 3
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name mta.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/smtpd/smtpd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I /usr/src/usr.sbin/smtpd/smtpd/.. -D IO_TLS -D QUEUE_PROFILING -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/smtpd/smtpd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/smtpd/smtpd/../mta.c
1/* $OpenBSD: mta.c,v 1.247 2024/01/03 08:11:15 op Exp $ */
2
3/*
4 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
5 * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org>
6 * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net>
7 * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22#include <inttypes.h>
23#include <stdlib.h>
24#include <string.h>
25#include <time.h>
26#include <tls.h>
27
28#include "smtpd.h"
29#include "log.h"
30#include "ssl.h"
31
32#define MAXERROR_PER_ROUTE4 4
33
34#define DELAY_CHECK_SOURCE1 1
35#define DELAY_CHECK_SOURCE_SLOW10 10
36#define DELAY_CHECK_SOURCE_FAST0 0
37#define DELAY_CHECK_LIMIT5 5
38
39#define DELAY_QUADRATIC1 1
40#define DELAY_ROUTE_BASE15 15
41#define DELAY_ROUTE_MAX3600 3600
42
43#define RELAY_ONHOLD0x01 0x01
44#define RELAY_HOLDQ0x02 0x02
45
46static void mta_setup_dispatcher(struct dispatcher *);
47static void mta_handle_envelope(struct envelope *, const char *);
48static void mta_query_smarthost(struct envelope *);
49static void mta_on_smarthost(struct envelope *, const char *);
50static void mta_query_mx(struct mta_relay *);
51static void mta_query_secret(struct mta_relay *);
52static void mta_query_preference(struct mta_relay *);
53static void mta_query_source(struct mta_relay *);
54static void mta_on_mx(void *, void *, void *);
55static void mta_on_secret(struct mta_relay *, const char *);
56static void mta_on_preference(struct mta_relay *, int);
57static void mta_on_source(struct mta_relay *, struct mta_source *);
58static void mta_on_timeout(struct runq *, void *);
59static void mta_connect(struct mta_connector *);
60static void mta_route_enable(struct mta_route *);
61static void mta_route_disable(struct mta_route *, int, int);
62static void mta_drain(struct mta_relay *);
63static void mta_delivery_flush_event(int, short, void *);
64static void mta_flush(struct mta_relay *, int, const char *);
65static struct mta_route *mta_find_route(struct mta_connector *, time_t, int*,
66 time_t*, struct mta_mx **);
67static void mta_log(const struct mta_envelope *, const char *, const char *,
68 const char *, const char *);
69
70SPLAY_HEAD(mta_relay_tree, mta_relay)struct mta_relay_tree { struct mta_relay *sph_root; };
71static struct mta_relay *mta_relay(struct envelope *, struct relayhost *);
72static void mta_relay_ref(struct mta_relay *);
73static void mta_relay_unref(struct mta_relay *);
74static void mta_relay_show(struct mta_relay *, struct mproc *, uint32_t, time_t);
75static int mta_relay_cmp(const struct mta_relay *, const struct mta_relay *);
76SPLAY_PROTOTYPE(mta_relay_tree, mta_relay, entry, mta_relay_cmp)void mta_relay_tree_SPLAY(struct mta_relay_tree *, struct mta_relay
*); void mta_relay_tree_SPLAY_MINMAX(struct mta_relay_tree *
, int); struct mta_relay *mta_relay_tree_SPLAY_INSERT(struct mta_relay_tree
*, struct mta_relay *); struct mta_relay *mta_relay_tree_SPLAY_REMOVE
(struct mta_relay_tree *, struct mta_relay *); static __attribute__
((__unused__)) __inline struct mta_relay * mta_relay_tree_SPLAY_FIND
(struct mta_relay_tree *head, struct mta_relay *elm) { if (((
head)->sph_root == ((void *)0))) return(((void *)0)); mta_relay_tree_SPLAY
(head, elm); if ((mta_relay_cmp)(elm, (head)->sph_root) ==
0) return (head->sph_root); return (((void *)0)); } static
__attribute__((__unused__)) __inline struct mta_relay * mta_relay_tree_SPLAY_NEXT
(struct mta_relay_tree *head, struct mta_relay *elm) { mta_relay_tree_SPLAY
(head, elm); if ((elm)->entry.spe_right != ((void *)0)) { elm
= (elm)->entry.spe_right; while ((elm)->entry.spe_left
!= ((void *)0)) { elm = (elm)->entry.spe_left; } } else elm
= ((void *)0); return (elm); } static __attribute__((__unused__
)) __inline struct mta_relay * mta_relay_tree_SPLAY_MIN_MAX(struct
mta_relay_tree *head, int val) { mta_relay_tree_SPLAY_MINMAX
(head, val); return ((head)->sph_root); }
;
77
78SPLAY_HEAD(mta_host_tree, mta_host)struct mta_host_tree { struct mta_host *sph_root; };
79static struct mta_host *mta_host(const struct sockaddr *);
80static void mta_host_ref(struct mta_host *);
81static void mta_host_unref(struct mta_host *);
82static int mta_host_cmp(const struct mta_host *, const struct mta_host *);
83SPLAY_PROTOTYPE(mta_host_tree, mta_host, entry, mta_host_cmp)void mta_host_tree_SPLAY(struct mta_host_tree *, struct mta_host
*); void mta_host_tree_SPLAY_MINMAX(struct mta_host_tree *, int
); struct mta_host *mta_host_tree_SPLAY_INSERT(struct mta_host_tree
*, struct mta_host *); struct mta_host *mta_host_tree_SPLAY_REMOVE
(struct mta_host_tree *, struct mta_host *); static __attribute__
((__unused__)) __inline struct mta_host * mta_host_tree_SPLAY_FIND
(struct mta_host_tree *head, struct mta_host *elm) { if (((head
)->sph_root == ((void *)0))) return(((void *)0)); mta_host_tree_SPLAY
(head, elm); if ((mta_host_cmp)(elm, (head)->sph_root) == 0
) return (head->sph_root); return (((void *)0)); } static __attribute__
((__unused__)) __inline struct mta_host * mta_host_tree_SPLAY_NEXT
(struct mta_host_tree *head, struct mta_host *elm) { mta_host_tree_SPLAY
(head, elm); if ((elm)->entry.spe_right != ((void *)0)) { elm
= (elm)->entry.spe_right; while ((elm)->entry.spe_left
!= ((void *)0)) { elm = (elm)->entry.spe_left; } } else elm
= ((void *)0); return (elm); } static __attribute__((__unused__
)) __inline struct mta_host * mta_host_tree_SPLAY_MIN_MAX(struct
mta_host_tree *head, int val) { mta_host_tree_SPLAY_MINMAX(head
, val); return ((head)->sph_root); }
;
84
85SPLAY_HEAD(mta_domain_tree, mta_domain)struct mta_domain_tree { struct mta_domain *sph_root; };
86static struct mta_domain *mta_domain(char *, int);
87#if 0
88static void mta_domain_ref(struct mta_domain *);
89#endif
90static void mta_domain_unref(struct mta_domain *);
91static int mta_domain_cmp(const struct mta_domain *, const struct mta_domain *);
92SPLAY_PROTOTYPE(mta_domain_tree, mta_domain, entry, mta_domain_cmp)void mta_domain_tree_SPLAY(struct mta_domain_tree *, struct mta_domain
*); void mta_domain_tree_SPLAY_MINMAX(struct mta_domain_tree
*, int); struct mta_domain *mta_domain_tree_SPLAY_INSERT(struct
mta_domain_tree *, struct mta_domain *); struct mta_domain *
mta_domain_tree_SPLAY_REMOVE(struct mta_domain_tree *, struct
mta_domain *); static __attribute__((__unused__)) __inline struct
mta_domain * mta_domain_tree_SPLAY_FIND(struct mta_domain_tree
*head, struct mta_domain *elm) { if (((head)->sph_root ==
((void *)0))) return(((void *)0)); mta_domain_tree_SPLAY(head
, elm); if ((mta_domain_cmp)(elm, (head)->sph_root) == 0) return
(head->sph_root); return (((void *)0)); } static __attribute__
((__unused__)) __inline struct mta_domain * mta_domain_tree_SPLAY_NEXT
(struct mta_domain_tree *head, struct mta_domain *elm) { mta_domain_tree_SPLAY
(head, elm); if ((elm)->entry.spe_right != ((void *)0)) { elm
= (elm)->entry.spe_right; while ((elm)->entry.spe_left
!= ((void *)0)) { elm = (elm)->entry.spe_left; } } else elm
= ((void *)0); return (elm); } static __attribute__((__unused__
)) __inline struct mta_domain * mta_domain_tree_SPLAY_MIN_MAX
(struct mta_domain_tree *head, int val) { mta_domain_tree_SPLAY_MINMAX
(head, val); return ((head)->sph_root); }
;
93
94SPLAY_HEAD(mta_source_tree, mta_source)struct mta_source_tree { struct mta_source *sph_root; };
95static struct mta_source *mta_source(const struct sockaddr *);
96static void mta_source_ref(struct mta_source *);
97static void mta_source_unref(struct mta_source *);
98static const char *mta_source_to_text(struct mta_source *);
99static int mta_source_cmp(const struct mta_source *, const struct mta_source *);
100SPLAY_PROTOTYPE(mta_source_tree, mta_source, entry, mta_source_cmp)void mta_source_tree_SPLAY(struct mta_source_tree *, struct mta_source
*); void mta_source_tree_SPLAY_MINMAX(struct mta_source_tree
*, int); struct mta_source *mta_source_tree_SPLAY_INSERT(struct
mta_source_tree *, struct mta_source *); struct mta_source *
mta_source_tree_SPLAY_REMOVE(struct mta_source_tree *, struct
mta_source *); static __attribute__((__unused__)) __inline struct
mta_source * mta_source_tree_SPLAY_FIND(struct mta_source_tree
*head, struct mta_source *elm) { if (((head)->sph_root ==
((void *)0))) return(((void *)0)); mta_source_tree_SPLAY(head
, elm); if ((mta_source_cmp)(elm, (head)->sph_root) == 0) return
(head->sph_root); return (((void *)0)); } static __attribute__
((__unused__)) __inline struct mta_source * mta_source_tree_SPLAY_NEXT
(struct mta_source_tree *head, struct mta_source *elm) { mta_source_tree_SPLAY
(head, elm); if ((elm)->entry.spe_right != ((void *)0)) { elm
= (elm)->entry.spe_right; while ((elm)->entry.spe_left
!= ((void *)0)) { elm = (elm)->entry.spe_left; } } else elm
= ((void *)0); return (elm); } static __attribute__((__unused__
)) __inline struct mta_source * mta_source_tree_SPLAY_MIN_MAX
(struct mta_source_tree *head, int val) { mta_source_tree_SPLAY_MINMAX
(head, val); return ((head)->sph_root); }
;
101
102static struct mta_connector *mta_connector(struct mta_relay *,
103 struct mta_source *);
104static void mta_connector_free(struct mta_connector *);
105static const char *mta_connector_to_text(struct mta_connector *);
106
107SPLAY_HEAD(mta_route_tree, mta_route)struct mta_route_tree { struct mta_route *sph_root; };
108static struct mta_route *mta_route(struct mta_source *, struct mta_host *);
109static void mta_route_ref(struct mta_route *);
110static void mta_route_unref(struct mta_route *);
111static const char *mta_route_to_text(struct mta_route *);
112static int mta_route_cmp(const struct mta_route *, const struct mta_route *);
113SPLAY_PROTOTYPE(mta_route_tree, mta_route, entry, mta_route_cmp)void mta_route_tree_SPLAY(struct mta_route_tree *, struct mta_route
*); void mta_route_tree_SPLAY_MINMAX(struct mta_route_tree *
, int); struct mta_route *mta_route_tree_SPLAY_INSERT(struct mta_route_tree
*, struct mta_route *); struct mta_route *mta_route_tree_SPLAY_REMOVE
(struct mta_route_tree *, struct mta_route *); static __attribute__
((__unused__)) __inline struct mta_route * mta_route_tree_SPLAY_FIND
(struct mta_route_tree *head, struct mta_route *elm) { if (((
head)->sph_root == ((void *)0))) return(((void *)0)); mta_route_tree_SPLAY
(head, elm); if ((mta_route_cmp)(elm, (head)->sph_root) ==
0) return (head->sph_root); return (((void *)0)); } static
__attribute__((__unused__)) __inline struct mta_route * mta_route_tree_SPLAY_NEXT
(struct mta_route_tree *head, struct mta_route *elm) { mta_route_tree_SPLAY
(head, elm); if ((elm)->entry.spe_right != ((void *)0)) { elm
= (elm)->entry.spe_right; while ((elm)->entry.spe_left
!= ((void *)0)) { elm = (elm)->entry.spe_left; } } else elm
= ((void *)0); return (elm); } static __attribute__((__unused__
)) __inline struct mta_route * mta_route_tree_SPLAY_MIN_MAX(struct
mta_route_tree *head, int val) { mta_route_tree_SPLAY_MINMAX
(head, val); return ((head)->sph_root); }
;
114
115struct mta_block {
116 SPLAY_ENTRY(mta_block)struct { struct mta_block *spe_left; struct mta_block *spe_right
; }
entry;
117 struct mta_source *source;
118 char *domain;
119};
120
121SPLAY_HEAD(mta_block_tree, mta_block)struct mta_block_tree { struct mta_block *sph_root; };
122void mta_block(struct mta_source *, char *);
123void mta_unblock(struct mta_source *, char *);
124int mta_is_blocked(struct mta_source *, char *);
125static int mta_block_cmp(const struct mta_block *, const struct mta_block *);
126SPLAY_PROTOTYPE(mta_block_tree, mta_block, entry, mta_block_cmp)void mta_block_tree_SPLAY(struct mta_block_tree *, struct mta_block
*); void mta_block_tree_SPLAY_MINMAX(struct mta_block_tree *
, int); struct mta_block *mta_block_tree_SPLAY_INSERT(struct mta_block_tree
*, struct mta_block *); struct mta_block *mta_block_tree_SPLAY_REMOVE
(struct mta_block_tree *, struct mta_block *); static __attribute__
((__unused__)) __inline struct mta_block * mta_block_tree_SPLAY_FIND
(struct mta_block_tree *head, struct mta_block *elm) { if (((
head)->sph_root == ((void *)0))) return(((void *)0)); mta_block_tree_SPLAY
(head, elm); if ((mta_block_cmp)(elm, (head)->sph_root) ==
0) return (head->sph_root); return (((void *)0)); } static
__attribute__((__unused__)) __inline struct mta_block * mta_block_tree_SPLAY_NEXT
(struct mta_block_tree *head, struct mta_block *elm) { mta_block_tree_SPLAY
(head, elm); if ((elm)->entry.spe_right != ((void *)0)) { elm
= (elm)->entry.spe_right; while ((elm)->entry.spe_left
!= ((void *)0)) { elm = (elm)->entry.spe_left; } } else elm
= ((void *)0); return (elm); } static __attribute__((__unused__
)) __inline struct mta_block * mta_block_tree_SPLAY_MIN_MAX(struct
mta_block_tree *head, int val) { mta_block_tree_SPLAY_MINMAX
(head, val); return ((head)->sph_root); }
;
127
128/*
129 * This function is not publicy exported because it is a hack until libtls
130 * has a proper privsep setup
131 */
132void tls_config_use_fake_private_key(struct tls_config *config);
133
134static struct mta_relay_tree relays;
135static struct mta_domain_tree domains;
136static struct mta_host_tree hosts;
137static struct mta_source_tree sources;
138static struct mta_route_tree routes;
139static struct mta_block_tree blocks;
140
141static struct tree wait_mx;
142static struct tree wait_preference;
143static struct tree wait_secret;
144static struct tree wait_smarthost;
145static struct tree wait_source;
146static struct tree flush_evp;
147static struct event ev_flush_evp;
148
149static struct runq *runq_relay;
150static struct runq *runq_connector;
151static struct runq *runq_route;
152static struct runq *runq_hoststat;
153
154static time_t max_seen_conndelay_route;
155static time_t max_seen_discdelay_route;
156
157#define HOSTSTAT_EXPIRE_DELAY(4 * 3600) (4 * 3600)
158struct hoststat {
159 char name[HOST_NAME_MAX255+1];
160 time_t tm;
161 char error[LINE_MAX2048];
162 struct tree deferred;
163};
164static struct dict hoststat;
165
166void mta_hoststat_update(const char *, const char *);
167void mta_hoststat_cache(const char *, uint64_t);
168void mta_hoststat_uncache(const char *, uint64_t);
169void mta_hoststat_reschedule(const char *);
170static void mta_hoststat_remove_entry(struct hoststat *);
171
172void
173mta_imsg(struct mproc *p, struct imsg *imsg)
174{
175 struct mta_relay *relay;
176 struct mta_domain *domain;
177 struct mta_host *host;
178 struct mta_route *route;
179 struct mta_block *block;
180 struct mta_mx *mx, *imx;
181 struct mta_source *source;
182 struct hoststat *hs;
183 struct sockaddr_storage ss;
184 struct envelope evp, *e;
185 struct msg m;
186 const char *secret;
187 const char *hostname;
188 const char *dom;
189 const char *smarthost;
190 uint64_t reqid;
191 time_t t;
192 char buf[LINE_MAX2048];
193 int dnserror, preference, v, status;
194 void *iter;
195 uint64_t u64;
196
197 switch (imsg->hdr.type) {
198 case IMSG_QUEUE_TRANSFER:
199 m_msg(&m, imsg);
200 m_get_envelope(&m, &evp);
201 m_end(&m);
202 mta_handle_envelope(&evp, NULL((void *)0));
203 return;
204
205 case IMSG_MTA_OPEN_MESSAGE:
206 mta_session_imsg(p, imsg);
207 return;
208
209 case IMSG_MTA_LOOKUP_CREDENTIALS:
210 m_msg(&m, imsg);
211 m_get_id(&m, &reqid);
212 m_get_string(&m, &secret);
213 m_end(&m);
214 relay = tree_xpop(&wait_secret, reqid);
215 mta_on_secret(relay, secret[0] ? secret : NULL((void *)0));
216 return;
217
218 case IMSG_MTA_LOOKUP_SOURCE:
219 m_msg(&m, imsg);
220 m_get_id(&m, &reqid);
221 m_get_int(&m, &status);
222 if (status == LKA_OK)
223 m_get_sockaddr(&m, (struct sockaddr*)&ss);
224 m_end(&m);
225
226 relay = tree_xpop(&wait_source, reqid);
227 mta_on_source(relay, (status == LKA_OK) ?
228 mta_source((struct sockaddr *)&ss) : NULL((void *)0));
229 return;
230
231 case IMSG_MTA_LOOKUP_SMARTHOST:
232 m_msg(&m, imsg);
233 m_get_id(&m, &reqid);
234 m_get_int(&m, &status);
235 smarthost = NULL((void *)0);
236 if (status == LKA_OK)
237 m_get_string(&m, &smarthost);
238 m_end(&m);
239
240 e = tree_xpop(&wait_smarthost, reqid);
241 mta_on_smarthost(e, smarthost);
242 return;
243
244 case IMSG_MTA_LOOKUP_HELO:
245 mta_session_imsg(p, imsg);
246 return;
247
248 case IMSG_MTA_DNS_HOST:
249 m_msg(&m, imsg);
250 m_get_id(&m, &reqid);
251 m_get_string(&m, &hostname);
252 m_get_sockaddr(&m, (struct sockaddr*)&ss);
253 m_get_int(&m, &preference);
254 m_end(&m);
255 domain = tree_xget(&wait_mx, reqid);
256 mx = xcalloc(1, sizeof *mx);
257 mx->mxname = xstrdup(hostname);
258 mx->host = mta_host((struct sockaddr*)&ss);
259 mx->preference = preference;
260 TAILQ_FOREACH(imx, &domain->mxs, entry)for((imx) = ((&domain->mxs)->tqh_first); (imx) != (
(void *)0); (imx) = ((imx)->entry.tqe_next))
{
261 if (imx->preference > mx->preference) {
262 TAILQ_INSERT_BEFORE(imx, mx, entry)do { (mx)->entry.tqe_prev = (imx)->entry.tqe_prev; (mx)
->entry.tqe_next = (imx); *(imx)->entry.tqe_prev = (mx)
; (imx)->entry.tqe_prev = &(mx)->entry.tqe_next; } while
(0)
;
263 return;
264 }
265 }
266 TAILQ_INSERT_TAIL(&domain->mxs, mx, entry)do { (mx)->entry.tqe_next = ((void *)0); (mx)->entry.tqe_prev
= (&domain->mxs)->tqh_last; *(&domain->mxs)
->tqh_last = (mx); (&domain->mxs)->tqh_last = &
(mx)->entry.tqe_next; } while (0)
;
267 return;
268
269 case IMSG_MTA_DNS_HOST_END:
270 m_msg(&m, imsg);
271 m_get_id(&m, &reqid);
272 m_get_int(&m, &dnserror);
273 m_end(&m);
274 domain = tree_xpop(&wait_mx, reqid);
275 domain->mxstatus = dnserror;
276 if (domain->mxstatus == DNS_OK) {
277 log_debug("debug: MXs for domain %s:",
278 domain->name);
279 TAILQ_FOREACH(mx, &domain->mxs, entry)for((mx) = ((&domain->mxs)->tqh_first); (mx) != ((void
*)0); (mx) = ((mx)->entry.tqe_next))
280 log_debug(" %s preference %d",
281 sa_to_text(mx->host->sa),
282 mx->preference);
283 }
284 else {
285 log_debug("debug: Failed MX query for %s:",
286 domain->name);
287 }
288 domain->lastmxquery = time(NULL((void *)0));
289 waitq_run(&domain->mxs, domain);
290 return;
291
292 case IMSG_MTA_DNS_MX_PREFERENCE:
293 m_msg(&m, imsg);
294 m_get_id(&m, &reqid);
295 m_get_int(&m, &dnserror);
296 if (dnserror == 0)
297 m_get_int(&m, &preference);
298 m_end(&m);
299
300 relay = tree_xpop(&wait_preference, reqid);
301 if (dnserror) {
302 log_warnx("warn: Couldn't find backup "
303 "preference for %s: error %d",
304 mta_relay_to_text(relay), dnserror);
305 preference = INT_MAX0x7fffffff;
306 }
307 mta_on_preference(relay, preference);
308 return;
309
310 case IMSG_CTL_RESUME_ROUTE:
311 u64 = *((uint64_t *)imsg->data);
312 if (u64)
313 log_debug("resuming route: %llu",
314 (unsigned long long)u64);
315 else
316 log_debug("resuming all routes");
317 SPLAY_FOREACH(route, mta_route_tree, &routes)for ((route) = (((&routes)->sph_root == ((void *)0)) ?
((void *)0) : mta_route_tree_SPLAY_MIN_MAX(&routes, -1))
; (route) != ((void *)0); (route) = mta_route_tree_SPLAY_NEXT
(&routes, route))
{
318 if (u64 && route->id != u64)
319 continue;
320
321 if (route->flags & ROUTE_DISABLED0xf0) {
322 log_info("smtp-out: Enabling route %s per admin request",
323 mta_route_to_text(route));
324 if (!runq_cancel(runq_route, route)) {
325 log_warnx("warn: route not on runq");
326 fatalx("exiting");
327 }
328 route->flags &= ~ROUTE_DISABLED0xf0;
329 route->flags |= ROUTE_NEW0x01;
330 route->nerror = 0;
331 route->penalty = 0;
332 mta_route_unref(route); /* from mta_route_disable */
333 }
334
335 if (u64)
336 break;
337 }
338 return;
339
340 case IMSG_CTL_MTA_SHOW_HOSTS:
341 t = time(NULL((void *)0));
342 SPLAY_FOREACH(host, mta_host_tree, &hosts)for ((host) = (((&hosts)->sph_root == ((void *)0)) ? (
(void *)0) : mta_host_tree_SPLAY_MIN_MAX(&hosts, -1)); (host
) != ((void *)0); (host) = mta_host_tree_SPLAY_NEXT(&hosts
, host))
{
343 (void)snprintf(buf, sizeof(buf),
344 "%s %s refcount=%d nconn=%zu lastconn=%s",
345 sockaddr_to_text(host->sa),
346 host->ptrname,
347 host->refcount,
348 host->nconn,
349 host->lastconn ? duration_to_text(t - host->lastconn) : "-");
350 m_compose(p, IMSG_CTL_MTA_SHOW_HOSTS,
351 imsg->hdr.peerid, 0, -1,
352 buf, strlen(buf) + 1);
353 }
354 m_compose(p, IMSG_CTL_MTA_SHOW_HOSTS, imsg->hdr.peerid,
355 0, -1, NULL((void *)0), 0);
356 return;
357
358 case IMSG_CTL_MTA_SHOW_RELAYS:
359 t = time(NULL((void *)0));
360 SPLAY_FOREACH(relay, mta_relay_tree, &relays)for ((relay) = (((&relays)->sph_root == ((void *)0)) ?
((void *)0) : mta_relay_tree_SPLAY_MIN_MAX(&relays, -1))
; (relay) != ((void *)0); (relay) = mta_relay_tree_SPLAY_NEXT
(&relays, relay))
361 mta_relay_show(relay, p, imsg->hdr.peerid, t);
362 m_compose(p, IMSG_CTL_MTA_SHOW_RELAYS, imsg->hdr.peerid,
363 0, -1, NULL((void *)0), 0);
364 return;
365
366 case IMSG_CTL_MTA_SHOW_ROUTES:
367 SPLAY_FOREACH(route, mta_route_tree, &routes)for ((route) = (((&routes)->sph_root == ((void *)0)) ?
((void *)0) : mta_route_tree_SPLAY_MIN_MAX(&routes, -1))
; (route) != ((void *)0); (route) = mta_route_tree_SPLAY_NEXT
(&routes, route))
{
368 v = runq_pending(runq_route, route, &t);
369 (void)snprintf(buf, sizeof(buf),
370 "%llu. %s %c%c%c%c nconn=%zu nerror=%d penalty=%d timeout=%s",
371 (unsigned long long)route->id,
372 mta_route_to_text(route),
373 route->flags & ROUTE_NEW0x01 ? 'N' : '-',
374 route->flags & ROUTE_DISABLED0xf0 ? 'D' : '-',
375 route->flags & ROUTE_RUNQ0x02 ? 'Q' : '-',
376 route->flags & ROUTE_KEEPALIVE0x04 ? 'K' : '-',
377 route->nconn,
378 route->nerror,
379 route->penalty,
380 v ? duration_to_text(t - time(NULL((void *)0))) : "-");
381 m_compose(p, IMSG_CTL_MTA_SHOW_ROUTES,
382 imsg->hdr.peerid, 0, -1,
383 buf, strlen(buf) + 1);
384 }
385 m_compose(p, IMSG_CTL_MTA_SHOW_ROUTES, imsg->hdr.peerid,
386 0, -1, NULL((void *)0), 0);
387 return;
388
389 case IMSG_CTL_MTA_SHOW_HOSTSTATS:
390 iter = NULL((void *)0);
391 while (dict_iter(&hoststat, &iter, &hostname,
392 (void **)&hs)) {
393 (void)snprintf(buf, sizeof(buf),
394 "%s|%llu|%s",
395 hostname, (unsigned long long) hs->tm,
396 hs->error);
397 m_compose(p, IMSG_CTL_MTA_SHOW_HOSTSTATS,
398 imsg->hdr.peerid, 0, -1,
399 buf, strlen(buf) + 1);
400 }
401 m_compose(p, IMSG_CTL_MTA_SHOW_HOSTSTATS,
402 imsg->hdr.peerid,
403 0, -1, NULL((void *)0), 0);
404 return;
405
406 case IMSG_CTL_MTA_BLOCK:
407 m_msg(&m, imsg);
408 m_get_sockaddr(&m, (struct sockaddr*)&ss);
409 m_get_string(&m, &dom);
410 m_end(&m);
411 source = mta_source((struct sockaddr*)&ss);
412 if (*dom != '\0') {
413 if (!(strlcpy(buf, dom, sizeof(buf))
414 >= sizeof(buf)))
415 mta_block(source, buf);
416 }
417 else
418 mta_block(source, NULL((void *)0));
419 mta_source_unref(source);
420 m_compose(p, IMSG_CTL_OK, imsg->hdr.peerid, 0, -1, NULL((void *)0), 0);
421 return;
422
423 case IMSG_CTL_MTA_UNBLOCK:
424 m_msg(&m, imsg);
425 m_get_sockaddr(&m, (struct sockaddr*)&ss);
426 m_get_string(&m, &dom);
427 m_end(&m);
428 source = mta_source((struct sockaddr*)&ss);
429 if (*dom != '\0') {
430 if (!(strlcpy(buf, dom, sizeof(buf))
431 >= sizeof(buf)))
432 mta_unblock(source, buf);
433 }
434 else
435 mta_unblock(source, NULL((void *)0));
436 mta_source_unref(source);
437 m_compose(p, IMSG_CTL_OK, imsg->hdr.peerid, 0, -1, NULL((void *)0), 0);
438 return;
439
440 case IMSG_CTL_MTA_SHOW_BLOCK:
441 SPLAY_FOREACH(block, mta_block_tree, &blocks)for ((block) = (((&blocks)->sph_root == ((void *)0)) ?
((void *)0) : mta_block_tree_SPLAY_MIN_MAX(&blocks, -1))
; (block) != ((void *)0); (block) = mta_block_tree_SPLAY_NEXT
(&blocks, block))
{
442 (void)snprintf(buf, sizeof(buf), "%s -> %s",
443 mta_source_to_text(block->source),
444 block->domain ? block->domain : "*");
445 m_compose(p, IMSG_CTL_MTA_SHOW_BLOCK,
446 imsg->hdr.peerid, 0, -1, buf, strlen(buf) + 1);
447 }
448 m_compose(p, IMSG_CTL_MTA_SHOW_BLOCK, imsg->hdr.peerid,
449 0, -1, NULL((void *)0), 0);
450 return;
451 }
452
453 fatalx("mta_imsg: unexpected %s imsg", imsg_to_str(imsg->hdr.type));
454}
455
456void
457mta_postfork(void)
458{
459 struct dispatcher *dispatcher;
460 const char *key;
461 void *iter;
462
463 iter = NULL((void *)0);
464 while (dict_iter(env->sc_dispatchers, &iter, &key, (void **)&dispatcher)) {
465 log_debug("%s: %s", __func__, key);
466 mta_setup_dispatcher(dispatcher);
467 }
468}
469
470static void
471mta_setup_dispatcher(struct dispatcher *dispatcher)
472{
473 struct dispatcher_remote *remote;
474 static const char *dheparams[] = { "none", "auto", "legacy" };
475 struct tls_config *config;
476 struct pki *pki;
477 struct ca *ca;
478 const char *ciphers;
479 uint32_t protos;
480
481 if (dispatcher->type != DISPATCHER_REMOTE)
482 return;
483
484 remote = &dispatcher->u.remote;
485
486 if ((config = tls_config_new()) == NULL((void *)0))
487 fatal("smtpd: tls_config_new");
488
489 ciphers = env->sc_tls_ciphers;
490 if (remote->tls_ciphers)
491 ciphers = remote->tls_ciphers;
492 if (ciphers && tls_config_set_ciphers(config, ciphers) == -1)
493 fatalx("%s", tls_config_error(config));
494
495 if (remote->tls_protocols) {
496 if (tls_config_parse_protocols(&protos,
497 remote->tls_protocols) == -1)
498 fatalx("failed to parse protocols \"%s\"",
499 remote->tls_protocols);
500 if (tls_config_set_protocols(config, protos) == -1)
501 fatalx("%s", tls_config_error(config));
502 }
503
504 if (remote->pki) {
505 pki = dict_get(env->sc_pki_dict, remote->pki);
506 if (pki == NULL((void *)0))
507 fatalx("client pki \"%s\" not found", remote->pki);
508
509 tls_config_set_dheparams(config, dheparams[pki->pki_dhe]);
510 tls_config_use_fake_private_key(config);
511 if (tls_config_set_keypair_mem(config, pki->pki_cert,
512 pki->pki_cert_len, NULL((void *)0), 0) == -1)
513 fatalx("tls_config_set_keypair_mem: %s",
514 tls_config_error(config));
515 }
516
517 if (remote->ca) {
518 ca = dict_get(env->sc_ca_dict, remote->ca);
519 if (tls_config_set_ca_mem(config, ca->ca_cert, ca->ca_cert_len)
520 == -1)
521 fatalx("tls_config_set_ca_mem: %s",
522 tls_config_error(config));
523 }
524 else if (tls_config_set_ca_file(config, tls_default_ca_cert_file())
525 == -1)
526 fatalx("tls_config_set_ca_file: %s",
527 tls_config_error(config));
528
529 if (remote->tls_verify) {
530 tls_config_verify(config);
531 } else {
532 tls_config_insecure_noverifycert(config);
533 tls_config_insecure_noverifyname(config);
534 tls_config_insecure_noverifytime(config);
535 }
536
537 remote->tls_config = config;
538}
539
540void
541mta_postprivdrop(void)
542{
543 SPLAY_INIT(&relays)do { (&relays)->sph_root = ((void *)0); } while (0);
544 SPLAY_INIT(&domains)do { (&domains)->sph_root = ((void *)0); } while (0);
545 SPLAY_INIT(&hosts)do { (&hosts)->sph_root = ((void *)0); } while (0);
546 SPLAY_INIT(&sources)do { (&sources)->sph_root = ((void *)0); } while (0);
547 SPLAY_INIT(&routes)do { (&routes)->sph_root = ((void *)0); } while (0);
548 SPLAY_INIT(&blocks)do { (&blocks)->sph_root = ((void *)0); } while (0);
549
550 tree_init(&wait_secret)do { do { (&((&wait_secret)->tree))->sph_root =
((void *)0); } while (0); (&wait_secret)->count = 0; }
while(0)
;
551 tree_init(&wait_smarthost)do { do { (&((&wait_smarthost)->tree))->sph_root
= ((void *)0); } while (0); (&wait_smarthost)->count =
0; } while(0)
;
552 tree_init(&wait_mx)do { do { (&((&wait_mx)->tree))->sph_root = ((void
*)0); } while (0); (&wait_mx)->count = 0; } while(0)
;
553 tree_init(&wait_preference)do { do { (&((&wait_preference)->tree))->sph_root
= ((void *)0); } while (0); (&wait_preference)->count
= 0; } while(0)
;
554 tree_init(&wait_source)do { do { (&((&wait_source)->tree))->sph_root =
((void *)0); } while (0); (&wait_source)->count = 0; }
while(0)
;
555 tree_init(&flush_evp)do { do { (&((&flush_evp)->tree))->sph_root = (
(void *)0); } while (0); (&flush_evp)->count = 0; } while
(0)
;
556 dict_init(&hoststat)do { do { (&((&hoststat)->dict))->sph_root = ((
void *)0); } while (0); (&hoststat)->count = 0; } while
(0)
;
557
558 evtimer_set(&ev_flush_evp, mta_delivery_flush_event, NULL)event_set(&ev_flush_evp, -1, 0, mta_delivery_flush_event,
((void *)0))
;
559
560 runq_init(&runq_relay, mta_on_timeout);
561 runq_init(&runq_connector, mta_on_timeout);
562 runq_init(&runq_route, mta_on_timeout);
563 runq_init(&runq_hoststat, mta_on_timeout);
564}
565
566
567/*
568 * Local error on the given source.
569 */
570void
571mta_source_error(struct mta_relay *relay, struct mta_route *route, const char *e)
572{
573 struct mta_connector *c;
574
575 /*
576 * Remember the source as broken for this connector.
577 */
578 c = mta_connector(relay, route->src);
579 if (!(c->flags & CONNECTOR_ERROR_SOURCE0x0002))
580 log_info("smtp-out: Error on %s: %s",
581 mta_route_to_text(route), e);
582 c->flags |= CONNECTOR_ERROR_SOURCE0x0002;
583}
584
585void
586mta_route_error(struct mta_relay *relay, struct mta_route *route)
587{
588#if 0
589 route->nerror += 1;
590
591 if (route->nerror > MAXERROR_PER_ROUTE4) {
592 log_info("smtp-out: Too many errors on %s: "
593 "disabling for a while", mta_route_to_text(route));
594 mta_route_disable(route, 2, ROUTE_DISABLED_SMTP0x20);
595 }
596#endif
597}
598
599void
600mta_route_ok(struct mta_relay *relay, struct mta_route *route)
601{
602 struct mta_connector *c;
603
604 if (!(route->flags & ROUTE_NEW0x01))
605 return;
606
607 log_debug("debug: mta-routing: route %s is now valid.",
608 mta_route_to_text(route));
609
610 route->nerror = 0;
611 route->flags &= ~ROUTE_NEW0x01;
612
613 c = mta_connector(relay, route->src);
614 mta_connect(c);
615}
616
617void
618mta_route_down(struct mta_relay *relay, struct mta_route *route)
619{
620#if 0
621 mta_route_disable(route, 2, ROUTE_DISABLED_SMTP0x20);
622#endif
623}
624
625void
626mta_route_collect(struct mta_relay *relay, struct mta_route *route)
627{
628 struct mta_connector *c;
629
630 log_debug("debug: mta_route_collect(%s)",
631 mta_route_to_text(route));
632
633 relay->nconn -= 1;
634 relay->domain->nconn -= 1;
635 route->nconn -= 1;
636 route->src->nconn -= 1;
637 route->dst->nconn -= 1;
638 route->lastdisc = time(NULL((void *)0));
639
640 /* First connection failed */
641 if (route->flags & ROUTE_NEW0x01)
642 mta_route_disable(route, 1, ROUTE_DISABLED_NET0x10);
643
644 c = mta_connector(relay, route->src);
645 c->nconn -= 1;
646 mta_connect(c);
647 mta_route_unref(route); /* from mta_find_route() */
648 mta_relay_unref(relay); /* from mta_connect() */
649}
650
651struct mta_task *
652mta_route_next_task(struct mta_relay *relay, struct mta_route *route)
653{
654 struct mta_task *task;
655
656 if ((task = TAILQ_FIRST(&relay->tasks)((&relay->tasks)->tqh_first))) {
657 TAILQ_REMOVE(&relay->tasks, task, entry)do { if (((task)->entry.tqe_next) != ((void *)0)) (task)->
entry.tqe_next->entry.tqe_prev = (task)->entry.tqe_prev
; else (&relay->tasks)->tqh_last = (task)->entry
.tqe_prev; *(task)->entry.tqe_prev = (task)->entry.tqe_next
; ; ; } while (0)
;
658 relay->ntask -= 1;
659 task->relay = NULL((void *)0);
660
661 /* When the number of tasks is down to lowat, query some evp */
662 if (relay->ntask == (size_t)relay->limits->task_lowat) {
663 if (relay->state & RELAY_ONHOLD0x01) {
664 log_info("smtp-out: back to lowat on %s: releasing",
665 mta_relay_to_text(relay));
666 relay->state &= ~RELAY_ONHOLD0x01;
667 }
668 if (relay->state & RELAY_HOLDQ0x02) {
669 m_create(p_queue, IMSG_MTA_HOLDQ_RELEASE, 0, 0, -1);
670 m_add_id(p_queue, relay->id);
671 m_add_int(p_queue, relay->limits->task_release);
672 m_close(p_queue);
673 }
674 }
675 else if (relay->ntask == 0 && relay->state & RELAY_HOLDQ0x02) {
676 m_create(p_queue, IMSG_MTA_HOLDQ_RELEASE, 0, 0, -1);
677 m_add_id(p_queue, relay->id);
678 m_add_int(p_queue, 0);
679 m_close(p_queue);
680 }
681 }
682
683 return (task);
684}
685
686static void
687mta_handle_envelope(struct envelope *evp, const char *smarthost)
688{
689 struct mta_relay *relay;
690 struct mta_task *task;
691 struct mta_envelope *e;
692 struct dispatcher *dispatcher;
693 struct mailaddr maddr;
694 struct relayhost relayh;
695 char buf[LINE_MAX2048];
696
697 dispatcher = dict_xget(env->sc_dispatchers, evp->dispatcher);
698 if (dispatcher->u.remote.smarthost && smarthost == NULL((void *)0)) {
699 mta_query_smarthost(evp);
700 return;
701 }
702
703 memset(&relayh, 0, sizeof(relayh));
704 relayh.tls = RELAY_TLS_OPPORTUNISTIC0;
705 if (smarthost && !text_to_relayhost(&relayh, smarthost)) {
706 log_warnx("warn: Failed to parse smarthost %s", smarthost);
707 m_create(p_queue, IMSG_MTA_DELIVERY_TEMPFAIL, 0, 0, -1);
708 m_add_evpid(p_queue, evp->id);
709 m_add_string(p_queue, "Cannot parse smarthost");
710 m_add_int(p_queue, ESC_OTHER_STATUS);
711 m_close(p_queue);
712 return;
713 }
714
715 if (relayh.flags & RELAY_AUTH0x08 && dispatcher->u.remote.auth == NULL((void *)0)) {
716 log_warnx("warn: No auth table on action \"%s\" for relay %s",
717 evp->dispatcher, smarthost);
718 m_create(p_queue, IMSG_MTA_DELIVERY_TEMPFAIL, 0, 0, -1);
719 m_add_evpid(p_queue, evp->id);
720 m_add_string(p_queue, "No auth table for relaying");
721 m_add_int(p_queue, ESC_OTHER_STATUS);
722 m_close(p_queue);
723 return;
724 }
725
726 if (dispatcher->u.remote.tls_required) {
727 /* Reject relay if smtp+notls:// is requested */
728 if (relayh.tls == RELAY_TLS_NO3) {
729 log_warnx("warn: TLS required for action \"%s\"",
730 evp->dispatcher);
731 m_create(p_queue, IMSG_MTA_DELIVERY_TEMPFAIL, 0, 0, -1);
732 m_add_evpid(p_queue, evp->id);
733 m_add_string(p_queue, "TLS required for relaying");
734 m_add_int(p_queue, ESC_OTHER_STATUS);
735 m_close(p_queue);
736 return;
737 }
738 /* Update smtp:// to smtp+tls:// */
739 if (relayh.tls == RELAY_TLS_OPPORTUNISTIC0)
740 relayh.tls = RELAY_TLS_STARTTLS1;
741 }
742
743 relay = mta_relay(evp, &relayh);
744 /* ignore if we don't know the limits yet */
745 if (relay->limits &&
746 relay->ntask >= (size_t)relay->limits->task_hiwat) {
747 if (!(relay->state & RELAY_ONHOLD0x01)) {
748 log_info("smtp-out: hiwat reached on %s: holding envelopes",
749 mta_relay_to_text(relay));
750 relay->state |= RELAY_ONHOLD0x01;
751 }
752 }
753
754 /*
755 * If the relay has too many pending tasks, tell the
756 * scheduler to hold it until further notice
757 */
758 if (relay->state & RELAY_ONHOLD0x01) {
759 relay->state |= RELAY_HOLDQ0x02;
760 m_create(p_queue, IMSG_MTA_DELIVERY_HOLD, 0, 0, -1);
761 m_add_evpid(p_queue, evp->id);
762 m_add_id(p_queue, relay->id);
763 m_close(p_queue);
764 mta_relay_unref(relay); /* from here */
765 return;
766 }
767
768 task = NULL((void *)0);
769 TAILQ_FOREACH(task, &relay->tasks, entry)for((task) = ((&relay->tasks)->tqh_first); (task) !=
((void *)0); (task) = ((task)->entry.tqe_next))
770 if (task->msgid == evpid_to_msgid(evp->id))
771 break;
772
773 if (task == NULL((void *)0)) {
774 task = xmalloc(sizeof *task);
775 TAILQ_INIT(&task->envelopes)do { (&task->envelopes)->tqh_first = ((void *)0); (
&task->envelopes)->tqh_last = &(&task->envelopes
)->tqh_first; } while (0)
;
776 task->relay = relay;
777 relay->ntask += 1;
778 TAILQ_INSERT_TAIL(&relay->tasks, task, entry)do { (task)->entry.tqe_next = ((void *)0); (task)->entry
.tqe_prev = (&relay->tasks)->tqh_last; *(&relay
->tasks)->tqh_last = (task); (&relay->tasks)->
tqh_last = &(task)->entry.tqe_next; } while (0)
;
779 task->msgid = evpid_to_msgid(evp->id);
780 if (evp->sender.user[0] || evp->sender.domain[0])
781 (void)snprintf(buf, sizeof buf, "%s@%s",
782 evp->sender.user, evp->sender.domain);
783 else
784 buf[0] = '\0';
785
786 if (dispatcher->u.remote.mail_from && evp->sender.user[0]) {
787 memset(&maddr, 0, sizeof (maddr));
788 if (text_to_mailaddr(&maddr,
789 dispatcher->u.remote.mail_from)) {
790 (void)snprintf(buf, sizeof buf, "%s@%s",
791 maddr.user[0] ? maddr.user : evp->sender.user,
792 maddr.domain[0] ? maddr.domain : evp->sender.domain);
793 }
794 }
795
796 task->sender = xstrdup(buf);
797 stat_increment("mta.task", 1);
798 }
799
800 e = xcalloc(1, sizeof *e);
801 e->id = evp->id;
802 e->creation = evp->creation;
803 e->smtpname = xstrdup(evp->smtpname);
804 (void)snprintf(buf, sizeof buf, "%s@%s",
805 evp->dest.user, evp->dest.domain);
806 e->dest = xstrdup(buf);
807 (void)snprintf(buf, sizeof buf, "%s@%s",
808 evp->rcpt.user, evp->rcpt.domain);
809 if (strcmp(buf, e->dest))
810 e->rcpt = xstrdup(buf);
811 e->task = task;
812 if (evp->dsn_orcpt[0] != '\0')
813 e->dsn_orcpt = xstrdup(evp->dsn_orcpt);
814 (void)strlcpy(e->dsn_envid, evp->dsn_envid,
815 sizeof e->dsn_envid);
816 e->dsn_notify = evp->dsn_notify;
817 e->dsn_ret = evp->dsn_ret;
818
819 TAILQ_INSERT_TAIL(&task->envelopes, e, entry)do { (e)->entry.tqe_next = ((void *)0); (e)->entry.tqe_prev
= (&task->envelopes)->tqh_last; *(&task->envelopes
)->tqh_last = (e); (&task->envelopes)->tqh_last =
&(e)->entry.tqe_next; } while (0)
;
820 log_debug("debug: mta: received evp:%016" PRIx64"llx"
821 " for <%s>", e->id, e->dest);
822
823 stat_increment("mta.envelope", 1);
824
825 mta_drain(relay);
826 mta_relay_unref(relay); /* from here */
827}
828
829static void
830mta_delivery_flush_event(int fd, short event, void *arg)
831{
832 struct mta_envelope *e;
833 struct timeval tv;
834
835 if (tree_poproot(&flush_evp, NULL((void *)0), (void**)(&e))) {
836
837 if (e->delivery == IMSG_MTA_DELIVERY_OK) {
838 m_create(p_queue, IMSG_MTA_DELIVERY_OK, 0, 0, -1);
839 m_add_evpid(p_queue, e->id);
840 m_add_int(p_queue, e->ext);
841 m_close(p_queue);
842 } else if (e->delivery == IMSG_MTA_DELIVERY_TEMPFAIL) {
843 m_create(p_queue, IMSG_MTA_DELIVERY_TEMPFAIL, 0, 0, -1);
844 m_add_evpid(p_queue, e->id);
845 m_add_string(p_queue, e->status);
846 m_add_int(p_queue, ESC_OTHER_STATUS);
847 m_close(p_queue);
848 }
849 else if (e->delivery == IMSG_MTA_DELIVERY_PERMFAIL) {
850 m_create(p_queue, IMSG_MTA_DELIVERY_PERMFAIL, 0, 0, -1);
851 m_add_evpid(p_queue, e->id);
852 m_add_string(p_queue, e->status);
853 m_add_int(p_queue, ESC_OTHER_STATUS);
854 m_close(p_queue);
855 }
856 else if (e->delivery == IMSG_MTA_DELIVERY_LOOP) {
857 m_create(p_queue, IMSG_MTA_DELIVERY_LOOP, 0, 0, -1);
858 m_add_evpid(p_queue, e->id);
859 m_close(p_queue);
860 }
861 else {
862 log_warnx("warn: bad delivery type %d for %016" PRIx64"llx",
863 e->delivery, e->id);
864 fatalx("aborting");
865 }
866
867 log_debug("debug: mta: flush for %016"PRIx64"llx"" (-> %s)", e->id, e->dest);
868
869 free(e->smtpname);
870 free(e->dest);
871 free(e->rcpt);
872 free(e->dsn_orcpt);
873 free(e);
874
875 tv.tv_sec = 0;
876 tv.tv_usec = 0;
877 evtimer_add(&ev_flush_evp, &tv)event_add(&ev_flush_evp, &tv);
878 }
879}
880
881void
882mta_delivery_log(struct mta_envelope *e, const char *source, const char *relay,
883 int delivery, const char *status)
884{
885 if (delivery == IMSG_MTA_DELIVERY_OK)
886 mta_log(e, "Ok", source, relay, status);
887 else if (delivery == IMSG_MTA_DELIVERY_TEMPFAIL)
888 mta_log(e, "TempFail", source, relay, status);
889 else if (delivery == IMSG_MTA_DELIVERY_PERMFAIL)
890 mta_log(e, "PermFail", source, relay, status);
891 else if (delivery == IMSG_MTA_DELIVERY_LOOP)
892 mta_log(e, "PermFail", source, relay, "Loop detected");
893 else {
894 log_warnx("warn: bad delivery type %d for %016" PRIx64"llx",
895 delivery, e->id);
896 fatalx("aborting");
897 }
898
899 e->delivery = delivery;
900 if (status)
901 (void)strlcpy(e->status, status, sizeof(e->status));
902}
903
904void
905mta_delivery_notify(struct mta_envelope *e)
906{
907 struct timeval tv;
908
909 tree_xset(&flush_evp, e->id, e);
910 if (tree_count(&flush_evp)((&flush_evp)->count) == 1) {
911 tv.tv_sec = 0;
912 tv.tv_usec = 0;
913 evtimer_add(&ev_flush_evp, &tv)event_add(&ev_flush_evp, &tv);
914 }
915}
916
917static void
918mta_query_mx(struct mta_relay *relay)
919{
920 uint64_t id;
921
922 if (relay->status & RELAY_WAIT_MX0x01)
923 return;
924
925 log_debug("debug: mta: querying MX for %s...",
926 mta_relay_to_text(relay));
927
928 if (waitq_wait(&relay->domain->mxs, mta_on_mx, relay)) {
929 id = generate_uid();
930 tree_xset(&wait_mx, id, relay->domain);
931 if (relay->domain->as_host)
932 m_create(p_lka, IMSG_MTA_DNS_HOST, 0, 0, -1);
933 else
934 m_create(p_lka, IMSG_MTA_DNS_MX, 0, 0, -1);
935 m_add_id(p_lka, id);
936 m_add_string(p_lka, relay->domain->name);
937 m_close(p_lka);
938 }
939 relay->status |= RELAY_WAIT_MX0x01;
940 mta_relay_ref(relay);
941}
942
943static void
944mta_query_limits(struct mta_relay *relay)
945{
946 if (relay->status & RELAY_WAIT_LIMITS0x08)
947 return;
948
949 relay->limits = dict_get(env->sc_limits_dict, relay->domain->name);
950 if (relay->limits == NULL((void *)0))
951 relay->limits = dict_get(env->sc_limits_dict, "default");
952
953 if (max_seen_conndelay_route < relay->limits->conndelay_route)
954 max_seen_conndelay_route = relay->limits->conndelay_route;
955 if (max_seen_discdelay_route < relay->limits->discdelay_route)
956 max_seen_discdelay_route = relay->limits->discdelay_route;
957}
958
959static void
960mta_query_secret(struct mta_relay *relay)
961{
962 if (relay->status & RELAY_WAIT_SECRET0x04)
963 return;
964
965 log_debug("debug: mta: querying secret for %s...",
966 mta_relay_to_text(relay));
967
968 tree_xset(&wait_secret, relay->id, relay);
969 relay->status |= RELAY_WAIT_SECRET0x04;
970
971 m_create(p_lka, IMSG_MTA_LOOKUP_CREDENTIALS, 0, 0, -1);
972 m_add_id(p_lka, relay->id);
973 m_add_string(p_lka, relay->authtable);
974 m_add_string(p_lka, relay->authlabel);
975 m_close(p_lka);
976
977 mta_relay_ref(relay);
978}
979
980static void
981mta_query_smarthost(struct envelope *evp0)
982{
983 struct dispatcher *dispatcher;
984 struct envelope *evp;
985
986 evp = malloc(sizeof(*evp));
987 memmove(evp, evp0, sizeof(*evp));
988
989 dispatcher = dict_xget(env->sc_dispatchers, evp->dispatcher);
990
991 log_debug("debug: mta: querying smarthost for %s:%s...",
992 evp->dispatcher, dispatcher->u.remote.smarthost);
993
994 tree_xset(&wait_smarthost, evp->id, evp);
995
996 m_create(p_lka, IMSG_MTA_LOOKUP_SMARTHOST, 0, 0, -1);
997 m_add_id(p_lka, evp->id);
998 if (dispatcher->u.remote.smarthost_domain)
999 m_add_string(p_lka, evp->dest.domain);
1000 else
1001 m_add_string(p_lka, NULL((void *)0));
1002 m_add_string(p_lka, dispatcher->u.remote.smarthost);
1003 m_close(p_lka);
1004
1005 log_debug("debug: mta: querying smarthost");
1006}
1007
1008static void
1009mta_query_preference(struct mta_relay *relay)
1010{
1011 if (relay->status & RELAY_WAIT_PREFERENCE0x02)
1012 return;
1013
1014 log_debug("debug: mta: querying preference for %s...",
1015 mta_relay_to_text(relay));
1016
1017 tree_xset(&wait_preference, relay->id, relay);
1018 relay->status |= RELAY_WAIT_PREFERENCE0x02;
1019
1020 m_create(p_lka, IMSG_MTA_DNS_MX_PREFERENCE, 0, 0, -1);
1021 m_add_id(p_lka, relay->id);
1022 m_add_string(p_lka, relay->domain->name);
1023 m_add_string(p_lka, relay->backupname);
1024 m_close(p_lka);
1025
1026 mta_relay_ref(relay);
1027}
1028
1029static void
1030mta_query_source(struct mta_relay *relay)
1031{
1032 log_debug("debug: mta: querying source for %s...",
1033 mta_relay_to_text(relay));
1034
1035 relay->sourceloop += 1;
1036
1037 if (relay->sourcetable
15.1
Field 'sourcetable' is equal to NULL
== NULL((void *)0)) {
16
Taking true branch
1038 /*
1039 * This is a recursive call, but it only happens once, since
1040 * another source will not be queried immediately.
1041 */
1042 mta_relay_ref(relay);
1043 mta_on_source(relay, mta_source(NULL((void *)0)));
17
Calling 'mta_on_source'
36
Returning; memory was released via 1st parameter
1044 return;
1045 }
1046
1047 m_create(p_lka, IMSG_MTA_LOOKUP_SOURCE, 0, 0, -1);
1048 m_add_id(p_lka, relay->id);
1049 m_add_string(p_lka, relay->sourcetable);
1050 m_close(p_lka);
1051
1052 tree_xset(&wait_source, relay->id, relay);
1053 relay->status |= RELAY_WAIT_SOURCE0x10;
1054 mta_relay_ref(relay);
1055}
1056
1057static void
1058mta_on_mx(void *tag, void *arg, void *data)
1059{
1060 struct mta_domain *domain = data;
1061 struct mta_relay *relay = arg;
1062
1063 log_debug("debug: mta: ... got mx (%p, %s, %s)",
1064 tag, domain->name, mta_relay_to_text(relay));
1065
1066 switch (domain->mxstatus) {
1067 case DNS_OK:
1068 break;
1069 case DNS_RETRY:
1070 relay->fail = IMSG_MTA_DELIVERY_TEMPFAIL;
1071 relay->failstr = "Temporary failure in MX lookup";
1072 break;
1073 case DNS_EINVAL:
1074 relay->fail = IMSG_MTA_DELIVERY_PERMFAIL;
1075 relay->failstr = "Invalid domain name";
1076 break;
1077 case DNS_ENONAME:
1078 relay->fail = IMSG_MTA_DELIVERY_PERMFAIL;
1079 relay->failstr = "Domain does not exist";
1080 break;
1081 case DNS_ENOTFOUND:
1082 relay->fail = IMSG_MTA_DELIVERY_TEMPFAIL;
1083 if (relay->domain->as_host)
1084 relay->failstr = "Host not found";
1085 else
1086 relay->failstr = "No MX found for domain";
1087 break;
1088 case DNS_NULLMX:
1089 relay->fail = IMSG_MTA_DELIVERY_PERMFAIL;
1090 relay->failstr = "Domain does not accept mail";
1091 break;
1092 default:
1093 fatalx("bad DNS lookup error code");
1094 break;
1095 }
1096
1097 if (domain->mxstatus)
1098 log_info("smtp-out: Failed to resolve MX for %s: %s",
1099 mta_relay_to_text(relay), relay->failstr);
1100
1101 relay->status &= ~RELAY_WAIT_MX0x01;
1102 mta_drain(relay);
1103 mta_relay_unref(relay); /* from mta_drain() */
1104}
1105
1106static void
1107mta_on_secret(struct mta_relay *relay, const char *secret)
1108{
1109 log_debug("debug: mta: ... got secret for %s: %s",
1110 mta_relay_to_text(relay), secret);
1111
1112 if (secret)
1113 relay->secret = strdup(secret);
1114
1115 if (relay->secret == NULL((void *)0)) {
1116 log_warnx("warn: Failed to retrieve secret "
1117 "for %s", mta_relay_to_text(relay));
1118 relay->fail = IMSG_MTA_DELIVERY_TEMPFAIL;
1119 relay->failstr = "Could not retrieve credentials";
1120 }
1121
1122 relay->status &= ~RELAY_WAIT_SECRET0x04;
1123 mta_drain(relay);
1124 mta_relay_unref(relay); /* from mta_query_secret() */
1125}
1126
1127static void
1128mta_on_smarthost(struct envelope *evp, const char *smarthost)
1129{
1130 if (smarthost == NULL((void *)0)) {
1131 log_warnx("warn: Failed to retrieve smarthost "
1132 "for envelope %"PRIx64"llx", evp->id);
1133 m_create(p_queue, IMSG_MTA_DELIVERY_TEMPFAIL, 0, 0, -1);
1134 m_add_evpid(p_queue, evp->id);
1135 m_add_string(p_queue, "Cannot retrieve smarthost");
1136 m_add_int(p_queue, ESC_OTHER_STATUS);
1137 m_close(p_queue);
1138 return;
1139 }
1140
1141 log_debug("debug: mta: ... got smarthost for %016"PRIx64"llx"": %s",
1142 evp->id, smarthost);
1143 mta_handle_envelope(evp, smarthost);
1144 free(evp);
1145}
1146
1147static void
1148mta_on_preference(struct mta_relay *relay, int preference)
1149{
1150 log_debug("debug: mta: ... got preference for %s: %d",
1151 mta_relay_to_text(relay), preference);
1152
1153 relay->backuppref = preference;
1154
1155 relay->status &= ~RELAY_WAIT_PREFERENCE0x02;
1156 mta_drain(relay);
1157 mta_relay_unref(relay); /* from mta_query_preference() */
1158}
1159
1160static void
1161mta_on_source(struct mta_relay *relay, struct mta_source *source)
1162{
1163 struct mta_connector *c;
1164 void *iter;
1165 int delay, errmask;
1166
1167 log_debug("debug: mta: ... got source for %s: %s",
1168 mta_relay_to_text(relay), source
17.1
'source' is non-null
? mta_source_to_text(source) : "NULL");
18
'?' condition is true
1169
1170 relay->lastsource = time(NULL((void *)0));
1171 delay = DELAY_CHECK_SOURCE_SLOW10;
1172
1173 if (source
18.1
'source' is non-null
) {
19
Taking true branch
1174 c = mta_connector(relay, source);
1175 if (c->flags & CONNECTOR_NEW0x10000) {
20
Assuming the condition is false
21
Taking false branch
1176 c->flags &= ~CONNECTOR_NEW0x10000;
1177 delay = DELAY_CHECK_SOURCE1;
1178 }
1179 mta_connect(c);
1180 if ((c->flags & CONNECTOR_ERROR0x00ff) == 0)
22
Assuming the condition is false
23
Taking false branch
1181 relay->sourceloop = 0;
1182 else
1183 delay = DELAY_CHECK_SOURCE_FAST0;
1184 mta_source_unref(source); /* from constructor */
1185 }
1186 else {
1187 log_warnx("warn: Failed to get source address for %s",
1188 mta_relay_to_text(relay));
1189 }
1190
1191 if (tree_count(&relay->connectors)((&relay->connectors)->count) == 0) {
24
Assuming field 'count' is not equal to 0
25
Taking false branch
1192 relay->fail = IMSG_MTA_DELIVERY_TEMPFAIL;
1193 relay->failstr = "Could not retrieve source address";
1194 }
1195 if (tree_count(&relay->connectors)((&relay->connectors)->count) < relay->sourceloop) {
26
Assuming field 'count' is >= field 'sourceloop'
27
Taking false branch
1196 relay->fail = IMSG_MTA_DELIVERY_TEMPFAIL;
1197 relay->failstr = "No valid route to remote MX";
1198
1199 errmask = 0;
1200 iter = NULL((void *)0);
1201 while (tree_iter(&relay->connectors, &iter, NULL((void *)0), (void **)&c))
1202 errmask |= c->flags;
1203
1204 if (errmask & CONNECTOR_ERROR_ROUTE_SMTP0x0010)
1205 relay->failstr = "Destination seem to reject all mails";
1206 else if (errmask & CONNECTOR_ERROR_ROUTE_NET0x0008)
1207 relay->failstr = "Network error on destination MXs";
1208 else if (errmask & CONNECTOR_ERROR_MX0x0004)
1209 relay->failstr = "No MX found for destination";
1210 else if (errmask & CONNECTOR_ERROR_FAMILY0x0001)
1211 relay->failstr = "Address family mismatch on destination MXs";
1212 else if (errmask & CONNECTOR_ERROR_BLOCKED0x0020)
1213 relay->failstr = "All routes to destination blocked";
1214 else
1215 relay->failstr = "No valid route to destination";
1216 }
1217
1218 relay->nextsource = relay->lastsource + delay;
1219 relay->status &= ~RELAY_WAIT_SOURCE0x10;
1220 mta_drain(relay);
1221 mta_relay_unref(relay); /* from mta_query_source() */
28
Calling 'mta_relay_unref'
35
Returning; memory was released via 1st parameter
1222}
1223
1224static void
1225mta_connect(struct mta_connector *c)
1226{
1227 struct mta_route *route;
1228 struct mta_mx *mx;
1229 struct mta_limits *l = c->relay->limits;
1230 int limits;
1231 time_t nextconn, now;
1232
1233 /* toggle the block flag */
1234 if (mta_is_blocked(c->source, c->relay->domain->name))
1235 c->flags |= CONNECTOR_ERROR_BLOCKED0x0020;
1236 else
1237 c->flags &= ~CONNECTOR_ERROR_BLOCKED0x0020;
1238
1239 again:
1240
1241 log_debug("debug: mta: connecting with %s", mta_connector_to_text(c));
1242
1243 /* Do not connect if this connector has an error. */
1244 if (c->flags & CONNECTOR_ERROR0x00ff) {
1245 log_debug("debug: mta: connector error");
1246 return;
1247 }
1248
1249 if (c->flags & CONNECTOR_WAIT0x20000) {
1250 log_debug("debug: mta: cancelling connector timeout");
1251 runq_cancel(runq_connector, c);
1252 c->flags &= ~CONNECTOR_WAIT0x20000;
1253 }
1254
1255 /* No job. */
1256 if (c->relay->ntask == 0) {
1257 log_debug("debug: mta: no task for connector");
1258 return;
1259 }
1260
1261 /* Do not create more connections than necessary */
1262 if ((c->relay->nconn_ready >= c->relay->ntask) ||
1263 (c->relay->nconn > 2 && c->relay->nconn >= c->relay->ntask / 2)) {
1264 log_debug("debug: mta: enough connections already");
1265 return;
1266 }
1267
1268 limits = 0;
1269 nextconn = now = time(NULL((void *)0));
1270
1271 if (c->relay->domain->lastconn + l->conndelay_domain > nextconn) {
1272 log_debug("debug: mta: cannot use domain %s before %llus",
1273 c->relay->domain->name,
1274 (unsigned long long) c->relay->domain->lastconn + l->conndelay_domain - now);
1275 nextconn = c->relay->domain->lastconn + l->conndelay_domain;
1276 }
1277 if (c->relay->domain->nconn >= l->maxconn_per_domain) {
1278 log_debug("debug: mta: hit domain limit");
1279 limits |= CONNECTOR_LIMIT_DOMAIN0x2000;
1280 }
1281
1282 if (c->source->lastconn + l->conndelay_source > nextconn) {
1283 log_debug("debug: mta: cannot use source %s before %llus",
1284 mta_source_to_text(c->source),
1285 (unsigned long long) c->source->lastconn + l->conndelay_source - now);
1286 nextconn = c->source->lastconn + l->conndelay_source;
1287 }
1288 if (c->source->nconn >= l->maxconn_per_source) {
1289 log_debug("debug: mta: hit source limit");
1290 limits |= CONNECTOR_LIMIT_SOURCE0x0400;
1291 }
1292
1293 if (c->lastconn + l->conndelay_connector > nextconn) {
1294 log_debug("debug: mta: cannot use %s before %llus",
1295 mta_connector_to_text(c),
1296 (unsigned long long) c->lastconn + l->conndelay_connector - now);
1297 nextconn = c->lastconn + l->conndelay_connector;
1298 }
1299 if (c->nconn >= l->maxconn_per_connector) {
1300 log_debug("debug: mta: hit connector limit");
1301 limits |= CONNECTOR_LIMIT_CONN0x1000;
1302 }
1303
1304 if (c->relay->lastconn + l->conndelay_relay > nextconn) {
1305 log_debug("debug: mta: cannot use %s before %llus",
1306 mta_relay_to_text(c->relay),
1307 (unsigned long long) c->relay->lastconn + l->conndelay_relay - now);
1308 nextconn = c->relay->lastconn + l->conndelay_relay;
1309 }
1310 if (c->relay->nconn >= l->maxconn_per_relay) {
1311 log_debug("debug: mta: hit relay limit");
1312 limits |= CONNECTOR_LIMIT_RELAY0x0800;
1313 }
1314
1315 /* We can connect now, find a route */
1316 if (!limits && nextconn <= now)
1317 route = mta_find_route(c, now, &limits, &nextconn, &mx);
1318 else
1319 route = NULL((void *)0);
1320
1321 /* No route */
1322 if (route == NULL((void *)0)) {
1323
1324 if (c->flags & CONNECTOR_ERROR0x00ff) {
1325 /* XXX we might want to clear this flag later */
1326 log_debug("debug: mta-routing: no route available for %s: errors on connector",
1327 mta_connector_to_text(c));
1328 return;
1329 }
1330 else if (limits) {
1331 log_debug("debug: mta-routing: no route available for %s: limits reached",
1332 mta_connector_to_text(c));
1333 nextconn = now + DELAY_CHECK_LIMIT5;
1334 }
1335 else {
1336 log_debug("debug: mta-routing: no route available for %s: must wait a bit",
1337 mta_connector_to_text(c));
1338 }
1339 log_debug("debug: mta: retrying to connect on %s in %llus...",
1340 mta_connector_to_text(c),
1341 (unsigned long long) nextconn - time(NULL((void *)0)));
1342 c->flags |= CONNECTOR_WAIT0x20000;
1343 runq_schedule_at(runq_connector, nextconn, c);
1344 return;
1345 }
1346
1347 log_debug("debug: mta-routing: spawning new connection on %s",
1348 mta_route_to_text(route));
1349
1350 c->nconn += 1;
1351 c->lastconn = time(NULL((void *)0));
1352
1353 c->relay->nconn += 1;
1354 c->relay->lastconn = c->lastconn;
1355 c->relay->domain->nconn += 1;
1356 c->relay->domain->lastconn = c->lastconn;
1357 route->nconn += 1;
1358 route->lastconn = c->lastconn;
1359 route->src->nconn += 1;
1360 route->src->lastconn = c->lastconn;
1361 route->dst->nconn += 1;
1362 route->dst->lastconn = c->lastconn;
1363
1364 mta_session(c->relay, route, mx->mxname); /* this never fails synchronously */
1365 mta_relay_ref(c->relay);
1366
1367 goto again;
1368}
1369
1370static void
1371mta_on_timeout(struct runq *runq, void *arg)
1372{
1373 struct mta_connector *connector = arg;
1374 struct mta_relay *relay = arg;
1375 struct mta_route *route = arg;
1376 struct hoststat *hs = arg;
1377
1378 if (runq == runq_relay) {
1
Assuming 'runq' is equal to 'runq_relay'
2
Taking true branch
1379 log_debug("debug: mta: ... timeout for %s",
1380 mta_relay_to_text(relay));
1381 relay->status &= ~RELAY_WAIT_CONNECTOR0x20;
1382 mta_drain(relay);
3
Calling 'mta_drain'
38
Returning; memory was released via 1st parameter
1383 mta_relay_unref(relay); /* from mta_drain() */
39
Use of memory after it is freed
1384 }
1385 else if (runq == runq_connector) {
1386 log_debug("debug: mta: ... timeout for %s",
1387 mta_connector_to_text(connector));
1388 connector->flags &= ~CONNECTOR_WAIT0x20000;
1389 mta_connect(connector);
1390 }
1391 else if (runq == runq_route) {
1392 route->flags &= ~ROUTE_RUNQ0x02;
1393 mta_route_enable(route);
1394 mta_route_unref(route);
1395 }
1396 else if (runq == runq_hoststat) {
1397 log_debug("debug: mta: ... timeout for hoststat %s",
1398 hs->name);
1399 mta_hoststat_remove_entry(hs);
1400 free(hs);
1401 }
1402}
1403
1404static void
1405mta_route_disable(struct mta_route *route, int penalty, int reason)
1406{
1407 unsigned long long delay;
1408
1409 route->penalty += penalty;
1410 route->lastpenalty = time(NULL((void *)0));
1411 delay = (unsigned long long)DELAY_ROUTE_BASE15 * route->penalty * route->penalty;
1412 if (delay > DELAY_ROUTE_MAX3600)
1413 delay = DELAY_ROUTE_MAX3600;
1414#if 0
1415 delay = 60;
1416#endif
1417
1418 log_info("smtp-out: Disabling route %s for %llus",
1419 mta_route_to_text(route), delay);
1420
1421 if (route->flags & ROUTE_DISABLED0xf0)
1422 runq_cancel(runq_route, route);
1423 else
1424 mta_route_ref(route);
1425
1426 route->flags |= reason & ROUTE_DISABLED0xf0;
1427 runq_schedule(runq_route, delay, route);
1428}
1429
1430static void
1431mta_route_enable(struct mta_route *route)
1432{
1433 if (route->flags & ROUTE_DISABLED0xf0) {
1434 log_info("smtp-out: Enabling route %s",
1435 mta_route_to_text(route));
1436 route->flags &= ~ROUTE_DISABLED0xf0;
1437 route->flags |= ROUTE_NEW0x01;
1438 route->nerror = 0;
1439 }
1440
1441 if (route->penalty) {
1442#if DELAY_QUADRATIC1
1443 route->penalty -= 1;
1444 route->lastpenalty = time(NULL((void *)0));
1445#else
1446 route->penalty = 0;
1447#endif
1448 }
1449}
1450
1451static void
1452mta_drain(struct mta_relay *r)
1453{
1454 char buf[64];
1455
1456 log_debug("debug: mta: draining %s "
1457 "refcount=%d, ntask=%zu, nconnector=%zu, nconn=%zu",
1458 mta_relay_to_text(r),
1459 r->refcount, r->ntask, tree_count(&r->connectors)((&r->connectors)->count), r->nconn);
1460
1461 /*
1462 * All done.
1463 */
1464 if (r->ntask == 0) {
4
Assuming field 'ntask' is not equal to 0
5
Taking false branch
1465 log_debug("debug: mta: all done for %s", mta_relay_to_text(r));
1466 return;
1467 }
1468
1469 /*
1470 * If we know that this relay is failing flush the tasks.
1471 */
1472 if (r->fail) {
6
Assuming field 'fail' is 0
1473 mta_flush(r, r->fail, r->failstr);
1474 return;
1475 }
1476
1477 /* Query secret if needed. */
1478 if (r->flags & RELAY_AUTH0x08 && r->secret == NULL((void *)0))
1479 mta_query_secret(r);
1480
1481 /* Query our preference if needed. */
1482 if (r->backupname
6.1
Field 'backupname' is null
&& r->backuppref == -1)
1483 mta_query_preference(r);
1484
1485 /* Query the domain MXs if needed. */
1486 if (r->domain->lastmxquery == 0)
7
Assuming field 'lastmxquery' is not equal to 0
8
Taking false branch
1487 mta_query_mx(r);
1488
1489 /* Query the limits if needed. */
1490 if (r->limits == NULL((void *)0))
9
Assuming field 'limits' is not equal to NULL
10
Taking false branch
1491 mta_query_limits(r);
1492
1493 /* Wait until we are ready to proceed. */
1494 if (r->status & RELAY_WAITMASK0x7f) {
11
Assuming the condition is false
12
Taking false branch
1495 buf[0] = '\0';
1496 if (r->status & RELAY_WAIT_MX0x01)
1497 (void)strlcat(buf, " MX", sizeof buf);
1498 if (r->status & RELAY_WAIT_PREFERENCE0x02)
1499 (void)strlcat(buf, " preference", sizeof buf);
1500 if (r->status & RELAY_WAIT_SECRET0x04)
1501 (void)strlcat(buf, " secret", sizeof buf);
1502 if (r->status & RELAY_WAIT_SOURCE0x10)
1503 (void)strlcat(buf, " source", sizeof buf);
1504 if (r->status & RELAY_WAIT_CONNECTOR0x20)
1505 (void)strlcat(buf, " connector", sizeof buf);
1506 log_debug("debug: mta: %s waiting for%s",
1507 mta_relay_to_text(r), buf);
1508 return;
1509 }
1510
1511 /*
1512 * We have pending task, and it's maybe time too try a new source.
1513 */
1514 if (r->nextsource <= time(NULL((void *)0)))
13
Assuming the condition is true
14
Taking true branch
1515 mta_query_source(r);
15
Calling 'mta_query_source'
37
Returning; memory was released via 1st parameter
1516 else {
1517 log_debug("debug: mta: scheduling relay %s in %llus...",
1518 mta_relay_to_text(r),
1519 (unsigned long long) r->nextsource - time(NULL((void *)0)));
1520 runq_schedule_at(runq_relay, r->nextsource, r);
1521 r->status |= RELAY_WAIT_CONNECTOR0x20;
1522 mta_relay_ref(r);
1523 }
1524}
1525
1526static void
1527mta_flush(struct mta_relay *relay, int fail, const char *error)
1528{
1529 struct mta_envelope *e;
1530 struct mta_task *task;
1531 const char *domain;
1532 void *iter;
1533 struct mta_connector *c;
1534 size_t n, r;
1535
1536 log_debug("debug: mta_flush(%s, %d, \"%s\")",
1537 mta_relay_to_text(relay), fail, error);
1538
1539 if (fail != IMSG_MTA_DELIVERY_TEMPFAIL && fail != IMSG_MTA_DELIVERY_PERMFAIL)
1540 fatalx("unexpected delivery status %d", fail);
1541
1542 n = 0;
1543 while ((task = TAILQ_FIRST(&relay->tasks)((&relay->tasks)->tqh_first))) {
1544 TAILQ_REMOVE(&relay->tasks, task, entry)do { if (((task)->entry.tqe_next) != ((void *)0)) (task)->
entry.tqe_next->entry.tqe_prev = (task)->entry.tqe_prev
; else (&relay->tasks)->tqh_last = (task)->entry
.tqe_prev; *(task)->entry.tqe_prev = (task)->entry.tqe_next
; ; ; } while (0)
;
1545 while ((e = TAILQ_FIRST(&task->envelopes)((&task->envelopes)->tqh_first))) {
1546 TAILQ_REMOVE(&task->envelopes, e, entry)do { if (((e)->entry.tqe_next) != ((void *)0)) (e)->entry
.tqe_next->entry.tqe_prev = (e)->entry.tqe_prev; else (
&task->envelopes)->tqh_last = (e)->entry.tqe_prev
; *(e)->entry.tqe_prev = (e)->entry.tqe_next; ; ; } while
(0)
;
1547
1548 /*
1549 * host was suspended, cache envelope id in hoststat tree
1550 * so that it can be retried when a delivery succeeds for
1551 * that domain.
1552 */
1553 domain = strchr(e->dest, '@');
1554 if (fail == IMSG_MTA_DELIVERY_TEMPFAIL && domain) {
1555 r = 0;
1556 iter = NULL((void *)0);
1557 while (tree_iter(&relay->connectors, &iter,
1558 NULL((void *)0), (void **)&c)) {
1559 if (c->flags & CONNECTOR_ERROR_ROUTE0x0018)
1560 r++;
1561 }
1562 if (tree_count(&relay->connectors)((&relay->connectors)->count) == r)
1563 mta_hoststat_cache(domain+1, e->id);
1564 }
1565
1566 mta_delivery_log(e, NULL((void *)0), relay->domain->name, fail, error);
1567 mta_delivery_notify(e);
1568
1569 n++;
1570 }
1571 free(task->sender);
1572 free(task);
1573 }
1574
1575 stat_decrement("mta.task", relay->ntask);
1576 stat_decrement("mta.envelope", n);
1577 relay->ntask = 0;
1578
1579 /* release all waiting envelopes for the relay */
1580 if (relay->state & RELAY_HOLDQ0x02) {
1581 m_create(p_queue, IMSG_MTA_HOLDQ_RELEASE, 0, 0, -1);
1582 m_add_id(p_queue, relay->id);
1583 m_add_int(p_queue, -1);
1584 m_close(p_queue);
1585 }
1586}
1587
1588/*
1589 * Find a route to use for this connector
1590 */
1591static struct mta_route *
1592mta_find_route(struct mta_connector *c, time_t now, int *limits,
1593 time_t *nextconn, struct mta_mx **pmx)
1594{
1595 struct mta_route *route, *best;
1596 struct mta_limits *l = c->relay->limits;
1597 struct mta_mx *mx;
1598 int level, limit_host, limit_route;
1599 int family_mismatch, seen, suspended_route;
1600 time_t tm;
1601
1602 log_debug("debug: mta-routing: searching new route for %s...",
1603 mta_connector_to_text(c));
1604
1605 tm = 0;
1606 limit_host = 0;
1607 limit_route = 0;
1608 suspended_route = 0;
1609 family_mismatch = 0;
1610 level = -1;
1611 best = NULL((void *)0);
1612 seen = 0;
1613
1614 TAILQ_FOREACH(mx, &c->relay->domain->mxs, entry)for((mx) = ((&c->relay->domain->mxs)->tqh_first
); (mx) != ((void *)0); (mx) = ((mx)->entry.tqe_next))
{
1615 /*
1616 * New preference level
1617 */
1618 if (mx->preference > level) {
1619#ifndef IGNORE_MX_PREFERENCE
1620 /*
1621 * Use the current best MX if found.
1622 */
1623 if (best)
1624 break;
1625
1626 /*
1627 * No candidate found. There are valid MXs at this
1628 * preference level but they reached their limit, or
1629 * we can't connect yet.
1630 */
1631 if (limit_host || limit_route || tm)
1632 break;
1633
1634 /*
1635 * If we are a backup MX, do not relay to MXs with
1636 * a greater preference value.
1637 */
1638 if (c->relay->backuppref >= 0 &&
1639 mx->preference >= c->relay->backuppref)
1640 break;
1641
1642 /*
1643 * Start looking at MXs on this preference level.
1644 */
1645#endif
1646 level = mx->preference;
1647 }
1648
1649 if (mx->host->flags & HOST_IGNORE0x01)
1650 continue;
1651
1652 /* Found a possibly valid mx */
1653 seen++;
1654
1655 if ((c->source->sa &&
1656 c->source->sa->sa_family != mx->host->sa->sa_family) ||
1657 (l->family && l->family != mx->host->sa->sa_family)) {
1658 log_debug("debug: mta-routing: skipping host %s: AF mismatch",
1659 mta_host_to_text(mx->host));
1660 family_mismatch = 1;
1661 continue;
1662 }
1663
1664 if (mx->host->nconn >= l->maxconn_per_host) {
1665 log_debug("debug: mta-routing: skipping host %s: too many connections",
1666 mta_host_to_text(mx->host));
1667 limit_host = 1;
1668 continue;
1669 }
1670
1671 if (mx->host->lastconn + l->conndelay_host > now) {
1672 log_debug("debug: mta-routing: skipping host %s: cannot use before %llus",
1673 mta_host_to_text(mx->host),
1674 (unsigned long long) mx->host->lastconn + l->conndelay_host - now);
1675 if (tm == 0 || mx->host->lastconn + l->conndelay_host < tm)
1676 tm = mx->host->lastconn + l->conndelay_host;
1677 continue;
1678 }
1679
1680 route = mta_route(c->source, mx->host);
1681
1682 if (route->flags & ROUTE_DISABLED0xf0) {
1683 log_debug("debug: mta-routing: skipping route %s: suspend",
1684 mta_route_to_text(route));
1685 suspended_route |= route->flags & ROUTE_DISABLED0xf0;
1686 mta_route_unref(route); /* from here */
1687 continue;
1688 }
1689
1690 if (route->nconn && (route->flags & ROUTE_NEW0x01)) {
1691 log_debug("debug: mta-routing: skipping route %s: not validated yet",
1692 mta_route_to_text(route));
1693 limit_route = 1;
1694 mta_route_unref(route); /* from here */
1695 continue;
1696 }
1697
1698 if (route->nconn >= l->maxconn_per_route) {
1699 log_debug("debug: mta-routing: skipping route %s: too many connections",
1700 mta_route_to_text(route));
1701 limit_route = 1;
1702 mta_route_unref(route); /* from here */
1703 continue;
1704 }
1705
1706 if (route->lastconn + l->conndelay_route > now) {
1707 log_debug("debug: mta-routing: skipping route %s: cannot use before %llus (delay after connect)",
1708 mta_route_to_text(route),
1709 (unsigned long long) route->lastconn + l->conndelay_route - now);
1710 if (tm == 0 || route->lastconn + l->conndelay_route < tm)
1711 tm = route->lastconn + l->conndelay_route;
1712 mta_route_unref(route); /* from here */
1713 continue;
1714 }
1715
1716 if (route->lastdisc + l->discdelay_route > now) {
1717 log_debug("debug: mta-routing: skipping route %s: cannot use before %llus (delay after disconnect)",
1718 mta_route_to_text(route),
1719 (unsigned long long) route->lastdisc + l->discdelay_route - now);
1720 if (tm == 0 || route->lastdisc + l->discdelay_route < tm)
1721 tm = route->lastdisc + l->discdelay_route;
1722 mta_route_unref(route); /* from here */
1723 continue;
1724 }
1725
1726 /* Use the route with the lowest number of connections. */
1727 if (best && route->nconn >= best->nconn) {
1728 log_debug("debug: mta-routing: skipping route %s: current one is better",
1729 mta_route_to_text(route));
1730 mta_route_unref(route); /* from here */
1731 continue;
1732 }
1733
1734 if (best)
1735 mta_route_unref(best); /* from here */
1736 best = route;
1737 *pmx = mx;
1738 log_debug("debug: mta-routing: selecting candidate route %s",
1739 mta_route_to_text(route));
1740 }
1741
1742 if (best)
1743 return (best);
1744
1745 /* Order is important */
1746 if (seen == 0) {
1747 log_info("smtp-out: No MX found for %s",
1748 mta_connector_to_text(c));
1749 c->flags |= CONNECTOR_ERROR_MX0x0004;
1750 }
1751 else if (limit_route) {
1752 log_debug("debug: mta: hit route limit");
1753 *limits |= CONNECTOR_LIMIT_ROUTE0x0200;
1754 }
1755 else if (limit_host) {
1756 log_debug("debug: mta: hit host limit");
1757 *limits |= CONNECTOR_LIMIT_HOST0x0100;
1758 }
1759 else if (tm) {
1760 if (tm > *nextconn)
1761 *nextconn = tm;
1762 }
1763 else if (family_mismatch) {
1764 log_info("smtp-out: Address family mismatch on %s",
1765 mta_connector_to_text(c));
1766 c->flags |= CONNECTOR_ERROR_FAMILY0x0001;
1767 }
1768 else if (suspended_route) {
1769 log_info("smtp-out: No valid route for %s",
1770 mta_connector_to_text(c));
1771 if (suspended_route & ROUTE_DISABLED_NET0x10)
1772 c->flags |= CONNECTOR_ERROR_ROUTE_NET0x0008;
1773 if (suspended_route & ROUTE_DISABLED_SMTP0x20)
1774 c->flags |= CONNECTOR_ERROR_ROUTE_SMTP0x0010;
1775 }
1776
1777 return (NULL((void *)0));
1778}
1779
1780static void
1781mta_log(const struct mta_envelope *evp, const char *prefix, const char *source,
1782 const char *relay, const char *status)
1783{
1784 log_info("%016"PRIx64"llx"" mta delivery evpid=%016"PRIx64"llx"" "
1785 "from=<%s> to=<%s> rcpt=<%s> source=\"%s\" "
1786 "relay=\"%s\" delay=%s result=\"%s\" stat=\"%s\"",
1787 evp->session,
1788 evp->id,
1789 evp->task->sender,
1790 evp->dest,
1791 evp->rcpt ? evp->rcpt : "-",
1792 source ? source : "-",
1793 relay,
1794 duration_to_text(time(NULL((void *)0)) - evp->creation),
1795 prefix,
1796 status);
1797}
1798
1799static struct mta_relay *
1800mta_relay(struct envelope *e, struct relayhost *relayh)
1801{
1802 struct dispatcher *dispatcher;
1803 struct mta_relay key, *r;
1804
1805 dispatcher = dict_xget(env->sc_dispatchers, e->dispatcher);
1806
1807 memset(&key, 0, sizeof key);
1808
1809 key.pki_name = dispatcher->u.remote.pki;
1810 key.ca_name = dispatcher->u.remote.ca;
1811 key.authtable = dispatcher->u.remote.auth;
1812 key.sourcetable = dispatcher->u.remote.source;
1813 key.helotable = dispatcher->u.remote.helo_source;
1814 key.heloname = dispatcher->u.remote.helo;
1815 key.srs = dispatcher->u.remote.srs;
1816
1817 if (relayh->hostname[0]) {
1818 key.domain = mta_domain(relayh->hostname, 1);
1819 }
1820 else {
1821 key.domain = mta_domain(e->dest.domain, 0);
1822 if (dispatcher->u.remote.backup) {
1823 key.backupname = dispatcher->u.remote.backupmx;
1824 if (key.backupname == NULL((void *)0))
1825 key.backupname = e->smtpname;
1826 }
1827 }
1828
1829 key.tls = relayh->tls;
1830 key.flags |= relayh->flags;
1831 key.port = relayh->port;
1832 key.authlabel = relayh->authlabel;
1833 if (!key.authlabel[0])
1834 key.authlabel = NULL((void *)0);
1835
1836 if ((r = SPLAY_FIND(mta_relay_tree, &relays, &key)mta_relay_tree_SPLAY_FIND(&relays, &key)) == NULL((void *)0)) {
1837 r = xcalloc(1, sizeof *r);
1838 TAILQ_INIT(&r->tasks)do { (&r->tasks)->tqh_first = ((void *)0); (&r->
tasks)->tqh_last = &(&r->tasks)->tqh_first; }
while (0)
;
1839 r->id = generate_uid();
1840 r->dispatcher = dispatcher;
1841 r->tls = key.tls;
1842 r->flags = key.flags;
1843 r->domain = key.domain;
1844 r->backupname = key.backupname ?
1845 xstrdup(key.backupname) : NULL((void *)0);
1846 r->backuppref = -1;
1847 r->port = key.port;
1848 r->pki_name = key.pki_name ? xstrdup(key.pki_name) : NULL((void *)0);
1849 r->ca_name = key.ca_name ? xstrdup(key.ca_name) : NULL((void *)0);
1850 if (key.authtable)
1851 r->authtable = xstrdup(key.authtable);
1852 if (key.authlabel)
1853 r->authlabel = xstrdup(key.authlabel);
1854 if (key.sourcetable)
1855 r->sourcetable = xstrdup(key.sourcetable);
1856 if (key.helotable)
1857 r->helotable = xstrdup(key.helotable);
1858 if (key.heloname)
1859 r->heloname = xstrdup(key.heloname);
1860 r->srs = key.srs;
1861 SPLAY_INSERT(mta_relay_tree, &relays, r)mta_relay_tree_SPLAY_INSERT(&relays, r);
1862 stat_increment("mta.relay", 1);
1863 } else {
1864 mta_domain_unref(key.domain); /* from here */
1865 }
1866
1867 r->refcount++;
1868 return (r);
1869}
1870
1871static void
1872mta_relay_ref(struct mta_relay *r)
1873{
1874 r->refcount++;
1875}
1876
1877static void
1878mta_relay_unref(struct mta_relay *relay)
1879{
1880 struct mta_connector *c;
1881
1882 if (--relay->refcount)
29
Assuming the condition is false
30
Taking false branch
1883 return;
1884
1885 /* Make sure they are no envelopes held for this relay */
1886 if (relay->state & RELAY_HOLDQ0x02) {
31
Assuming the condition is false
32
Taking false branch
1887 m_create(p_queue, IMSG_MTA_HOLDQ_RELEASE, 0, 0, -1);
1888 m_add_id(p_queue, relay->id);
1889 m_add_int(p_queue, 0);
1890 m_close(p_queue);
1891 }
1892
1893 log_debug("debug: mta: freeing %s", mta_relay_to_text(relay));
1894 SPLAY_REMOVE(mta_relay_tree, &relays, relay)mta_relay_tree_SPLAY_REMOVE(&relays, relay);
1895
1896 while ((tree_poproot(&relay->connectors, NULL((void *)0), (void**)&c)))
33
Loop condition is false. Execution continues on line 1899
1897 mta_connector_free(c);
1898
1899 free(relay->authlabel);
1900 free(relay->authtable);
1901 free(relay->backupname);
1902 free(relay->pki_name);
1903 free(relay->ca_name);
1904 free(relay->helotable);
1905 free(relay->heloname);
1906 free(relay->secret);
1907 free(relay->sourcetable);
1908
1909 mta_domain_unref(relay->domain); /* from constructor */
1910 free(relay);
34
Memory is released
1911 stat_decrement("mta.relay", 1);
1912}
1913
1914const char *
1915mta_relay_to_text(struct mta_relay *relay)
1916{
1917 static char buf[1024];
1918 char tmp[32];
1919 const char *sep = ",";
1920
1921 (void)snprintf(buf, sizeof buf, "[relay:%s", relay->domain->name);
1922
1923 if (relay->port) {
1924 (void)strlcat(buf, sep, sizeof buf);
1925 (void)snprintf(tmp, sizeof tmp, "port=%d", (int)relay->port);
1926 (void)strlcat(buf, tmp, sizeof buf);
1927 }
1928
1929 (void)strlcat(buf, sep, sizeof buf);
1930 switch(relay->tls) {
1931 case RELAY_TLS_OPPORTUNISTIC0:
1932 (void)strlcat(buf, "smtp", sizeof buf);
1933 break;
1934 case RELAY_TLS_STARTTLS1:
1935 (void)strlcat(buf, "smtp+tls", sizeof buf);
1936 break;
1937 case RELAY_TLS_SMTPS2:
1938 (void)strlcat(buf, "smtps", sizeof buf);
1939 break;
1940 case RELAY_TLS_NO3:
1941 if (relay->flags & RELAY_LMTP0x80)
1942 (void)strlcat(buf, "lmtp", sizeof buf);
1943 else
1944 (void)strlcat(buf, "smtp+notls", sizeof buf);
1945 break;
1946 default:
1947 (void)strlcat(buf, "???", sizeof buf);
1948 }
1949
1950 if (relay->flags & RELAY_AUTH0x08) {
1951 (void)strlcat(buf, sep, sizeof buf);
1952 (void)strlcat(buf, "auth=", sizeof buf);
1953 (void)strlcat(buf, relay->authtable, sizeof buf);
1954 (void)strlcat(buf, ":", sizeof buf);
1955 (void)strlcat(buf, relay->authlabel, sizeof buf);
1956 }
1957
1958 if (relay->pki_name) {
1959 (void)strlcat(buf, sep, sizeof buf);
1960 (void)strlcat(buf, "pki_name=", sizeof buf);
1961 (void)strlcat(buf, relay->pki_name, sizeof buf);
1962 }
1963
1964 if (relay->domain->as_host) {
1965 (void)strlcat(buf, sep, sizeof buf);
1966 (void)strlcat(buf, "mx", sizeof buf);
1967 }
1968
1969 if (relay->backupname) {
1970 (void)strlcat(buf, sep, sizeof buf);
1971 (void)strlcat(buf, "backup=", sizeof buf);
1972 (void)strlcat(buf, relay->backupname, sizeof buf);
1973 }
1974
1975 if (relay->sourcetable) {
1976 (void)strlcat(buf, sep, sizeof buf);
1977 (void)strlcat(buf, "sourcetable=", sizeof buf);
1978 (void)strlcat(buf, relay->sourcetable, sizeof buf);
1979 }
1980
1981 if (relay->helotable) {
1982 (void)strlcat(buf, sep, sizeof buf);
1983 (void)strlcat(buf, "helotable=", sizeof buf);
1984 (void)strlcat(buf, relay->helotable, sizeof buf);
1985 }
1986
1987 if (relay->heloname) {
1988 (void)strlcat(buf, sep, sizeof buf);
1989 (void)strlcat(buf, "heloname=", sizeof buf);
1990 (void)strlcat(buf, relay->heloname, sizeof buf);
1991 }
1992
1993 (void)strlcat(buf, "]", sizeof buf);
1994
1995 return (buf);
1996}
1997
1998static void
1999mta_relay_show(struct mta_relay *r, struct mproc *p, uint32_t id, time_t t)
2000{
2001 struct mta_connector *c;
2002 void *iter;
2003 char buf[1024], flags[1024], dur[64];
2004 time_t to;
2005
2006 flags[0] = '\0';
2007
2008#define SHOWSTATUS(f, n) do { \
2009 if (r->status & (f)) { \
2010 if (flags[0]) \
2011 (void)strlcat(flags, ",", sizeof(flags)); \
2012 (void)strlcat(flags, (n), sizeof(flags)); \
2013 } \
2014 } while(0)
2015
2016 SHOWSTATUS(RELAY_WAIT_MX0x01, "MX");
2017 SHOWSTATUS(RELAY_WAIT_PREFERENCE0x02, "preference");
2018 SHOWSTATUS(RELAY_WAIT_SECRET0x04, "secret");
2019 SHOWSTATUS(RELAY_WAIT_LIMITS0x08, "limits");
2020 SHOWSTATUS(RELAY_WAIT_SOURCE0x10, "source");
2021 SHOWSTATUS(RELAY_WAIT_CONNECTOR0x20, "connector");
2022#undef SHOWSTATUS
2023
2024 if (runq_pending(runq_relay, r, &to))
2025 (void)snprintf(dur, sizeof(dur), "%s", duration_to_text(to - t));
2026 else
2027 (void)strlcpy(dur, "-", sizeof(dur));
2028
2029 (void)snprintf(buf, sizeof(buf), "%s refcount=%d ntask=%zu nconn=%zu lastconn=%s timeout=%s wait=%s%s",
2030 mta_relay_to_text(r),
2031 r->refcount,
2032 r->ntask,
2033 r->nconn,
2034 r->lastconn ? duration_to_text(t - r->lastconn) : "-",
2035 dur,
2036 flags,
2037 (r->state & RELAY_ONHOLD0x01) ? "ONHOLD" : "");
2038 m_compose(p, IMSG_CTL_MTA_SHOW_RELAYS, id, 0, -1, buf, strlen(buf) + 1);
2039
2040 iter = NULL((void *)0);
2041 while (tree_iter(&r->connectors, &iter, NULL((void *)0), (void **)&c)) {
2042
2043 if (runq_pending(runq_connector, c, &to))
2044 (void)snprintf(dur, sizeof(dur), "%s", duration_to_text(to - t));
2045 else
2046 (void)strlcpy(dur, "-", sizeof(dur));
2047
2048 flags[0] = '\0';
2049
2050#define SHOWFLAG(f, n) do { \
2051 if (c->flags & (f)) { \
2052 if (flags[0]) \
2053 (void)strlcat(flags, ",", sizeof(flags)); \
2054 (void)strlcat(flags, (n), sizeof(flags)); \
2055 } \
2056 } while(0)
2057
2058 SHOWFLAG(CONNECTOR_NEW0x10000, "NEW");
2059 SHOWFLAG(CONNECTOR_WAIT0x20000, "WAIT");
2060
2061 SHOWFLAG(CONNECTOR_ERROR_FAMILY0x0001, "ERROR_FAMILY");
2062 SHOWFLAG(CONNECTOR_ERROR_SOURCE0x0002, "ERROR_SOURCE");
2063 SHOWFLAG(CONNECTOR_ERROR_MX0x0004, "ERROR_MX");
2064 SHOWFLAG(CONNECTOR_ERROR_ROUTE_NET0x0008, "ERROR_ROUTE_NET");
2065 SHOWFLAG(CONNECTOR_ERROR_ROUTE_SMTP0x0010, "ERROR_ROUTE_SMTP");
2066 SHOWFLAG(CONNECTOR_ERROR_BLOCKED0x0020, "ERROR_BLOCKED");
2067
2068 SHOWFLAG(CONNECTOR_LIMIT_HOST0x0100, "LIMIT_HOST");
2069 SHOWFLAG(CONNECTOR_LIMIT_ROUTE0x0200, "LIMIT_ROUTE");
2070 SHOWFLAG(CONNECTOR_LIMIT_SOURCE0x0400, "LIMIT_SOURCE");
2071 SHOWFLAG(CONNECTOR_LIMIT_RELAY0x0800, "LIMIT_RELAY");
2072 SHOWFLAG(CONNECTOR_LIMIT_CONN0x1000, "LIMIT_CONN");
2073 SHOWFLAG(CONNECTOR_LIMIT_DOMAIN0x2000, "LIMIT_DOMAIN");
2074#undef SHOWFLAG
2075
2076 (void)snprintf(buf, sizeof(buf),
2077 " connector %s refcount=%d nconn=%zu lastconn=%s timeout=%s flags=%s",
2078 mta_source_to_text(c->source),
2079 c->refcount,
2080 c->nconn,
2081 c->lastconn ? duration_to_text(t - c->lastconn) : "-",
2082 dur,
2083 flags);
2084 m_compose(p, IMSG_CTL_MTA_SHOW_RELAYS, id, 0, -1, buf,
2085 strlen(buf) + 1);
2086
2087
2088 }
2089}
2090
2091static int
2092mta_relay_cmp(const struct mta_relay *a, const struct mta_relay *b)
2093{
2094 int r;
2095
2096 if (a->domain < b->domain)
2097 return (-1);
2098 if (a->domain > b->domain)
2099 return (1);
2100
2101 if (a->tls < b->tls)
2102 return (-1);
2103 if (a->tls > b->tls)
2104 return (1);
2105
2106 if (a->flags < b->flags)
2107 return (-1);
2108 if (a->flags > b->flags)
2109 return (1);
2110
2111 if (a->port < b->port)
2112 return (-1);
2113 if (a->port > b->port)
2114 return (1);
2115
2116 if (a->authtable == NULL((void *)0) && b->authtable)
2117 return (-1);
2118 if (a->authtable && b->authtable == NULL((void *)0))
2119 return (1);
2120 if (a->authtable && ((r = strcmp(a->authtable, b->authtable))))
2121 return (r);
2122 if (a->authlabel == NULL((void *)0) && b->authlabel)
2123 return (-1);
2124 if (a->authlabel && b->authlabel == NULL((void *)0))
2125 return (1);
2126 if (a->authlabel && ((r = strcmp(a->authlabel, b->authlabel))))
2127 return (r);
2128 if (a->sourcetable == NULL((void *)0) && b->sourcetable)
2129 return (-1);
2130 if (a->sourcetable && b->sourcetable == NULL((void *)0))
2131 return (1);
2132 if (a->sourcetable && ((r = strcmp(a->sourcetable, b->sourcetable))))
2133 return (r);
2134 if (a->helotable == NULL((void *)0) && b->helotable)
2135 return (-1);
2136 if (a->helotable && b->helotable == NULL((void *)0))
2137 return (1);
2138 if (a->helotable && ((r = strcmp(a->helotable, b->helotable))))
2139 return (r);
2140 if (a->heloname == NULL((void *)0) && b->heloname)
2141 return (-1);
2142 if (a->heloname && b->heloname == NULL((void *)0))
2143 return (1);
2144 if (a->heloname && ((r = strcmp(a->heloname, b->heloname))))
2145 return (r);
2146
2147 if (a->pki_name == NULL((void *)0) && b->pki_name)
2148 return (-1);
2149 if (a->pki_name && b->pki_name == NULL((void *)0))
2150 return (1);
2151 if (a->pki_name && ((r = strcmp(a->pki_name, b->pki_name))))
2152 return (r);
2153
2154 if (a->ca_name == NULL((void *)0) && b->ca_name)
2155 return (-1);
2156 if (a->ca_name && b->ca_name == NULL((void *)0))
2157 return (1);
2158 if (a->ca_name && ((r = strcmp(a->ca_name, b->ca_name))))
2159 return (r);
2160
2161 if (a->backupname == NULL((void *)0) && b->backupname)
2162 return (-1);
2163 if (a->backupname && b->backupname == NULL((void *)0))
2164 return (1);
2165 if (a->backupname && ((r = strcmp(a->backupname, b->backupname))))
2166 return (r);
2167
2168 if (a->srs < b->srs)
2169 return (-1);
2170 if (a->srs > b->srs)
2171 return (1);
2172
2173 return (0);
2174}
2175
2176SPLAY_GENERATE(mta_relay_tree, mta_relay, entry, mta_relay_cmp)struct mta_relay * mta_relay_tree_SPLAY_INSERT(struct mta_relay_tree
*head, struct mta_relay *elm) { if (((head)->sph_root == (
(void *)0))) { (elm)->entry.spe_left = (elm)->entry.spe_right
= ((void *)0); } else { int __comp; mta_relay_tree_SPLAY(head
, elm); __comp = (mta_relay_cmp)(elm, (head)->sph_root); if
(__comp < 0) { (elm)->entry.spe_left = ((head)->sph_root
)->entry.spe_left; (elm)->entry.spe_right = (head)->
sph_root; ((head)->sph_root)->entry.spe_left = ((void *
)0); } else if (__comp > 0) { (elm)->entry.spe_right = (
(head)->sph_root)->entry.spe_right; (elm)->entry.spe_left
= (head)->sph_root; ((head)->sph_root)->entry.spe_right
= ((void *)0); } else return ((head)->sph_root); } (head)
->sph_root = (elm); return (((void *)0)); } struct mta_relay
* mta_relay_tree_SPLAY_REMOVE(struct mta_relay_tree *head, struct
mta_relay *elm) { struct mta_relay *__tmp; if (((head)->sph_root
== ((void *)0))) return (((void *)0)); mta_relay_tree_SPLAY(
head, elm); if ((mta_relay_cmp)(elm, (head)->sph_root) == 0
) { if (((head)->sph_root)->entry.spe_left == ((void *)
0)) { (head)->sph_root = ((head)->sph_root)->entry.spe_right
; } else { __tmp = ((head)->sph_root)->entry.spe_right;
(head)->sph_root = ((head)->sph_root)->entry.spe_left
; mta_relay_tree_SPLAY(head, elm); ((head)->sph_root)->
entry.spe_right = __tmp; } return (elm); } return (((void *)0
)); } void mta_relay_tree_SPLAY(struct mta_relay_tree *head, struct
mta_relay *elm) { struct mta_relay __node, *__left, *__right
, *__tmp; int __comp; (&__node)->entry.spe_left = (&
__node)->entry.spe_right = ((void *)0); __left = __right =
&__node; while ((__comp = (mta_relay_cmp)(elm, (head)->
sph_root))) { if (__comp < 0) { __tmp = ((head)->sph_root
)->entry.spe_left; if (__tmp == ((void *)0)) break; if ((mta_relay_cmp
)(elm, __tmp) < 0){ do { ((head)->sph_root)->entry.spe_left
= (__tmp)->entry.spe_right; (__tmp)->entry.spe_right =
(head)->sph_root; (head)->sph_root = __tmp; } while (0
); if (((head)->sph_root)->entry.spe_left == ((void *)0
)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if ((mta_relay_cmp)(elm, __tmp
) > 0){ do { ((head)->sph_root)->entry.spe_right = (
__tmp)->entry.spe_left; (__tmp)->entry.spe_left = (head
)->sph_root; (head)->sph_root = __tmp; } while (0); if (
((head)->sph_root)->entry.spe_right == ((void *)0)) break
; } do { (__left)->entry.spe_right = (head)->sph_root; __left
= (head)->sph_root; (head)->sph_root = ((head)->sph_root
)->entry.spe_right; } while (0); } } do { (__left)->entry
.spe_right = ((head)->sph_root)->entry.spe_left; (__right
)->entry.spe_left = ((head)->sph_root)->entry.spe_right
; ((head)->sph_root)->entry.spe_left = (&__node)->
entry.spe_right; ((head)->sph_root)->entry.spe_right = (
&__node)->entry.spe_left; } while (0); } void mta_relay_tree_SPLAY_MINMAX
(struct mta_relay_tree *head, int __comp) { struct mta_relay __node
, *__left, *__right, *__tmp; (&__node)->entry.spe_left
= (&__node)->entry.spe_right = ((void *)0); __left = __right
= &__node; while (1) { if (__comp < 0) { __tmp = ((head
)->sph_root)->entry.spe_left; if (__tmp == ((void *)0))
break; if (__comp < 0){ do { ((head)->sph_root)->entry
.spe_left = (__tmp)->entry.spe_right; (__tmp)->entry.spe_right
= (head)->sph_root; (head)->sph_root = __tmp; } while (
0); if (((head)->sph_root)->entry.spe_left == ((void *)
0)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if (__comp > 0) { do { (
(head)->sph_root)->entry.spe_right = (__tmp)->entry.
spe_left; (__tmp)->entry.spe_left = (head)->sph_root; (
head)->sph_root = __tmp; } while (0); if (((head)->sph_root
)->entry.spe_right == ((void *)0)) break; } do { (__left)->
entry.spe_right = (head)->sph_root; __left = (head)->sph_root
; (head)->sph_root = ((head)->sph_root)->entry.spe_right
; } while (0); } } do { (__left)->entry.spe_right = ((head
)->sph_root)->entry.spe_left; (__right)->entry.spe_left
= ((head)->sph_root)->entry.spe_right; ((head)->sph_root
)->entry.spe_left = (&__node)->entry.spe_right; ((head
)->sph_root)->entry.spe_right = (&__node)->entry
.spe_left; } while (0); }
;
2177
2178static struct mta_host *
2179mta_host(const struct sockaddr *sa)
2180{
2181 struct mta_host key, *h;
2182 struct sockaddr_storage ss;
2183
2184 memmove(&ss, sa, sa->sa_len);
2185 key.sa = (struct sockaddr*)&ss;
2186 h = SPLAY_FIND(mta_host_tree, &hosts, &key)mta_host_tree_SPLAY_FIND(&hosts, &key);
2187
2188 if (h == NULL((void *)0)) {
2189 h = xcalloc(1, sizeof(*h));
2190 h->sa = xmemdup(sa, sa->sa_len);
2191 SPLAY_INSERT(mta_host_tree, &hosts, h)mta_host_tree_SPLAY_INSERT(&hosts, h);
2192 stat_increment("mta.host", 1);
2193 }
2194
2195 h->refcount++;
2196 return (h);
2197}
2198
2199static void
2200mta_host_ref(struct mta_host *h)
2201{
2202 h->refcount++;
2203}
2204
2205static void
2206mta_host_unref(struct mta_host *h)
2207{
2208 if (--h->refcount)
2209 return;
2210
2211 SPLAY_REMOVE(mta_host_tree, &hosts, h)mta_host_tree_SPLAY_REMOVE(&hosts, h);
2212 free(h->sa);
2213 free(h->ptrname);
2214 free(h);
2215 stat_decrement("mta.host", 1);
2216}
2217
2218const char *
2219mta_host_to_text(struct mta_host *h)
2220{
2221 static char buf[1024];
2222
2223 if (h->ptrname)
2224 (void)snprintf(buf, sizeof buf, "%s (%s)",
2225 sa_to_text(h->sa), h->ptrname);
2226 else
2227 (void)snprintf(buf, sizeof buf, "%s", sa_to_text(h->sa));
2228
2229 return (buf);
2230}
2231
2232static int
2233mta_host_cmp(const struct mta_host *a, const struct mta_host *b)
2234{
2235 if (a->sa->sa_len < b->sa->sa_len)
2236 return (-1);
2237 if (a->sa->sa_len > b->sa->sa_len)
2238 return (1);
2239 return (memcmp(a->sa, b->sa, a->sa->sa_len));
2240}
2241
2242SPLAY_GENERATE(mta_host_tree, mta_host, entry, mta_host_cmp)struct mta_host * mta_host_tree_SPLAY_INSERT(struct mta_host_tree
*head, struct mta_host *elm) { if (((head)->sph_root == (
(void *)0))) { (elm)->entry.spe_left = (elm)->entry.spe_right
= ((void *)0); } else { int __comp; mta_host_tree_SPLAY(head
, elm); __comp = (mta_host_cmp)(elm, (head)->sph_root); if
(__comp < 0) { (elm)->entry.spe_left = ((head)->sph_root
)->entry.spe_left; (elm)->entry.spe_right = (head)->
sph_root; ((head)->sph_root)->entry.spe_left = ((void *
)0); } else if (__comp > 0) { (elm)->entry.spe_right = (
(head)->sph_root)->entry.spe_right; (elm)->entry.spe_left
= (head)->sph_root; ((head)->sph_root)->entry.spe_right
= ((void *)0); } else return ((head)->sph_root); } (head)
->sph_root = (elm); return (((void *)0)); } struct mta_host
* mta_host_tree_SPLAY_REMOVE(struct mta_host_tree *head, struct
mta_host *elm) { struct mta_host *__tmp; if (((head)->sph_root
== ((void *)0))) return (((void *)0)); mta_host_tree_SPLAY(head
, elm); if ((mta_host_cmp)(elm, (head)->sph_root) == 0) { if
(((head)->sph_root)->entry.spe_left == ((void *)0)) { (
head)->sph_root = ((head)->sph_root)->entry.spe_right
; } else { __tmp = ((head)->sph_root)->entry.spe_right;
(head)->sph_root = ((head)->sph_root)->entry.spe_left
; mta_host_tree_SPLAY(head, elm); ((head)->sph_root)->entry
.spe_right = __tmp; } return (elm); } return (((void *)0)); }
void mta_host_tree_SPLAY(struct mta_host_tree *head, struct mta_host
*elm) { struct mta_host __node, *__left, *__right, *__tmp; int
__comp; (&__node)->entry.spe_left = (&__node)->
entry.spe_right = ((void *)0); __left = __right = &__node
; while ((__comp = (mta_host_cmp)(elm, (head)->sph_root)))
{ if (__comp < 0) { __tmp = ((head)->sph_root)->entry
.spe_left; if (__tmp == ((void *)0)) break; if ((mta_host_cmp
)(elm, __tmp) < 0){ do { ((head)->sph_root)->entry.spe_left
= (__tmp)->entry.spe_right; (__tmp)->entry.spe_right =
(head)->sph_root; (head)->sph_root = __tmp; } while (0
); if (((head)->sph_root)->entry.spe_left == ((void *)0
)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if ((mta_host_cmp)(elm, __tmp
) > 0){ do { ((head)->sph_root)->entry.spe_right = (
__tmp)->entry.spe_left; (__tmp)->entry.spe_left = (head
)->sph_root; (head)->sph_root = __tmp; } while (0); if (
((head)->sph_root)->entry.spe_right == ((void *)0)) break
; } do { (__left)->entry.spe_right = (head)->sph_root; __left
= (head)->sph_root; (head)->sph_root = ((head)->sph_root
)->entry.spe_right; } while (0); } } do { (__left)->entry
.spe_right = ((head)->sph_root)->entry.spe_left; (__right
)->entry.spe_left = ((head)->sph_root)->entry.spe_right
; ((head)->sph_root)->entry.spe_left = (&__node)->
entry.spe_right; ((head)->sph_root)->entry.spe_right = (
&__node)->entry.spe_left; } while (0); } void mta_host_tree_SPLAY_MINMAX
(struct mta_host_tree *head, int __comp) { struct mta_host __node
, *__left, *__right, *__tmp; (&__node)->entry.spe_left
= (&__node)->entry.spe_right = ((void *)0); __left = __right
= &__node; while (1) { if (__comp < 0) { __tmp = ((head
)->sph_root)->entry.spe_left; if (__tmp == ((void *)0))
break; if (__comp < 0){ do { ((head)->sph_root)->entry
.spe_left = (__tmp)->entry.spe_right; (__tmp)->entry.spe_right
= (head)->sph_root; (head)->sph_root = __tmp; } while (
0); if (((head)->sph_root)->entry.spe_left == ((void *)
0)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if (__comp > 0) { do { (
(head)->sph_root)->entry.spe_right = (__tmp)->entry.
spe_left; (__tmp)->entry.spe_left = (head)->sph_root; (
head)->sph_root = __tmp; } while (0); if (((head)->sph_root
)->entry.spe_right == ((void *)0)) break; } do { (__left)->
entry.spe_right = (head)->sph_root; __left = (head)->sph_root
; (head)->sph_root = ((head)->sph_root)->entry.spe_right
; } while (0); } } do { (__left)->entry.spe_right = ((head
)->sph_root)->entry.spe_left; (__right)->entry.spe_left
= ((head)->sph_root)->entry.spe_right; ((head)->sph_root
)->entry.spe_left = (&__node)->entry.spe_right; ((head
)->sph_root)->entry.spe_right = (&__node)->entry
.spe_left; } while (0); }
;
2243
2244static struct mta_domain *
2245mta_domain(char *name, int as_host)
2246{
2247 struct mta_domain key, *d;
2248
2249 key.name = name;
2250 key.as_host = as_host;
2251 d = SPLAY_FIND(mta_domain_tree, &domains, &key)mta_domain_tree_SPLAY_FIND(&domains, &key);
2252
2253 if (d == NULL((void *)0)) {
2254 d = xcalloc(1, sizeof(*d));
2255 d->name = xstrdup(name);
2256 d->as_host = as_host;
2257 TAILQ_INIT(&d->mxs)do { (&d->mxs)->tqh_first = ((void *)0); (&d->
mxs)->tqh_last = &(&d->mxs)->tqh_first; } while
(0)
;
2258 SPLAY_INSERT(mta_domain_tree, &domains, d)mta_domain_tree_SPLAY_INSERT(&domains, d);
2259 stat_increment("mta.domain", 1);
2260 }
2261
2262 d->refcount++;
2263 return (d);
2264}
2265
2266#if 0
2267static void
2268mta_domain_ref(struct mta_domain *d)
2269{
2270 d->refcount++;
2271}
2272#endif
2273
2274static void
2275mta_domain_unref(struct mta_domain *d)
2276{
2277 struct mta_mx *mx;
2278
2279 if (--d->refcount)
2280 return;
2281
2282 while ((mx = TAILQ_FIRST(&d->mxs)((&d->mxs)->tqh_first))) {
2283 TAILQ_REMOVE(&d->mxs, mx, entry)do { if (((mx)->entry.tqe_next) != ((void *)0)) (mx)->entry
.tqe_next->entry.tqe_prev = (mx)->entry.tqe_prev; else (
&d->mxs)->tqh_last = (mx)->entry.tqe_prev; *(mx)
->entry.tqe_prev = (mx)->entry.tqe_next; ; ; } while (0
)
;
2284 mta_host_unref(mx->host); /* from IMSG_DNS_HOST */
2285 free(mx->mxname);
2286 free(mx);
2287 }
2288
2289 SPLAY_REMOVE(mta_domain_tree, &domains, d)mta_domain_tree_SPLAY_REMOVE(&domains, d);
2290 free(d->name);
2291 free(d);
2292 stat_decrement("mta.domain", 1);
2293}
2294
2295static int
2296mta_domain_cmp(const struct mta_domain *a, const struct mta_domain *b)
2297{
2298 if (a->as_host < b->as_host)
2299 return (-1);
2300 if (a->as_host > b->as_host)
2301 return (1);
2302 return (strcasecmp(a->name, b->name));
2303}
2304
2305SPLAY_GENERATE(mta_domain_tree, mta_domain, entry, mta_domain_cmp)struct mta_domain * mta_domain_tree_SPLAY_INSERT(struct mta_domain_tree
*head, struct mta_domain *elm) { if (((head)->sph_root ==
((void *)0))) { (elm)->entry.spe_left = (elm)->entry.spe_right
= ((void *)0); } else { int __comp; mta_domain_tree_SPLAY(head
, elm); __comp = (mta_domain_cmp)(elm, (head)->sph_root); if
(__comp < 0) { (elm)->entry.spe_left = ((head)->sph_root
)->entry.spe_left; (elm)->entry.spe_right = (head)->
sph_root; ((head)->sph_root)->entry.spe_left = ((void *
)0); } else if (__comp > 0) { (elm)->entry.spe_right = (
(head)->sph_root)->entry.spe_right; (elm)->entry.spe_left
= (head)->sph_root; ((head)->sph_root)->entry.spe_right
= ((void *)0); } else return ((head)->sph_root); } (head)
->sph_root = (elm); return (((void *)0)); } struct mta_domain
* mta_domain_tree_SPLAY_REMOVE(struct mta_domain_tree *head,
struct mta_domain *elm) { struct mta_domain *__tmp; if (((head
)->sph_root == ((void *)0))) return (((void *)0)); mta_domain_tree_SPLAY
(head, elm); if ((mta_domain_cmp)(elm, (head)->sph_root) ==
0) { if (((head)->sph_root)->entry.spe_left == ((void *
)0)) { (head)->sph_root = ((head)->sph_root)->entry.
spe_right; } else { __tmp = ((head)->sph_root)->entry.spe_right
; (head)->sph_root = ((head)->sph_root)->entry.spe_left
; mta_domain_tree_SPLAY(head, elm); ((head)->sph_root)->
entry.spe_right = __tmp; } return (elm); } return (((void *)0
)); } void mta_domain_tree_SPLAY(struct mta_domain_tree *head
, struct mta_domain *elm) { struct mta_domain __node, *__left
, *__right, *__tmp; int __comp; (&__node)->entry.spe_left
= (&__node)->entry.spe_right = ((void *)0); __left = __right
= &__node; while ((__comp = (mta_domain_cmp)(elm, (head)
->sph_root))) { if (__comp < 0) { __tmp = ((head)->sph_root
)->entry.spe_left; if (__tmp == ((void *)0)) break; if ((mta_domain_cmp
)(elm, __tmp) < 0){ do { ((head)->sph_root)->entry.spe_left
= (__tmp)->entry.spe_right; (__tmp)->entry.spe_right =
(head)->sph_root; (head)->sph_root = __tmp; } while (0
); if (((head)->sph_root)->entry.spe_left == ((void *)0
)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if ((mta_domain_cmp)(elm, __tmp
) > 0){ do { ((head)->sph_root)->entry.spe_right = (
__tmp)->entry.spe_left; (__tmp)->entry.spe_left = (head
)->sph_root; (head)->sph_root = __tmp; } while (0); if (
((head)->sph_root)->entry.spe_right == ((void *)0)) break
; } do { (__left)->entry.spe_right = (head)->sph_root; __left
= (head)->sph_root; (head)->sph_root = ((head)->sph_root
)->entry.spe_right; } while (0); } } do { (__left)->entry
.spe_right = ((head)->sph_root)->entry.spe_left; (__right
)->entry.spe_left = ((head)->sph_root)->entry.spe_right
; ((head)->sph_root)->entry.spe_left = (&__node)->
entry.spe_right; ((head)->sph_root)->entry.spe_right = (
&__node)->entry.spe_left; } while (0); } void mta_domain_tree_SPLAY_MINMAX
(struct mta_domain_tree *head, int __comp) { struct mta_domain
__node, *__left, *__right, *__tmp; (&__node)->entry.spe_left
= (&__node)->entry.spe_right = ((void *)0); __left = __right
= &__node; while (1) { if (__comp < 0) { __tmp = ((head
)->sph_root)->entry.spe_left; if (__tmp == ((void *)0))
break; if (__comp < 0){ do { ((head)->sph_root)->entry
.spe_left = (__tmp)->entry.spe_right; (__tmp)->entry.spe_right
= (head)->sph_root; (head)->sph_root = __tmp; } while (
0); if (((head)->sph_root)->entry.spe_left == ((void *)
0)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if (__comp > 0) { do { (
(head)->sph_root)->entry.spe_right = (__tmp)->entry.
spe_left; (__tmp)->entry.spe_left = (head)->sph_root; (
head)->sph_root = __tmp; } while (0); if (((head)->sph_root
)->entry.spe_right == ((void *)0)) break; } do { (__left)->
entry.spe_right = (head)->sph_root; __left = (head)->sph_root
; (head)->sph_root = ((head)->sph_root)->entry.spe_right
; } while (0); } } do { (__left)->entry.spe_right = ((head
)->sph_root)->entry.spe_left; (__right)->entry.spe_left
= ((head)->sph_root)->entry.spe_right; ((head)->sph_root
)->entry.spe_left = (&__node)->entry.spe_right; ((head
)->sph_root)->entry.spe_right = (&__node)->entry
.spe_left; } while (0); }
;
2306
2307static struct mta_source *
2308mta_source(const struct sockaddr *sa)
2309{
2310 struct mta_source key, *s;
2311 struct sockaddr_storage ss;
2312
2313 if (sa) {
2314 memmove(&ss, sa, sa->sa_len);
2315 key.sa = (struct sockaddr*)&ss;
2316 } else
2317 key.sa = NULL((void *)0);
2318 s = SPLAY_FIND(mta_source_tree, &sources, &key)mta_source_tree_SPLAY_FIND(&sources, &key);
2319
2320 if (s == NULL((void *)0)) {
2321 s = xcalloc(1, sizeof(*s));
2322 if (sa)
2323 s->sa = xmemdup(sa, sa->sa_len);
2324 SPLAY_INSERT(mta_source_tree, &sources, s)mta_source_tree_SPLAY_INSERT(&sources, s);
2325 stat_increment("mta.source", 1);
2326 }
2327
2328 s->refcount++;
2329 return (s);
2330}
2331
2332static void
2333mta_source_ref(struct mta_source *s)
2334{
2335 s->refcount++;
2336}
2337
2338static void
2339mta_source_unref(struct mta_source *s)
2340{
2341 if (--s->refcount)
2342 return;
2343
2344 SPLAY_REMOVE(mta_source_tree, &sources, s)mta_source_tree_SPLAY_REMOVE(&sources, s);
2345 free(s->sa);
2346 free(s);
2347 stat_decrement("mta.source", 1);
2348}
2349
2350static const char *
2351mta_source_to_text(struct mta_source *s)
2352{
2353 static char buf[1024];
2354
2355 if (s->sa == NULL((void *)0))
2356 return "[]";
2357 (void)snprintf(buf, sizeof buf, "%s", sa_to_text(s->sa));
2358 return (buf);
2359}
2360
2361static int
2362mta_source_cmp(const struct mta_source *a, const struct mta_source *b)
2363{
2364 if (a->sa == NULL((void *)0))
2365 return ((b->sa == NULL((void *)0)) ? 0 : -1);
2366 if (b->sa == NULL((void *)0))
2367 return (1);
2368 if (a->sa->sa_len < b->sa->sa_len)
2369 return (-1);
2370 if (a->sa->sa_len > b->sa->sa_len)
2371 return (1);
2372 return (memcmp(a->sa, b->sa, a->sa->sa_len));
2373}
2374
2375SPLAY_GENERATE(mta_source_tree, mta_source, entry, mta_source_cmp)struct mta_source * mta_source_tree_SPLAY_INSERT(struct mta_source_tree
*head, struct mta_source *elm) { if (((head)->sph_root ==
((void *)0))) { (elm)->entry.spe_left = (elm)->entry.spe_right
= ((void *)0); } else { int __comp; mta_source_tree_SPLAY(head
, elm); __comp = (mta_source_cmp)(elm, (head)->sph_root); if
(__comp < 0) { (elm)->entry.spe_left = ((head)->sph_root
)->entry.spe_left; (elm)->entry.spe_right = (head)->
sph_root; ((head)->sph_root)->entry.spe_left = ((void *
)0); } else if (__comp > 0) { (elm)->entry.spe_right = (
(head)->sph_root)->entry.spe_right; (elm)->entry.spe_left
= (head)->sph_root; ((head)->sph_root)->entry.spe_right
= ((void *)0); } else return ((head)->sph_root); } (head)
->sph_root = (elm); return (((void *)0)); } struct mta_source
* mta_source_tree_SPLAY_REMOVE(struct mta_source_tree *head,
struct mta_source *elm) { struct mta_source *__tmp; if (((head
)->sph_root == ((void *)0))) return (((void *)0)); mta_source_tree_SPLAY
(head, elm); if ((mta_source_cmp)(elm, (head)->sph_root) ==
0) { if (((head)->sph_root)->entry.spe_left == ((void *
)0)) { (head)->sph_root = ((head)->sph_root)->entry.
spe_right; } else { __tmp = ((head)->sph_root)->entry.spe_right
; (head)->sph_root = ((head)->sph_root)->entry.spe_left
; mta_source_tree_SPLAY(head, elm); ((head)->sph_root)->
entry.spe_right = __tmp; } return (elm); } return (((void *)0
)); } void mta_source_tree_SPLAY(struct mta_source_tree *head
, struct mta_source *elm) { struct mta_source __node, *__left
, *__right, *__tmp; int __comp; (&__node)->entry.spe_left
= (&__node)->entry.spe_right = ((void *)0); __left = __right
= &__node; while ((__comp = (mta_source_cmp)(elm, (head)
->sph_root))) { if (__comp < 0) { __tmp = ((head)->sph_root
)->entry.spe_left; if (__tmp == ((void *)0)) break; if ((mta_source_cmp
)(elm, __tmp) < 0){ do { ((head)->sph_root)->entry.spe_left
= (__tmp)->entry.spe_right; (__tmp)->entry.spe_right =
(head)->sph_root; (head)->sph_root = __tmp; } while (0
); if (((head)->sph_root)->entry.spe_left == ((void *)0
)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if ((mta_source_cmp)(elm, __tmp
) > 0){ do { ((head)->sph_root)->entry.spe_right = (
__tmp)->entry.spe_left; (__tmp)->entry.spe_left = (head
)->sph_root; (head)->sph_root = __tmp; } while (0); if (
((head)->sph_root)->entry.spe_right == ((void *)0)) break
; } do { (__left)->entry.spe_right = (head)->sph_root; __left
= (head)->sph_root; (head)->sph_root = ((head)->sph_root
)->entry.spe_right; } while (0); } } do { (__left)->entry
.spe_right = ((head)->sph_root)->entry.spe_left; (__right
)->entry.spe_left = ((head)->sph_root)->entry.spe_right
; ((head)->sph_root)->entry.spe_left = (&__node)->
entry.spe_right; ((head)->sph_root)->entry.spe_right = (
&__node)->entry.spe_left; } while (0); } void mta_source_tree_SPLAY_MINMAX
(struct mta_source_tree *head, int __comp) { struct mta_source
__node, *__left, *__right, *__tmp; (&__node)->entry.spe_left
= (&__node)->entry.spe_right = ((void *)0); __left = __right
= &__node; while (1) { if (__comp < 0) { __tmp = ((head
)->sph_root)->entry.spe_left; if (__tmp == ((void *)0))
break; if (__comp < 0){ do { ((head)->sph_root)->entry
.spe_left = (__tmp)->entry.spe_right; (__tmp)->entry.spe_right
= (head)->sph_root; (head)->sph_root = __tmp; } while (
0); if (((head)->sph_root)->entry.spe_left == ((void *)
0)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if (__comp > 0) { do { (
(head)->sph_root)->entry.spe_right = (__tmp)->entry.
spe_left; (__tmp)->entry.spe_left = (head)->sph_root; (
head)->sph_root = __tmp; } while (0); if (((head)->sph_root
)->entry.spe_right == ((void *)0)) break; } do { (__left)->
entry.spe_right = (head)->sph_root; __left = (head)->sph_root
; (head)->sph_root = ((head)->sph_root)->entry.spe_right
; } while (0); } } do { (__left)->entry.spe_right = ((head
)->sph_root)->entry.spe_left; (__right)->entry.spe_left
= ((head)->sph_root)->entry.spe_right; ((head)->sph_root
)->entry.spe_left = (&__node)->entry.spe_right; ((head
)->sph_root)->entry.spe_right = (&__node)->entry
.spe_left; } while (0); }
;
2376
2377static struct mta_connector *
2378mta_connector(struct mta_relay *relay, struct mta_source *source)
2379{
2380 struct mta_connector *c;
2381
2382 c = tree_get(&relay->connectors, (uintptr_t)(source));
2383 if (c == NULL((void *)0)) {
2384 c = xcalloc(1, sizeof(*c));
2385 c->relay = relay;
2386 c->source = source;
2387 c->flags |= CONNECTOR_NEW0x10000;
2388 mta_source_ref(source);
2389 tree_xset(&relay->connectors, (uintptr_t)(source), c);
2390 stat_increment("mta.connector", 1);
2391 log_debug("debug: mta: new %s", mta_connector_to_text(c));
2392 }
2393
2394 return (c);
2395}
2396
2397static void
2398mta_connector_free(struct mta_connector *c)
2399{
2400 log_debug("debug: mta: freeing %s",
2401 mta_connector_to_text(c));
2402
2403 if (c->flags & CONNECTOR_WAIT0x20000) {
2404 log_debug("debug: mta: cancelling timeout for %s",
2405 mta_connector_to_text(c));
2406 runq_cancel(runq_connector, c);
2407 }
2408 mta_source_unref(c->source); /* from constructor */
2409 free(c);
2410
2411 stat_decrement("mta.connector", 1);
2412}
2413
2414static const char *
2415mta_connector_to_text(struct mta_connector *c)
2416{
2417 static char buf[1024];
2418
2419 (void)snprintf(buf, sizeof buf, "[connector:%s->%s,0x%x]",
2420 mta_source_to_text(c->source),
2421 mta_relay_to_text(c->relay),
2422 c->flags);
2423 return (buf);
2424}
2425
2426static struct mta_route *
2427mta_route(struct mta_source *src, struct mta_host *dst)
2428{
2429 struct mta_route key, *r;
2430 static uint64_t rid = 0;
2431
2432 key.src = src;
2433 key.dst = dst;
2434 r = SPLAY_FIND(mta_route_tree, &routes, &key)mta_route_tree_SPLAY_FIND(&routes, &key);
2435
2436 if (r == NULL((void *)0)) {
2437 r = xcalloc(1, sizeof(*r));
2438 r->src = src;
2439 r->dst = dst;
2440 r->flags |= ROUTE_NEW0x01;
2441 r->id = ++rid;
2442 SPLAY_INSERT(mta_route_tree, &routes, r)mta_route_tree_SPLAY_INSERT(&routes, r);
2443 mta_source_ref(src);
2444 mta_host_ref(dst);
2445 stat_increment("mta.route", 1);
2446 }
2447 else if (r->flags & ROUTE_RUNQ0x02) {
2448 log_debug("debug: mta: mta_route_ref(): cancelling runq for route %s",
2449 mta_route_to_text(r));
2450 r->flags &= ~(ROUTE_RUNQ0x02 | ROUTE_KEEPALIVE0x04);
2451 runq_cancel(runq_route, r);
2452 r->refcount--; /* from mta_route_unref() */
2453 }
2454
2455 r->refcount++;
2456 return (r);
2457}
2458
2459static void
2460mta_route_ref(struct mta_route *r)
2461{
2462 r->refcount++;
2463}
2464
2465static void
2466mta_route_unref(struct mta_route *r)
2467{
2468 time_t sched, now;
2469 int delay;
2470
2471 if (--r->refcount)
2472 return;
2473
2474 /*
2475 * Nothing references this route, but we might want to keep it alive
2476 * for a while.
2477 */
2478 now = time(NULL((void *)0));
2479 sched = 0;
2480
2481 if (r->penalty) {
2482#if DELAY_QUADRATIC1
2483 delay = DELAY_ROUTE_BASE15 * r->penalty * r->penalty;
2484#else
2485 delay = 15 * 60;
2486#endif
2487 if (delay > DELAY_ROUTE_MAX3600)
2488 delay = DELAY_ROUTE_MAX3600;
2489 sched = r->lastpenalty + delay;
2490 log_debug("debug: mta: mta_route_unref(): keeping route %s alive for %llus (penalty %d)",
2491 mta_route_to_text(r), (unsigned long long) sched - now, r->penalty);
2492 } else if (!(r->flags & ROUTE_KEEPALIVE0x04)) {
2493 if (r->lastconn + max_seen_conndelay_route > now)
2494 sched = r->lastconn + max_seen_conndelay_route;
2495 if (r->lastdisc + max_seen_discdelay_route > now &&
2496 r->lastdisc + max_seen_discdelay_route < sched)
2497 sched = r->lastdisc + max_seen_discdelay_route;
2498
2499 if (sched > now)
2500 log_debug("debug: mta: mta_route_unref(): keeping route %s alive for %llus (imposed delay)",
2501 mta_route_to_text(r), (unsigned long long) sched - now);
2502 }
2503
2504 if (sched > now) {
2505 r->flags |= ROUTE_RUNQ0x02;
2506 runq_schedule_at(runq_route, sched, r);
2507 r->refcount++;
2508 return;
2509 }
2510
2511 log_debug("debug: mta: mta_route_unref(): really discarding route %s",
2512 mta_route_to_text(r));
2513
2514 SPLAY_REMOVE(mta_route_tree, &routes, r)mta_route_tree_SPLAY_REMOVE(&routes, r);
2515 mta_source_unref(r->src); /* from constructor */
2516 mta_host_unref(r->dst); /* from constructor */
2517 free(r);
2518 stat_decrement("mta.route", 1);
2519}
2520
2521static const char *
2522mta_route_to_text(struct mta_route *r)
2523{
2524 static char buf[1024];
2525
2526 (void)snprintf(buf, sizeof buf, "%s <-> %s",
2527 mta_source_to_text(r->src),
2528 mta_host_to_text(r->dst));
2529
2530 return (buf);
2531}
2532
2533static int
2534mta_route_cmp(const struct mta_route *a, const struct mta_route *b)
2535{
2536 if (a->src < b->src)
2537 return (-1);
2538 if (a->src > b->src)
2539 return (1);
2540
2541 if (a->dst < b->dst)
2542 return (-1);
2543 if (a->dst > b->dst)
2544 return (1);
2545
2546 return (0);
2547}
2548
2549SPLAY_GENERATE(mta_route_tree, mta_route, entry, mta_route_cmp)struct mta_route * mta_route_tree_SPLAY_INSERT(struct mta_route_tree
*head, struct mta_route *elm) { if (((head)->sph_root == (
(void *)0))) { (elm)->entry.spe_left = (elm)->entry.spe_right
= ((void *)0); } else { int __comp; mta_route_tree_SPLAY(head
, elm); __comp = (mta_route_cmp)(elm, (head)->sph_root); if
(__comp < 0) { (elm)->entry.spe_left = ((head)->sph_root
)->entry.spe_left; (elm)->entry.spe_right = (head)->
sph_root; ((head)->sph_root)->entry.spe_left = ((void *
)0); } else if (__comp > 0) { (elm)->entry.spe_right = (
(head)->sph_root)->entry.spe_right; (elm)->entry.spe_left
= (head)->sph_root; ((head)->sph_root)->entry.spe_right
= ((void *)0); } else return ((head)->sph_root); } (head)
->sph_root = (elm); return (((void *)0)); } struct mta_route
* mta_route_tree_SPLAY_REMOVE(struct mta_route_tree *head, struct
mta_route *elm) { struct mta_route *__tmp; if (((head)->sph_root
== ((void *)0))) return (((void *)0)); mta_route_tree_SPLAY(
head, elm); if ((mta_route_cmp)(elm, (head)->sph_root) == 0
) { if (((head)->sph_root)->entry.spe_left == ((void *)
0)) { (head)->sph_root = ((head)->sph_root)->entry.spe_right
; } else { __tmp = ((head)->sph_root)->entry.spe_right;
(head)->sph_root = ((head)->sph_root)->entry.spe_left
; mta_route_tree_SPLAY(head, elm); ((head)->sph_root)->
entry.spe_right = __tmp; } return (elm); } return (((void *)0
)); } void mta_route_tree_SPLAY(struct mta_route_tree *head, struct
mta_route *elm) { struct mta_route __node, *__left, *__right
, *__tmp; int __comp; (&__node)->entry.spe_left = (&
__node)->entry.spe_right = ((void *)0); __left = __right =
&__node; while ((__comp = (mta_route_cmp)(elm, (head)->
sph_root))) { if (__comp < 0) { __tmp = ((head)->sph_root
)->entry.spe_left; if (__tmp == ((void *)0)) break; if ((mta_route_cmp
)(elm, __tmp) < 0){ do { ((head)->sph_root)->entry.spe_left
= (__tmp)->entry.spe_right; (__tmp)->entry.spe_right =
(head)->sph_root; (head)->sph_root = __tmp; } while (0
); if (((head)->sph_root)->entry.spe_left == ((void *)0
)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if ((mta_route_cmp)(elm, __tmp
) > 0){ do { ((head)->sph_root)->entry.spe_right = (
__tmp)->entry.spe_left; (__tmp)->entry.spe_left = (head
)->sph_root; (head)->sph_root = __tmp; } while (0); if (
((head)->sph_root)->entry.spe_right == ((void *)0)) break
; } do { (__left)->entry.spe_right = (head)->sph_root; __left
= (head)->sph_root; (head)->sph_root = ((head)->sph_root
)->entry.spe_right; } while (0); } } do { (__left)->entry
.spe_right = ((head)->sph_root)->entry.spe_left; (__right
)->entry.spe_left = ((head)->sph_root)->entry.spe_right
; ((head)->sph_root)->entry.spe_left = (&__node)->
entry.spe_right; ((head)->sph_root)->entry.spe_right = (
&__node)->entry.spe_left; } while (0); } void mta_route_tree_SPLAY_MINMAX
(struct mta_route_tree *head, int __comp) { struct mta_route __node
, *__left, *__right, *__tmp; (&__node)->entry.spe_left
= (&__node)->entry.spe_right = ((void *)0); __left = __right
= &__node; while (1) { if (__comp < 0) { __tmp = ((head
)->sph_root)->entry.spe_left; if (__tmp == ((void *)0))
break; if (__comp < 0){ do { ((head)->sph_root)->entry
.spe_left = (__tmp)->entry.spe_right; (__tmp)->entry.spe_right
= (head)->sph_root; (head)->sph_root = __tmp; } while (
0); if (((head)->sph_root)->entry.spe_left == ((void *)
0)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if (__comp > 0) { do { (
(head)->sph_root)->entry.spe_right = (__tmp)->entry.
spe_left; (__tmp)->entry.spe_left = (head)->sph_root; (
head)->sph_root = __tmp; } while (0); if (((head)->sph_root
)->entry.spe_right == ((void *)0)) break; } do { (__left)->
entry.spe_right = (head)->sph_root; __left = (head)->sph_root
; (head)->sph_root = ((head)->sph_root)->entry.spe_right
; } while (0); } } do { (__left)->entry.spe_right = ((head
)->sph_root)->entry.spe_left; (__right)->entry.spe_left
= ((head)->sph_root)->entry.spe_right; ((head)->sph_root
)->entry.spe_left = (&__node)->entry.spe_right; ((head
)->sph_root)->entry.spe_right = (&__node)->entry
.spe_left; } while (0); }
;
2550
2551void
2552mta_block(struct mta_source *src, char *dom)
2553{
2554 struct mta_block key, *b;
2555
2556 key.source = src;
2557 key.domain = dom;
2558
2559 b = SPLAY_FIND(mta_block_tree, &blocks, &key)mta_block_tree_SPLAY_FIND(&blocks, &key);
2560 if (b != NULL((void *)0))
2561 return;
2562
2563 b = xcalloc(1, sizeof(*b));
2564 if (dom)
2565 b->domain = xstrdup(dom);
2566 b->source = src;
2567 mta_source_ref(src);
2568 SPLAY_INSERT(mta_block_tree, &blocks, b)mta_block_tree_SPLAY_INSERT(&blocks, b);
2569}
2570
2571void
2572mta_unblock(struct mta_source *src, char *dom)
2573{
2574 struct mta_block key, *b;
2575
2576 key.source = src;
2577 key.domain = dom;
2578
2579 b = SPLAY_FIND(mta_block_tree, &blocks, &key)mta_block_tree_SPLAY_FIND(&blocks, &key);
2580 if (b == NULL((void *)0))
2581 return;
2582
2583 SPLAY_REMOVE(mta_block_tree, &blocks, b)mta_block_tree_SPLAY_REMOVE(&blocks, b);
2584
2585 mta_source_unref(b->source);
2586 free(b->domain);
2587 free(b);
2588}
2589
2590int
2591mta_is_blocked(struct mta_source *src, char *dom)
2592{
2593 struct mta_block key;
2594
2595 key.source = src;
2596 key.domain = dom;
2597
2598 if (SPLAY_FIND(mta_block_tree, &blocks, &key)mta_block_tree_SPLAY_FIND(&blocks, &key))
2599 return (1);
2600
2601 return (0);
2602}
2603
2604static
2605int
2606mta_block_cmp(const struct mta_block *a, const struct mta_block *b)
2607{
2608 if (a->source < b->source)
2609 return (-1);
2610 if (a->source > b->source)
2611 return (1);
2612 if (!a->domain && b->domain)
2613 return (-1);
2614 if (a->domain && !b->domain)
2615 return (1);
2616 if (a->domain == b->domain)
2617 return (0);
2618 return (strcasecmp(a->domain, b->domain));
2619}
2620
2621SPLAY_GENERATE(mta_block_tree, mta_block, entry, mta_block_cmp)struct mta_block * mta_block_tree_SPLAY_INSERT(struct mta_block_tree
*head, struct mta_block *elm) { if (((head)->sph_root == (
(void *)0))) { (elm)->entry.spe_left = (elm)->entry.spe_right
= ((void *)0); } else { int __comp; mta_block_tree_SPLAY(head
, elm); __comp = (mta_block_cmp)(elm, (head)->sph_root); if
(__comp < 0) { (elm)->entry.spe_left = ((head)->sph_root
)->entry.spe_left; (elm)->entry.spe_right = (head)->
sph_root; ((head)->sph_root)->entry.spe_left = ((void *
)0); } else if (__comp > 0) { (elm)->entry.spe_right = (
(head)->sph_root)->entry.spe_right; (elm)->entry.spe_left
= (head)->sph_root; ((head)->sph_root)->entry.spe_right
= ((void *)0); } else return ((head)->sph_root); } (head)
->sph_root = (elm); return (((void *)0)); } struct mta_block
* mta_block_tree_SPLAY_REMOVE(struct mta_block_tree *head, struct
mta_block *elm) { struct mta_block *__tmp; if (((head)->sph_root
== ((void *)0))) return (((void *)0)); mta_block_tree_SPLAY(
head, elm); if ((mta_block_cmp)(elm, (head)->sph_root) == 0
) { if (((head)->sph_root)->entry.spe_left == ((void *)
0)) { (head)->sph_root = ((head)->sph_root)->entry.spe_right
; } else { __tmp = ((head)->sph_root)->entry.spe_right;
(head)->sph_root = ((head)->sph_root)->entry.spe_left
; mta_block_tree_SPLAY(head, elm); ((head)->sph_root)->
entry.spe_right = __tmp; } return (elm); } return (((void *)0
)); } void mta_block_tree_SPLAY(struct mta_block_tree *head, struct
mta_block *elm) { struct mta_block __node, *__left, *__right
, *__tmp; int __comp; (&__node)->entry.spe_left = (&
__node)->entry.spe_right = ((void *)0); __left = __right =
&__node; while ((__comp = (mta_block_cmp)(elm, (head)->
sph_root))) { if (__comp < 0) { __tmp = ((head)->sph_root
)->entry.spe_left; if (__tmp == ((void *)0)) break; if ((mta_block_cmp
)(elm, __tmp) < 0){ do { ((head)->sph_root)->entry.spe_left
= (__tmp)->entry.spe_right; (__tmp)->entry.spe_right =
(head)->sph_root; (head)->sph_root = __tmp; } while (0
); if (((head)->sph_root)->entry.spe_left == ((void *)0
)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if ((mta_block_cmp)(elm, __tmp
) > 0){ do { ((head)->sph_root)->entry.spe_right = (
__tmp)->entry.spe_left; (__tmp)->entry.spe_left = (head
)->sph_root; (head)->sph_root = __tmp; } while (0); if (
((head)->sph_root)->entry.spe_right == ((void *)0)) break
; } do { (__left)->entry.spe_right = (head)->sph_root; __left
= (head)->sph_root; (head)->sph_root = ((head)->sph_root
)->entry.spe_right; } while (0); } } do { (__left)->entry
.spe_right = ((head)->sph_root)->entry.spe_left; (__right
)->entry.spe_left = ((head)->sph_root)->entry.spe_right
; ((head)->sph_root)->entry.spe_left = (&__node)->
entry.spe_right; ((head)->sph_root)->entry.spe_right = (
&__node)->entry.spe_left; } while (0); } void mta_block_tree_SPLAY_MINMAX
(struct mta_block_tree *head, int __comp) { struct mta_block __node
, *__left, *__right, *__tmp; (&__node)->entry.spe_left
= (&__node)->entry.spe_right = ((void *)0); __left = __right
= &__node; while (1) { if (__comp < 0) { __tmp = ((head
)->sph_root)->entry.spe_left; if (__tmp == ((void *)0))
break; if (__comp < 0){ do { ((head)->sph_root)->entry
.spe_left = (__tmp)->entry.spe_right; (__tmp)->entry.spe_right
= (head)->sph_root; (head)->sph_root = __tmp; } while (
0); if (((head)->sph_root)->entry.spe_left == ((void *)
0)) break; } do { (__right)->entry.spe_left = (head)->sph_root
; __right = (head)->sph_root; (head)->sph_root = ((head
)->sph_root)->entry.spe_left; } while (0); } else if (__comp
> 0) { __tmp = ((head)->sph_root)->entry.spe_right;
if (__tmp == ((void *)0)) break; if (__comp > 0) { do { (
(head)->sph_root)->entry.spe_right = (__tmp)->entry.
spe_left; (__tmp)->entry.spe_left = (head)->sph_root; (
head)->sph_root = __tmp; } while (0); if (((head)->sph_root
)->entry.spe_right == ((void *)0)) break; } do { (__left)->
entry.spe_right = (head)->sph_root; __left = (head)->sph_root
; (head)->sph_root = ((head)->sph_root)->entry.spe_right
; } while (0); } } do { (__left)->entry.spe_right = ((head
)->sph_root)->entry.spe_left; (__right)->entry.spe_left
= ((head)->sph_root)->entry.spe_right; ((head)->sph_root
)->entry.spe_left = (&__node)->entry.spe_right; ((head
)->sph_root)->entry.spe_right = (&__node)->entry
.spe_left; } while (0); }
;
2622
2623
2624
2625/* hoststat errors are not critical, we do best effort */
2626void
2627mta_hoststat_update(const char *host, const char *error)
2628{
2629 struct hoststat *hs = NULL((void *)0);
2630 char buf[HOST_NAME_MAX255+1];
2631
2632 if (!lowercase(buf, host, sizeof buf))
2633 return;
2634
2635 hs = dict_get(&hoststat, buf);
2636 if (hs == NULL((void *)0)) {
2637 if ((hs = calloc(1, sizeof *hs)) == NULL((void *)0))
2638 return;
2639 tree_init(&hs->deferred)do { do { (&((&hs->deferred)->tree))->sph_root
= ((void *)0); } while (0); (&hs->deferred)->count
= 0; } while(0)
;
2640 runq_schedule(runq_hoststat, HOSTSTAT_EXPIRE_DELAY(4 * 3600), hs);
2641 }
2642 (void)strlcpy(hs->name, buf, sizeof hs->name);
2643 (void)strlcpy(hs->error, error, sizeof hs->error);
2644 hs->tm = time(NULL((void *)0));
2645 dict_set(&hoststat, buf, hs);
2646
2647 runq_cancel(runq_hoststat, hs);
2648 runq_schedule(runq_hoststat, HOSTSTAT_EXPIRE_DELAY(4 * 3600), hs);
2649}
2650
2651void
2652mta_hoststat_cache(const char *host, uint64_t evpid)
2653{
2654 struct hoststat *hs = NULL((void *)0);
2655 char buf[HOST_NAME_MAX255+1];
2656
2657 if (!lowercase(buf, host, sizeof buf))
2658 return;
2659
2660 hs = dict_get(&hoststat, buf);
2661 if (hs == NULL((void *)0))
2662 return;
2663
2664 if (tree_count(&hs->deferred)((&hs->deferred)->count) >= env->sc_mta_max_deferred)
2665 return;
2666
2667 tree_set(&hs->deferred, evpid, NULL((void *)0));
2668}
2669
2670void
2671mta_hoststat_uncache(const char *host, uint64_t evpid)
2672{
2673 struct hoststat *hs = NULL((void *)0);
2674 char buf[HOST_NAME_MAX255+1];
2675
2676 if (!lowercase(buf, host, sizeof buf))
2677 return;
2678
2679 hs = dict_get(&hoststat, buf);
2680 if (hs == NULL((void *)0))
2681 return;
2682
2683 tree_pop(&hs->deferred, evpid);
2684}
2685
2686void
2687mta_hoststat_reschedule(const char *host)
2688{
2689 struct hoststat *hs = NULL((void *)0);
2690 char buf[HOST_NAME_MAX255+1];
2691 uint64_t evpid;
2692
2693 if (!lowercase(buf, host, sizeof buf))
2694 return;
2695
2696 hs = dict_get(&hoststat, buf);
2697 if (hs == NULL((void *)0))
2698 return;
2699
2700 while (tree_poproot(&hs->deferred, &evpid, NULL((void *)0))) {
2701 m_compose(p_queue, IMSG_MTA_SCHEDULE, 0, 0, -1,
2702 &evpid, sizeof evpid);
2703 }
2704}
2705
2706static void
2707mta_hoststat_remove_entry(struct hoststat *hs)
2708{
2709 while (tree_poproot(&hs->deferred, NULL((void *)0), NULL((void *)0)))
2710 ;
2711 dict_pop(&hoststat, hs->name);
2712 runq_cancel(runq_hoststat, hs);
2713}