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/rdp.c
Line
Count
Source
1
/*
2
 * rdp.c
3
 *
4
 * Copyright (C) 2009-11 - ipoque GmbH
5
 * Copyright (C) 2011-25 - ntop.org
6
 *
7
 * This file is part of nDPI, an open source deep packet inspection
8
 * library based on the OpenDPI and PACE technology by ipoque GmbH
9
 *
10
 * nDPI is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU Lesser General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * nDPI is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU Lesser General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU Lesser General Public License
21
 * along with nDPI.  If not, see <http://www.gnu.org/licenses/>.
22
 * 
23
 */
24
25
26
#include "ndpi_protocol_ids.h"
27
28
#define NDPI_CURRENT_PROTO NDPI_PROTOCOL_RDP
29
30
0
#define RDP_PORT 3389
31
32
#include "ndpi_api.h"
33
#include "ndpi_private.h"
34
35
extern int ndpi_tls_obfuscated_heur_search_again(struct ndpi_detection_module_struct* ndpi_struct,
36
             struct ndpi_flow_struct* flow);
37
38
/* **************************************** */
39
40
static void ndpi_int_rdp_add_connection(struct ndpi_detection_module_struct *ndpi_struct,
41
0
          struct ndpi_flow_struct *flow) {
42
0
  NDPI_LOG_INFO(ndpi_struct, "found RDP\n");
43
0
  ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_RDP, NDPI_PROTOCOL_UNKNOWN, NDPI_CONFIDENCE_DPI);
44
0
  ndpi_set_risk(ndpi_struct, flow, NDPI_DESKTOP_OR_FILE_SHARING_SESSION, "Found RDP"); /* Remote assistance */
45
0
}
46
47
/* **************************************** */
48
49
/* tls.c */
50
extern int ndpi_search_tls_tcp(struct ndpi_detection_module_struct *ndpi_struct,
51
             struct ndpi_flow_struct *flow);
