Skip to content

Commit 6ba2d27

Browse files
committed
feat: parse NetSign protocol
1 parent 4cdd266 commit 6ba2d27

File tree

19 files changed

+702
-2
lines changed

19 files changed

+702
-2
lines changed

agent/crates/enterprise-utils/src/lib.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,52 @@ pub mod l7 {
357357
}
358358

359359
pub mod rpc {
360+
pub mod net_sign {
361+
use public::l7_protocol::LogMessageType;
362+
363+
pub const PROCESSOR_SIGN: &str = "RAWSignProcessor";
364+
pub const PROCESSOR_VERIFY: &str = "PBCRAWVerifyProcessor";
365+
366+
#[derive(Default, Debug, Clone)]
367+
pub struct NetSignFields {
368+
pub processor_name: String,
369+
pub operation: String,
370+
pub result_code: String,
371+
pub biz_data_parts: Vec<String>,
372+
pub sig_present: bool,
373+
pub sig_len: u32,
374+
pub cert_id: String,
375+
pub cert_serial: String,
376+
pub cert_validity: String,
377+
pub issuer_dn_ca: String,
378+
pub app_ver: String,
379+
}
380+
381+
impl NetSignFields {
382+
pub fn trace_id(&self) -> &str {
383+
self.biz_data_parts.get(0).map(|s| s.as_str()).unwrap_or("")
384+
}
385+
pub fn biz_system(&self) -> &str {
386+
self.biz_data_parts.get(6).map(|s| s.as_str()).unwrap_or("")
387+
}
388+
pub fn signer_id(&self) -> String {
389+
String::new()
390+
}
391+
}
392+
393+
#[derive(Default)]
394+
pub struct NetSignParser;
395+
396+
impl NetSignParser {
397+
pub fn check_payload(&self, _: &[u8]) -> Option<LogMessageType> {
398+
unimplemented!()
399+
}
400+
pub fn parse_payload(&self, _: &[u8]) -> Option<NetSignFields> {
401+
unimplemented!()
402+
}
403+
}
404+
}
405+
360406
pub mod iso8583 {
361407
use public::bitmap::Bitmap;
362408

agent/crates/public/src/l7_protocol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ pub enum L7Protocol {
6363
SomeIp = 47,
6464
Iso8583 = 48,
6565
Triple = 49,
66+
NetSign = 50,
6667

6768
// SQL
6869
MySQL = 60,
@@ -149,6 +150,7 @@ impl From<String> for L7Protocol {
149150
"tls" => Self::TLS,
150151
"ping" => Self::Ping,
151152
"some/ip" | "someip" => Self::SomeIp,
153+
"netsign" | "net-sign" | "net_sign" => Self::NetSign,
152154
_ => Self::Unknown,
153155
}
154156
}

agent/src/common/l7_protocol_info.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ cfg_if::cfg_if! {
131131
PingInfo(PingInfo),
132132
CustomInfo(CustomInfo),
133133
Iso8583Info(crate::flow_generator::protocol_logs::rpc::Iso8583Info),
134+
NetSignInfo(crate::flow_generator::protocol_logs::rpc::NetSignInfo),
134135
// add new protocol info below
135136
);
136137
}

agent/src/common/l7_protocol_log.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ macro_rules! impl_protocol_parser {
103103
#[cfg(feature = "enterprise")]
104104
"ISO-8583"=>Ok(Self::Iso8583(Default::default())),
105105
#[cfg(feature = "enterprise")]
106+
"NetSign"|"netsign"|"net_sign"=>Ok(Self::NetSign(Default::default())),
107+
#[cfg(feature = "enterprise")]
106108
"WebSphereMQ"=>Ok(Self::WebSphereMq(Default::default())),
107109
$(
108110
stringify!($proto) => Ok(Self::$proto(Default::default())),
@@ -202,6 +204,7 @@ cfg_if::cfg_if! {
202204
Tars(TarsLog),
203205
Oracle(crate::flow_generator::protocol_logs::OracleLog),
204206
Iso8583(crate::flow_generator::protocol_logs::Iso8583Log),
207+
NetSign(crate::flow_generator::protocol_logs::NetSignLog),
205208
MQTT(MqttLog),
206209
AMQP(AmqpLog),
207210
NATS(NatsLog),

agent/src/config/config.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2044,6 +2044,7 @@ impl Default for Filters {
20442044
("Tars".to_string(), "1-65535".to_string()),
20452045
("SomeIP".to_string(), "1-65535".to_string()),
20462046
("ISO8583".to_string(), "1-65535".to_string()),
2047+
("NetSign".to_string(), "1-65535".to_string()),
20472048
("Triple".to_string(), "1-65535".to_string()),
20482049
("MySQL".to_string(), "1-65535".to_string()),
20492050
("PostgreSQL".to_string(), "1-65535".to_string()),
@@ -2076,6 +2077,7 @@ impl Default for Filters {
20762077
("Tars".to_string(), vec![]),
20772078
("SomeIP".to_string(), vec![]),
20782079
("ISO8583".to_string(), vec![]),
2080+
("NetSign".to_string(), vec![]),
20792081
("Triple".to_string(), vec![]),
20802082
("MySQL".to_string(), vec![]),
20812083
("PostgreSQL".to_string(), vec![]),

agent/src/ebpf/kernel/include/common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ enum traffic_protocol {
7777
PROTO_TARS = 46,
7878
PROTO_SOME_IP = 47,
7979
PROTO_ISO8583 = 48,
80+
PROTO_TRIPLE = 49,
81+
PROTO_NET_SIGN = 50,
8082
PROTO_MYSQL = 60,
8183
PROTO_POSTGRESQL = 61,
8284
PROTO_ORACLE = 62,

agent/src/ebpf/kernel/include/protocol_inference.h

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1269,6 +1269,119 @@ static __inline enum message_type infer_iso8583_message(const char *buf,
12691269
return MSG_REQUEST;
12701270
}
12711271

1272+
/*
1273+
* NetSign (签名验签) protocol identification.
1274+
*
1275+
* Wire format (all offsets absolute from TCP payload start):
1276+
*
1277+
* [0] outer_tag = 0x02
1278+
* [1..12] outer_len (12 ASCII decimal digits)
1279+
* [13] TAG_PROCESSOR_NAME = 0x01
1280+
* [14] type indicator = 0x01 (text)
1281+
* [15..26] processorName length (12 ASCII decimal digits)
1282+
* [25..26] last two digits of length:
1283+
* '1','6' → RAWSignProcessor (16 B): name at [27..42]
1284+
* '2','1' → PBCRAWVerifyProcessor (21 B): name at [27..47]
1285+
*
1286+
* Protocol identification uses only the first 32 bytes (buf[0..31]).
1287+
* Request/response detection requires bytes beyond 32 and is read via
1288+
* bpf_probe_read_user from conn_info->syscall_infer_addr:
1289+
*
1290+
* RAWSignProcessor:
1291+
* op tag at [43] (extra[0]), op len last digit at [56] (extra[13])
1292+
* PBCRAWVerifyProcessor:
1293+
* op tag at [48] (extra[5]), op len last digit at [61] (extra[18])
1294+
*
1295+
* Operation length last digit: '7' → "request", '8' → "response"
1296+
*/
1297+
static __inline enum message_type infer_net_sign_message(const char *buf,
1298+
size_t count,
1299+
struct conn_info_s
1300+
*conn_info)
1301+
{
1302+
if (!protocol_port_check_2(PROTO_NET_SIGN, conn_info))
1303+
return MSG_UNKNOWN;
1304+
if (conn_info->tuple.l4_protocol != IPPROTO_TCP || count < 62)
1305+
return MSG_UNKNOWN;
1306+
if (is_infer_socket_valid(conn_info->socket_info_ptr)) {
1307+
if (conn_info->socket_info_ptr->l7_proto != PROTO_NET_SIGN)
1308+
return MSG_UNKNOWN;
1309+
/*
1310+
* Socket already confirmed as NetSign. Continuation reads (mid-message
1311+
* syscall splits) do not start at message offset 0, so the byte-pattern
1312+
* checks below would fail. Return MSG_REQUEST unconditionally here; the
1313+
* Rust-level parser derives the real message type from the TLV content.
1314+
*/
1315+
return MSG_REQUEST;
1316+
}
1317+
1318+
/*
1319+
* Protocol identification within the first 32 bytes.
1320+
*/
1321+
// Byte 0: outer tag must be 0x02
1322+
if ((uint8_t)buf[0] != 0x02)
1323+
return MSG_UNKNOWN;
1324+
// Byte 1: first digit of outer_len must be ASCII decimal
1325+
if (buf[1] < '0' || buf[1] > '9')
1326+
return MSG_UNKNOWN;
1327+
// Byte 13: first inner TLV tag must be TAG_PROCESSOR_NAME (0x01)
1328+
if ((uint8_t)buf[13] != 0x01)
1329+
return MSG_UNKNOWN;
1330+
// Byte 14: inner TLV type indicator must be 0x01 (text)
1331+
if ((uint8_t)buf[14] != 0x01)
1332+
return MSG_UNKNOWN;
1333+
// processorName len field [15..26]: leading and near-last bytes must be '0'
1334+
if (buf[15] != '0' || buf[24] != '0')
1335+
return MSG_UNKNOWN;
1336+
1337+
// Bytes [25..26]: last two digits of processorName length.
1338+
// Also validate the processor name prefix (bytes [27..29]) within 32 bytes.
1339+
if (buf[25] == '1' && buf[26] == '6') {
1340+
// RAWSignProcessor (len=16): prefix "RAW" at [27..29]
1341+
if (buf[27] != 'R' || buf[28] != 'A' || buf[29] != 'W')
1342+
return MSG_UNKNOWN;
1343+
} else if (buf[25] == '2' && buf[26] == '1') {
1344+
// PBCRAWVerifyProcessor (len=21): prefix "PBC" at [27..29]
1345+
if (buf[27] != 'P' || buf[28] != 'B' || buf[29] != 'C')
1346+
return MSG_UNKNOWN;
1347+
} else {
1348+
return MSG_UNKNOWN;
1349+
}
1350+
1351+
/*
1352+
* Request/response detection: read 19 bytes from offset 43 via
1353+
* bpf_probe_read_user to cover the operation TLV for both processors.
1354+
*
1355+
* extra[0] = payload[43]: op tag for RAWSignProcessor
1356+
* extra[5] = payload[48]: op tag for PBCRAWVerifyProcessor
1357+
* extra[13] = payload[56]: op len last digit for RAWSignProcessor
1358+
* extra[18] = payload[61]: op len last digit for PBCRAWVerifyProcessor
1359+
*/
1360+
char extra[19];
1361+
bpf_probe_read_user(extra, sizeof(extra),
1362+
conn_info->syscall_infer_addr + 43);
1363+
1364+
if (buf[25] == '1' && buf[26] == '6') {
1365+
// RAWSignProcessor: op tag at extra[0], op len last digit at extra[13]
1366+
if ((uint8_t)extra[0] != 0x02)
1367+
return MSG_UNKNOWN;
1368+
if (extra[13] == '7')
1369+
return MSG_REQUEST; // "request" len=7
1370+
if (extra[13] == '8')
1371+
return MSG_RESPONSE; // "response" len=8
1372+
} else {
1373+
// PBCRAWVerifyProcessor: op tag at extra[5], op len last digit at extra[18]
1374+
if ((uint8_t)extra[5] != 0x02)
1375+
return MSG_UNKNOWN;
1376+
if (extra[18] == '7')
1377+
return MSG_REQUEST; // "request" len=7
1378+
if (extra[18] == '8')
1379+
return MSG_RESPONSE; // "response" len=8
1380+
}
1381+
1382+
return MSG_UNKNOWN;
1383+
}
1384+
12721385
#define CSTR_LEN(s) (sizeof(s) / sizeof(char) - 1)
12731386
#define CSTR_MASK(s) ((~0ull) >> (64 - CSTR_LEN(s) * 8))
12741387
// convert const string with length <= 8 for matching
@@ -4145,6 +4258,14 @@ infer_protocol_2(const char *infer_buf, size_t count,
41454258
syscall_infer_len,
41464259
conn_info)) != MSG_UNKNOWN) {
41474260
inferred_message.protocol = PROTO_ISO8583;
4261+
#if defined(LINUX_VER_KFUNC) || defined(LINUX_VER_5_2_PLUS)
4262+
} else if (skip_proto != PROTO_NET_SIGN && (inferred_message.type =
4263+
#else
4264+
} else if ((inferred_message.type =
4265+
#endif
4266+
infer_net_sign_message(infer_buf,
4267+
count, conn_info)) != MSG_UNKNOWN) {
4268+
inferred_message.protocol = PROTO_NET_SIGN;
41484269
#if defined(LINUX_VER_KFUNC) || defined(LINUX_VER_5_2_PLUS)
41494270
} else if (skip_proto != PROTO_MEMCACHED && (inferred_message.type =
41504271
#else
@@ -4493,6 +4614,14 @@ infer_protocol_1(struct ctx_info_s *ctx,
44934614
return inferred_message;
44944615
}
44954616
break;
4617+
case PROTO_NET_SIGN:
4618+
if ((inferred_message.type =
4619+
infer_net_sign_message(infer_buf, count,
4620+
conn_info)) != MSG_UNKNOWN) {
4621+
inferred_message.protocol = PROTO_NET_SIGN;
4622+
return inferred_message;
4623+
}
4624+
break;
44964625
case PROTO_MEMCACHED:
44974626
if ((inferred_message.type =
44984627
infer_memcached_message(infer_buf, count,

agent/src/ebpf/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ pub const SOCK_DATA_SOME_IP: u16 = 47;
6969
#[allow(dead_code)]
7070
pub const SOCK_DATA_ISO8583: u16 = 48;
7171
#[allow(dead_code)]
72+
pub const SOCK_DATA_TRIPLE: u16 = 49;
73+
#[allow(dead_code)]
74+
pub const SOCK_DATA_NET_SIGN: u16 = 50;
75+
#[allow(dead_code)]
7276
pub const SOCK_DATA_MYSQL: u16 = 60;
7377
#[allow(dead_code)]
7478
pub const SOCK_DATA_POSTGRESQL: u16 = 61;

agent/src/ebpf/user/ctrl_tracer.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ static void datadump_help(void)
147147
fprintf(stderr, " 46: PROTO_TARS\n");
148148
fprintf(stderr, " 47: PROTO_SOME_IP\n");
149149
fprintf(stderr, " 48: PROTO_ISO8583\n");
150+
fprintf(stderr, " 49: PROTO_TRIPLE\n");
151+
fprintf(stderr, " 50: PROTO_NET_SIGN\n");
150152
fprintf(stderr, " 60: PROTO_MYSQL\n");
151153
fprintf(stderr, " 61: PROTO_POSTGRESQL\n");
152154
fprintf(stderr, " 62: PROTO_ORACLE\n");

agent/src/ebpf/user/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,8 @@ static inline char *get_proto_name(uint16_t proto_id)
297297
return "Some/IP";
298298
case PROTO_ISO8583:
299299
return "ISO-8583";
300+
case PROTO_NET_SIGN:
301+
return "NetSign";
300302
case PROTO_POSTGRESQL:
301303
return "PgSQL";
302304
case PROTO_ORACLE:

0 commit comments

Comments
 (0)