设为首页 友情链接
在线留言 发表文章
加入收藏 广告联系

刺猬首页

| 专案技术 | 网络技术 | 图形图象 | 网络编程 | 网页设计 | 操作系统 | 服务器 | 技术白皮书 | 在线实验室 | 刺猬论坛 |
小说专版  | 数据库 | 设计赏析 | 存储频道 | 网络安全 | 私服架设 |  Solaris | 网站评估 | PC维护技巧 | 下载中心 | 博 客 |
专   题: | Linux | java | cisco | 防病毒 | 刀片 | SOA | iscsi | ASP.NET | SQL | Oracle |
您现在的位置: IT公社 IT community >> Linux专题 >> Linux 软件开发 >> 教程正文 用户登录 新用户注册
专 题 栏 目
最 新 热 门
最 新 推 荐
相 关 文 章
Linux下程序开发:QT的信…
Linux下程序开发:QT中使…
Linux操作系统的X86汇编…
Linux下程序开发:使用Q…
Linux程序开发:QT的内部…
Linux程序开发:QT中的多…
Linux系统编程之C++游戏…
编写多线程Java应用程序…
Linux上找出并解决程序错…
Linux上找出并解决程序错…
  程序员眼中的qmail(qmail源代码分析)         
程序员眼中的qmail(qmail源代码分析)
 