52
53
int ndpi_search_tls_over_rdp(struct ndpi_detection_module_struct *ndpi_struct,
54
0
           struct ndpi_flow_struct *flow) {
55
0
  const struct ndpi_packet_struct * const packet = &ndpi_struct->packet;
56
  
57
0
  if((packet->payload_packet_len > 1)
58
0
     && (packet->payload[0] == 0x16 /* This might be a TLS block */)) {
59
0
    int rc = ndpi_search_tls_tcp(ndpi_struct, flow);
60
61
0
    return(rc);
62
0
  } else
63
0
    return 1; /* Keep searching */
64
0
}
65
66
/* **************************************** */
67
68
static void ndpi_search_rdp(struct ndpi_detection_module_struct *ndpi_struct,
69
0
          struct ndpi_flow_struct *flow) {
70
0
  const struct ndpi_packet_struct * const packet = &ndpi_struct->packet;
71
  
72
0
  NDPI_LOG_DBG(ndpi_struct, "search RDP\n");
73
74
0
  if (packet->tcp != NULL) {
75
0
    if(packet->payload_packet_len > 13 &&
76
0
       tpkt_verify_hdr(packet) &&
77
       /* COTP */
78
0
       packet->payload[4] == packet->payload_packet_len - 5) {
79
80
0
      if(current_pkt_from_client_to_server(ndpi_struct, flow)) {
81
0
        if(packet->payload[5] == 0xE0 && /* COTP CR */
82
0
     ((packet->payload[11] == 0x01 && /* RDP Negotiation Request */
83
0
             packet->payload[13] == 0x08 /* RDP Length */) ||
84
0
      (packet->payload_packet_len > 17 &&
85
0
       memcmp(&packet->payload[11], "Cookie:", 7) == 0))) /* RDP Cookie */ {
86
87
0
    if(packet->payload_packet_len > 43) {
88
0
      u_int8_t rdp_requested_proto = packet->payload[43];
89
90
      /* Check if TLS support has been requested in RDP */
91
0
      if((rdp_requested_proto & 0x1) == 0x1) {
92
        /* RDP Response + Client Hello + Server hello */
93
0
        flow->max_extra_packets_to_check = 5;
94
0
        flow->tls_quic.from_rdp = 1;
95
0
        flow->extra_packets_func = ndpi_search_tls_over_rdp;
96
0
      }
97
0
    }
98
    
99
0
          ndpi_int_rdp_add_connection(ndpi_struct, flow);
100
101
0
          return;
102
0
  }
103
0
      } else {
104
        /* Asymmetric detection via RDP Negotiation Response */
105
0
        if(packet->payload[5] == 0xD0 && /* COTP CC */
106
0
     packet->payload[11] == 0x02 && /* RDP Negotiation Response */
107
0
           packet->payload[13] == 0x08 /* RDP Length */) {
108
0
          ndpi_int_rdp_add_connection(ndpi_struct, flow);
109
0
    return;
110
0
  }
111
0
      }
112
0
    }
113
0
    NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
114
0
  } else if(packet->udp != NULL) {
115
0
    u_int16_t s_port = ntohs(packet->udp->source);
116
0
    u_int16_t d_port = ntohs(packet->udp->dest);
117
118
    /* Detection:
119
       * initial syn/syn-ack pair for RDPUDP v1 & v2
120
       * mid-flow (only v1) */
121
122
0
    if((packet->payload_packet_len >= 10) && ((s_port == RDP_PORT) || (d_port == RDP_PORT))) {
123
0
      if(s_port == RDP_PORT) {
124
  /* Server -> Client */
125
0
  if(flow->l4.udp.rdp_from_srv_pkts == 0) {
126
0
    if(memcmp(packet->payload, flow->l4.udp.rdp_from_srv, 3) == 0 &&
127
0
       packet->payload_packet_len >= 16 &&
128
0
       (ntohs(get_u_int16_t(packet->payload, 6)) & 0x0003) && /* Flags: syn-ack */
129
0
       ntohs(get_u_int16_t(packet->payload, 12)) <= 1600 && /* Sensible values for upstream MTU */
130
0
       ntohs(get_u_int16_t(packet->payload, 14)) <= 1600) { /* Sensible values for downstream MTU */
131
      /* Initial "syn-ack" */
132
0
      ndpi_int_rdp_add_connection(ndpi_struct, flow);
133
0
      return;
134
0
    } else {
135
      /* Mid-flow session? */
136
0
      memcpy(flow->l4.udp.rdp_from_srv, packet->payload, 3), flow->l4.udp.rdp_from_srv_pkts = 1;
137
0
    }
138
0
  } else {
139
0
    if(memcmp(flow->l4.udp.rdp_from_srv, packet->payload, 3) != 0)
140
0
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
141
0
    else {
142
0
      flow->l4.udp.rdp_from_srv_pkts = 2 /* stage 2 */;
143
144
0
      if(flow->l4.udp.rdp_to_srv_pkts == 2) {
145
0
        ndpi_int_rdp_add_connection(ndpi_struct, flow);
146
0
        return;
147
0
      }
148
0
    }
149
0
  }
150
0
      } else {
151
  /* Client -> Server */
152
0
  if(flow->l4.udp.rdp_to_srv_pkts == 0) {
153
0
    if(get_u_int32_t(packet->payload, 0) == 0xFFFFFFFF &&
154
0
       packet->payload_packet_len >= 16 &&
155
0
       (ntohs(get_u_int16_t(packet->payload, 6)) & 0x0001) && /* Flags: syn */
156
0
       ntohs(get_u_int16_t(packet->payload, 12)) <= 1600 && /* Sensible values for upstream MTU */
157
0
       ntohs(get_u_int16_t(packet->payload, 14)) <= 1600) { /* Sensible values for downstream MTU */
158
      /* Initial "syn" */
159
0
      memcpy(flow->l4.udp.rdp_from_srv, packet->payload + 8, 3);
160
0
    } else {
161
      /* Mid-flow session? */
162
0
      memcpy(flow->l4.udp.rdp_to_srv, packet->payload, 3), flow->l4.udp.rdp_to_srv_pkts = 1;
163
0
    }
164
0
  } else {
165
0
    if(memcmp(flow->l4.udp.rdp_to_srv, packet->payload, 3) != 0)
166
0
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
167
0
    else {
168
0
      flow->l4.udp.rdp_to_srv_pkts = 2 /* stage 2 */;
169
      
170
0
      if(flow->l4.udp.rdp_from_srv_pkts == 2) {
171
0
              ndpi_int_rdp_add_connection(ndpi_struct, flow);
172
0
              return;
173
0
      }
174
0
    }
175
0
  }
176
0
      }
177
0
    } else
178
0
      NDPI_EXCLUDE_DISSECTOR(ndpi_struct, flow);
179
0
  }
180
0
}
181
182
/* **************************************** */
183
184
void init_rdp_dissector(struct ndpi_detection_module_struct *ndpi_struct)
185
1
{
186
1
  register_dissector("RDP", ndpi_struct,
187
1
                     ndpi_search_rdp,
188
1
                     NDPI_SELECTION_BITMASK_PROTOCOL_V4_V6_TCP_OR_UDP_WITH_PAYLOAD_WITHOUT_RETRANSMISSION,
189
1
                     1, NDPI_PROTOCOL_RDP);
190
1
}