Skip to content

Commit 5967e62

Browse files
committed
mysql: fix bug and add userguide and upgrade document
Task #3446
1 parent 8095542 commit 5967e62

16 files changed

+649
-1649
lines changed

doc/userguide/output/eve/eve-json-format.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3057,3 +3057,32 @@ Example of ARP logging: request and response
30573057
"dest_mac": "00:1d:09:f0:92:ab",
30583058
"dest_ip": "10.10.10.1"
30593059
}
3060+
3061+
Event type: MySQL
3062+
---------------
3063+
3064+
Fields
3065+
~~~~~~
3066+
3067+
* "version": the MySQL protocol version offered by the server.
3068+
* "tls": protocol need to be upgrade to tls.
3069+
* "command": sql query statement or utility command like ping.
3070+
* "rows": zero or multi results from executing sql query statement, one row is splited by comma.
3071+
3072+
Examples
3073+
~~~~~~~~
3074+
3075+
Example of MySQL logging:
3076+
3077+
::
3078+
3079+
{
3080+
"mysql": {
3081+
"version": "8.0.32",
3082+
"tls": false,
3083+
"command": "SELECT VERSION()",
3084+
"rows": [
3085+
"8.0.32"
3086+
]
3087+
}
3088+
}

doc/userguide/rules/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ Suricata Rules
3737
nfs-keywords
3838
smtp-keywords
3939
websocket-keywords
40+
mysql-keywords
4041
app-layer
4142
xbits
4243
noalert
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
MySQL Keywords
2+
============
3+
4+
The MySQL keywords are implemented and can be used to match on fields in MySQL messages.
5+
6+
============================== ==================
7+
Keyword Direction
8+
============================== ==================
9+
mysql.command Request
10+
mysql.rows Response
11+
============================== ==================
12+
13+
mysql.command
14+
----------
15+
16+
This keyword matches on the query statement like `select * from xxx where yyy = zzz` found in a MySQL request.
17+
18+
Syntax
19+
~~~~~~
20+
21+
::
22+
23+
mysql.command; content:<command>;
24+
25+
Examples
26+
~~~~~~~~
27+
28+
::
29+
30+
mysql.commands; content:"select";
31+
32+
mysql.rows
33+
-------
34+
35+
This keyword matches on the rows which come from query statement result found in a Mysql response.
36+
row format: 1,foo,bar
37+
38+
Syntax
39+
~~~~~~
40+
41+
::
42+
43+
mysql.rows; content:<rows>;
44+
45+
Examples
46+
~~~~~~~~
47+
48+
::
49+
50+
mysql.rows; content:"foo,bar";

doc/userguide/upgrade.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ Major changes
7777
- sip.to
7878
- sip.content_type
7979
- sip.content_length
80+
- MySQL parser and logger have been introduced.
81+
- The MySQL keywords ``mysql.command`` and ``mysql.command`` have been introduced.
8082

8183
Removals
8284
~~~~~~~~

etc/schema.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,23 +2388,27 @@
23882388
"optional": true,
23892389
"properties": {
23902390
"version": {
2391-
"type": "string"
2391+
"type": "string",
2392+
"description": "Mysql server version"
23922393
},
23932394
"tls": {
23942395
"type": "boolean"
23952396
},
23962397
"command": {
2397-
"type": "string"
2398+
"type": "string",
2399+
"description": "sql query statement or some utility commands like ping."
23982400
},
23992401
"affected_rows": {
24002402
"type": "integer"
24012403
},
24022404
"rows": {
24032405
"type": "array",
24042406
"optional": true,
2407+
"minItems": 1,
24052408
"items": {
24062409
"type": "string"
2407-
}
2410+
},
2411+
"description": "Comma separated result from sql statement"
24082412
}
24092413
}
24102414
},

