20 Ocak 2013 Pazar

qmail and out() function adventure

Note: This article was published at http://www.surgate.com/blog officialy.

The author of Qmail, `DJB`, is really fantastic person. He wrote the qmail code more than ten years ago and I am also working on qmail more than ten years. Before I was doing system administration of qmail servers and create little patches and scripts.

Nowadays, me and my SurGATE Labs R&D team is working on qmail codes to understand better and add some functionality. We especially focused on qmail-remote code these days.

We tried to add more log to qmail-remote to report sender,receiver and remote IP on every possible log line. It was something like an adventure on the forest. You can not estimate what you will see on the next lines :)

The most mysteries part is out function. It is a very little code but do many reporting on different level of the SMTP connection.  I would like to mention about this function little bit.

The main rules of the out function is that the log must be start a "very very special letters":Z,D,K, r,h and(the letters are "CASE SENSITIVE")

If you do not put one of these letters at the beginning, you will be in trouble at mail delivery for sure!
At least it happened for us many times.

The meaning of the letters:

The following 3 letters is about message/data report:
Z: Temporary failure at the DATA session.
D: Permanent failure at the DATA session.
K: Success, Remote server received the mail successfuly.

Related source code from qmail-remote.c:

if (code >= 500) quit("D"," failed on DATA command");  /* 5XX is permanent error */
  if (code >= 400) quit("Z"," failed on DATA command");  /* 4XX temporary error */

  blast();
  code = smtpcode();
  flagcritical = 0;
  if (code >= 500) quit("D"," failed after I sent the message");
  if (code >= 400) quit("Z"," failed after I sent the message");
  quit("K"," accepted message");



The following 3 letters is about recipient report:

h: Permanent Rejection at RCPT level
s: Temporary Rejection at RCPT level
r: Recipient accepted at RCPT level

Thanks to http://binarios.com/lnb/qmail.html document author.

Related source code from qmail-remote.c:

 substdio_puts(&smtpto,"RCPT TO:<");
    substdio_put(&smtpto,reciplist.sa[i].s,reciplist.sa[i].len);
    substdio_puts(&smtpto,">\r\n");
    substdio_flush(&smtpto);
    code = smtpcode();
    if (code >= 500) {
      out("h"); outhost(); out(" does not like recipient.\n");
      outsmtptext(); zero();
    }
    else if (code >= 400) {
      out("s"); outhost(); out(" does not like recipient.\n");




As SurGATE Labs R&D team we changed the source code as belove:

Original code:

  substdio_puts(&smtpto,"HELO ");
  substdio_put(&smtpto,helohost.s,helohost.len);
  substdio_puts(&smtpto,"\r\n");
  substdio_flush(&smtpto);
  if (smtpcode() != 250) quit("ZConnected to "," but my name was rejected");


Our Code:
 substdio_puts(&smtpto,"HELO ");
  substdio_put(&smtpto,helohost.s,helohost.len);
  substdio_puts(&smtpto,"\r\n");
  substdio_flush(&smtpto);

        code = smtpcode();
        if (code >= 500) {
                out("h <from:"); outsafe(&sender); 

out(" to:"); outsafe(&reciplist.sa[0]); out("> ");  
outhost(); 
out(" Connected  but greeting failed\n"); 
quit("DConnected to "," but greeting failed");
        }
        if (code != 250) {
out("s <from:"); outsafe(&sender); 

out(" to:"); outsafe(&reciplist.sa[0]); out("> ");  
outhost(); 
out("  Connected  but greeting failed\n"); 
quit("ZConnected to "," but greeting failed");


Original code at MAIL FROM part:




substdio_puts(&smtpto,"MAIL FROM:<");
  substdio_put(&smtpto,sender.s,sender.len);
  substdio_puts(&smtpto,">\r\n");
  substdio_flush(&smtpto);
  code = smtpcode();
  if (code >= 500) quit("DConnected to "," but sender was rejected");
  if (code >= 400) quit("ZConnected to "," but sender was rejected");


Our code:



  substdio_puts(&smtpto,"MAIL FROM:<");
  substdio_put(&smtpto,sender.s,sender.len);
  substdio_puts(&smtpto,">\r\n");
  substdio_flush(&smtpto);
  code = smtpcode();
  if (code >= 500) {
          //Surgate R&D Team 

out("h <from:"); 
outsafe(&sender); 
out(" to:"); outsafe(&reciplist.sa[0]); out("> ");  
outhost(); out(" Connected   but sender was rejected\n");
quit("DConnected to "," but sender was rejected");
}
  if (code >= 400) {
          //Surgate R&D Team
out("s <from:"); 

outsafe(&sender); 
out(" to:"); 
outsafe(&reciplist.sa[0]); out("> ");  
outhost(); 
out(" Connected   but sender was rejected\n");                   quit("ZConnected to "," but sender was rejected")
  }


Original Code at DATA

substdio_putsflush(&smtpto,"DATA\r\n");
  code = smtpcode();
  if (code >= 500) quit("D"," failed on DATA command");
  if (code >= 400) quit("Z"," failed on DATA command");


Our code:

substdio_putsflush(&smtpto,"DATA\r\n");
  code = smtpcode();
  if (code >= 500) {
          //Surgate R&D Team           

out("D <from:"); outsafe(&sender); 
out(" to:"); 
outsafe(&reciplist.sa[0]); out("> ");  
outhost();  
out(" failed on DATA command\n");
quit("D"," failed on DATA command");
  }
  if (code >= 400) {
out("Z <from:"); 

outsafe(&sender); 
out(" to:"); 
outsafe(&reciplist.sa[0]); out("> ");  
outhost();  
out(" failed on DATA command\n");
quit("Z"," failed on DATA command");
}


Hiç yorum yok:

Yorum Gönder