Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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