Coverage Report

Created: 2025-11-02 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ndpi/src/lib/protocols/smpp.c
Line
Count
Source
1
/*
2
 * smpp.c
3
 * 
4
 * Copyright (C) 2016 - Damir Franusic <df@release14.org>
5
 * Copyright (C) 2016-22 - ntop.org
6
 *
7
 * nDPI is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * nDPI is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with nDPI.  If not, see <http://www.gnu.org/licenses/>.
19
 *
20
 */
21
22
23
#include "ndpi_protocol_ids.h"
24
25
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_SMPP
26
27
#include "ndpi_api.h"
28
#include "ndpi_private.h"
29
30
31
static void ndpi_int_smpp_add_connection(struct ndpi_detection_module_struct* ndpi_struct, 
32
                                         struct ndpi_flow_struct* flow)
33
0
{
34
0
  ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_SMPP, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
35
0
}
36
37
static  u_int8_t ndpi_check_overflow(u_int32_t current_length, u_int32_t total_lenth)
38
0
{
39
0
    return (current_length > 0 && current_length > INT_MAX - total_lenth);
40
0
}
41
42
static void ndpi_search_smpp_tcp(struct ndpi_detection_module_struct* ndpi_struct,
43
                                 struct ndpi_flow_struct* flow)
44
0
{
45
0
  struct ndpi_packet_struct* packet = &ndpi_struct->packet;
46
47
0
  NDPI_LOG_DBG(ndpi_struct, "search SMPP\n");
48
0
  if (flow->detected_protocol_stack[0] != NDPI_PROTOCOL_SMPP){
49
    // min SMPP packet length = 16 bytes
50
0
    if (packet->payload_packet_len < 16) {
51
0
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
52
0
      return;
53
0
    }
54
    // get PDU length
55
0
    u_int32_t pdu_l = ntohl(get_u_int32_t(packet->payload, 0));
56
57
0
    NDPI_LOG_DBG2(ndpi_struct, 
58
0
       "calculated PDU Length: %d, received PDU Length: %d\n", 
59
0
       pdu_l, packet->payload_packet_len);
60
61
    // if PDU size was invalid, try the following TCP segments, 3 attempts max
62
0
    if(flow->packet_counter > 3) {
63
0
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
64
0
      return;
65
0
    }
66
    // verify PDU length
67
0
    if(pdu_l != packet->payload_packet_len) {
68
      // check if multiple PDUs included
69
0
      u_int32_t total_pdu_l = pdu_l;
70
0
      u_int32_t tmp_pdu_l = 0;
71
#ifdef NDPI_ENABLE_DEBUG_MESSAGES
72
      u_int16_t pdu_c = 1;
73
#endif
74
      // loop PDUs (check if lengths are valid)
75
0
      while(total_pdu_l < ((uint32_t)packet->payload_packet_len-4)) {
76
  // get next PDU length
77
0
  tmp_pdu_l = ntohl(get_u_int32_t(packet->payload, total_pdu_l));
78
  // if zero or overflowing , return, will try the next TCP segment
79
0
  if(tmp_pdu_l == 0 ||  ndpi_check_overflow(tmp_pdu_l, total_pdu_l) ) return;
80
  // inc total PDU length
81
0
  total_pdu_l += ntohl(get_u_int32_t(packet->payload, total_pdu_l));
82
#ifdef NDPI_ENABLE_DEBUG_MESSAGES
83
  // inc total PDU count
84
  ++pdu_c;
85
#endif
86
0
      }
87
        
88
0
      NDPI_LOG_DBG2(ndpi_struct, 
89
0
         "multiple PDUs included, calculated total PDU Length: %d, PDU count: %d, TCP payload length: %d\n", 
90
0
         total_pdu_l, pdu_c, packet->payload_packet_len);
91
92
      // verify multi PDU total length
93
0
      if(total_pdu_l != packet->payload_packet_len){
94
  // return, will try the next TCP segment
95
0
  return;
96
0
      }
97
0
    }
98
99
    // *** check PDU type ***
100
0
    u_int32_t pdu_type = ntohl(get_u_int32_t(packet->payload, 4));
101
    // first byte of PDU type is either 0x00 of 0x80
102
0
    if(!(packet->payload[4] == 0x00 || packet->payload[4] == 0x80)) {
103
0
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
104
0
      return;
105
0
    }
106
    // remove 0x80, get request type pdu
107
0
    u_int32_t pdu_req = pdu_type & 0x00FFFFFF;
108
    // list of known PDU types
109
0
    if((pdu_req <= 0x00000009) || /* [0-9] */
110
0
       (pdu_req == 0x0000000B || pdu_req == 0x00000015  ||
111
0
        pdu_req == 0x00000021 || pdu_req == 0x00000102  ||
112
0
        pdu_req == 0x00000103)){
113
114
0
      NDPI_LOG_DBG2(ndpi_struct, 
115
0
         "PDU type: %x, Request PDU type = %x\n", 
116
0
         pdu_type, pdu_req);
117
118
      // fresult flag
119
0
      char extra_passed = 1;
120
      // check PDU type specifics
121
0
      switch(pdu_type){
122
  // GENERIC_NACK
123
0
      case 0x80000000:
124
  // body length must be zero
125
0
  if(pdu_l > 16) extra_passed = 0;
126
0
  break;
127
128
  // BIND_RECEIVER
129
  // BIND_TRANSMITTER
130
  // BIND_TRANSCEIVER
131
0
      case 0x00000001:
132
0
      case 0x00000002:
133
0
      case 0x00000009:
134
  // status field must be NULL
135
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
136
  // min body length = 10 bytes (+16 in header)
137
0
  if(pdu_l < 26) extra_passed = 0; 
138
0
  break;
139
140
  // BIND_RECEIVER_RESP
141
  // BIND_TRANSMITTER_RESP
142
  // BIND_TRANSCEIVER_RESP
143
0
      case 0x80000001:
144
0
      case 0x80000002:
145
0
      case 0x80000009:
146
  // min body length = 2 bytes (+16 in header)
147
0
  if(pdu_l < 18) extra_passed = 0;
148
0
  break;
149
150
  // OUTBIND
151
0
      case 0x0000000B:
152
  // status field must be NULL
153
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
154
  // min body length = 4 bytes (+16 in header)
155
0
  if(pdu_l < 20) extra_passed = 0;
156
0
  break;
157
158
  // UNBIND
159
0
      case 0x00000006:
160
  // status field must be NULL
161
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
162
  // body length must be zero
163
0
  if(pdu_l > 16) extra_passed = 0;
164
0
  break;
165
166
  // UNBIND_RESP
167
0
      case 0x80000006:
168
  // body length must be zero
169
0
  if(pdu_l > 16) extra_passed = 0;
170
0
  break;
171
172
173
  // SUBMIT_SM
174
0
      case 0x00000004:
175
  // status field must be NULL
176
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
177
  // min body length = 17 bytes (+16 in header)
178
0
  if(pdu_l < 33) extra_passed = 0;
179
0
  break;
180
       
181
  // SUBMIT_SM_RESP
182
0
      case 0x80000004:
183
  // - if status != 0, body length is 2 bytes min
184
  // - if status > 0, body lenth must be zero
185
0
  if(get_u_int32_t(packet->payload, 8) != 0){
186
0
    if(pdu_l > 16) extra_passed = 0; 
187
188
0
  }else if(pdu_l < 18) extra_passed = 0;
189
0
  break;
190
191
  // SUBMIT_MULTI
192
0
      case 0x00000021:
193
  // status field must be NULL
194
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
195
  // min body length = 17 bytes (+16 in header)
196
0
  if(pdu_l < 33) extra_passed = 0;
197
0
  break;
198
199
  // SUBMIT_MULTI_RESP
200
0
      case 0x80000021:
201
  // min body length = 10 bytes (+16 in header)
202
0
  if(pdu_l < 26) extra_passed = 0;
203
0
  break;
204
205
  // DELIVER_SM
206
0
      case 0x00000005:
207
  // status field must be NULL
208
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
209
  // min body length = 17 bytes (+16 in header)
210
0
  if(pdu_l < 33) extra_passed = 0;
211
0
  break;
212
213
  // DELIVER_SM_RESP
214
0
      case 0x80000005:
215
  // min body length = 1 byte (+16 in header)
216
0
  if(pdu_l < 17) extra_passed = 0;
217
0
  break;
218
            
219
  // DATA_SM
220
0
      case 0x00000103:
221
  // status field must be NULL
222
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
223
  // min body length = 10 bytes (+16 in header)
224
0
  if(pdu_l < 26) extra_passed = 0;
225
0
  break;
226
227
  // DATA_SM_RESP
228
0
      case 0x80000103:
229
  // min body length = 2 bytes (+16 in header)
230
0
  if(pdu_l < 18) extra_passed = 0;
231
0
  break;
232
233
  // QUERY_SM
234
0
      case 0x00000003:
235
  // status field must be NULL
236
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
237
  // min body length = 4 bytes (+16 in header)
238
0
  if(pdu_l < 20) extra_passed = 0;
239
0
  break;
240
241
  // QUERY_SM_RESP
242
0
      case 0x80000003:
243
  // min body length = 5 bytes (+16 in header)
244
0
  if(pdu_l < 21) extra_passed = 0;
245
0
  break;
246
247
  // CANCEL_SM
248
0
      case 0x00000008:
249
  // status field must be NULL
250
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
251
  // min body length = 8 bytes (+16 in header)
252
0
  if(pdu_l < 24) extra_passed = 0;
253
0
  break;
254
255
  // CANCEL_SM_RESP
256
0
      case 0x80000008:
257
  // body lenth must be zero
258
0
  if(pdu_l > 16) extra_passed = 0;
259
0
  break;
260
261
  // REPLACE_SM
262
0
      case 0x00000007:
263
  // status field must be NULL
264
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
265
  // min body length = 9 bytes (+16 in header)
266
0
  if(pdu_l < 25) extra_passed = 0;
267
0
  break;
268
269
  // REPLACE_SM_RESP
270
0
      case 0x80000007:
271
  // body lenth must be zero
272
0
  if(pdu_l > 16) extra_passed = 0;
273
0
  break;
274
275
  // ENQUIRE_LINK
276
0
      case 0x00000015:
277
  // status field must be NULL
278
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
279
  // body length must be zero
280
0
  if(pdu_l > 16) extra_passed = 0;
281
0
  break;
282
283
  // ENQUIRE_LINK_RESP
284
0
      case 0x80000015:
285
  // body length must be zero
286
0
  if(pdu_l > 16) extra_passed = 0;
287
0
  break;
288
289
  // ALERT_NOTIFICATION
290
0
      case 0x00000102:
291
  // status field must be NULL
292
0
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
293
  // min body length = 6 bytes (+16 in header)
294
0
  if(pdu_l < 22) extra_passed = 0;
295
0
  break;
296
297
0
      default: break;
298
0
      }
299
300
      // if extra checks passed, set as identified
301
0
      if(extra_passed) {
302
0
  NDPI_LOG_INFO(ndpi_struct, "found SMPP\n");
303
0
  ndpi_int_smpp_add_connection(ndpi_struct, flow);
304
0
  return;
305
0
      }
306
0
    }
307
308
0
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
309
0
  }
310
0
}
311
312
313
void init_smpp_dissector(struct ndpi_detection_module_struct* ndpi_struct)
314
1
{
315
1
  register_dissector("SMPP", ndpi_struct,
316
1
                     ndpi_search_smpp_tcp,
317
1
                     NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
318
1
                     1, NDPI_PROTOCOL_SMPP);
319
1
}