rust/src/mysql/detect.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
/* Copyright (C) 2024 Open Information Security Foundation
2+
*
3+
* You can copy, redistribute or modify this Program under the terms of
4+
* the GNU General Public License version 2 as published by the Free
5+
* Software Foundation.
6+
*
7+
* This program is distributed in the hope that it will be useful,
8+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
* GNU General Public License for more details.
11+
*
12+
* You should have received a copy of the GNU General Public License
13+
* version 2 along with this program; if not, write to the Free Software
14+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15+
* 02110-1301, USA.
16+
*/
17+
18+
// Author: QianKaiLin <linqiankai666@outlook.com>
19+
20+
/// Detect
21+
/// Get the mysql query
22+
use super::mysql::{MysqlTransaction, ALPROTO_MYSQL};
23+
use crate::detect::{
24+
DetectBufferSetActiveList, DetectHelperBufferMpmRegister, DetectHelperGetData,
25+
DetectHelperGetMultiData, DetectHelperKeywordRegister, DetectHelperMultiBufferMpmRegister,
26+
DetectSignatureSetAppProto, SCSigTableElmt, SIGMATCH_NOOPT,
27+
};
28+
use std::os::raw::{c_int, c_void};
29+
30+
static mut G_MYSQL_COMMAND_BUFFER_ID: c_int = 0;
31+
static mut G_MYSQL_ROWS_BUFFER_ID: c_int = 0;
32+
33+
#[no_mangle]
34+
unsafe extern "C" fn SCMysqlCommandSetup(
35+
de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char,
36+
) -> c_int {
37+
if DetectSignatureSetAppProto(s, ALPROTO_MYSQL) != 0 {
38+
return -1;
39+
}
40+
if DetectBufferSetActiveList(de, s, G_MYSQL_COMMAND_BUFFER_ID) < 0 {
41+
return -1;
42+
}
43+
return 0;
44+
}
45+
46+
#[no_mangle]
47+
unsafe extern "C" fn SCMysqlGetCommand(
48+
de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8,
49+
tx: *const c_void, list_id: c_int,
50+
) -> *mut c_void {
51+
return DetectHelperGetData(
52+
de,
53+
transforms,
54+
flow,
55+
flow_flags,
56+
tx,
57+
list_id,
58+
SCMysqlGetCommandData,
59+
);
60+
}
61+
62+
#[no_mangle]
63+
unsafe extern "C" fn SCMysqlGetCommandData(
64+
tx: *const c_void, _flags: u8, buf: *mut *const u8, len: *mut u32,
65+
) -> bool {
66+
let tx = cast_pointer!(tx, MysqlTransaction);
67+
if let Some(command) = &tx.command {
68+
if !command.is_empty() {
69+
*buf = command.as_ptr();
70+
*len = command.len() as u32;
71+
return true;
72+
}
73+
}
74+
75+
false
76+
}
77+
78+
#[no_mangle]
79+
unsafe extern "C" fn SCMysqlRowsSetup(
80+
de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char,
81+
) -> c_int {
82+
if DetectSignatureSetAppProto(s, ALPROTO_MYSQL) != 0 {
83+
return -1;
84+
}
85+
if DetectBufferSetActiveList(de, s, G_MYSQL_ROWS_BUFFER_ID) < 0 {
86+
return -1;
87+
}
88+
return 0;
89+
}
90+
91+
#[no_mangle]
92+
unsafe extern "C" fn SCMysqlGetRows(
93+
de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8,
94+
tx: *const c_void, list_id: c_int, local_id: u32,
95+
) -> *mut c_void {
96+
return DetectHelperGetMultiData(
97+
de,
98+
transforms,
99+
flow,
100+
flow_flags,
101+
tx,
102+
list_id,
103+
local_id,
104+
SCMysqlGetRowsData,
105+
);
106+
}
107+
108+
/// Get the mysql rows at index i
109+
#[no_mangle]
110+
pub unsafe extern "C" fn SCMysqlGetRowsData(
111+
tx: *const c_void, _flow_flags: u8, local_id: u32, buf: *mut *const u8, len: *mut u32,
112+
) -> bool {
113+
let tx = cast_pointer!(tx, MysqlTransaction);
114+
if let Some(rows) = &tx.rows {
115+
if !rows.is_empty() {
116+
let index = local_id as usize;
117+
if let Some(row) = rows.get(index) {
118+
*buf = row.as_ptr();
119+
*len = row.len() as u32;
120+
return true;
121+
}
122+
}
123+
}
124+
125+
false
126+
}
127+
128+
#[no_mangle]
129+
pub unsafe extern "C" fn ScDetectMysqlRegister() {
130+
let kw = SCSigTableElmt {
131+
name: b"mysql.command\0".as_ptr() as *const libc::c_char,
132+
desc: b"sticky buffer to match on the MySQL command\0".as_ptr() as *const libc::c_char,
133+
url: b"/rules/mysql-keywords.html#mysql-command\0".as_ptr() as *const libc::c_char,
134+
Setup: SCMysqlCommandSetup,
135+
flags: SIGMATCH_NOOPT,
136+
AppLayerTxMatch: None,
137+
Free: None,
138+
};
139+
let _g_mysql_command_kw_id = DetectHelperKeywordRegister(&kw);
140+
G_MYSQL_COMMAND_BUFFER_ID = DetectHelperBufferMpmRegister(
141+
b"mysql.command\0".as_ptr() as *const libc::c_char,
142+
b"mysql.command\0".as_ptr() as *const libc::c_char,
143+
ALPROTO_MYSQL,
144+
false,
145+
true,
146+
SCMysqlGetCommand,
147+
);
148+
let kw = SCSigTableElmt {
149+
name: b"mysql.rows\0".as_ptr() as *const libc::c_char,
150+
desc: b"sticky buffer to match on the MySQL Rows\0".as_ptr() as *const libc::c_char,
151+
url: b"/rules/mysql-keywords.html#mysql-rows\0".as_ptr() as *const libc::c_char,
152+
Setup: SCMysqlRowsSetup,
153+
flags: SIGMATCH_NOOPT,
154+
AppLayerTxMatch: None,
155+
Free: None,
156+
};
157+
let _g_mysql_rows_kw_id = DetectHelperKeywordRegister(&kw);
158+
G_MYSQL_ROWS_BUFFER_ID = DetectHelperMultiBufferMpmRegister(
159+
b"mysql.rows\0".as_ptr() as *const libc::c_char,
160+
b"mysql select statement resultset\0".as_ptr() as *const libc::c_char,
161+
ALPROTO_MYSQL,
162+
true,
163+
false,
164+
SCMysqlGetRows,
165+
);
166+
}

