zoukankan      html  css  js  c++  java
  • VC++分析数据包实现SMTP协议分析


    SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式。SMTP协议属于TCP/IP协议族,它帮助每台计算机在发送或中转信件时找到下一个目的地。通过SMTP协议所指定的服务器,就可以把E-mail寄到收信人的服务器上了,整个过程只要几分钟。SMTP服务器则是遵循SMTP协议的发送邮件服务器,用来发送或中转发出的电子邮件。
     SMTP 是一种TCP协议支持的提供可靠且有效电子邮件传输的应用层协议。SMTP 是建立在 FTP 文件传输服务上的一种邮件服务,主要用于传输系统之间的邮件信息并提供来信有关的通知。
      SMTP 独立于特定的传输子系统,且只需要可靠有序的数据流信道支持。SMTP 重要特性之一是其能跨越网络传输邮件,即“ SMTP 邮件中继”。通常,  SMTP一个网络可以由公用互联网上 TCP 可相互访问的主机、防火墙分隔的 TCP/IP 网络上 TCP 可相互访问的主机,及其它 LAN/WAN 中的主机利用非 TCP 传输层协议组成。使用 SMTP ,可实现相同网络上处理机之间的邮件传输,也可通过中继器或网关实现某处理机与其它网络之间的邮件传输。
      在这种方式下,邮件的发送可能经过从发送端到接收端路径上的大量中间中继器或网关主机。域名服务系统(DNS)的邮件交换服务器可以用来识别出传输邮件的下一条 IP 地址。
      在传输文件过程中使用端口:25


    协议原理


      SMTP-简单邮件传输协议(SimpleMailTransferProtocol),是定义邮件传输的协议,它是基于TCP服务的应用层协议,由RFC821所定义。SMTP协议规定的命令是以明文方式进行的。为了说明SMTP的工作原理,我们以向163发送邮件为实例进行说明。
      在linux环境下,使用"telnet smtp.163. com 25"连接smtp.163. com的25号端口(SMTP的标准服务端口);在windows下使用telnet程序,远程主机指定为smtp.163. com,而端口号指定为25,然后连接smtp.163. com:交互过程如下:  SMTP[lix@nslix]$telnet smtp.163. com 25
      220 163 .com Anti-spam GT for Coremail System (163com[071018])
      HELO smtp.163 .com
      250 OK
      auth login
      334 dXNlcm5hbWU6
      USER base64加密后的用户名
      334 UGFzc3dvcmQ6
      PASS base64加密后的密码
      235 Authentication successful
      MAILFROM:XXX@163 .COM
      250 Mail OK
      RCPTTO:XXX@163 .COM
      250 Mail OK
      DATA
      354 End data with .
      QUIT  SMTP250 Mail OK queued as smtp5,D9GowLArizfIFTpIxFX8AA==.41385S2 1211766217
      HELO是客户向对方邮件服务器发出的标识自己的身份的命令,这里假设发送者为ideal;MAILFROM命令用来表示发送者的邮件地址;RCPTTO:标识接收者的邮件地址,这里表示希望发送邮件给XXX@163. COM,如果邮件接收者不是本地用户,例如RCPTTO:ideal,则说明希望对方邮件服务器为自己转发(Relay)邮件,若该机器允许转发这样的邮件,则表示该邮件服务器是OPENRELAY的,否则说明该服务器不允许RELAY;DATA表示下面是邮件的数据部分,输入完毕以后,以一个"."开始的行作为数据部分的结束标识;QUIT表示退出这次会话,结束邮件发送。
      这就是一个简单的发送邮件的会话过程,其实当使用outlookexpress等客户软件发送时,后台进行的交互也是这样的,当然,SMTP协议为了处理复杂的邮件发送情况如附件等等,定义了很多的命令及规定,具体可以通过阅读RFC821来获得。
      当你的一个朋友向你发送邮件时,他的邮件服务器和你的邮件服务器通过S  SMTPMTP协议通信,将邮件传递给你邮件地址所指示的邮件服务器上(这里假设你的本地邮件服务器是Linux系统),若你通过telnet协议直接登录到邮件服务器上,则可以使用mail等客户软件直接阅读邮件,但是若你希望使用本地的MUA(MailUserAgent,如outlookexpress等客户软件)来阅读邮件,则本地客户端通过POP3或IMAP协议与邮件服务器交互,将邮件信息传递到客户端(如:win98系统)。而如果你向你的朋友回复一封信件时,你所使用的MUA也是通过SMTP协议与邮件服务(一般为发送邮件地址对应的email地址)器通信,指示其希望邮件服务器帮助转发一封邮件到你朋友的邮件地址指定的邮件服务器中。若本地邮件服务器允许你通过它转发邮件,则服务器通过SMTP协议发送邮件到对方的邮件服务器。这就是接受和发送邮件的全部过程。


    配置方法


    安装POP3和SMTP
      Windows Server 2003默认情况下是没有安装POP3和SMTP服务组件的,因此我们要手工添加。
      1.安装POP3服务组件
      以系统管理员身份登录Windows Server 2003 系统。依次进入“控制面板→添加或删除程序→添加/删除Windows组件”,在弹出的“Windows组件向导”对话框中选中“电子邮件服务”选项,点击“详细信息”按钮,可以看到该选项包括两部分内容:POP3服务和POP3服务Web管理。为方便用户远程Web方式管理邮件服务器,建议选中“POP 3服务Web管理”。
      2.安装SMTP服务组件
      选中“应用程序服务器”选项,点击“详细信息”按钮,接着在“Internet信息服务(IIS)”选项中查看详细信息,选中“SMTP Service”选项,最后点击“确定”按钮。此外,如果用户需要对邮件服务器进行远程Web管理,一定要选中“万维网服务”中的“远程管理(HTML)”组件。完成以上设置后,点击“下一步”按钮,系统就开始安装配置POP3和SMTP服务了。
    配置POP3服务器
      1.创建邮件域
      点击“开始→管理工具→POP3服务”,弹出POP3服务控制台窗口。选中左栏中的POP3服务后,点击右栏中的“新域”,弹出“添加域”对话框,接着在“域名”栏中输入邮件服务器的域名,也就是邮件地址“@”后面的部分,
      2.创建用户邮箱
      选中刚才新建的,在右栏中点击“添加邮箱”,弹出添加邮箱对话框,在“邮箱名”栏中输入邮件用户名,然后设置用户密码,最后点击“确定”按钮,完成邮箱的创建。
      完成POP3服务器的配置后,就可开始配置SMTP服务器了。点击“开始→程序→管理工具→Internet信息服务(IIS)管理器”,在“IIS管理器”窗口中右键点击“默认SMTP虚拟服务器”选项,在弹出的菜单中选中“属性”,进入“默认SM TP虚拟服务器”窗口,切换到“常规”标签页,在“IP地址”下拉列表框中选中邮件服务器的IP地址即可。点击“确定”按钮,此时SMTP服务器默认的是匿名访问,打开切换到“访问”标签页,点击“身份验证”按钮,在对话框中去掉“匿名访问“选项,选中”基本身份验证(Basic authentication)“。这样一个简单的邮件服务器就架设完成了。


    工作机制


      SMTP通常有两种工作模式:发送SMTP和接收SMTP。具体工作方式为:发送SMTP在接到用户的邮件请求后,判断此邮件是否为本地邮件,若是直接投送到用户的邮箱,否则向dns查询远端邮件服务器的MX纪录,并建立与远端接收SMTP之间的一个双向传送通道,此后SMTP命令由发送SMTP发出,由接收SMTP接收,而应答则反方面传送。一旦传送通道建立,SMTP发送者发送MAIL命令指明邮件发送者。如果SMTP接收者可以接收邮件则返回OK应答。SMTP发送者再发出RCPT命令确认邮件是否接收到。如果SMTP接收者接收,则返回OK应答;如果不能接收到,则发出拒绝接收应答(但不中止整个邮件操作),双方将如此重复多次。当接收者收到全部邮件后会接收到特别的序列,如果接收者成功处理了邮件,则返回OK应答即可。


    工作过程


      简单邮件传输协议(SMTP)是一种基于文本的电子邮件传输协议,是在因特网中用于在邮件服务器之间交换邮件的协议。SMTP是应用层的服务,可以适应于各种网络系统。
      SMTP的命令和响应都是基于文本,以命令行为单位,换行符为CR/LF。响应信息一般只有一行,由一个3位数的代码开始,后面可附上很简短的文字说明。  SMTPSMTP要经过建立连接、传送邮件和释放连接3个阶段。具体为:
      (1)建立TCP连接。
      (2)客户端向服务器发送HELLO命令以标识发件人自己的身份,然后客户端发送MAIL命令。
      (3)服务器端以OK作为响应,表示准备接收。
      (4)客户端发送RCPT命令。
      (5)服务器端表示是否愿意为收件人接收邮件。
      (6)协商结束,发送邮件,用命令DATA发送输入内容。
      (7)结束此次发送,用QUIT命令退出。
      SMTP服务器基于DNS中的邮件交换(MX)记录路由电子邮件。电子邮件系统发邮件时是根据收信人的地址后缀来定位邮件服务器的。SMTP通过用户代理程序(UA)完成邮件的编辑、收取和阅读等功能;通过邮件传输代理程序(MTA)将邮件传送到目的地。


    X.25上应用


      1.本备忘录的状态
      本备忘录讲述了一种基于CCITT的X.25标准提供的虚电路业务的SMTP标准。
      本备忘录的发布不受任何限制。
      2.简介
      在RFC821("SIMPLEMAILTRANSPORTPROTOCOL",SMTP,简单邮件传输协议)
      的附录D中提到了直接将SMTP置于X.25虚电路(ISO第3层)上的可能性。并建议“利
      用一种类似于TCP可靠的端到端协议在X.25的连接上”。在1981年时,考虑到PSDNs的
      总体的可靠性,这毫无疑问是可行的。这一业务现在(1989年)已经非常可靠,它允许直
      接将其置于虚电路业务上。
      在包括22个不同的国家的24个PSDN网的许多产品,证明了这种方法是成功的,结
      果证明,即使使用在一些花费比较昂贵的PSDN中,这种方法还是十分经济的,在X.25专
      网和X.25局域网中,这种方法也是成功。
      每一个SMTP会话必须打开一条X.25虚电路(VirtualCircuit,VC),SMTP会话将
      使用由VC提供的全双工通道。通常,VC是由发起呼叫的一方关闭的。
      3.协议ID和呼叫用户数据
      呼叫用户数据区的前4个字节应该是0xC0F7,0000(十六进制),十进制是19224700。
      这个字段通常用来标识一个协议ID,或者PRID。
      但是在实际的操作中,应该有能力在基本前缀地址上配置呼叫用户数据,包括协议ID
      字段。
      4.数据流
      在发送端通常把SMTP数据分成许多数据包,相应地,在数据包封装的时候应该置M
      位(表示有后续数据包)。数据包的总长度可以达到2048个字节。
      通常我们建议SMTP命令和响应应在一个数据包发送出去,或者只有一个后续数据包。
      只要对调试协议方便即可。但这并不要求是必须的。
      5.识别数据
      Q比特被置位的分组和中断分组是没有用的。如果收到了,应该被忽略掉。
      6.电路复位
      如果收到了一个3层的电路复位指示,这条VC应该清除,SMTP连接应该重新建立。
      重新建立会带来一些时延,也可能是不同的呼叫业务。
      7.呼叫业务
      任何被X.25呼叫请求业务选择的协商特征都可以使用。使用时应有能力为每一个被叫
      地址指定业务。
      8.字符编码
      X.25使用的字符编码是完整的8位ASCII码,没有任何遗漏和修改。一行应该以CRLF
      (十进制:1310)结尾,也可以仅仅以LF(十进制:10)来标识一行的结束。
      9.关闭连接
      跟TCP协议不同,在清除请求的过程中,X.25不提供数据的同步传送;当清除虚电
      路时,就丢弃所有正在传送的数据包。因此,当收到“服务关闭”消息时,主叫的一边关闭
      SMTP会话层(在X.25上),这种消息要么是QUIT命令的响应,或者是因为服务必须中止。
      10.超时  SMTPSMTP通常不提供超时会话,在X.25,以下几项是有效的:
      10.1呼叫请求
      如果在100秒内没有收到“呼叫接受”信息,或者在120秒(另外)内没有收到“服
      务准备好”信息,那么应该清除这次呼叫,然后重试。
      10.2已经建立的呼叫
      当协议会话建立之后,在10分钟内如果没有收到任何响应,那么就应该清除这条虚
      电路。
      10.3关闭
      执行QUIT命令后,超时时间缩短为20秒。这可能会导致不经意地退出,但它不会影
      响已经完成的SMTP业务。
      10.4清除
      当X.25“清除请求”发出时,这条虚电路将在X.25协议指定的时间内超时。
      11.其他特性
      X.25的其他特性,如永久虚电路和D比特的选择,都没有用到。


    垃圾邮件


      最初的SMTP的局限之一在于它没有对发送方进行身份验证的机制。因此,后来定义了SMTP-AUTH扩展。
      尽管有了身份认证机制,垃圾邮件仍然是一个主要的问题。但由于庞大的SMTP安装数量带来的网络效应,大刀阔斧地修改或完全替代SMTP被认为是不现实的。Internet Mail 2000就是一个替代SMTP的建议方案。
      因此,出现了一些同SMTP工作的辅助协议。IRTF的反垃圾邮件研究小组正在研究一些建议方案,以提供简单、灵活、轻量级的、可升级的源端认证。最有可能被接受的建议方案是发送方策略框架协议。
      SMTP模型
      smtp提供了一种邮件传输的机制,当收件方和发件方都在一个网络上时,可以把邮件直传给对方;当双方不在同一个网络上时,需要通过一个或几个中间服务器转发。smtp首先由发件方提出申请,要求与接收方smtp建立双向的通信渠道,收件方可以是最终收件人也可以是中间转发的服务器。收件方服务器确认可以建立连接后,双发就可以开始通信。
      发件方smtp向收件方发处mail命令,告知发件方的身份;如果收件方接受,就会回答ok。发件方再发出rcpt命令,告知收件人的身份,收件方smtp确认是否接收或转发,如果同意就回答ok;接下来就可以进行数据传输了。通信过程中,发件方smtp与收件方smtp 采用对话式的交互方式,发件方提出要求,收件方进行确认,确认后才进行下一步的动作。整个过程由发件方控制,有时需要确认几回才可以。
      为了保证回复命令的有效,smtp要求发件方必须提供接收方的服务器及邮箱。邮件的命令和答复有严格的语法定义,并且回复具有相应的数字代码。所有的命令由ascii码组成。命令代码是大小写无关的,如mail和 mail ﹑mail是等效的。


    服务扩展


      SMTP提供一种可靠的有效的传送机制,它用于传送电子邮件。虽然十几年来,它的作用已经有目共睹,可是对它功能的扩充也是必不可少的。对SMTP服务的扩展我们介绍一下:在SMTP转发的邮件中包括信封和内容这两种东西。我们写信也写信封和信皮,我们可以借生活中的信件来帮助理解。
      (1)SMTP信封比较容易理解,它被作为一系列的SMTP协议单元传送,它包括发送者地址,传送模式,还有一个或多个接收者地址。如果有不清楚的地方,请参阅《SMTP协议标准》。
        SMTP(2)至于内容,它是由两部分组成的,一部分是信头,一部分是信体,信头是由一个个的域/值对(一个域,一个值)组成的,如果信体有结构的话,它的结构是以MIME构造的。内容从根本上来说是文本的,一般也是由ASCII码构成的,但是由于使用了MIME,所以这个限制应该也是没有了,但信头却不行,一般都应该使用ASCII码表示。虽然SMTP协议是一个不错的协议,可是对它的扩展还是不可避免,本文主要说明了一种扩展方法,使用这种扩展方法,服务器和用户之间可以相互知道对方使用了扩展,使用了多少,如果进行通信。


    通讯模型


      SMTP协议是TCP/IP协议族中的一员,主要对如何将电子邮件从发送方地址传送到接收方地址,也即是对传输的规则做了规定。SMTP协议的通信模型并不复杂,主要工作集中在发送SMTP和接收SMTP上:首先针对用户发出的邮件请求,由发送SMTP建立一条连接到接收SMTP的双工通讯链路,这里的接收SMTP是相对于发送SMTP而言的,实际上它既可以是最终的接收者也可以是中间传送者。发送SMTP负责向接收SMTP发送SMTP命令,而接收SMTP则负责接收并反馈应答。SMTP协议的命令和应答
      从前面的通讯模型可以看出SMTP协议在发送SMTP和接收SMTP之间的会话是靠发送SMTP的SMTP命令和接收SMTP反馈的应答来完成的。在通讯链路建立后,发送SMTP发送MAIL命令指令邮件发送者,若接收SMTP此时可以接收邮件则作出OK的应答,然后发送SMTP继续发出RCPT命令以确认邮件是否收到,如果接收到就作出OK的应答,否则就发出拒绝接收应答,但这并不会对整个邮件操作造成影响。双方如此反复多次,直至邮件处理完毕。SMTP协议共包含10个SMTP命令,列表如下:
      SMTP命令命令说明
      HELLO<domain><CRLF>;识别发送方到接收SMTP的一个HELLO命令
      MAILFROM:<reverse-path><CRLF><reverse-path>;为发送者地址。此命令告诉接收方一个新邮件发送的开始,并对所有的状态和缓冲区进行初始化。此命令开始一个邮件传输处理,最终完成将邮件数据传送到一个或多个邮箱中。
      RCPTTO:<forward-path><CRLF><forward-path>;标识各个邮件接收者的地址
      DATA<CRLF>
      接收SMTP将把其后的行为看作邮件数据去处理,以<CRLF>.<CRLF>;标识数据的结尾。
      REST<CRLF>;退出/复位当前的邮件传输
      NOOP<CRLF>;要求接收SMTP仅做OK应答。(用于测试)
      QUIT<CRLF>;要求接收SMTP返回一个OK应答并关闭传输。
      VRFY<string><CRLF>;验证指定的邮箱是否存在,由于安全因素,服务器多禁止此命令。
      EXPN<string><CRLF>;验证给定的邮箱列表是否存在,扩充邮箱列表,也常禁止使用。
      HELP<CRLF>;查询服务器支持什么命令


    通信安全


      sendmail是在Unix环境下使用最广泛的实现邮件发送/接受的邮件传输代理程序。由于Sendmail邮件服务器的特点是功能强大而复杂,因此为保证Sendmail的安全性,需要作以下一些工作。
      1、设置Sendmail使用"smrsh"
      smrsh程序的目的是作为在mailer中为sendmail定义的"/bin/sh"的替代shell。smrsh是一种受限shell工具,它通过"/
      etc/smrsh"目录来明确指定可执行文件的列表。简而言之smrsh限制了攻击者可以执行的程序集。当它与sendmail程序一起使用的时候,smrsh有效的将sendmail可以执行的程序的范围限制在smrsh目录之下。
      第一步:
      决定smrsh可以允许sendmail运行的命令列表。缺省情况下应当包含以下命令,但不局限于这些命令:
      "/bin/mail"(如果在你的系统中安装了的话)
      "/usr/bin/procmail"(如果在你的系统中安装了的话)
      注意:不可在命令列表里包括命令解释程序,例如sh(1),csh(1),perl(1),uudecode(1)及流编辑器sed(1)。
      第二步:
      在"/etc/smrsh"目录中创建允许sendmail运行的程序的符号连接。
      使用以下命令允许mail程序"/bin/mail"运行:
      [root@deep]#cd/etc/smrsh
      [root@deep]#ln-s/bin/mailmail
      用以下命令允许procmail程序"/usr/bin/procmail"运行:
      [root@deep]#cd/etc/smrsh
      [root@deep]#ln-s/usr/bin/procmailprocmail
      这将允许位于".forward"和"aliases"中的用户采用"|program"语法来运行mail及procmail程序。
      第三步
      配置sendmail使之使用受限shell。mailer程序在sendmail的配置文件"/etc/sendmail .cf"中仅有一行。必须修改"sendmail. cf"文件中"Mprog"定义的那一行。将"/bin/sh"替换为"/usr/sbin/smrsh"。
      编辑"sendmail .cf"文件(vi/etc/sendmail. cf)并改动下面这一行:
      例如:
      Mprog,P=/bin/sh,F=lsDFMoqeu9,S=10/30,R=20/40,D=$z:/,T=X-Unix,A=sh-c$u
      应该被改为:
      Mprog,P=/usr/sbin/smrsh,F=lsDFMoqeu9,S=10/30,R=20/40,D=$z:/,T=X-Unix,A=sh-c$u
      现在用以下命令手工重起sendmail进程:
      [root@deep]#/etc/rc.d/init.d/sendmailrestart
      2、"/etc/aliases"文件
      如果没有加以正确和严格的管理的话,别名文件被用来获取特权。例如,很多发行版本在别名文件中带有"decode"别名。现在这种情况越来越少了。
      这样做的目的是为用户提供一个通过mail传输二进制文件的方便的方式。在邮件的发送地,用户把二进制文件用"uuencode"转换成ASCII格式,并把结果邮递给接收地"decode"别名。那个别名通过管道把邮件消息发送到"/usr/bin/uuencode"程序,由这个程序来完成从ASCII转回到原始的二进制文件的工作。
      删除"decode"别名。类似的,对于所有用于执行没有被放在smrsh目录下的程序的别名,你都要仔细的检查,可能它们都值得怀疑并应当删除它们。要想使你的改变生效,需要运行:
      [root@deep]#/usr/bin/newaliases
      编辑别名文件(vi/etc/aliases)并删除以下各行:
      #Basicsystemaliases--theseMUSTbepresent.
      MAILER-DAEMON:postmaster
      postmaster:root
      #Generalredirectionsforpseudoaccounts.
      bin:root
      daemon:root
      games:root??删除这一行
      ingres:root??删除这一行
      nobody:root
      system:root??删除这一行
      toor:root??删除这一行
      uucp:root??删除这一行
      #Well-knownaliases.
      manager:root??删除这一行
      dumper:root??删除这一行
      operator:root??删除这一行
      #trapdecodetocatchsecurityattacks
      decode:root??删除这一行
      #Personwhoshouldgetroot'smail
      #root:marc
      最后应该运行"/usr/bin/newaliases"程序使改动生效
      3、避免你的Sendmail被未授权的用户滥用
      最新版本的Sendmail(8.9.3)加入了很强的防止欺骗的特性。它们可以防止你的邮件服务器被未授权的用户滥用。编辑你的"/etc/sendmail.c f"文件,修改一下这个配置文件,使你的邮件服务器能够挡住欺骗邮件。
      编辑"sendmail.c f"文件(vi/etc/sendmail. cf)并更改下面一行:
      OPrivacyOptions=authwarnings
      改为:
      OPrivacyOptions=authwarnings,noexpn,novrfy
      设置"noexpn"使sendmail禁止所有SMTP的"EXPN"命令,它也使sendmail拒绝所有SMTP的"VERB"命令。设置"novrfy"使sendmail禁止所有SMTP的"VRFY"命令。这种更改可以防止欺骗者使用"EXPN"和"VRFY"命令,而这些命令恰恰被那些不守规矩的人所滥用。
      4、SMTP的问候信息
      当sendmail接受一个SMTP连接的时候,它会向那台机器发送一个问候信息,这些信息作为本台主机的标识,而且它所做的第一件事就是告诉对方它已经准备好了。
      编辑"sendmail. cf"文件(vi/etc/sendmail. cf)并更改下面一行:
      OSmtpGreetingMessage=$jSendmail$v/$Z;$b
      改为:
      OSmtpGreetingMessage=$jSendmail$v/$Z;$bNOUCEC=xxL=xx
      现在手工重起一下sendmail进程,使刚才所做的更改生效:
      [root@deep]#/etc/rc.d/init.d/sendmailrestart
      以上的更改将影响到Sendmail在接收一个连接时所显示的标志信息。你应该把"`C=xxL=xx"条目中的"xx"换成你所在的国家和地区代码。后面的更改其实不会影响任何东西。但这是"news.admin.net-abuse.email"新闻组的伙伴们推荐的合法做法。
      5、限制可以审核邮件队列内容的人员
      通常情况下,任何人都可以使用"mailq"命令来查看邮件队列的内容。为了限制可以审核邮件队列内容的人员,只需要在"/etc/sendmail .cf"文件中指定"restrictmailq"选项即可。在这种情况下,sendmail只允许与这个队列所在目录的组属主相同的用户可以查看它的内容。这将允许权限为0700的邮件队列目录被完全保护起来,而我们限定的合法用户仍然可以看到它的内容。
      编辑"sendmail. cf"文件(vi/etc/sendmail. cf)并更改下面一行:
      OPrivacyOptions=authwarnings,noexpn,novrfy
      改为:
      OPrivacyOptions=authwarnings,noexpn,novrfy,restrictmailq
      现在我们更改邮件队列目录的权限使它被完全保护起来:
      [root@deep]#chmod0700/var/spool/mqueue
      注意:我们已经在sendmail.c f中的"PrivacyOptions="行中添加了"noexpn"和"novrfy"选项,现在在这一行中我们接着添加"restrictmailq"选项。
      任何一个没有特权的用户如果试图查看邮件队列的内容会收到下面的信息:
      [user@deep]$/usr/bin/mailq
      Youarenotpermittedtoseethequeue
      SMTP
      6、限制处理邮件队列的权限为"root"
      通常,任何人都可以使用"-q"开关来处理邮件队列,为限制只允许root处理邮件队列,需要在"/etc/sendma il. cf"文件中指定"restrictqrun"。
      编辑"sendmail. cf"文件(vi/etc/sendmail. cf)并更改下面一行:
      OPrivacyOptions=authwarnings,noexpn,novrfy,restrictmailq
      改为:
      OPrivacyOptions=authwarnings,noexpn,novrfy,restrictmailq,restrictqrun
      任何一个没有特权的用户如果试图处理邮件队列的内容会收到下面的信息:
      [user@deep]$/usr/sbin/sendmail-q
      Youdonothavepermissiontoprocessthequeue
      7、在重要的sendmail文件上设置不可更改位
      可以通过使用"chattr"命令而使重要的Sendmail文件不会被擅自更改,可以提高系统的安全性。具有"+i"属性的文件不能被修改:它不能被删除和改名,不能创建到这个文件的链接,不能向这个文件写入数据。只有超级用户才能设置和清除这个属性。
      为"sendmail. cf"文件设置不可更改位:
      [root@deep]#chattr+i/etc/sendmail. cf
      为"sendmail.cw"文件设置不可更改位:
      [root@deep]#chattr+i/etc/sendmail.cw
      为"sendmail. mc"文件设置不可更改位:
      [root@deep]#chattr+i/etc/sendmail. mc
      为"null. mc"文件设置不可更改位:
      [root@deep]#chattr+i/etc/null. mc
      为"aliases"文件设置不可更改位:
      [root@deep]#chattr+i/etc/aliases
      为"access"文件设置不可更改位:
      [root@deep]#chattr+i/etc/mail/access
      qmail安全
      qmail有一个名为rcpthosts(该文件名源于RCPTTO命令)的配置文件,其决定了是否接受一个邮件。只有当一个RCPTTO命令中的接收者地址的域名存在于rcpthosts文件中时,才接受该邮件,否则就拒绝该邮件。若该文件不存在,则所有的邮件将被接受。当一个邮件服务器不管邮件接收者和邮件接收者是谁,而是对所有邮件进行转发(relay),则该邮件服务器就被称为开放转发(openrelay)的。当qmail服务器没有rcpthosts时,其是开放转发的。
      设置自己服务器为非openrelay的最简单的办法就是将你的邮件服务器的所有域名(若DNS的MX记录指向该机器,也应该包括该域名。但是这将导致你的本地客户也被拒绝使用你的服务器转发邮件,而要支持客户使用MUA来发送邮件,必须允许客户使用服务器转发邮件。qmail-smtpd支持一种有选择性的忽略rcpthosts文件的方法:若qmail-smtpd的环境变量RELAYCLIENT被设置,则rcpthost文件将被忽略,relay将被允许。但是如何识别一个邮件发送者是否是自己的客户呢?qmail并没有采用密码认证的方法,而是判断发送邮件者的源IP地址,若该IP地址属于本地网络,则认为该发送者为自己的客户。
      这里就要使用ucspi-tcp软件包。在这里我们要使用该软件包的tcpserver程序。该程序的功能类似于inetd-监听进入的连接请求,为要启动的服务设置各种环境变量,然后启动指定的服务。
      tcpserver的配置文件是/etc/tcp.smtp,该文件定义了是否对某个网络设置RELAYCLIENT环境变量。例如,本地网络是地址为192.168.10.0/24的C类地址,则tcp.smtp的内容应该设置如下:
      127.0.0.1:allow,RELAYCLIENT=""
      192.168.10.:allow,RELAYCLIENT=""
      :allow
      这几个规则的含义是指若连接来自127.0.0.1和192.168.10则允许,并且为其设置环境变量RELAYCLIENT,否则允许其他连接,但是不设置RELAYCLIENT环境变量。这样当从其他地方到本地的25号连接将会被允许,但是由于没有被设置环境变量,所以其连接将会被qmail-smptd所拒绝。
      但是tcopserver并不直接使用/etc/tcp.smtp文件,而是需要先将该文件转化为cbd文件:
      [lix@mail/etc]$#tcprulestcp.smtp.cdbtcp.smtp.temp<tcp.smtp
      然后再回头看在/service/qmail-smtpd目录下的run文件中有
      /usr/local/bin/tcpserver-v-p-x/etc/tcp.smtp.cdb
      可以看到,tcpserver利用了/etc/smtp.cbd文件。若本地有多个网络,则需要这些网络都出现在/etc/tcp.smtp文件中。
      这样就实现了允许本地客户relay邮件,而防止relay被滥用。









    #include "nids.h"   
    char ascii_string[10000];   
    char *char_to_ascii(char ch)   
    {   
        char *string;   
        ascii_string[0] = 0;   
        string = ascii_string;   
        if (isgraph(ch))   
            *string++ = ch;   
        else if (ch == ' ')   
            *string++ = ch;   
        else if (ch == '\n' || ch == '\r')   
            *string++ = ch;   
        else   
            *string++ = '.';   
        *string = 0;   
        return ascii_string;   
    }   
    /*  
    =======================================================================================================================  
    下面是分析SMTP协议的回调函数  
    =======================================================================================================================  
     */   
    void smtp_protocol_callback(struct tcp_stream *smtp_connection, void **arg)   
    {   
        int i;   
        char address_string[1024];   
        char content[65535];   
        char content_urgent[65535];   
        struct tuple4 ip_and_port = smtp_connection->addr;   
        strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
        sprintf(address_string + strlen(address_string), " : %i", ip_and_port.source);   
        strcat(address_string, " <---> ");   
        strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
        sprintf(address_string + strlen(address_string), " : %i", ip_and_port.dest);   
        strcat(address_string, "\n");   
        switch (smtp_connection->nids_state)   
        {   
            case NIDS_JUST_EST:   
                if (smtp_connection->addr.dest == 25)   
                {   
                    /* SMTP客户端和SMTP服务器端建立连接 */   
                    smtp_connection->client.collect++;   
                    /* SMTP客户端接收数据 */   
                    smtp_connection->server.collect++;   
                    /* SMTP服务器接收数据 */   
                    smtp_connection->server.collect_urg++;   
                    /* SMTP服务器接收紧急数据 */   
                    smtp_connection->client.collect_urg++;   
                    /* SMTP客户端接收紧急数据 */   
                    printf("%sSMTP发送方与SMTP接收方建立连接\n", address_string);   
                }   
                return ;   
            case NIDS_CLOSE:   
                /* SMTP客户端与SMTP服务器连接正常关闭 */   
                printf("--------------------------------\n");   
                printf("%sSMTP发送方与SMTP接收方连接正常关闭\n", address_string);   
                return ;   
            case NIDS_RESET:   
                /* SMTP客户端与SMTP服务器连接被RST关闭 */   
                printf("--------------------------------\n");   
                printf("%sSMTP发送方与SMTP接收方连接被REST关闭\n", address_string);   
                return ;   
            case NIDS_DATA:   
                {   
                    /* SMTP协议接收到新的数据 */   
                    char status_code[4];   
                    struct half_stream *hlf;   
                    if (smtp_connection->server.count_new_urg)   
                    {   
                        /* SMTP服务器接收到新的紧急数据 */   
                        printf("--------------------------------\n");   
                        strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
                        sprintf(address_string + strlen(address_string), " : %i", ip_and_port.source);   
                        strcat(address_string, " urgent---> ");   
                        strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
                        sprintf(address_string + strlen(address_string), " : %i", ip_and_port.dest);   
                        strcat(address_string, "\n");   
                        address_string[strlen(address_string) + 1] = 0;   
                        address_string[strlen(address_string)] = smtp_connection->server.urgdata;   
                        printf("%s", address_string);   
                        return ;   
                    }   
                    if (smtp_connection->client.count_new_urg)   
                    {   
                        /* SMTP客户端接收到新的紧急数据 */   
                        printf("--------------------------------\n");   
                        strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
                        sprintf(address_string + strlen(address_string), " : %i", ip_and_port.source);   
                        strcat(address_string, " <--- urgent ");   
                        strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
                        sprintf(address_string + strlen(address_string), " : %i", ip_and_port.dest);   
                        strcat(address_string, "\n");   
                        address_string[strlen(address_string) + 1] = 0;   
                        address_string[strlen(address_string)] = smtp_connection->client.urgdata;   
                        printf("%s", address_string);   
                        return ;   
                    }   
                    if (smtp_connection->client.count_new)   
                    {   
                        /* SMTP客户端接收到新的数据 */   
                        hlf = &smtp_connection->client;   
                        strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
                        sprintf(address_string + strlen(address_string), ":%i", ip_and_port.source);   
                        strcat(address_string, " <--- ");   
                        strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
                        sprintf(address_string + strlen(address_string), ":%i", ip_and_port.dest);   
                        strcat(address_string, "\n");   
                        printf("--------------------------------\n");   
                        printf("%s", address_string);   
                        memcpy(content, hlf->data, hlf->count_new);   
                        content[hlf->count_new] = '\0';   
                        if (strstr(strncpy(status_code, content, 3), "221"))   
                            printf("连接中止\n");   
                        if (strstr(strncpy(status_code, content, 3), "250"))   
                            printf("操作成功\n");   
                        if (strstr(strncpy(status_code, content, 3), "220"))   
                            printf("表示服务就绪\n");   
                        if (strstr(strncpy(status_code, content, 3), "354"))   
                            printf("开始邮件输入,以\".\"结束\n");   
                        if (strstr(strncpy(status_code, content, 3), "334"))   
                            printf("服务器响应验证\n");   
                        if (strstr(strncpy(status_code, content, 3), "235"))   
                            printf("认证成功可以发送邮件了\n");   
                        for (i = 0; i < hlf->count_new; i++)   
                        {   
                            printf("%s", char_to_ascii(content[i]));   
                        }   
                        printf("\n");   
                    }   
                    else   
                    {   
                        /* SMTP服务器接收到新的数据 */   
                        hlf = &smtp_connection->server;   
                        strcpy(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.saddr))));   
                        sprintf(address_string + strlen(address_string), ":%i", ip_and_port.source);   
                        strcat(address_string, " ---> ");   
                        strcat(address_string, inet_ntoa(*((struct in_addr*) &(ip_and_port.daddr))));   
                        sprintf(address_string + strlen(address_string), ":%i", ip_and_port.dest);   
                        strcat(address_string, "\n");   
                        printf("--------------------------------\n");   
                        printf("%s", address_string);   
                        memcpy(content, hlf->data, hlf->count_new);   
                        content[hlf->count_new] = '\0';   
                        if (strstr(content, "EHLO"))   
                            printf("HELLO命令\n");   
                        if (strstr(content, "QUIT"))   
                            printf("退出连接\n");   
                        if (strstr(content, "DATA"))   
                            printf("开始传输数据\n");   
                        if (strstr(content, "MAIL FROM"))   
                            printf("发送方邮件地址为\n");   
                        if (strstr(content, "RCPT TO"))   
                            printf("接收方邮件地址为\n");   
                        if (strstr(content, "AUTH"))   
                            printf("请求认证\n");   
                        if (strstr(content, "LOGIN"))   
                            printf("认证机制为LOGIN\n");   
                        for (i = 0; i < hlf->count_new; i++)   
                        {   
                            printf("%s", char_to_ascii(content[i]));   
                        }   
                        printf("\n");   
                        if (strstr(content, "\n."))   
                            printf("数据传输结束\n");   
                    }   
                }   
            default:   
                break;   
        }   
        return ;   
    }   
    /*  
    =======================================================================================================================  
    主函数  
    =======================================================================================================================  
     */   
    void main()   
    {   
        if (!nids_init())   
         /* Libnids初始化 */   
        {   
            printf("%s\n", nids_errbuf);   
            exit(1);   
        }   
        nids_register_tcp(smtp_protocol_callback);   
        /* 注册分析TCP协议的回调函数 */   
        nids_run();   
        /* 进入循环捕获数据包状态 */   
    }   


  • 相关阅读:
    LeetCode——37. 解数独
    LeetCode ——42. 接雨水
    异常
    IO/FILE
    函数与模块
    选择与循环
    运算符
    字符串、列表、元组等
    SVTyper
    Error:Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-not69mld/pysam/
  • 原文地址:https://www.cnblogs.com/new0801/p/6177684.html
Copyright © 2011-2022 走看看