postfix_log_parser/events/
smtpd.rs

1use serde::{Deserialize, Serialize};
2
3/// SMTPD组件事件
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub enum SmtpdEvent {
6    /// 客户端连接
7    Connect {
8        client_ip: String,
9        client_hostname: String,
10        port: Option<u16>,
11    },
12    /// 客户端断开连接
13    Disconnect {
14        client_ip: String,
15        client_hostname: String,
16        port: Option<u16>,
17        /// SMTP命令统计信息
18        command_stats: Option<CommandStats>,
19    },
20    /// 连接丢失
21    LostConnection {
22        client_ip: String,
23        client_hostname: String,
24        /// 丢失连接时的SMTP命令
25        last_command: Option<String>,
26    },
27    /// 连接超时
28    Timeout {
29        client_ip: String,
30        client_hostname: String,
31        /// 超时时的SMTP命令
32        last_command: Option<String>,
33    },
34    /// 客户端邮件队列ID分配
35    ClientAssignment {
36        queue_id: String,
37        client_ip: String,
38        client_hostname: String,
39        port: Option<u16>,
40    },
41    /// SASL身份验证
42    Auth {
43        method: String,
44        username: String,
45        /// 认证是否成功
46        success: bool,
47        /// 失败原因(如果失败)
48        failure_reason: Option<String>,
49    },
50    /// 邮件被拒绝
51    Reject {
52        reason: String,
53        code: Option<u16>,
54        /// 拒绝类型(NOQUEUE, 普通拒绝等)
55        reject_type: RejectType,
56        /// 发送者地址
57        from: Option<String>,
58        /// 接收者地址
59        to: Option<String>,
60        /// 客户端信息
61        client_ip: Option<String>,
62        client_hostname: Option<String>,
63    },
64    /// NOQUEUE过滤器事件
65    NoQueueFilter {
66        client_ip: String,
67        client_hostname: String,
68        filter_info: String,
69        /// 触发的过滤器类型
70        filter_target: String,
71    },
72    /// HELO/EHLO命令
73    Helo {
74        hostname: String,
75        client_ip: Option<String>,
76        client_hostname: Option<String>,
77    },
78    /// 邮件接收完成
79    Accept {
80        from: Option<String>,
81        to: Vec<String>,
82        size: Option<u64>,
83        queue_id: Option<String>,
84    },
85    /// 协议违规
86    ProtocolViolation {
87        client_ip: String,
88        client_hostname: String,
89        violation_type: String,
90        details: String,
91    },
92    /// 系统警告
93    SystemWarning {
94        warning_type: String,
95        message: String,
96        client_info: Option<ClientInfo>,
97    },
98}
99
100/// SMTP命令统计信息
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct CommandStats {
103    pub ehlo: Option<u32>,
104    pub helo: Option<u32>,
105    pub mail: Option<u32>,
106    pub rcpt: Option<u32>,
107    pub data: Option<u32>,
108    pub bdat: Option<u32>,
109    pub quit: Option<u32>,
110    pub commands: Option<u32>,
111}
112
113/// 拒绝类型
114#[derive(Debug, Clone, Serialize, Deserialize)]
115pub enum RejectType {
116    /// NOQUEUE拒绝(邮件未进入队列)
117    NoQueue,
118    /// 队列拒绝(邮件已进入队列但被拒绝)
119    Queued,
120    /// 未知类型
121    Unknown,
122}
123
124/// 客户端信息
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct ClientInfo {
127    pub ip: String,
128    pub hostname: String,
129    pub port: Option<u16>,
130}
131
132impl SmtpdEvent {
133    pub fn event_type(&self) -> &'static str {
134        match self {
135            SmtpdEvent::Connect { .. } => "connect",
136            SmtpdEvent::Disconnect { .. } => "disconnect",
137            SmtpdEvent::LostConnection { .. } => "lost_connection",
138            SmtpdEvent::Timeout { .. } => "timeout",
139            SmtpdEvent::ClientAssignment { .. } => "client_assignment",
140            SmtpdEvent::Auth { .. } => "auth",
141            SmtpdEvent::Reject { .. } => "reject",
142            SmtpdEvent::NoQueueFilter { .. } => "noqueue_filter",
143            SmtpdEvent::Helo { .. } => "helo",
144            SmtpdEvent::Accept { .. } => "accept",
145            SmtpdEvent::ProtocolViolation { .. } => "protocol_violation",
146            SmtpdEvent::SystemWarning { .. } => "system_warning",
147        }
148    }
149
150    /// 获取队列ID(如果存在)
151    pub fn queue_id(&self) -> Option<&str> {
152        match self {
153            SmtpdEvent::ClientAssignment { queue_id, .. } => Some(queue_id),
154            SmtpdEvent::Accept { queue_id, .. } => queue_id.as_deref(),
155            _ => None,
156        }
157    }
158}