Example #1
0
/*
 * Sendmail wants to establish a connection to us
 */
static sfsistat
blacklist_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
{
	const char *remoteIP;
	struct privdata *privdata;
	time_t now;
	int i;
	struct bip *bip;
	char ip[INET_ADDRSTRLEN];	/* IPv4 only */

	if(hostname == NULL) {
		syslog(LOG_ERR, "blacklist_connect: hostname is null");
		return SMFIS_CONTINUE;
	}
	if((hostaddr == NULL) || (&(((struct sockaddr_in *)(hostaddr))->sin_addr) == NULL))
		/*
		 * According to the sendmail API hostaddr is NULL if
		 * "the type is not supported in the current version". What
		 * the documentation doesn't say is the type of what.
		 *
		 * Possibly the input is not a TCP/IP socket e.g. stdin?
		 */
		return SMFIS_ACCEPT;

	remoteIP = inet_ntop(AF_INET, &((struct sockaddr_in *)(hostaddr))->sin_addr, ip, sizeof(ip));

#ifdef	DEBUG
	printf("blacklist_milter: connection from %s\n", remoteIP);
#endif
	syslog(LOG_INFO, "blacklist_milter: connection from %s", remoteIP);

	if(remoteIP == NULL) {
#ifdef	DEBUG
		puts("blacklist_connect: remoteIP is null");
#endif
		syslog(LOG_ERR, "blacklist_connect: remoteIP is null");
		return SMFIS_CONTINUE;
	}
	if(strcmp(remoteIP, "127.0.0.1") == 0) {
		/*syslog(LOG_DEBUG, "blacklist_connect: not scanning outgoing messages");*/
#ifdef	DEBUG
		puts("blacklist_connect: not scanning outgoing messages");
#endif
		return SMFIS_ACCEPT;
	}
	if(isLocalAddr(inet_addr(remoteIP))) {
#ifdef	DEBUG
		puts("blacklist_connect: not scanning local messages");
#endif
		/*syslog(LOG_DEBUG, "blacklist_connect: not scanning local messages");*/
		return SMFIS_ACCEPT;
	}
	if(isWhiteList(remoteIP)) {
		/*syslog(LOG_DEBUG, "blacklist_connect: not scanning %s", remoteIP);*/
#ifdef	DEBUG
		printf("blacklist_connect: not scanning %s\n", remoteIP);
#endif
		return SMFIS_ACCEPT;
	}
	for(i = 0, bip = bips; i < NBLACKLISTED; i++, bip++)
		if(strcmp(bip->ip, remoteIP) == 0) {
			now = time((time_t *)0);

			if((now - bip->time) < TIMEOUT) {
				syslog(LOG_NOTICE, "Rejected connexion from blacklisted IP %s for %s\n", remoteIP, bip->reason);
				thread_sleep(2);	/* waste their time */
				smfi_setreply(ctx, "550", "5.7.1", "Your IP is blacklisted because you are sending spam");
				bip->time = now;
				return SMFIS_REJECT;
			} else
				/* timeout */
				bip->ip[0] = '\0';
			break;
		}

	privdata = (struct privdata *)calloc(1, sizeof(struct privdata));
	smfi_setpriv(ctx, privdata);
	strcpy(privdata->ip, remoteIP);

	return SMFIS_CONTINUE;
}
Example #2
0
int 
spamdscan(SMFICTX *ctx, struct mlfi_priv *priv, struct config_file *cfg, char **subject, int extra)
{
	int retry, r = -2, hr = 0, to_trace = 0;
	struct timeval t;
	double ts, tf;
	struct spamd_server *selected = NULL;
	char rbuf[BUFSIZ], hdrbuf[BUFSIZ];
	char *prefix = "s", *mid = NULL, *c;
	rspamd_result_t res;
	struct rspamd_metric_result *cur = NULL, *tmp;
	struct rspamd_symbol *cur_symbol, *tmp_symbol;
	enum rspamd_metric_action res_action = METRIC_ACTION_NOACTION;
	struct timespec sleep_ts;
	

	gettimeofday(&t, NULL);
	ts = t.tv_sec + t.tv_usec / 1000000.0;
	retry = cfg->spamd_retry_count;
	sleep_ts.tv_sec = cfg->spamd_retry_timeout / 1000;
	sleep_ts.tv_nsec = (cfg->spamd_retry_timeout % 1000) * 1000000ULL;

	TAILQ_INIT(&res);

	/* try to scan with available servers */
	while (1) {
		if (extra) {
			selected = (struct spamd_server *) get_random_upstream ((void *)cfg->extra_spamd_servers,
					cfg->extra_spamd_servers_num, sizeof (struct spamd_server),
					t.tv_sec, cfg->spamd_error_time, cfg->spamd_dead_time, cfg->spamd_maxerrors);
		}
		else {
			selected = (struct spamd_server *) get_random_upstream ((void *)cfg->spamd_servers,
					cfg->spamd_servers_num, sizeof (struct spamd_server),
					t.tv_sec, cfg->spamd_error_time, cfg->spamd_dead_time, cfg->spamd_maxerrors);
		}
		if (selected == NULL) {
			msg_err ("spamdscan: upstream get error, %s", priv->file);
			return -1;
		}
		
		if (selected->type == SPAMD_SPAMASSASSIN) {
			prefix = "s";
			r = spamdscan_socket (priv->file, selected, cfg, &res);
		}
		else {
			prefix = "rs";
			r = rspamdscan_socket (ctx, priv, selected, cfg, &res, &mid);
		}
		if (r == 0 || r == 1) {
			upstream_ok (&selected->up, t.tv_sec);
			break;
		}
		upstream_fail (&selected->up, t.tv_sec);
		if (r == -2) {
			msg_warn("%spamdscan: unexpected problem, %s, %s", prefix, selected->name, priv->file);
			break;
		}
		if (--retry < 1) {
			msg_warn("%spamdscan: retry limit exceeded, %s, %s", prefix, selected->name, priv->file);
			break;
		}

		msg_warn("%spamdscan: failed to scan, retry, %s, %s", prefix, selected->name, priv->file);
		nanosleep (&sleep_ts, NULL);
	}

	/*
	 * print scanning time, server and result
	 */
	gettimeofday(&t, NULL);
	tf = t.tv_sec + t.tv_usec / 1000000.0;
	
	/* Parse res tailq */
	cur = TAILQ_FIRST(&res);
	while (cur) {
		if (cur->metric_name) {
			if (cfg->extended_spam_headers) {
				hr = snprintf (hdrbuf, sizeof (hdrbuf), "%s: %s [%.2f / %.2f]%c",
						cur->metric_name,
						cur->score > cur->required_score ? "True" : "False",
						cur->score,
						cur->required_score,
						TAILQ_FIRST(&cur->symbols) != NULL ? '\n' : ' ');
			}
			r = snprintf (rbuf, sizeof (rbuf), "spamdscan: scan qid: <%s>, mid: <%s>, %f, %s, metric: %s: [%f / %f], symbols: ",
					priv->mlfi_id,
					(mid != NULL) ? mid : "undef",
					tf - ts,
					selected->name,
					cur->metric_name,
					cur->score,
					cur->required_score);
			free (cur->metric_name);
		}
		else {
			if (cfg->extended_spam_headers) {
				hr = snprintf (hdrbuf, sizeof (hdrbuf), "%s: %s [%.2f / %.2f]%c",
						"default",
						cur->score > cur->required_score ? "True" : "False",
						cur->score,
						cur->required_score,
						TAILQ_FIRST(&cur->symbols) != NULL ? '\n' : ' ');
			}
			r = snprintf (rbuf, sizeof (rbuf), "spamdscan: scan <%s>, %f, %s, metric: default: [%f / %f], symbols: ",
					priv->mlfi_id,
					tf - ts,
					selected->name,
					cur->score,
					cur->required_score);
		
		}
		if (cur->action > res_action) {
			res_action = cur->action;
			if (res_action == METRIC_ACTION_REWRITE_SUBJECT && cur->subject != NULL) {
				/* Copy subject as it would be freed further */
				if (*subject != NULL) {
					free (*subject);
				}
				*subject = strdup (cur->subject);
			}
		}
		/* Write symbols */
		cur_symbol = TAILQ_FIRST(&cur->symbols);
		if (cur_symbol == NULL) {
			r += snprintf (rbuf + r, sizeof (rbuf) - r, "no symbols");
		}
		else {
			while (cur_symbol) {
				if (cur_symbol->symbol) {
					if (TAILQ_NEXT (cur_symbol, entry)) {
						r += snprintf (rbuf + r, sizeof (rbuf) - r, "%s, ", cur_symbol->symbol);
					}
					else {
						r += snprintf (rbuf + r, sizeof (rbuf) - r, "%s", cur_symbol->symbol);
					}
					if (cfg->trace_symbol) {
						c = strchr (cur_symbol->symbol, '(');
						if (c != NULL) {
							*c = '\0';
						}
						if ( !strcmp (cfg->trace_symbol, cur_symbol->symbol)) {
							to_trace ++;
						}
					}
					if (cfg->extended_spam_headers) {
						if (TAILQ_NEXT (cur_symbol, entry)) {
							hr += snprintf (hdrbuf + hr, sizeof (hdrbuf) - hr, " %s\n",
									cur_symbol->symbol);
						}
						else {
							hr += snprintf (hdrbuf + hr, sizeof (hdrbuf) - hr, " %s",
									cur_symbol->symbol);
						}
					}
					free (cur_symbol->symbol);
				}
				tmp_symbol = cur_symbol;
				cur_symbol = TAILQ_NEXT(cur_symbol, entry);
				free (tmp_symbol);
			}
		}
		msg_info ("%s", rbuf);
		if (cur->subject != NULL) {
			free (cur->subject);
		}

		tmp = cur;
		cur = TAILQ_NEXT(cur, entry);

		free (tmp);
		if (cfg->extended_spam_headers) {
			if (extra) {
				smfi_addheader (ctx, "X-Spamd-Extra-Result", hdrbuf);
			}
			else {
				smfi_addheader (ctx, "X-Spamd-Result", hdrbuf);
			}
		}
	}
	/* All other statistic headers */
	if (cfg->extended_spam_headers) {
		if (extra) {
			smfi_addheader (ctx, "X-Spamd-Extra-Server", selected->name);
			snprintf (hdrbuf, sizeof (hdrbuf), "%.2f", tf - ts);
			smfi_addheader (ctx, "X-Spamd-Extra-Scan-Time", hdrbuf);
		}
		else {
			smfi_addheader (ctx, "X-Spamd-Server", selected->name);
			snprintf (hdrbuf, sizeof (hdrbuf), "%.2f", tf - ts);
			smfi_addheader (ctx, "X-Spamd-Scan-Time", hdrbuf);
			smfi_addheader (ctx, "X-Spamd-Queue-ID", priv->mlfi_id);
		}
	}
	/* Trace spam messages to specific addr */
	if (!extra && to_trace && cfg->trace_addr) {
		smfi_addrcpt (ctx, cfg->trace_addr);
		smfi_setpriv (ctx, priv);
	}


	return (r > 0 ? res_action : r);
}