Date: Sun, 16 May 2004 01:46:53 +0300 From: Anton Alin-Adrian <aanton@reversedhell.net> To: freebsd-security@freebsd.org Subject: Re: How do fix a good solution against spam.. Message-ID: <40A69DDD.30603@reversedhell.net>
next in thread | raw e-mail | index | archive | help
This is an OpenPGP/MIME signed message (RFC 2440 and 3156) --------------enig50494E6F7C055A8B68812667 Content-Type: multipart/mixed; boundary="------------090801040700050009080104" This is a multi-part message in MIME format. --------------090801040700050009080104 Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit It's half off topic, half not. Something has to be done, and it takes technical skills and knowleged ppl to handle the issues.At least this is how I rationate when deciding where to ask. I started an anti-spam project on my own. At some point others offered to help, but we all know boring real-life shuts down all the enthusiasm. M.Jessa> Not only it's way faster than perl based messagewall, amavisd and M.Jessa> mailscanner etc but it also has neat stuff like making connections M.Jessa> back to the sender's MX checking for validity of the sender's M.Jessa> email. So far I can only release this code. It implements exactly what was mentioned about exim. I use it with qmail because qmail I have, but can be used with postfix/sendmail with ease. So now not only exim can do that hack. I just wanted to make the code available so users can benefit from it (hopefully). PS - this is how i use it: .qmail-file: | /usr/local/bin/check /usr/local/bin/safecat /path/to/Maildir/tmp /path/to/Maildir/new #the above after | is on a single line. Hope there are not many bugs. Yours Sincerely, -- Alin-Adrian Anton Reversed Hell Networks GPG keyID 0x1E2FFF2E (2963 0C11 1AF1 96F6 0030 6EE9 D323 639D 1E2F FF2E) gpg --keyserver pgp.mit.edu --recv-keys 1E2FFF2E --------------090801040700050009080104 Content-Type: text/plain; name="check.c" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="check.c" /* * The MX query routines are Copyrighted (C) 2004 by HL Combrinck and are licensed under GPL (see below), * and they provide "Sample C code to resolve MX records for an address". * * * This program is derivative work based on his original functions, and is distributed under the following terms: * * LICENSE: * * The program provides functions for testing if an e-mail address was faked by a spammer or it's real, and it's * part of the L.A.U.R.A anti-spam project and campaign. * * Copyright (C) 2004 Anton Alin-Adrian aanton()reversedhell.net * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * END OF LICENSE * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <netdb.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/types.h> #include <arpa/nameser.h> #include <resolv.h> #define PORT 25 /* SMTP default port */ #define MAXDATASIZE 1024 /* we don't need more */ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! REPLACE WITH YOUR *REAL* DOMAIN & *FAKE* E-MAIL USER !!!!!!!!!!!!!!!!!!!!!!! */ #define MY_VALID_MAIL_DOMAIN "INEXISTENT-USER-HERE@reversedhell.net" /* replace user with something decent like 'antispamrobot' */ #define MY_VALID_DOMAIN "reversedhell.net" /* must be your real domain you are connecting from */ struct mx { int pref; char host[1024]; }; #ifndef HFIXEDSZ # define HFIXEDSZ 12 #endif #ifndef INT16SZ # define INT16SZ sizeof(cit_int16_t) #endif #ifndef INT32SZ # define INT32SZ sizeof(cit_int32_t) #endif int totalsize=0; /* * Compare the preference of two MX records. Check the actual * number listed in the MX record - if they're the same, randomize. */ int mxcomp(int p1, int p2) { if (p1 > p2) return(1); else if (p1 < p2) return(0); else return(rand() % 2); } /* * sort_mxrecs() * * Sort MX records * */ void sort_mxrecs (struct mx *mxrecs, int nmx) { int a, b; struct mx t1, t2; if (nmx < 2) return; for (a = nmx - 2; a >= 0; --a) { for (b = 0; b <= a; ++b) { if (mxcomp(mxrecs[b].pref,mxrecs[b+1].pref)) { memcpy(&t1, &mxrecs[b], sizeof(struct mx)); memcpy(&t2, &mxrecs[b+1], sizeof(struct mx)); memcpy(&mxrecs[b], &t2, sizeof(struct mx)); memcpy(&mxrecs[b+1], &t1, sizeof(struct mx)); } } } } /* * getmx() * * Get MX recs for an address. * * Upon success, it fills 'mxbuff' with one or more MX hosts, delimited by * ':' chars, and returns the number of hosts. 0 if none found. * */ int getmx(char *mxbuff, char *dest, int maxbuffsz) { union { u_char bytes[1024]; HEADER header; } ans; int ret; unsigned char *startptr, *endptr, *ptr; char expanded_buf[1024]; unsigned short pref, type; int n = 0; int qdcount; struct mx *mxrecs = NULL; int nmx = 0; ret = res_query (dest, C_IN, T_MX, (unsigned char *)ans.bytes, sizeof(ans)); if (ret < 0) { mxrecs = malloc(sizeof(struct mx)); mxrecs[0].pref = 0; strcpy(mxrecs[0].host, dest); nmx = 0; } else { if (ret > sizeof(ans)) ret = sizeof(ans); startptr = &ans.bytes[0]; endptr = &ans.bytes[ret]; ptr = startptr + HFIXEDSZ; /* skip header */ for (qdcount = ntohs(ans.header.qdcount); qdcount--; ptr += ret + QFIXEDSZ) { if ((ret = dn_skipname(ptr, endptr)) < 0) return(0); } while(1) { memset (expanded_buf, 0, sizeof(expanded_buf)); ret = dn_expand (startptr, endptr, ptr, expanded_buf, sizeof(expanded_buf)); if (ret < 0) break; ptr += ret; GETSHORT (type, ptr); ptr += INT16SZ + INT32SZ; GETSHORT (n, ptr); if (type != T_MX) ptr += n; else { GETSHORT(pref, ptr); ret = dn_expand(startptr, endptr, ptr, expanded_buf, sizeof(expanded_buf)); ptr += ret; ++nmx; if (mxrecs == NULL) mxrecs = malloc(sizeof(struct mx)); else mxrecs = realloc (mxrecs, (sizeof(struct mx) * nmx)); mxrecs[nmx - 1].pref = pref; strcpy(mxrecs[nmx - 1].host, expanded_buf); } } } /* sort by MX pref */ sort_mxrecs(mxrecs, nmx); strcpy(mxbuff, ""); for (n=0; n<nmx; ++n) { if (strlen(mxbuff)+strlen(mxrecs[n].host) < maxbuffsz) strcat(mxbuff, mxrecs[n].host); else break; strcat(mxbuff, ":"); } /* kill last ':' */ if (mxbuff[strlen(mxbuff)-1] == ':') mxbuff[strlen(mxbuff)-1] = 0; free(mxrecs); return(nmx); } int checkmail(char *addy,char *myhost) { int sockfd, numbytes; char buf[MAXDATASIZE]; struct hostent *he; struct sockaddr_in their_addr; fd_set readfds; if ((he=gethostbyname(myhost)) == NULL) { //perror("gethostbyname"); return -2; } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); return -1; } their_addr.sin_family = AF_INET; // host byte order their_addr.sin_port = htons(PORT); // short, network byte order their_addr.sin_addr = *((struct in_addr *)he->h_addr); memset(&(their_addr.sin_zero), '\0', 8); // zero the rest of the struct if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) { //perror("connect"); close(sockfd); return -2; } if ((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { perror("recv"); close(sockfd); return -1; } buf[3]='\0'; if (atoi(buf)!=220) { close(sockfd); return -1; } memset(buf,0x0,sizeof(buf)); snprintf(buf,sizeof(buf),"helo %s\r\n",MY_VALID_DOMAIN); if (send(sockfd,buf,strlen(buf),0)==-1) { perror("send"); close(sockfd); return -1; } memset(buf,0x0,sizeof(buf)); if ((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { perror("recv"); close(sockfd); return -1; } buf[3]='\0'; if (atoi(buf)!=250) { close(sockfd); return -1; } memset(buf,0x0,sizeof(buf)); snprintf(buf,sizeof(buf),"MAIL FROM:<%s>\r\n",MY_VALID_MAIL_DOMAIN); if (send(sockfd,buf,strlen(buf),0)==-1) { perror("send"); close(sockfd); return -1; } memset(buf,0x0,sizeof(buf)); if ((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { perror("recv"); close(sockfd); return -1; } buf[3]='\0'; if (atoi(buf)!=250) { close(sockfd); return -1; } memset(buf,0x0,sizeof(buf)); snprintf(buf,sizeof(buf),"RCPT TO:<%s>\r\n",addy); if (send(sockfd,buf,strlen(buf),0)==-1) { perror("send"); close(sockfd); return -1; } memset(buf,0x0,sizeof(buf)); if ((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { perror("recv"); close(sockfd); return -1; } buf[3]='\0'; if (atoi(buf)!=250) { close(sockfd); return -2; } return 0; } // checkmail int loopcheckmail(char *addy) { int n,ret; char buf[1024], *ptr; char *myhost; myhost=(char *) malloc(strlen(addy)+1); myhost=strchr(addy,'@')+1; n = getmx (buf, myhost, sizeof(buf)-1); if (!n) { ret=checkmail(addy,myhost); } else { ptr=strchr(buf,':'); if (ptr!=NULL) *ptr='\0'; ret=checkmail(addy,buf); } return ret; } char *read_mail_buffer(FILE *fp) { char c='\0'; int i=0; long int size=1024+1; int padder=1024; char *ptr,*s; if ((s=(char *) malloc((size_t)size))==NULL) { perror("malloc"); exit(EXIT_FAILURE); } memset(s,(char)0x0,(size_t) size); ptr=s; while ((c!=(char)EOF)){ c=(char) getc(fp); if (i>=size-1) { size+=padder; if ( (s=(char *)realloc(s,(size_t)size) ) == NULL) { perror("realloc"); exit(EXIT_FAILURE); } ptr=s+i*sizeof(char); if (totalsize > 700000) padder=padder*2; } i++; *(ptr++)=c; } *(--ptr)='\0'; totalsize=size; return (char *) s; } int filtervalidmail(char *s) { char *ptr; char *addy; char *left,*right; int i,j,stop=0; char c; ptr = strcasestr(s,"From:"); if (ptr==NULL) return -1; ptr+=5; ptr=strchr(ptr,'@'); left=ptr; right=ptr; while (isalnum(*(--left)) ) { c=*(--left); ptr=strchr(ptr,'<')+1; for (i=0;*(ptr++)!='>';i++); addy=(char *) malloc((i+1)*sizeof(char)); memset(addy,0x0,i+1); } int main (int argc,char *argv[]) { int ret; char *bigbuf; /* if (argc < 2) { fprintf(stderr,"What to check? Give me valid e-mail format.\n"); exit(EXIT_FAILURE); } ret=loopcheckmail(argv[1]); switch (ret) { case -1: fprintf(stderr,"IRRELEVANT: Error..\n"); break; case -2: fprintf(stderr,"BLOCK!\n"); break; case 0: fprintf(stderr,"IRRELEVANT\n"); break; } */ bigbuf=read_mail_buffer(stdin); filtervalidmail(bigbuf); return 0; } --------------090801040700050009080104-- --------------enig50494E6F7C055A8B68812667 Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.4 (FreeBSD) iD8DBQFApp3i0yNjnR4v/y4RAnQVAJ4i0ugAIDwqI2hQvU02Q0+mMibAcwCgwiP3 JR+al0ccDXcrxSB9yXqkCOA= =UzGe -----END PGP SIGNATURE----- --------------enig50494E6F7C055A8B68812667--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?40A69DDD.30603>