ze-filter  (ze-filter-0.8.0-develop-180218)
ze-mxcheck.c
Go to the documentation of this file.
1  /*
2  *
3  * ze-filter - Mail Server Filter for sendmail
4  *
5  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
6  *
7  * Auteur : Jose Marcio Martins da Cruz
8  * jose.marcio.mc@gmail.org
9  *
10  * Historique :
11  * Creation : Thu Oct 27 13:42:06 CEST 2005
12  *
13  * This program is free software, but with restricted license :
14  *
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * More details about ze-filter license can be found at ze-filter
21  * web site : http://foss.jose-marcio.org
22  */
23 
24 
25 #include <ze-sys.h>
26 #include <libze.h>
27 #include <ze-filter.h>
28 #include <ze-filter-data.h>
29 #include <ze-mxcheck.h>
30 
31 
32 /* ****************************************************************************
33  * *
34  * *
35  ******************************************************************************/
36 #define SZ_NAME 64
37 
38 typedef struct MX_T {
39  char domain[SZ_NAME];
40  char mx[SZ_NAME];
41  time_t last_update;
42  time_t last_query;
43 } MX__T;
44 
45 static struct {
46  bool ok;
47  time_t last;
48  int nb;
49 
50  pthread_mutex_t mutex;
51 
53 } hdata = {
54 FALSE, (time_t) 0, 0, PTHREAD_MUTEX_INITIALIZER, JBT_INITIALIZER};
55 
56 #define MX_OK(x) (strcasecmp(x, "OK") == 0)
57 
58 
59 /* ****************************************************************************
60  * *
61  * *
62  ******************************************************************************/
63 #define MSG_BAD_MX(a,b) \
64  do { \
65  ZE_MessageInfo(9, "%s BAD MXs for domain %s : %s (%s)", \
66  CONNID_STR(priv->id), a, b, priv->peer_addr); \
67  } while (0)
68 
70 
71 int
72 check_sender_mx(ctx, mail_host)
73  SMFICTX *ctx;
74  char *mail_host;
75 {
76  CTXPRIV_T *priv = MLFIPRIV(ctx);
77  int ip_class = (priv != NULL ? priv->netclass.class : 0);
78  int result = SMFIS_UNDEF;
79 
80  timems_T ti, tf;
81 
82  ti = tf = 0;
83 
84  if (mail_host == NULL || strlen(mail_host) == 0)
85  return SMFIS_CONTINUE;
86  ZE_MessageInfo(11, "%s Checking MXs for domain %s", CONNID_STR(priv->id),
87  mail_host);
88 
89  if (IS_KNOWN(ip_class))
90  goto fin;
91 
92  if (mx_check_level < 0) {
93  char *env;
94 
95  if ((env = getenv("MXCHECKLEVEL")) != NULL) {
96  int i;
97 
98  i = zeStr2long(env, NULL, 1);
99  if (errno == 0 && i < 100)
100  mx_check_level = i;
101  }
102 
103  if (mx_check_level < 0)
104  mx_check_level = 1;
105  }
106 
107  if (!((mx_check_level > 1) || IS_UNKNOWN(ip_class)))
108  goto fin;
109 
110 #if _FFR_USE_MX_CACHE
111  /*
112  * Let's check if this guy is already in cache...
113  */
114  {
115  char buf[256];
116 
117  if (res_cache_check("mx", mail_host, buf, sizeof (buf))) {
118 
119  }
120  }
121 #endif /* _FFR_USE_MX_CACHE */
122 
123  ti = zeTime_ms();
124 
125  {
127  int i;
128  int res = 0;
129  int nchk = 0;
130  char buf[256];
131  smtp_reply_T r;
132 
133  if (check_policy("BadMX", mail_host, buf, sizeof (buf), FALSE)) {
134  if (!MX_OK(buf)) {
135  MSG_BAD_MX(mail_host, mail_host);
136 
137  jc_string2reply(&r, buf);
138  (void) jsmfi_setreply(ctx, r.rcode, r.xcode, r.msg);
139  result = r.result;
140  } else
141  result = SMFIS_CONTINUE;
142  }
143 
144  if (result != SMFIS_UNDEF)
145  goto fin;
146 
147  memset(&mx, 0, sizeof (mx));
148  res = dns_get_mx(mail_host, &mx);
149 
150  /*
151  * some MXs found : let's check them
152  */
153  if (res > 0) {
154  for (i = 0; i < mx.count; i++) {
155  nchk++;
156 
157  ZE_MessageInfo(11, "%s -> MX %3d %-16s %s\n",
158  CONNID_STR(priv->id),
159  mx.host[i].pref,
160  STRNULL(mx.host[i].ip, ""), STRNULL(mx.host[i].name,
161  ""));
162 
163  memset(buf, 0, sizeof (buf));
164  if (check_policy("BadMX", mx.host[i].ip, buf, sizeof (buf), FALSE)) {
165  if (!MX_OK(buf)) {
166  MSG_BAD_MX(mail_host, mx.host[i].ip);
167 
168  /*
169  * Found at database - let's decode
170  */
171  jc_string2reply(&r, buf);
172  (void) jsmfi_setreply(ctx, r.rcode, r.xcode, r.msg);
173  result = r.result;
174  } else
175  result = SMFIS_CONTINUE;
176  break;
177  }
178  if (check_policy("BadMX", mx.host[i].name, buf, sizeof (buf), FALSE)) {
179  if (!MX_OK(buf)) {
180  MSG_BAD_MX(mail_host, mx.host[i].name);
181 
182  /*
183  * Found at database - let's decode
184  */
185  jc_string2reply(&r, buf);
186  (void) jsmfi_setreply(ctx, r.rcode, r.xcode, r.msg);
187  result = r.result;
188  } else
189  result = SMFIS_CONTINUE;
190  break;
191  }
192  }
193  }
194  dns_free_hostarr(&mx);
195 
196  if (result != SMFIS_UNDEF)
197  goto fin;
198 
199  /*
200  * No MX found - let's look for IP address associated to the domain part
201  */
202  if (nchk == 0) {
203  memset(&mx, 0, sizeof (mx));
204  res = dns_get_a(mail_host, &mx);
205  if (res > 0) {
206  for (i = 0; i < mx.count; i++) {
207  nchk++;
208 
209  ZE_MessageInfo(11, "%s -> A %3d %-16s %s\n",
210  CONNID_STR(priv->id),
211  mx.host[i].pref,
212  STRNULL(mx.host[i].ip, ""), STRNULL(mx.host[i].name,
213  ""));
214 
215  memset(buf, 0, sizeof (buf));
216  if (check_policy("BadMX", mx.host[i].ip, buf, sizeof (buf), FALSE)) {
217  if (!MX_OK(buf)) {
218  MSG_BAD_MX(mail_host, mx.host[i].ip);
219 
220  /*
221  * Found at database - let's decode
222  */
223  jc_string2reply(&r, buf);
224  (void) jsmfi_setreply(ctx, r.rcode, r.xcode, r.msg);
225  result = r.result;
226  } else
227  result = SMFIS_CONTINUE;
228  break;
229  }
230  }
231  }
232  dns_free_hostarr(&mx);
233 
234  if (result != SMFIS_UNDEF)
235  goto fin;
236 
237  /*
238  * NO IP associated with this domain name ???
239  */
240  if (nchk == 0) {
241  char *reply = NULL;
242 
243  ZE_MessageInfo(10, "%s Domain %s doesn't resolve", CONNID_STR(priv->id),
244  mail_host);
245 
247  if (reply == NULL || strlen(reply) == 0)
248  reply = "ERROR:421:4.5.1:DNS problems... Try later !";
249 
250  strlcpy(buf, reply, sizeof (buf));
251 
252  if (jc_string2reply(&r, buf) != SMFIS_CONTINUE) {
253  (void) jsmfi_setreply(ctx, r.rcode, r.xcode, r.msg);
254  result = r.result;
255  }
256  }
257 
258  if (res < 0) {
259  }
260  }
261  }
262 
263 fin:
264  if (result == SMFIS_UNDEF)
265  result = SMFIS_CONTINUE;
266 
267  tf = zeTime_ms();
268  if (ti != 0 && tf > ti) {
269  static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
270  static kstats_T st = KSTATS_INITIALIZER;
271  static int ns = 0;
272 
273  double dt;
274 
275  MUTEX_LOCK(&mutex);
276 
277  dt = (double) (tf - ti);
278 
279  zeKStatsUpdate(&st, dt);
280 
281  if ((++ns % 1000) == 0) {
282  ZE_MessageInfo(10,
283  "MX CHECK delay : nb=%d min=%5.3f mean=%5.3f max=%5.3f stddev=%5.3f ",
284  ns, zeKMin(&st), zeKMean(&st), zeKMax(&st), zeKStdDev(&st));
285  zeKStatsReset(&st);
286  ns = 0;
287  }
288 
289  /*
290  * add to resolve cache map
291  */
292  if (dt >= 1000 || result != SMFIS_CONTINUE) {
293 #if _FFR_USE_MX_CACHE
294  /*
295  * don't know what exactly add to the map...
296  */
297  res_cache_add("mx", mail_host, "xxx");
298 #endif /* _FFR_USE_MX_CACHE */
299  }
300 
301  MUTEX_UNLOCK(&mutex);
302  }
303 
304  if (result != SMFIS_CONTINUE) {
305  char logbuf[256];
306 
307  priv->rej_badmx++;
308  stats_inc(STAT_BADMX, 1);
309  snprintf(logbuf, sizeof (logbuf), "%s %s", "BAD MX -> ", mail_host);
310 
311  log_msg_context(ctx, logbuf);
312  }
313 
314  return result;
315 }
void dns_free_hostarr(DNS_HOSTARR_T *mx)
Definition: ze-dns-parse.c:89
void stats_inc(int, long)
Definition: ze-stats.c:401
bool check_policy(char *prefix, char *key, char *buf, size_t size, bool cdef)
Definition: ze-policy.c:119
bool ok
Definition: ze-mxcheck.c:46
time_t last_query
Definition: ze-mxcheck.c:42
int jsmfi_setreply(SMFICTX *, char *, char *, char *)
Definition: ze-libmilter.c:99
char domain[SZ_NAME]
Definition: ze-mxcheck.c:39
int nb
Definition: ze-mxcheck.c:48
#define JBT_INITIALIZER
Definition: zeBTree.h:85
#define MUTEX_UNLOCK(mutex)
Definition: macros.h:101
uint64_t zeTime_ms()
Definition: zeTime.c:34
#define STRNULL(x, r)
Definition: macros.h:81
ZEBT_T db_open
Definition: ze-mxcheck.c:52
int dns_get_mx(char *domain, DNS_HOSTARR_T *mx)
Definition: ze-dns-parse.c:357
#define MUTEX_LOCK(mutex)
Definition: macros.h:93
void zeKStatsReset(kstats_T *)
Definition: zeKStats.c:92
double zeKMin(kstats_T *s)
Definition: zeKStats.c:62
#define FALSE
Definition: macros.h:160
#define SMFIS_CONTINUE
#define strlcpy
Definition: zeString.h:32
time_t last
Definition: ze-mxcheck.c:47
#define MLFIPRIV(ctx)
#define CF_DEFAULT_BAD_MX_REPLY
Definition: cfh-defs.h:175
int mx_check_level
Definition: ze-mxcheck.c:69
CONNID_T id
long zeStr2long(char *s, int *error, long dval)
Definition: zeStrConvert.c:35
#define IS_KNOWN(class)
Definition: ze-netclass.h:50
void zeKStatsUpdate(kstats_T *, double)
Definition: zeKStats.c:101
struct MX_T MX__T
#define IS_UNKNOWN(class)
Definition: ze-netclass.h:51
DNS_HOST_T host[MAX_HOST]
Definition: ze-dns-parse.h:46
char mx[SZ_NAME]
Definition: ze-mxcheck.c:40
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
#define SZ_NAME
Definition: ze-mxcheck.c:36
#define MX_OK(x)
Definition: ze-mxcheck.c:56
#define KSTATS_INITIALIZER
Definition: zeKStats.h:36
char * cf_get_str(int id)
Definition: ze-cf.c:854
char * name
Definition: ze-dns-parse.h:39
#define SMFIS_UNDEF
Definition: ze-libmilter.h:28
char msg[256]
#define MSG_BAD_MX(a, b)
Definition: ze-mxcheck.c:63
int dns_get_a(char *domain, DNS_HOSTARR_T *a)
Definition: ze-dns-parse.c:153
#define CONNID_STR(connid)
Definition: ze-filter.h:113
char * ip
Definition: ze-dns-parse.h:38
double zeKMean(kstats_T *s)
Definition: zeKStats.c:43
int check_sender_mx(SMFICTX *ctx, char *mail_host)
Definition: ze-mxcheck.c:72
netclass_T netclass
double zeKMax(kstats_T *s)
Definition: zeKStats.c:72
double zeKStdDev(kstats_T *s)
Definition: zeKStats.c:53
void log_msg_context(SMFICTX *ctx, char *why)
#define STAT_BADMX
Definition: ze-stats.h:78
pthread_mutex_t mutex
Definition: ze-mxcheck.c:50
int jc_string2reply(smtp_reply_T *, char *)
uint64_t timems_T
Definition: zeTime.h:32
Definition: zeBTree.h:73
time_t last_update
Definition: ze-mxcheck.c:41