rust/src/mysql/logger.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (C) 2022 Open Information Security Foundation
1+
/* Copyright (C) 2024 Open Information Security Foundation
22
*
33
* You can copy, redistribute or modify this Program under the terms of
44
* the GNU General Public License version 2 as published by the Free
@@ -15,21 +15,15 @@
1515
* 02110-1301, USA.
1616
*/
1717

18-
// written by linqiankai <linqiankai@geweian.com>
19-
//
18+
// Author: QianKaiLin <linqiankai666@outlook.com>
19+
2020
use crate::jsonbuilder::{JsonBuilder, JsonError};
2121
use crate::mysql::mysql::*;
2222

2323
fn log_mysql(tx: &MysqlTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> {
2424
js.open_object("mysql")?;
25-
if let Some(version) = &tx.version {
26-
js.set_string("version", version)?;
27-
}
28-
if let Some(tls) = &tx.tls {
29-
js.set_bool("tls", *tls)?;
30-
} else {
31-
js.set_bool("tls", false)?;
32-
}
25+
js.set_string("version", tx.version.as_str())?;
26+
js.set_bool("tls", tx.tls)?;
3327

3428
if let Some(command) = &tx.command {
3529
js.set_string("command", command)?;
@@ -57,13 +51,9 @@ pub unsafe extern "C" fn SCMysqlLogger(
5751
tx: *mut std::os::raw::c_void, js: &mut JsonBuilder,
5852
) -> bool {
5953
let tx_mysql = cast_pointer!(tx, MysqlTransaction);
60-
SCLogDebug!(
61-
"----------- MySQL rs_mysql_logger call. Tx is {:?}",
62-
tx_mysql
63-
);
6454
let result = log_mysql(tx_mysql, js);
65-
if let Err(ref err) = result {
66-
SCLogError!("----------- MySQL rs_mysql_logger failed. err is {:?}", err);
55+
if let Err(ref _err) = result {
56+
return false;
6757
}
6858
return result.is_ok();
6959
}

rust/src/mysql/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (C) 2022 Open Information Security Foundation
1+
/* Copyright (C) 2024 Open Information Security Foundation
22
*
33
* You can copy, redistribute or modify this Program under the terms of
44
* the GNU General Public License version 2 as published by the Free
@@ -15,9 +15,9 @@
1515
* 02110-1301, USA.
1616
*/
1717

18-
//! MySQL parser, logger and application layer module.
19-
//!
20-
//! written by Kotodian <blackfaceuncle@gmail.com>
18+
// Author: QianKaiLin <linqiankai666@outlook.com>
19+
20+
pub mod detect;
2121
pub mod logger;
2222
pub mod mysql;
2323
pub mod parser;

0 commit comments

Comments
 (0)