From 06a582d95c7827a6782c63336f21d065620e015a Mon Sep 17 00:00:00 2001 From: "Jean-Marc Pigeon (Delson)" Date: Sun, 18 May 2025 08:26:28 -0400 Subject: [PATCH] Detecting if MX is defined for an email address --- data-feed/feed01.tst | 6 +++--- data-feed/xxfeed.tst | 2 +- lib/Makefile | 2 +- lib/lvleml.c | 25 +++++++++++++++++++++---- lib/unidns.c | 27 +++++++++++++++++++++------ lib/unidns.h | 2 +- lib/unieml.c | 43 ++++++++++++++++++++++--------------------- lib/unieml.h | 3 ++- 8 files changed, 72 insertions(+), 38 deletions(-) diff --git a/data-feed/feed01.tst b/data-feed/feed01.tst index 38e7cc5..acbacc4 100644 --- a/data-feed/feed01.tst +++ b/data-feed/feed01.tst @@ -1,6 +1,6 @@ #very simple test to feed SMTP server #==================================================== -T:Very Simple email sending +T:Testing if MX is found R:220 mailleur.example.com ESMTP (cleartext) emlrcvr... #==================================================== S:HELO example.com @@ -9,9 +9,9 @@ R:250-mailleur.example.com, link (cleartext) ready,... S:MAIL FROM: R:250 2.1.3 postmaster@example.com.. sender ok S:RCPT TO: -S:563 0.0.0 No valid MX found for recipient domain name (subdom0.example.com) +R:563 5.6.3 No valid MX found for recipient domain name (rcpt=subdom0.example.com) S:RCPT TO: -R:250 3.5.3 Message accepted for delivery +R:250 2.6.4 Address accepted S:QUIT R:221 2.0.0 Bye, closing connection... #------------------------------------------------------------------------- diff --git a/data-feed/xxfeed.tst b/data-feed/xxfeed.tst index 7d7a87c..acbacc4 100644 --- a/data-feed/xxfeed.tst +++ b/data-feed/xxfeed.tst @@ -9,7 +9,7 @@ R:250-mailleur.example.com, link (cleartext) ready,... S:MAIL FROM: R:250 2.1.3 postmaster@example.com.. sender ok S:RCPT TO: -R:563 0.0.0 No valid MX found for recipient domain name (subdom0.example.com) +R:563 5.6.3 No valid MX found for recipient domain name (rcpt=subdom0.example.com) S:RCPT TO: R:250 2.6.4 Address accepted S:QUIT diff --git a/lib/Makefile b/lib/Makefile index 1fe3def..dd27e33 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -39,7 +39,7 @@ modrec.o: \ lvleml.o: \ subrou.h \ - unieml.h \ + unieml.h unidns.h \ lvleml.h lvleml.c gesspf.o: \ diff --git a/lib/lvleml.c b/lib/lvleml.c index 7fab83e..b000301 100644 --- a/lib/lvleml.c +++ b/lib/lvleml.c @@ -18,6 +18,7 @@ #include #include "subrou.h" +#include "unidns.h" #include "unieml.h" #include "devlog.h" #include "lvleml.h" @@ -461,12 +462,14 @@ static _Bool checkto(CONTYP *contact,char *rcptto) #define OPEP "lvleml.c:checkto," _Bool success; const char *detail; +const char *domain; char *report; _Bool proceed; int phase; success=false; detail="Address accepted"; +domain=(const char *)0; report=(char *)0; proceed=true; phase=0; @@ -489,19 +492,33 @@ while (proceed==true) { rcptto[strlen(rcptto)-1]='\000'; (void) memmove(rcptto,rcptto+1,strlen(rcptto)); break; - case 2 : //checking repto format - if (eml_isemailok(rcptto,&report)==false) { + case 2 : //checking rcptto format + if (eml_isemailok(rcptto,&domain,&report)==false) { (void) transmit(contact,"%d 5.6.2 %s",NOTEML,report); report=rou_freestr(report); phase=999; //no need to go further } break; - case 3 : //Storing rcpt to + case 3 : //Do we have a domain MX + if (domain!=(const char *)0) { //always + MXTYP **mx; + + if ((mx=dns_getmx(domain))==(MXTYP **)0) { + (void) transmit(contact,"%d 5.6.3 %s (rcpt=%s)", + MISSMX, + "No valid MX found for recipient domain name", + domain); + phase=999; //no need to go further + } + mx=dns_freemxlist(mx); + } + break; + case 4 : //Storing rcpt to if (eml_addemail(&(contact->rcptto),rcptto)==false) { detail="duplicate recipients will be consolidated"; } break; - case 4 : //everything ok + case 5 : //everything ok (void) transmit(contact,"%d 2.6.4 %s",CMDOK,detail); success=true; break; diff --git a/lib/unidns.c b/lib/unidns.c index 20b416a..f418859 100644 --- a/lib/unidns.c +++ b/lib/unidns.c @@ -95,7 +95,7 @@ return got; /* from DNS record. */ /* */ /********************************************************/ -static char **extracting(RSPTYP *rsp,int rsplen,char *request,char *field) +static char **extracting(RSPTYP *rsp,int rsplen,const char *request,char *field) { #define OPEP "unidns.c:extracting," @@ -316,7 +316,7 @@ return mxlist; /* MX preference (low preference first) */ /* */ /********************************************************/ -PUBLIC MXTYP **dns_getmx(char *domain) +PUBLIC MXTYP **dns_getmx(const char *domain) { #define OPEP "unidns.c:dns_getmx" @@ -338,23 +338,38 @@ while (proceed==true) { switch (phase) { case 0 : //Are the parameters available if ((domain==(char *)0)||(strlen(domain)==0)) { - (void) rou_alert(0,"%s missing domainame",OPEP); + (void) rou_alert(0,"%s missing domainname",OPEP); phase=999; //trouble trouble } break; - case 1 : //Requesting MX for domain + case 1 : //cleaning domain + if (domain!=(char *)0) { //always + char *ptr; + + if ((ptr=strchr(domain,'@'))!=(char *)0) { + ptr++; + if (strlen(ptr)==0) { + (void) rou_alert(0,"%s Incorrect domainname <%s>",OPEP,domain); + phase=999; //trouble trouble + } + domain=ptr; + } + } + break; + case 2 : //Requesting MX for domain + (void) rou_alert(0,"%s JMPDBG domain=<%s>",OPEP,domain); answer=myquery(domain,C_IN,T_MX,rsp.buf,sizeof(rsp.buf)); if (answer<=0) phase=999; //Trouble trouble to get MX break; - case 2 : //extracting result + case 3 : //extracting result if (answer>=sizeof(rsp.buf)) answer=sizeof(rsp.buf)-1; list=extracting(&rsp,answer,domain,"MX"); if (list==(char **)0) phase=999; //list empty? break; - case 3 : //ordering list + case 4 : //ordering list answer=0; for (int i=0;list[i]!=(char *)0;i+=2) { if ((list[i+1]!=(char *)0)&&(strlen(list[i+1])>0)) { diff --git a/lib/unidns.h b/lib/unidns.h index 689d706..7b8ee83 100644 --- a/lib/unidns.h +++ b/lib/unidns.h @@ -24,7 +24,7 @@ extern MXTYP **dns_freemxlist(MXTYP **mxlist); //procedure to get a list of MX IP releated to a specific //domain. -extern MXTYP **dns_getmx(char *domain); +extern MXTYP **dns_getmx(const char *domain); //Procedure to check if an IP (Origin IP) is part //of domain A record list diff --git a/lib/unieml.c b/lib/unieml.c index d2d9afe..8aeab4e 100644 --- a/lib/unieml.c +++ b/lib/unieml.c @@ -443,47 +443,54 @@ return status; /* acceptable. */ /* */ /********************************************************/ -PUBLIC _Bool eml_isemailok(char *email,char **rapport) +PUBLIC _Bool eml_isemailok(char *email,const char **domain,char **rapport) { #define OPEP "unieml.c:eml_isemailok" int status; char *localpart; -char *domain; int phase; _Bool proceed; status=false; localpart=(char *)0; -domain=(char *)0; +*domain=(const char *)0; phase=0; proceed=true; while (proceed==true) { //(void) rou_alert(0,"JMPDBG %s phase='%d'",OPEP,phase); switch (phase) { case 0 : //do we have an email - if (email==(char *)0) { + if ((email==(char *)0)||strlen(email)==0) { (void) rou_alert(0,"%s Email missing! (bug?)",OPEP); proceed=false; } break; - case 1 : //duplicating email to localpart + case 1 : //splitting local domain part + if ((*domain=strchr(email,'@'))!=(const char *)0) + (*domain)++; + if ((*domain)==(char *)0) { + *rapport=strdup("Missing domain part"); + phase=999; //trouble trouble + } + break; + case 2 : //double checking domain part + if (strchr(*domain,'@')!=(char *)0) { + *rapport=strdup("malformed domain part"); + *domain=(const char *)0; + phase=999; //trouble trouble + } + break; + case 3 : //duplicating email to localpart localpart=strdup(email); + *(strchr(localpart,'@'))='\000'; //removing domain if (strlen(localpart)==0) { *rapport=strdup("email address is empty"); - phase=999; //never reached + phase=999; //trouble trouble } break; - case 2 : //splitting local domain part - if ((domain=strchr(localpart,'@'))!=(char *)0) - domain++; - if (domain==(char *)0) { - *rapport=strdup("Missing domain part"); - phase=999; //never reached - } - break; - case 3 : //checking localpart email + case 4 : //checking localpart email if (strlen(localpart)>0) { //always char *ptr; char cmt[200]; @@ -509,12 +516,6 @@ while (proceed==true) { } } break; - case 4 : //checking domain part - if (strlen(domain)==0) { - *rapport=strdup("No domain part"); - phase=999; //No need to go further - } - break; case 5 : //everythin fine status=true; break; diff --git a/lib/unieml.h b/lib/unieml.h index 962573a..a680f37 100644 --- a/lib/unieml.h +++ b/lib/unieml.h @@ -20,6 +20,7 @@ #define CMDBAD 502 //command not implemented #define DATRJC 521 //Data Rejected #define NOTEML 553 //Not an email address +#define MISSMX 563 //NO MX found for recipient //list of keyword @@ -73,6 +74,6 @@ extern _Bool eml_addemail(char ***emails,char *email); //procedure to check email address format //of an email address -extern _Bool eml_isemailok(char *email,char **report); +extern _Bool eml_isemailok(char *email,const char **domain,char **report); #endif -- 2.47.3