/src/ndpi/src/lib/protocols/z3950.c
Line | Count | Source |
1 | | /* |
2 | | * z3950.c |
3 | | * |
4 | | * Copyright (C) 2012-22 - ntop.org |
5 | | * |
6 | | * This module is free software: you can redistribute it and/or modify |
7 | | * it under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation, either version 3 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This module is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License. |
17 | | * If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | */ |
20 | | |
21 | | #include "ndpi_protocol_ids.h" |
22 | | |
23 | | #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_Z3950 |
24 | | |
25 | | #include "ndpi_api.h" |
26 | | #include "ndpi_private.h" |
27 | | |
28 | | /* https://github.com/wireshark/wireshark/blob/master/epan/dissectors/asn1/z3950/z3950.asn */ |
29 | | |
30 | | static void ndpi_int_z3950_add_connection(struct ndpi_detection_module_struct *ndpi_struct, |
31 | 0 | struct ndpi_flow_struct *flow) { |
32 | 0 | ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_Z3950, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI); |
33 | 0 | } |
34 | | |
35 | | /* ***************************************************************** */ |
36 | | |
37 | | static int z3950_parse_sequences(struct ndpi_flow_struct *flow, struct ndpi_packet_struct const * const packet, |
38 | 0 | int max_sequences) { |
39 | 0 | size_t payload_offset = 2; |
40 | 0 | int cur_sequences = 0; |
41 | 0 | u_int8_t pdu_type; |
42 | |
|
43 | 0 | pdu_type = packet->payload[0] & 0x1F; |
44 | |
|
45 | 0 | if((pdu_type < 20) || ((pdu_type > 36) && ((pdu_type < 43) || (pdu_type > 48)))) |
46 | 0 | return(-1); |
47 | | |
48 | | /* Simple check to avoid false positives: the first pkt after the 3WHS |
49 | | should be a initRequest or a initResponse */ |
50 | 0 | if(ndpi_seen_flow_beginning(flow) && flow->packet_counter == 1 && |
51 | 0 | pdu_type != 20 && pdu_type != 21) |
52 | 0 | return(-1); |
53 | | |
54 | 0 | while(cur_sequences++ < max_sequences) { |
55 | 0 | u_int8_t const * payload; |
56 | 0 | u_int8_t seq_type; |
57 | 0 | u_int8_t seq_length; |
58 | | |
59 | 0 | if((payload_offset + 2) >= packet->payload_packet_len) |
60 | 0 | return(-1); |
61 | | |
62 | 0 | payload = &packet->payload[payload_offset]; |
63 | |
|
64 | 0 | if((payload[0] & 0x1F) == 0x1F) |
65 | | /* We ignore decoding of complex sequences for now. */ |
66 | 0 | return(cur_sequences); |
67 | 0 | else |
68 | 0 | seq_type = payload[0] & 0x1F; |
69 | | |
70 | 0 | seq_length = payload[1]; |
71 | |
|
72 | 0 | if(seq_type > 51 && (seq_type < 100 || seq_type > 105) && |
73 | 0 | (seq_type < 110 || seq_type > 112) && (seq_type < 120 || seq_type > 121) && |
74 | 0 | (seq_type < 201 || seq_type > 221)) |
75 | 0 | return(-1); |
76 | | |
77 | 0 | if(seq_length >= packet->payload_packet_len - payload_offset + 1) |
78 | 0 | return(-1); |
79 | | |
80 | 0 | payload_offset += seq_length + 2; |
81 | |
|
82 | 0 | if(payload_offset == packet->payload_packet_len) |
83 | 0 | return(cur_sequences); |
84 | 0 | } |
85 | | |
86 | 0 | return(cur_sequences - 1); |
87 | 0 | } |
88 | | |
89 | | /* ***************************************************************** */ |
90 | | |
91 | | static void ndpi_search_z3950(struct ndpi_detection_module_struct *ndpi_struct, |
92 | 0 | struct ndpi_flow_struct *flow) { |
93 | 0 | struct ndpi_packet_struct * packet = &ndpi_struct->packet; |
94 | 0 | int const minimum_expected_sequences = 6; |
95 | |
|
96 | 0 | NDPI_LOG_DBG(ndpi_struct, "search z39.50\n"); |
97 | |
|
98 | 0 | if(packet->tcp != NULL && packet->payload_packet_len >= 6 && |
99 | 0 | flow->packet_counter >= 1 && flow->packet_counter <= 8) { |
100 | 0 | int ret = z3950_parse_sequences(flow, packet, minimum_expected_sequences); |
101 | |
|
102 | 0 | if(ret < 0) { |
103 | 0 | NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow); |
104 | 0 | return; |
105 | 0 | } |
106 | | |
107 | 0 | if(ret < minimum_expected_sequences) { |
108 | | /* We've seen not enough sequences, wait for the next packet. */ |
109 | 0 | return; |
110 | 0 | } |
111 | | |
112 | 0 | if(flow->l4.tcp.z3950_stage == 3) { |
113 | 0 | if(flow->packet_direction_counter[0] && flow->packet_direction_counter[1]) |
114 | 0 | ndpi_int_z3950_add_connection(ndpi_struct, flow); |
115 | 0 | else |
116 | 0 | NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow); /* Skip if unidirectional traffic */ |
117 | 0 | } else |
118 | 0 | flow->l4.tcp.z3950_stage++; |
119 | |
|
120 | 0 | return; |
121 | 0 | } |
122 | | |
123 | 0 | NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow); |
124 | 0 | } |
125 | | |
126 | | /* ***************************************************************** */ |
127 | | |
128 | 0 | void init_z3950_dissector(struct ndpi_detection_module_struct *ndpi_struct) { |
129 | 0 | register_dissector("Z3950", ndpi_struct, |
130 | 0 | ndpi_search_z3950, |
131 | 0 | NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION, |
132 | 0 | 1, NDPI_PROTOCOL_Z3950); |
133 | 0 | } |