@@ -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,
0 commit comments