很多人对qmail smtp的认证机制,环境变量,执行顺序不太了解。

  仔细看完这一大篇代码后相信你会明白很多你过去不太明白的问题。

  当然你要有一点点c语言基础。也只要一点点。

  Come from: ChongQing Gearbox co.,ltd

  这份文件还不完善,如果您完善了它请发一份给我: beggar110@163.com

  这份文件是给想深入了解qmail和想hacker qmail的人读的,如果你只是想建立一个能够运作的mail服务器,没有必要读下去了。它将浪费你很多的时间。

  如果你对qmail控制文件还不是很了解,阅读这份文件之前,请先阅读rainbow的《qmail控制文件详解》

  在这里你可以找到www.chinaunix.net/forum/viewtopic.php?t=1126

  好的。开始我们qmail内部的漫游吧!!!Let's go!

  代码:

  qmail 总览

  tcpserver MUA

  | |

  V V

  qmail-smtpd qmail-inject

  | |

  +----------->qmail-queue<-----------+

  |

  |

  qmail-send

  |

  +------------+------------+

  | |

  V V

  qmail-rspawn qmail-lspawn

  | |

  V V

  qmail-remote qmail-local

  | |

  | |

  V V

  INTERNET <----qmail-pop3d

  |

  |

  vchkpw

  |

  |

  qmail-popup

  |

  |

  tcpserver--+

  qmail-smtpd.c源代码分析(去掉了所有include)

  qmail -smtpd是由tcpserver或由tcp-env启动。tcpserver负责监听端口,如果指定了-x rule.cbd,tcpserver会先决断是断开连接还是启动qmail子进程。如果没有指定-x参数启动tcpserver,那么直接启动 qmail-smtpd.启动qmail-smtpd之前将来自网络的数据连接重定向到qmail-smtpd的fd0,fd1.还会初始化一些 qmail-smtpd需要的环境变量,如TCPREMOTEIP.

  tcp-env只会初始化qmail-smtpd的环境变量,不负责监听端口及重定向网络连接。所以tcp-env要和inetd配合使用。当然,由于初始化环境变量的工作tcpserver也会作,所以没有必要tcpserver和tcp-env配合使用.

  qmail-smtpd完成邮件smtp命令的接收,并调用相应的处理程序。

  检查mail 中的地址是否在control/badmailfrom中定义(MAIL命令)

  检查是否设置了RELAYCLIENT环境变量或 rcpt 中的地址是否是control/rcpthosts中定义(RCPT命令)

  需要明确的是qmail-smtpd只是简单的接收邮件内容传送给qmail-queue,并不对邮件进行转发(DATA命令)。

  当然还要向qmail-queue传送mailfrom,mailto

  代码:

  #define MAXHOPS 100

  unsigned int databytes = 0; //邮件最大长度:0=无限

  int timeout = 1200; //默认超时20分钟

  //向网络写,超时值为control/timeoutsmtpd指定的值。没有这个文件则取默认值20分钟

  int safewrite(fd,buf,len) int fd; char *buf; int len;

  {

  int r;

  r = timeoutwrite(timeout,fd,buf,len);

  if (r <= 0) _exit(1);

  return r;

  }

  char ssoutbuf[512];

  substdio ssout = SUBSTDIO_FDBUF(safewrite,1,ssoutbuf,sizeof ssoutbuf);

  void flush() { substdio_flush(&ssout); }

  void out(s) char *s; { substdio_puts(&ssout,s); }

  //错误处理函数

  void die_read() { _exit(1); }

  void die_alarm() { out("451 timeout (#4.4.2)\r\n"); flush(); _exit(1); }

  void die_nomem() { out("421 out of memory (#4.3.0)\r\n"); flush(); _exit(1); }

  void die_control() { out("421 unable to read controls (#4.3.0)\r\n"); flush(); _exit(1); }

  void die_ipme() { out("421 unable to figure out my IP addresses (#4.3.0)\r\n"); flush(); _exit(1); }

  void straynewline() { out("451 See pobox.com/~djb/docs/smtplf.html.\r\n"); flush(); _exit(1); }

  void err_bmf() { out("553 sorry, your envelope sender is in my badmailfrom list (#5.7.1)\r\n"); }

  void err_nogateway() { out("553 sorry, that domain isn't in my list of allowed rcpthosts (#5.7.1)\r\n"); }

  void err_unimpl() { out("502 unimplemented (#5.5.1)\r\n"); }

  void err_syntax() { out("555 syntax error (#5.5.4)\r\n"); }

  void err_wantmail() { out("503 MAIL first (#5.5.1)\r\n"); }

  void err_wantrcpt() { out("503 RCPT first (#5.5.1)\r\n"); }

  void err_noop() { out("250 ok\r\n"); }

  void err_vrfy() { out("252 send some mail, i'll try my best\r\n"); }

  void err_qqt() { out("451 qqt failure (#4.3.0)\r\n"); }

  stralloc greeting = {0};

  //输出提示信息*code

  void smtp_greet(code) char *code;

  {

  substdio_puts(&ssout,code);

  substdio_put(&ssout,greeting.s,greeting.len);

  }

  void smtp_help()

  {

  out("214 qmail home page:

  void>pobox.com/~djb/qmail.html\r\n");

  }

  void smtp_quit()

  {

  smtp_greet("221 "); out("\r\n"); flush(); _exit(0);

  }

  char *remoteip; //远端ip地址

  char *remotehost; //远端主机名

  char *remoteinfo; //远端信息

  char *local; //本地主机

  char *relayclient; //是否检查rcpthosts文件

  stralloc helohost = {0};

  char *fakehelo; /* pointer into helohost, or 0 */

  void dohelo(arg) char *arg; {

  if (!stralloc_copys(&helohost,arg)) die_nomem();

  if (!stralloc_0(&helohost)) die_nomem();

  //fakehelo变量,如果helo 参数指定的主机名与TCPREMOTEHOST环境变量中的主机名不同则

  //fakehelo的值为helo命令的参数指定的主机名.如果两者相同则fekehelo为NULL;

  //data命令处理程式用到这个变量

  fakehelo = case_diffs(remotehost,helohost.s) ? helohost.s : 0;

  }

  int liphostok = 0;

  stralloc liphost = {0};

  int bmfok = 0;

  stralloc bmf = {0};

  struct constmap mapbmf;

  void setup()

  {

  char *x;

  unsigned long u;

  if (control_init() == -1) die_control(); //control/me

  //读入欢迎信息greeting,如果不存在则从me文件复制

  if (control_rldef(&greeting,"control/smtpgreeting",1,(char *) 0) != 1)

  die_control();

  //读入localiphost,如果文件不存在则从me文件复制

  liphostok = control_rldef(&liphost,"control/localiphost",1,(char *) 0);

  if (liphostok == -1) die_control();

  //读control/timeoutsmtpd存入timeout,用于控制超时的情况.

  if (control_readint(&timeout,"control/timeoutsmtpd") == -1) die_control();

  if (timeout <= 0) timeout = 1;

  if (rcpthosts_init() == -1) die_control();

  //读入badmailfrom文件存入 bmf

  bmfok = control_readfile(&bmf,"control/badmailfrom",0);

  if (bmfok == -1) die_control();

  if (bmfok)

  if (!constmap_init(&mapbmf,bmf.s,bmf.len,0)) die_nomem();

  //读入databytes文件存入 databytes,如果该文件不存在,则将

  //databytes的值设为0.

  if (control_readint(&databytes,"control/databytes") == -1) die_control();

  x = env_get("DATABYTES");

  if (x) { scan_ulong(x,&u); databytes = u; }

  if (!(databytes + 1)) --databytes;

  //取tcp-environ环境变量,如果环境变量没有设置,将它的值设置为unknow.

  //这些信息来自tcpserver,或tcp-env之类的程式

  remoteip = env_get("TCPREMOTEIP");

  if (!remoteip) remoteip = "unknown";

  local = env_get("TCPLOCALHOST");

  if (!local) local = env_get("TCPLOCALIP");

  if (!local) local = "unknown";

  remotehost = env_get("TCPREMOTEHOST");

  if (!remotehost) remotehost = "unknown";

  remoteinfo = env_get("TCPREMOTEINFO");

  //从环境变量RELAYCLIENT读入.

  //如果RELAYCLIENT变量没有设置那么relayclient将会是NULL.

  relayclient = env_get("RELAYCLIENT");

  dohelo(remotehost);

  }

  stralloc addr = {0}; /* will be 0-terminated, if addrparse returns 1 */

  //对命令参数arg进行邮件地址分析

  //并将分离出的email地址存入全局缓存addr

  //成功返回值为1,失败返回0

  int addrparse(arg)

  char *arg;

  {

  int i;

  char ch;

  char terminator;

  struct ip_address ip;

  int flagesc;

  int flagquoted;

  //分离出邮件地址

  //例如: arg="",或 arg=": email@eg.org "

  //执行下面这段程式后arg="email@eg.org"

  terminator = '>';

  i = str_chr(arg,'<');

  if (arg[i])

  arg += i + 1;

  else { /* partner should go read rfc 821 */

  terminator = ' ';

  arg += str_chr(arg,':');

  if (*arg == ':') ++arg;

  while (*arg == ' ') ++arg;

  }

  /* strip source route */

  if (*arg == '@') while (*arg) if (*arg++ == ':') break;

  if (!stralloc_copys(&addr,"")) die_nomem();

  flagesc = 0;

  flagquoted = 0;

  for (i = 0;ch = arg[i];++i) { /* copy arg to addr, stripping quotes */
Linux联盟收集整理

频道声明:本频道的文章除部分特别声明禁止转载的专稿外,可以自由转载.但请务必注明出出处和原始作者 文章版权归本频道与文章作者所有.对于被频道转载文章的个人和网站,我们表示深深的谢意。

原始作者:佚名 录入时间:2007-1-2 3:24:20
信息来源:不详 投稿信箱:itqoo@126.com
教程录入:itqoo    责任编辑:itqoo 
  • 上一个教程:

  • 下一个教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    - 关于我们 - 合作伙伴 - 友情链接 - 广告刊登 - 投稿热线 - 在线留言版权声明联系方式 -
    IT公社版权所有 粤ICP备05127012号
    Copyrigh@2005-2006 itqoo.com.Inc All Rights Reserved  推荐分辨率 1024*768
    联系站长:E-Mail:itqoo@126.com     MSN:urchincc@hotmail.com    QQ:点击这里给我发消息
    特别感谢:亿太网络提供空间支持