Coverage Report

Created: 2026-10-08 07:18

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
1.82k
{
34
1.82k
  ndpi_set_detected_protocol(ndpi_struct, &flow->core, NDPI_PROTOCOL_SMPP, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
35
1.82k
}
36
37
static  u_int8_t ndpi_check_overflow(u_int32_t current_length, u_int32_t total_lenth)
38
15.0k
{
39
15.0k
    return (current_length > 0 && current_length > INT_MAX - total_lenth);
40
15.0k
}
41
42
static void ndpi_search_smpp_tcp(struct ndpi_detection_module_struct* ndpi_struct,
43
                                 struct ndpi_flow_struct* flow)
44
4.08M
{
45
4.08M
  struct ndpi_packet_struct* packet = &ndpi_struct->packet;
46
47
4.08M
  NDPI_LOG_DBG(ndpi_struct, "search SMPP\n");
48
4.08M
  if (flow->core.detected_protocol_stack[0] != NDPI_PROTOCOL_SMPP){
49
    // min SMPP packet length = 16 bytes
50
4.08M
    if (packet->payload_packet_len < 16) {
51
1.28M
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
52
1.28M
      return;
53
1.28M
    }
54
    // get PDU length
55
2.80M
    u_int32_t pdu_l = ntohl(get_u_int32_t(packet->payload, 0));
56
57
2.80M
    NDPI_LOG_DBG2(ndpi_struct, 
58
2.80M
       "calculated PDU Length: %d, received PDU Length: %d\n", 
59
2.80M
       pdu_l, packet->payload_packet_len);
60
61
    // if PDU size was invalid, try the following TCP segments, 3 attempts max
62
2.80M
    if(flow->core.packet_counter > 3) {
63
113k
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
64
113k
      return;
65
113k
    }
66
    // verify PDU length
67
2.68M
    if(pdu_l != packet->payload_packet_len) {
68
      // check if multiple PDUs included
69
2.68M
      u_int32_t total_pdu_l = pdu_l;
70
2.68M
      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
2.69M
      while(total_pdu_l < ((uint32_t)packet->payload_packet_len-4)) {
76
  // get next PDU length
77
333k
  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
333k
  if(tmp_pdu_l == 0 ||  ndpi_check_overflow(tmp_pdu_l, total_pdu_l) ) return;
80
  // inc total PDU length
81
11.5k
  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
11.5k
      }
87
        
88
2.35M
      NDPI_LOG_DBG2(ndpi_struct, 
89
2.35M
         "multiple PDUs included, calculated total PDU Length: %d, PDU count: %d, TCP payload length: %d\n", 
90
2.35M
         total_pdu_l, pdu_c, packet->payload_packet_len);
91
92
      // verify multi PDU total length
93
2.35M
      if(total_pdu_l != packet->payload_packet_len){
94
  // return, will try the next TCP segment
95
2.35M
  return;
96
2.35M
      }
97
2.35M
    }
98
99
    // *** check PDU type ***
100
6.99k
    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
6.99k
    if(!(packet->payload[4] == 0x00 || packet->payload[4] == 0x80)) {
103
391
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
104
391
      return;
105
391
    }
106
    // remove 0x80, get request type pdu
107
6.60k
    u_int32_t pdu_req = pdu_type & 0x00FFFFFF;
108
    // list of known PDU types
109
6.60k
    if((pdu_req <= 0x00000009) || /* [0-9] */
110
2.50k
       (pdu_req == 0x0000000B || pdu_req == 0x00000015  ||
111
1.80k
        pdu_req == 0x00000021 || pdu_req == 0x00000102  ||
112
5.75k
        pdu_req == 0x00000103)){
113
114
5.75k
      NDPI_LOG_DBG2(ndpi_struct, 
115
5.75k
         "PDU type: %x, Request PDU type = %x\n", 
116
5.75k
         pdu_type, pdu_req);
117
118
      // fresult flag
119
5.75k
      char extra_passed = 1;
120
      // check PDU type specifics
121
5.75k
      switch(pdu_type){
122
  // GENERIC_NACK
123
161
      case 0x80000000:
124
  // body length must be zero
125
161
  if(pdu_l > 16) extra_passed = 0;
126
161
  break;
127
128
  // BIND_RECEIVER
129
  // BIND_TRANSMITTER
130
  // BIND_TRANSCEIVER
131
144
      case 0x00000001:
132
354
      case 0x00000002:
133
457
      case 0x00000009:
134
  // status field must be NULL
135
457
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
136
  // min body length = 10 bytes (+16 in header)
137
457
  if(pdu_l < 26) extra_passed = 0; 
138
457
  break;
139
140
  // BIND_RECEIVER_RESP
141
  // BIND_TRANSMITTER_RESP
142
  // BIND_TRANSCEIVER_RESP
143
87
      case 0x80000001:
144
193
      case 0x80000002:
145
285
      case 0x80000009:
146
  // min body length = 2 bytes (+16 in header)
147
285
  if(pdu_l < 18) extra_passed = 0;
148
285
  break;
149
150
  // OUTBIND
151
233
      case 0x0000000B:
152
  // status field must be NULL
153
233
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
154
  // min body length = 4 bytes (+16 in header)
155
233
  if(pdu_l < 20) extra_passed = 0;
156
233
  break;
157
158
  // UNBIND
159
266
      case 0x00000006:
160
  // status field must be NULL
161
266
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
162
  // body length must be zero
163
266
  if(pdu_l > 16) extra_passed = 0;
164
266
  break;
165
166
  // UNBIND_RESP
167
151
      case 0x80000006:
168
  // body length must be zero
169
151
  if(pdu_l > 16) extra_passed = 0;
170
151
  break;
171
172
173
  // SUBMIT_SM
174
415
      case 0x00000004:
175
  // status field must be NULL
176
415
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
177
  // min body length = 17 bytes (+16 in header)
178
415
  if(pdu_l < 33) extra_passed = 0;
179
415
  break;
180
       
181
  // SUBMIT_SM_RESP
182
334
      case 0x80000004:
183
  // - if status != 0, body length is 2 bytes min
184
  // - if status > 0, body lenth must be zero
185
334
  if(get_u_int32_t(packet->payload, 8) != 0){
186
198
    if(pdu_l > 16) extra_passed = 0; 
187
188
198
  }else if(pdu_l < 18) extra_passed = 0;
189
334
  break;
190
191
  // SUBMIT_MULTI
192
268
      case 0x00000021:
193
  // status field must be NULL
194
268
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
195
  // min body length = 17 bytes (+16 in header)
196
268
  if(pdu_l < 33) extra_passed = 0;
197
268
  break;
198
199
  // SUBMIT_MULTI_RESP
200
147
      case 0x80000021:
201
  // min body length = 10 bytes (+16 in header)
202
147
  if(pdu_l < 26) extra_passed = 0;
203
147
  break;
204
205
  // DELIVER_SM
206
314
      case 0x00000005:
207
  // status field must be NULL
208
314
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
209
  // min body length = 17 bytes (+16 in header)
210
314
  if(pdu_l < 33) extra_passed = 0;
211
314
  break;
212
213
  // DELIVER_SM_RESP
214
175
      case 0x80000005:
215
  // min body length = 1 byte (+16 in header)
216
175
  if(pdu_l < 17) extra_passed = 0;
217
175
  break;
218
            
219
  // DATA_SM
220
186
      case 0x00000103:
221
  // status field must be NULL
222
186
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
223
  // min body length = 10 bytes (+16 in header)
224
186
  if(pdu_l < 26) extra_passed = 0;
225
186
  break;
226
227
  // DATA_SM_RESP
228
112
      case 0x80000103:
229
  // min body length = 2 bytes (+16 in header)
230
112
  if(pdu_l < 18) extra_passed = 0;
231
112
  break;
232
233
  // QUERY_SM
234
300
      case 0x00000003:
235
  // status field must be NULL
236
300
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
237
  // min body length = 4 bytes (+16 in header)
238
300
  if(pdu_l < 20) extra_passed = 0;
239
300
  break;
240
241
  // QUERY_SM_RESP
242
142
      case 0x80000003:
243
  // min body length = 5 bytes (+16 in header)
244
142
  if(pdu_l < 21) extra_passed = 0;
245
142
  break;
246
247
  // CANCEL_SM
248
340
      case 0x00000008:
249
  // status field must be NULL
250
340
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
251
  // min body length = 8 bytes (+16 in header)
252
340
  if(pdu_l < 24) extra_passed = 0;
253
340
  break;
254
255
  // CANCEL_SM_RESP
256
141
      case 0x80000008:
257
  // body lenth must be zero
258
141
  if(pdu_l > 16) extra_passed = 0;
259
141
  break;
260
261
  // REPLACE_SM
262
338
      case 0x00000007:
263
  // status field must be NULL
264
338
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
265
  // min body length = 9 bytes (+16 in header)
266
338
  if(pdu_l < 25) extra_passed = 0;
267
338
  break;
268
269
  // REPLACE_SM_RESP
270
135
      case 0x80000007:
271
  // body lenth must be zero
272
135
  if(pdu_l > 16) extra_passed = 0;
273
135
  break;
274
275
  // ENQUIRE_LINK
276
284
      case 0x00000015:
277
  // status field must be NULL
278
284
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
279
  // body length must be zero
280
284
  if(pdu_l > 16) extra_passed = 0;
281
284
  break;
282
283
  // ENQUIRE_LINK_RESP
284
154
      case 0x80000015:
285
  // body length must be zero
286
154
  if(pdu_l > 16) extra_passed = 0;
287
154
  break;
288
289
  // ALERT_NOTIFICATION
290
225
      case 0x00000102:
291
  // status field must be NULL
292
225
  if(get_u_int32_t(packet->payload, 8) != 0) extra_passed = 0;
293
  // min body length = 6 bytes (+16 in header)
294
225
  if(pdu_l < 22) extra_passed = 0;
295
225
  break;
296
297
190
      default: break;
298
5.75k
      }
299
300
      // if extra checks passed, set as identified
301
5.75k
      if(extra_passed) {
302
1.82k
  NDPI_LOG_INFO(ndpi_struct, "found SMPP\n");
303
1.82k
  ndpi_int_smpp_add_connection(ndpi_struct, flow);
304
1.82k
  return;
305
1.82k
      }
306
5.75k
    }
307
308
4.78k
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
309
4.78k
  }
310
4.08M
}
311
312
313
void init_smpp_dissector(struct ndpi_detection_module_struct* ndpi_struct)
314
15.4k
{
315
15.4k
  ndpi_register_dissector("SMPP", ndpi_struct,
316
15.4k
                     ndpi_search_smpp_tcp,
317
15.4k
                     NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
318
15.4k
                     DISSECTOR_LICENSE_LGPL,
319
15.4k
                     1, NDPI_PROTOCOL_SMPP);
320
15.4k
}