1 /*
2  * rx.c
3  *
4  * Copyright (C) 2012-21 - ntop.org
5  *
6  * Giovanni Mascellani <gio@debian.org>
7  *
8  * This file is part of nDPI, an open source deep packet inspection
9  * library based on the OpenDPI and PACE technology by ipoque GmbH
10  *
11  * nDPI is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * nDPI is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with nDPI.  If not, see <http://www.gnu.org/licenses/>.
23  *
24  */
25 #include "ndpi_protocol_ids.h"
26 
27 
28 #define NDPI_CURRENT_PROTO NDPI_PROTOCOL_RX
29 
30 #include "ndpi_api.h"
31 
32 /* See http://web.mit.edu/kolya/afs/rx/rx-spec for protocol description. */
33 
34 /* The should be no need for explicit packing, but just in case... */
35 PACK_ON
36 struct ndpi_rx_header {
37   u_int32_t conn_epoch;
38   u_int32_t conn_id;
39   u_int32_t call_number;
40   u_int32_t sequence_number;
41   u_int32_t serial_number;
42   u_int8_t type;
43   u_int8_t flags;
44   u_int8_t status;
45   u_int8_t security;
46   u_int16_t checksum;
47   u_int16_t service_id;
48 } PACK_OFF;
49 
50 /* Type values */
51 #define DATA	           1
52 #define	ACK	           2
53 #define	BUSY	           3
54 #define	ABORT	           4
55 #define	ACKALL	           5
56 #define	CHALLENGE          6
57 #define	RESPONSE           7
58 #define	DEBUG	           8
59 #define	PARAM_1            9
60 #define	PARAM_2           10
61 #define	PARAM_3           11
62 #define	PARAMS_4          12
63 #define	VERS	          13
64 
65 /* Flags values */
66 #define EMPTY              0
67 #define CLIENT_INIT_1      1
68 #define REQ_ACK            2
69 #define PLUS_0             3
70 #define LAST_PKT           4
71 #define PLUS_1             5
72 #define PLUS_2             6
73 #define MORE_1             9
74 #define CLIENT_INIT_2     33
75 
76 
77 
ndpi_check_rx(struct ndpi_detection_module_struct * ndpi_struct,struct ndpi_flow_struct * flow)78 void ndpi_check_rx(struct ndpi_detection_module_struct *ndpi_struct,
79                    struct ndpi_flow_struct *flow)
80 {
81   struct ndpi_packet_struct *packet = &flow->packet;
82   u_int32_t payload_len = packet->payload_packet_len;
83 
84   NDPI_LOG_DBG2(ndpi_struct, "RX: pck: %d, dir[0]: %d, dir[1]: %d\n",
85            flow->packet_counter, flow->packet_direction_counter[0], flow->packet_direction_counter[1]);
86 
87   /* Check that packet is long enough */
88   if (payload_len < sizeof(struct ndpi_rx_header)) {
89     NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
90     return;
91   }
92 
93   struct ndpi_rx_header *header = (struct ndpi_rx_header*) packet->payload;
94 
95   /**
96    * Useless check: a session could be detected also after it starts
97    * and this check limit the correct detection for -d option (disable guess)
98    * TODO - maybe to improve
99    **/
100   /* Check whether the packet has counters beginning from one; the
101      Sequence Number can be zero if the packet is just an ACK. */
102   /* if ((ntohl(header->sequence_number) | 1) != 1 || ntohl(header->serial_number) != 1) */
103 
104 
105   /**
106    *  Check the TYPE and FLAGS fields of an RX packet header.
107    *  This check is necessary because we could detect an RX session already begun
108   **/
109 
110   /* TYPE field */
111   if((header->type < DATA) || (header->type > VERS)) {
112     NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
113     return;
114   }
115 
116   /* FLAGS fields */
117   if(header->flags == EMPTY || header->flags == LAST_PKT ||
118      header->flags == PLUS_0 || header->flags == PLUS_1 ||
119      header->flags == PLUS_2 || header->flags == REQ_ACK ||
120      header->flags == MORE_1 || header->flags == CLIENT_INIT_1 ||
121      header->flags == CLIENT_INIT_2) {
122 
123     /* TYPE and FLAGS combo */
124     switch(header->type)
125     {
126       case DATA:
127 	if(header->flags == LAST_PKT || header->flags == EMPTY ||
128 	   header->flags == PLUS_0 || header->flags == PLUS_1 ||
129 	   header->flags == PLUS_2 || header->flags == REQ_ACK ||
130 	   header->flags == MORE_1)
131 	  goto security;
132 	/* Fall-through */
133       case ACK:
134 	if(header->flags == CLIENT_INIT_1 || header->flags == CLIENT_INIT_2 ||
135 	   header->flags == EMPTY)
136 	  goto security;
137 	/* Fall-through */
138       case CHALLENGE:
139 	if(header->flags == EMPTY || header->call_number == 0)
140 	  goto security;
141 	/* Fall-through */
142       case RESPONSE:
143 	if(header->flags == EMPTY || header->call_number == 0)
144 	  goto security;
145 	/* Fall-through */
146       case ACKALL:
147 	if(header->flags == EMPTY)
148 	  goto security;
149 	/* Fall-through */
150       case BUSY:
151 	goto security;
152       case ABORT:
153 	goto security;
154       case DEBUG:
155 	goto security;
156       case PARAM_1:
157 	goto security;
158       case PARAM_2:
159         goto security;
160       case PARAM_3:
161 	goto security;
162       case VERS:
163 	goto security;
164       default:
165 	NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
166 	return;
167     } // switch
168   } else { // FLAG
169     NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
170     return;
171   }
172 
173  security:
174   /* SECURITY field */
175   if(header->security > 3)
176   {
177     NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
178     return;
179   }
180 
181   /* If we have already seen one packet in the other direction, then
182      the two must have matching connection numbers. Otherwise store
183      them. */
184   if(flow->packet_direction_counter[!packet->packet_direction] != 0)
185   {
186     if (flow->l4.udp.rx_conn_epoch == header->conn_epoch &&
187 	flow->l4.udp.rx_conn_id == header->conn_id)
188     {
189       NDPI_LOG_INFO(ndpi_struct, "found RX\n");
190       ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_RX, NDPI_PROTOCOL_UNKNOWN);
191     }
192     /* https://www.central.org/frameless/numbers/rxservice.html. */
193     else
194     {
195       NDPI_EXCLUDE_PROTO(ndpi_struct, flow);
196       return;
197     }
198   } else {
199     flow->l4.udp.rx_conn_epoch = header->conn_epoch;
200     flow->l4.udp.rx_conn_id = header->conn_id;
201     {
202       NDPI_LOG_INFO(ndpi_struct, "found RX\n");
203       ndpi_set_detected_protocol(ndpi_struct, flow, NDPI_PROTOCOL_RX, NDPI_PROTOCOL_UNKNOWN);
204     }
205   }
206 }
207 
ndpi_search_rx(struct ndpi_detection_module_struct * ndpi_struct,struct ndpi_flow_struct * flow)208 void ndpi_search_rx(struct ndpi_detection_module_struct *ndpi_struct,
209                     struct ndpi_flow_struct *flow)
210 {
211   struct ndpi_packet_struct *packet = &flow->packet;
212 
213   NDPI_LOG_DBG(ndpi_struct, "search RX\n");
214   if (packet->detected_protocol_stack[0] != NDPI_PROTOCOL_RX) {
215     ndpi_check_rx(ndpi_struct, flow);
216   }
217 }
218 
init_rx_dissector(struct ndpi_detection_module_struct * ndpi_struct,u_int32_t * id,NDPI_PROTOCOL_BITMASK * detection_bitmask)219 void init_rx_dissector(struct ndpi_detection_module_struct *ndpi_struct,
220                        u_int32_t *id,
221                        NDPI_PROTOCOL_BITMASK *detection_bitmask)
222 {
223   ndpi_set_bitmask_protocol_detection("RX", ndpi_struct, detection_bitmask, *id,
224 				      NDPI_PROTOCOL_RX,
225 				      ndpi_search_rx,
226 				      NDPI_SELECTION_BITMASK_PROTOCOL_UDP_WITH_PAYLOAD,
227 				      SAVE_DETECTION_BITMASK_AS_UNKNOWN,
228 				      ADD_TO_DETECTION_BITMASK);
229 
230   *id += 1;
231 }
232 
233