3.8.2 smtpd_chat_query和smtpd_chat_replay:与smtp客户端交互
来源:互联网 发布:js获取鼠标点击次数 编辑:程序博客网 时间:2024/05/20 09:07
VSTRING和VSTREAM用来支持postfix的上层逻辑。我们来看两个应用场景:
第一个场景:smtpd.c利用smtpd_chat_query和smtpd_chat_replay函数与客户端通信。
在smtpd.c中的smtp协议解析过程中,与客户端的通信在两个函数中完成:smtpd_chat_query和smtpd_chat_replay。也就是从客户端取得和回应一行。这两个函数为smtp会话过程封装了通信技术细节。它们通过逐步封装VSTING和VSTREAM实现。在协议解析过程中,我们主要关注于业务而非底层操作,VSTRING和VSTREAM可以为我们屏蔽底层操作细节。与smtp服务器通信的客户可能来自网络或控制台,但在协议解析中我们不必区分这些细节——VSTREAM已经帮我们封装了这些底层差别,他们都是“流”。
我们来看一下这里的“层层封装”的过程:
(1)smtpd_chat_query和smtpd_chat_replay调用smtp_get和smtp_fputs函数实现,同时提供自己的处理。
/smtpd/smtpd_chat.c中的smtpd_chat_query和smtpd_chat_replay函数通过/global/smtp_stream.c中的smtp_get和smtp_fputs函数实现。
/smtpd/smtpd_chat.c124 /* smtpd_chat_query - receive andrecord an SMTP request */125126 void smtpd_chat_query(SMTPD_STATE *state)127 {128 int last_char;129130 /*131 * We can't parse or store input that exceeds var_line_limit, so we skip132 * over it to avoid loss of synchronization.133 */134 last_char = smtp_get(state->buffer, state->client, var_line_limit,135 SMTP_GET_FLAG_SKIP);136 smtp_chat_append(state, "In: ", STR(state->buffer));137 if (last_char != '\n')138 msg_warn("%s: request longer than %d: %.30s...",139 state->namaddr,var_line_limit,140 printable(STR(state->buffer), '?'));141142 if (msg_verbose)143 msg_info("< %s: %s", state->namaddr,STR(state->buffer));144 }
smtpd_chat_query的实现较为简单,调用smtp_get从流得到行,调用smtp_chat_append函数记录历史数据:
/smtpd/smtpd_chat.c107 /* smtp_chat_append - append record toSMTP transaction log */108109 static voidsmtp_chat_append(SMTPD_STATE *state, char *direction,110 const char *text)111 {112 char *line;113114 if (state->notify_mask == 0)115 return;116117 if (state->history == 0)118 state->history = argv_alloc(10);119 line = concatenate(direction, text, (char *) 0);120 argv_add(state->history, line, (char *) 0);121 myfree(line);122 }
smtpd_chat_replay函数则较为复杂:
/smtpd/smtp_chat.c146 /* smtpd_chat_reply - format, send andrecord an SMTP response */147148 void smtpd_chat_reply(SMTPD_STATE *state, const char *format,...)149 {156 /*157 * Slow down clients that make errors. Sleep-on-anything slows down158 * clients that make an excessive number of errors within a session.159 */160 if (state->error_count >= var_smtpd_soft_erlim)161 sleep(delay = var_smtpd_err_sleep);
160 变量var_smtpd_soft_erlim,即在smtpd.c中main函数中初始化的postfix参数smtpd_soft_error_limit,默认值为10
由于网络上针对邮件系统的恶意客户端很多,所以postfix设置了很多保护自己安全的方式。smtpd_soft_error_limit和smtpd_hard_error_limit就是其中两个参数:如果客户端出错过多,表明客户端可能有问题或者有攻击倾向,如果出错数大于smtpd_soft_error_limit所设定的值,且不超过smtpd_hard_error_limit(默认20)的值,则服务器等待(sleep)smtp_error_sleep_time参数所定义的时间(默认一秒)。如果错误数大于smtpd_hard_error_limit的值,则切断连接。
postfix没有简单粗暴的对客户端出错直接断开连接,所以用户通过telnet进行客户端会话时,如果出现输入错误,依然有重试命令的机会。这两个参数的效果可以在命令行模式的smtp会话中通过重复输入错误命令来查看,在默认参数下,重复10次输入错误命令后,可能用户感觉不到这个1秒的延迟,但重复输入20次错误命令后,服务器将断开客户连接。
如果客户端违反postfix的ACL规则,将累加SMTPD_STATE->error_count。
也就是smtpd_chat_reply函数不仅仅是会给出响应代码,它同时控制着服务器对客户端的反应行为。
167 if (*var_smtpd_rej_footer168 && (*(cp = STR(state->buffer)) == '4' || *cp == '5'))169 smtp_reply_footer(state->buffer, 0, var_smtpd_rej_footer,170 STR(smtpd_expand_filter), smtpd_expand_lookup,171 (void *) state);
167 smtpd_reject_footer是postfix2.8新增的一个参数,用来在输出smtp出错信息的同时(响应码第一位为4或5时表示出错),输出一个“页脚”,也就是一些附加帮助信息。
我们看一下官方文档上的例子:
http://www.postfix.org/postconf.5.html#smtpd_reject_footer
/etc/postfix/main.cf:
smtpd_reject_footer = \c. For assistance, call 800-555-0101.
Please provide the following information in your problem report:
time ($localtime), client ($client_address) and server
($server_name).
Server response:
550-5.5.1 <user@example> Recipient address rejected: User
unknown. For assistance, call 800-555-0101. Please provide the
following information in your problem report: time (Jan 4 15:42:00),
client (192.168.1.248) and server (mail1.example.com).
172173 /* All 5xx replies must have a 5.xx.xx detail code. */174 for (cp = STR(state->buffer), end = cp + strlen(STR(state->buffer));;){175 if (var_soft_bounce) {176 if (cp[0] == '5') {177 cp[0] = '4';178 if (cp[4] == '5')179 cp[4] = '4';180 }181 }
175 var_soft_bounce即参数soft_bounce,postfix使用此参数测试内部ACL限制的生效情况。以5开头的smtp响应码为不可恢复错误,以4开头的为可恢复错误。设置soft_bounce=yes后,将把以5开头的smtp响应码改为以4开头,以方便测试ACL限制条件。
182 /* This is why we use strlen() above instead of VSTRING_LEN(). */183 if ((next = strstr(cp, "\r\n")) != 0) {184 *next = 0;185 if (next[2] != 0)186 cp[3] = '-'; /* contact footer kludge */187 else188 next = end; /* strip trailing \r\n */189 } else {190 next = end;191 }192 smtp_chat_append(state, "Out: ", cp);
192 记录响应历史数据。
193194 if (msg_verbose)195 msg_info("> %s: %s",state->namaddr, cp);196197 smtp_fputs(cp, next - cp, state->client);
197 调用smtp_fputs向客户端返回一行。
198 if (next < end)199 cp = next + 2;200 else201 break;202 }203204 /*205 * Flush unsent output if no I/O happened for a while. This avoids206 * timeouts with pipelined SMTPsessions that have lots of server-side207 * delays (tarpit delays or DNS lookups for UCE restrictions).208 */209 if (delay || time((time_t *) 0) - vstream_ftime(state->client) >10)210 vstream_fflush(state->client);211212 /*213 * Abort immediately if the connection is broken.214 */215 if (vstream_ftimeout(state->client))216 vstream_longjmp(state->client, SMTP_ERR_TIME);217 if (vstream_ferror(state->client))218 vstream_longjmp(state->client,SMTP_ERR_EOF);
215-218 如果出现SMTP_ERR_TIME或SMTP_ERR_EOF错误,使用siglongjmp跳到出错处理语句执行。这也是处理smtp会话中错误的一处例子。
219220 /*221 * Orderly disconnect in case of 421 or 521 reply.222 */223 if (strncmp(STR(state->buffer), "421", 3) == 0224 || strncmp(STR(state->buffer), "521", 3) == 0)225 state->flags |= SMTPD_FLAG_HANGUP;226 }
223-225 对421(服务未就绪或临时禁止远端ip连接)和521(拒绝远端ip访问)错误设置SMTPD_FLAG_HANGUP标记,切断连接。
接着逐级封装如下:
(2)smtp_get和smtp_fputs函数调用vstring_get和vstring_fputs实现,同时提供了换行符(CRLF)的处理。
(3) vstring_get和vstring_fput实现了真正的从流中取出行的操作。
(4)vstring_get和vstring_fput的操作最终在其VBUF里实现。- 3.8.2 smtpd_chat_query和smtpd_chat_replay:与smtp客户端交互
- Socket与SMTP交互
- 客户端SMTP和POP3举例
- 与客户端交互
- JsBridge与客户端交互
- 服务端与客户端交互
- JS 与 客户端交互
- 网关和客户端交互
- SMTP客户端
- android客户端 与服务器交互
- 客户端与服务器端交互原理
- web 服务端与客户端交互
- 客户端与服务端如何交互
- 服务端与客户端交互流程
- fms 服务器与客户端交互
- Android 客户端与服务器交互
- 客户端与服务器的交互
- IOS JS与客户端交互
- 详解Javascript中的Url编码/解码
- centos 7 配置apache2.x PHP5.4 mysql(MariaDB)环境
- c++中ceil、round、floor取整
- (转载)ARC forbids explicit message send of release-关闭xCode项目的ARC
- Java通过锁的顺序避免死锁
- 3.8.2 smtpd_chat_query和smtpd_chat_replay:与smtp客户端交互
- svo: semi-direct visual odometry 论文解析
- markdown以html显示
- Error:No such property: GROUP for class: org.gradle.api.publication.maven.in
- 搜索算法-二分搜索-方程解问题(problem 1001)
- TIPS:.gitignore忽略多层文件夹用**
- LeetCode 102, 103, 107. Binary Tree Level Order Traversal i, ii, Zigzag Level Order
- JAVA缓存技术
- spring mvc+mybatis+ spring 基于全注解事务配置