⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 greylist.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include "common.h"#include "smtpd.h"#include "smtp.h"#include <ctype.h>#include <ip.h>#include <ndb.h>typedef struct {	int	existed;	/* these two are distinct to cope with errors */	int	created;	int	noperm;	long	mtime;		/* mod time, iff it already existed */} Greysts;/* * There's a bit of a problem with yahoo; they apparently have a vast * pool of machines that all run the same queue(s), so a 451 retry can * come from a different IP address for many, many retries, and it can * take ~5 hours for the same IP to call us back.  Various other goofballs, * notably the IEEE, try to send mail just before 9 AM, then refuse to try * again until after 5 PM.  Doh! */enum {	Nonspammax = 14*60*60,  /* must call back within this time if real */};static char whitelist[] = "/mail/grey/whitelist";/* * matches ip addresses or subnets in whitelist against nci->rsys. * ignores comments and blank lines in /mail/grey/whitelist. */static intonwhitelist(void){	int lnlen;	char *line, *parse, *p;	char input[128];	uchar ip[IPaddrlen], ipmasked[IPaddrlen];	uchar mask4[IPaddrlen], addr4[IPaddrlen];	uchar mask[IPaddrlen], addr[IPaddrlen], addrmasked[IPaddrlen];	Biobuf *wl;	static int beenhere;	static allzero[IPaddrlen];	if (!beenhere) {		beenhere = 1;		fmtinstall('I', eipfmt);	}	parseip(ip, nci->rsys);	wl = Bopen(whitelist, OREAD);	if (wl == nil)		return 1;	while ((line = Brdline(wl, '\n')) != nil) {		lnlen = Blinelen(wl);		line[lnlen-1] = '\0';		/* clobber newline */		p = strpbrk(line, " \t");		if (p)			*p = 0;		if (line[0] == '#' || line[0] == 0)			continue;				/* default mask is /32 (v4) or /128 (v6) for bare IP */		parse = line;		if (strchr(line, '/') == nil) {			strecpy(input, input+sizeof input-5, line);			if (strchr(line, '.') != nil)				strcat(input, "/32");			else				strcat(input, "/128");			parse = input;		}		/* sorry, dave; where's parsecidr for v4 or v6? */		v4parsecidr(addr4, mask4, parse);		v4tov6(addr, addr4);		v4tov6(mask, mask4);		maskip(addr, mask, addrmasked);		maskip(ip, mask, ipmasked);		if (memcmp(ipmasked, addrmasked, IPaddrlen) == 0)			break;	}	Bterm(wl);	return line != nil;}static int mkdirs(char *);/* * if any directories leading up to path don't exist, create them. * modifies but restores path. */static intmkpdirs(char *path){	int rv = 0;	char *sl = strrchr(path, '/');	if (sl != nil) {		*sl = '\0';		rv = mkdirs(path);		*sl = '/';	}	return rv;}/* * if path or any directories leading up to it don't exist, create them. * modifies but restores path. */static intmkdirs(char *path){	int fd;	if (access(path, AEXIST) >= 0)		return 0;	/* make presumed-missing intermediate directories */	if (mkpdirs(path) < 0)		return -1;	/* make final directory */	fd = create(path, OREAD, 0777|DMDIR);	if (fd < 0)		/*		 * we may have lost a race; if the directory now exists,		 * it's okay.		 */		return access(path, AEXIST) < 0? -1: 0;	close(fd);	return 0;}static longgetmtime(char *file){	long mtime = -1;	Dir *ds = dirstat(file);	if (ds != nil) {		mtime = ds->mtime;		free(ds);	}	return mtime;}static voidtryaddgrey(char *file, Greysts *gsp){	int fd = create(file, OWRITE|OEXCL, 0444|DMEXCL);	gsp->created = (fd >= 0);	if (fd >= 0) {		close(fd);		gsp->existed = 0;  /* just created; couldn't have existed */	} else {		/*		 * why couldn't we create file? it must have existed		 * (or we were denied perm on parent dir.).		 * if it existed, fill in gsp->mtime; otherwise		 * make presumed-missing intermediate directories.		 */		gsp->existed = access(file, AEXIST) >= 0;		if (gsp->existed)			gsp->mtime = getmtime(file);		else if (mkpdirs(file) < 0)			gsp->noperm = 1;	}}static voidaddgreylist(char *file, Greysts *gsp){	tryaddgrey(file, gsp);	if (!gsp->created && !gsp->existed && !gsp->noperm)		/* retry the greylist entry with parent dirs created */		tryaddgrey(file, gsp);}static intrecentcall(Greysts *gsp){	long delay = time(0) - gsp->mtime;	if (!gsp->existed)		return 0;	/* reject immediate call-back; spammers are doing that now */	return delay >= 30 && delay <= Nonspammax;}/* * policy: if (caller-IP, my-IP, rcpt) is not on the greylist, * reject this message as "451 temporary failure".  if the caller is real, * he'll retry soon, otherwise he's a spammer. * at the first rejection, create a greylist entry for (my-ip, caller-ip, * rcpt, time), where time is the file's mtime.  if they call back and there's * already a greylist entry, and it's within the allowed interval, * add their IP to the append-only whitelist. * * greylist files can be removed at will; at worst they'll cause a few * extra retries. */static intisrcptrecent(char *rcpt){	char *user;	char file[256];	Greysts gs;	Greysts *gsp = &gs;	if (rcpt[0] == '\0' || strchr(rcpt, '/') != nil ||	    strcmp(rcpt, ".") == 0 || strcmp(rcpt, "..") == 0)		return 0;	/* shorten names to fit pre-fossil or pre-9p2000 file servers */	user = strrchr(rcpt, '!');	if (user == nil)		user = rcpt;	else		user++;	/* check & try to update the grey list entry */	snprint(file, sizeof file, "/mail/grey/tmp/%s/%s/%s",		nci->lsys, nci->rsys, user);	memset(gsp, 0, sizeof *gsp);	addgreylist(file, gsp);	/* if on greylist already and prior call was recent, add to whitelist */	if (gsp->existed && recentcall(gsp)) {		syslog(0, "smtpd",			"%s/%s was grey; adding IP to white", nci->rsys, rcpt);		return 1;	} else if (gsp->existed)		syslog(0, "smtpd", "call for %s/%s was seconds ago or long ago",			nci->rsys, rcpt);	else		syslog(0, "smtpd", "no call registered for %s/%s; registering",			nci->rsys, rcpt);	return 0;}voidvfysenderhostok(void){	char *fqdn;	int recent = 0;	Link *l;	if (onwhitelist())		return;	for (l = rcvers.first; l; l = l->next)		if (isrcptrecent(s_to_c(l->p)))			recent = 1;	/* if on greylist already and prior call was recent, add to whitelist */	if (recent) {		int fd = create(whitelist, OWRITE, 0666|DMAPPEND);		if (fd >= 0) {			seek(fd, 0, 2);			/* paranoia */			fqdn = csgetvalue(nci->root, "ip", nci->rsys, "dom",				nil);			if (fqdn != nil)				fprint(fd, "%s %s\n", nci->rsys, fqdn);			else				fprint(fd, "%s\n", nci->rsys);			free(fqdn);			close(fd);		}	} else {		syslog(0, "smtpd",	"no recent call from %s for a rcpt; rejecting with temporary failure",			nci->rsys);		reply("451 please try again soon from the same IP.\r\n");		exits("no recent call for a rcpt");	}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -