5.6.7 执行指令状态机

来源:互联网 发布:网络视频电话机 编辑:程序博客网 时间:2024/06/08 11:49

经过了以上的准备工作,从4973行开始正式进入指令循环(状态机)工作。

 

首先要进行一些前置操作:

1 smtpd_hard_error_limit限制判断与处理。

2 如果开启smtputf8支持,判断state->buffer是否满足utf8格式。

3 非规范命令处理。

4 将会话信息按单词读取到SMTPD_TOKEN结构体。

5 smtpd_noop_commands参数处理。

/smtpd/smtpd.c49694970        /*4971          * The command read/execute loop.4972          */4973        for (;;) {4974             if (state->flags &SMTPD_FLAG_HANGUP)4975                 break;4976             if (state->error_count >=var_smtpd_hard_erlim) {4977                 state->reason =REASON_ERROR_LIMIT;4978                 state->error_mask |=MAIL_ERROR_PROTOCOL;4979                 smtpd_chat_reply(state,"421 4.7.0 %s Error: too many errors",4980                                 var_myhostname);4981                 break;4982             }

4976-4982 smtpd_hard_error_limit限制判断与处理

4969-4982在3.8.2节我们已经介绍了smtpd_soft_error_limit和smtpd_hard_error_limit参数的作用。目前为止我们一直间接的通过smtpd_chat_replay判断state->error_count是否超过了smtpd_soft_error_limit限制。现在我们已经开始进入指令循环了,要在此之前要和恶意客户端做结算,进行smtpd_hard_error_limit限制判断,不与恶意客户端进行会话。

4983             watchdog_pat();4984             smtpd_chat_query(state);

4984 从客户端读取行,开启协议解析旅程。

4985             /* Safety: protect internalinterfaces against malformed UTF-8. */4986             if (var_smtputf8_enable &&valid_utf8_string(STR(state->buffer),4987                                                 LEN(state->buffer)) == 0) {4988                 state->error_mask |=MAIL_ERROR_PROTOCOL;4989                 smtpd_chat_reply(state,"500 5.5.2 Error: bad UTF-8 syntax");4990                 state->error_count++;4991                 continue;4992             }

如果开启smtputf8支持,判断state->buffer是否满足utf8格式

4986-4992 var_smtputf8_enable即参数smtputf8_enable,这是postfix3.0新增功能。当smtputf8_enable值为yes时,postfix可以接收utf-8格式的收发件人域名。这里我们先判断一下如果smtputf8_enable开启时,state->buffer会话内容是否是正确的utf8编码。

4993             /* Move into smtpd_chat_query()and update session transcript. */4994             if (smtpd_cmd_filter != 0) {4995                 for (cp =STR(state->buffer); *cp && IS_SPACE_TAB(*cp); cp++)4996                      /* void */ ;4997                 if ((cp =dict_get(smtpd_cmd_filter, cp)) != 0) {4998                     msg_info("%s:replacing command \"%.100s\" with \"%.100s\"",4999                              state->namaddr,STR(state->buffer), cp);5000                    vstring_strcpy(state->buffer, cp);5001                 } else if(smtpd_cmd_filter->error != 0) {5002                     msg_warn("%s:%slookup error for \"%.100s\"",5003                              smtpd_cmd_filter->type,smtpd_cmd_filter->name,5004                             printable(STR(state->buffer), '?'));5005                    vstream_longjmp(state->client, SMTP_ERR_DATA);5006                 }5007             }

非规范命令处理

4993-5007

postfix2.7中加入的smtpd_command_filter参数用来设置一个字典表,记录对于客户端收到的不规范而postfix又不想放弃处理的smtp会话请求。示例如下:

/etc/postfix/main.cf:
    smtpd_command_filter = pcre:/etc/postfix/command_filter
# Work around clients that send empty lines.
    /^\s*$/     NOOP

这里我们将客户端发送的空行视为smtp NOOP指令

 

smtpd_cmd_filter即为保存字典表信息的DICT结构体,在pre_jail_init函数中被初始化

if (*var_smtpd_cmd_filter)         smtpd_cmd_filter= dict_open(var_smtpd_cmd_filter, O_RDONLY,                                          DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);


var_smtpd_cmd_filter即参数smtpd_command_filter

 

这里我们搜索smtpd_cmd_filter,如果客户端请求在表中,则将state->buffer命令信息设置为字典文件中相应的规范值。因为我们在smtpd_cmd_talbe[]数组(见5.1.3节)中存放的都是规范命令,所以我们首先看一下是否有需要处理的不规范命令,否则如果先进行指令循环,则这些客户端发来的信息将被视为错误。

5008             if ((argc = smtpd_token(vstring_str(state->buffer),&argv)) == 0) {5009                 state->error_mask |=MAIL_ERROR_PROTOCOL;5010                 smtpd_chat_reply(state,"500 5.5.2 Error: bad syntax");5011                 state->error_count++;5012                 continue;5013            }

将会话信息按单词读取到SMTPD_TOKEN结构体。

5008-5013 我们用smtpd_token函数将从客户端得到的字符串转化为SMTPD_TOKEN结构体,该结构体将会话内容保存为字符串数组。

typedef struct SMTPD_TOKEN {   int     tokval;   char   *strval;   VSTRING *vstrval;} SMTPD_TOKEN;

         我们看一下单元测试的结果(见图5-5):


图5-5 smtpd_token函数测试结果

 

smtpd_token函数将mailfrom:zhangsan@163.com读成3个字符串,类型为other

SMTPD_TOKEN共有3个类型:

#define SMTPD_TOK_OTHER  0

#define SMTPD_TOK_ADDR    1

#define SMTPD_TOK_ERROR  2

5014             /* Ignore smtpd_noop_cmds lookuperrors. Non-critical feature. */5015             if (*var_smtpd_noop_cmds5016                 &&string_list_match(smtpd_noop_cmds, argv[0].strval)) {5017                 smtpd_chat_reply(state,"250 2.0.0 Ok");5018                 if (state->junk_cmds++ >var_smtpd_junk_cmd_limit)5019                     state->error_count++;5020                 continue;5021             }

smtpd_noop_commands参数处理

5014-5021 smtpd_noop_commands参数表示对于该参数指定的smtp命令,服务器直接返回250成功码。

0 0
原创粉丝点击