1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** NetX Component                                                        */
16 /**                                                                       */
17 /**   Transmission Control Protocol (TCP)                                 */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 #define NX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "nx_api.h"
28 #include "nx_tcp.h"
29 #include "nx_packet.h"
30 #include "nx_ip.h"
31 
32 #ifdef NX_IPSEC_ENABLE
33 #include "nx_ipsec.h"
34 #endif /*NX_IPSEC_ENABLE*/
35 
36 #ifdef FEATURE_NX_IPV6
37 #include "nx_ipv6.h"
38 #endif /* FEATURE_NX_IPV6 */
39 
40 /**************************************************************************/
41 /*                                                                        */
42 /*  FUNCTION                                               RELEASE        */
43 /*                                                                        */
44 /*    _nx_tcp_no_connection_reset                         PORTABLE C      */
45 /*                                                           6.1          */
46 /*  AUTHOR                                                                */
47 /*                                                                        */
48 /*    Yuxin Zhou, Microsoft Corporation                                   */
49 /*                                                                        */
50 /*  DESCRIPTION                                                           */
51 /*                                                                        */
52 /*    This function sends a reset when there is no connection present,    */
53 /*    which avoids the timeout processing on the other side of the        */
54 /*    connection.                                                         */
55 /*                                                                        */
56 /*  INPUT                                                                 */
57 /*                                                                        */
58 /*    ip_ptr                                Pointer to IP control block   */
59 /*    packet_ptr                            Pointer to packet to send     */
60 /*    tcp_header_ptr                        TCP header                    */
61 /*                                                                        */
62 /*  OUTPUT                                                                */
63 /*                                                                        */
64 /*    None                                                                */
65 /*                                                                        */
66 /*  CALLS                                                                 */
67 /*                                                                        */
68 /*    _nxd_tcp_no_connect_reset             Invokes tcp no conn reset     */
69 /*                                                                        */
70 /*  CALLED BY                                                             */
71 /*                                                                        */
72 /*    _nx_tcp_packet_process                TCP packet processing         */
73 /*                                                                        */
74 /*  RELEASE HISTORY                                                       */
75 /*                                                                        */
76 /*    DATE              NAME                      DESCRIPTION             */
77 /*                                                                        */
78 /*  05-19-2020     Yuxin Zhou               Initial Version 6.0           */
79 /*  09-30-2020     Yuxin Zhou               Modified comment(s),          */
80 /*                                            resulting in version 6.1    */
81 /*                                                                        */
82 /**************************************************************************/
_nx_tcp_no_connection_reset(NX_IP * ip_ptr,NX_PACKET * packet_ptr,NX_TCP_HEADER * tcp_header_ptr)83 VOID  _nx_tcp_no_connection_reset(NX_IP *ip_ptr, NX_PACKET *packet_ptr, NX_TCP_HEADER *tcp_header_ptr)
84 {
85 
86 NX_TCP_SOCKET fake_socket;
87 ULONG         header_length;
88 #ifdef NX_IPSEC_ENABLE
89 VOID         *sa;
90 NXD_ADDRESS   source_ip;
91 NXD_ADDRESS   destination_ip;
92 UINT          ret;
93 ULONG         data_offset = 0;
94 #endif /* NX_IPSEC_ENABLE */
95 
96 
97     /* Clear the fake socket first.  */
98     memset((void *)&fake_socket, 0, sizeof(NX_TCP_SOCKET));
99 
100     /* Build a fake socket so we can send a reset TCP requests that are not valid.  */
101     fake_socket.nx_tcp_socket_ip_ptr = ip_ptr;
102 
103     /* Set the connection IP address.  */
104 #ifndef NX_DISABLE_IPV4
105     if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V4)
106     {
107     NX_IPV4_HEADER *ip_header_ptr;
108 
109         /* Set the IP header.  */
110         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
111         ip_header_ptr =  (NX_IPV4_HEADER *)packet_ptr -> nx_packet_ip_header;
112 
113         /* Set the connection ip.  */
114         fake_socket.nx_tcp_socket_connect_ip.nxd_ip_version = NX_IP_VERSION_V4;
115         fake_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4 = ip_header_ptr -> nx_ip_header_source_ip;
116 
117         /* Assume the interface that receives the incoming packet is the best interface
118            for sending responses. */
119         fake_socket.nx_tcp_socket_connect_interface = packet_ptr -> nx_packet_address.nx_packet_interface_ptr;
120         fake_socket.nx_tcp_socket_next_hop_address = NX_NULL;
121 
122         /* Find the next hop info. */
123         _nx_ip_route_find(ip_ptr, fake_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v4, &fake_socket.nx_tcp_socket_connect_interface,
124                           &fake_socket.nx_tcp_socket_next_hop_address);
125 
126 #ifdef NX_IPSEC_ENABLE
127         /* Get the source ip address.  */
128         source_ip.nxd_ip_version = NX_IP_VERSION_V4;
129         source_ip.nxd_ip_address.v4 = fake_socket.nx_tcp_socket_connect_interface -> nx_interface_ip_address;
130 
131         /* Get the destination ip address.  */
132         destination_ip.nxd_ip_version = NX_IP_VERSION_V4;
133         destination_ip.nxd_ip_address.v4 = ip_header_ptr -> nx_ip_header_source_ip;
134 #endif /*NX_IPSEC_ENABLE*/
135     }
136 #endif /* !NX_DISABLE_IPV4  */
137 
138 #ifdef FEATURE_NX_IPV6
139     if (packet_ptr -> nx_packet_ip_version == NX_IP_VERSION_V6)
140     {
141     NX_IPV6_HEADER *ipv6_header_ptr;
142 
143         /* Set the IP header.  */
144         /*lint -e{927} -e{826} suppress cast of pointer to pointer, since it is necessary  */
145         ipv6_header_ptr = (NX_IPV6_HEADER *)packet_ptr -> nx_packet_ip_header;
146 
147         /* Set the connection ip.  */
148         fake_socket.nx_tcp_socket_connect_ip.nxd_ip_version = NX_IP_VERSION_V6;
149         COPY_IPV6_ADDRESS(&ipv6_header_ptr -> nx_ip_header_source_ip[0], fake_socket.nx_tcp_socket_connect_ip.nxd_ip_address.v6);
150 
151         /* Set the outgoing address.  */
152         fake_socket.nx_tcp_socket_ipv6_addr = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr;
153 
154         /* Set the connect ip interface.  */
155         fake_socket.nx_tcp_socket_connect_interface = packet_ptr -> nx_packet_address.nx_packet_ipv6_address_ptr -> nxd_ipv6_address_attached;
156 
157 #ifdef NX_IPSEC_ENABLE
158         /* Get the source ip address.  */
159         source_ip.nxd_ip_version = NX_IP_VERSION_V6;
160         COPY_IPV6_ADDRESS(fake_socket.nx_tcp_socket_ipv6_addr -> nxd_ipv6_address, source_ip.nxd_ip_address.v6);
161 
162         /* Get the destination ip address.  */
163         destination_ip.nxd_ip_version = NX_IP_VERSION_V6;
164         COPY_IPV6_ADDRESS(&ipv6_header_ptr -> nx_ip_header_source_ip[0], destination_ip.nxd_ip_address.v6);
165 #endif /*NX_IPSEC_ENABLE*/
166     }
167 #endif /* FEATURE_NX_IPV6 */
168 
169     /* Set the source port and destination port.  */
170     fake_socket.nx_tcp_socket_port  = (UINT)(tcp_header_ptr -> nx_tcp_header_word_0 & NX_LOWER_16_MASK);
171     fake_socket.nx_tcp_socket_connect_port = (UINT)(tcp_header_ptr -> nx_tcp_header_word_0 >> NX_SHIFT_BY_16);
172 
173     /* Set the sequence number only if the incoming segment does not have the ACK flag, according to
174        Section 3.4, "Reset Generation" on page 37, RFC793. */
175     if (!(tcp_header_ptr -> nx_tcp_header_word_3 & NX_TCP_ACK_BIT))
176     {
177         /* Get the header length.  */
178         header_length = (tcp_header_ptr -> nx_tcp_header_word_3 >> NX_TCP_HEADER_SHIFT) * (ULONG)sizeof(ULONG);
179 
180         /* Update sequence number to set the reset acknowledge number.  */
181         tcp_header_ptr -> nx_tcp_sequence_number += (packet_ptr -> nx_packet_length - header_length);
182 
183         /* Check the SYN and FIN bits.  */
184         if (tcp_header_ptr -> nx_tcp_header_word_3 & (NX_TCP_SYN_BIT | NX_TCP_FIN_BIT))
185         {
186 
187             /* Update sequence number to set the reset acknowledge number.  */
188             tcp_header_ptr -> nx_tcp_sequence_number++;
189         }
190     }
191 
192 #ifdef NX_IPSEC_ENABLE
193     /* Check for possible SA match. */
194     if (ip_ptr -> nx_ip_packet_egress_sa_lookup != NX_NULL)                   /* IPsec is enabled. */
195     {
196 
197         /* If the SA has not been set. */
198         ret = ip_ptr -> nx_ip_packet_egress_sa_lookup(ip_ptr,                                   /* IP ptr */
199                                                       &source_ip,                               /* src_addr */
200                                                       &destination_ip,                          /* dest_addr */
201                                                       NX_PROTOCOL_TCP,                          /* protocol */
202                                                       fake_socket.nx_tcp_socket_port,           /* src_port */
203                                                       fake_socket.nx_tcp_socket_connect_port,   /* dest_port */
204                                                       &data_offset, &sa, 0);
205         if (ret == NX_IPSEC_TRAFFIC_PROTECT)
206         {
207 
208             /* Save the SA to the socket. */
209             fake_socket.nx_tcp_socket_egress_sa = sa;
210             fake_socket.nx_tcp_socket_egress_sa_data_offset = data_offset;
211         }
212         else if (ret == NX_IPSEC_TRAFFIC_DROP || ret == NX_IPSEC_TRAFFIC_PENDING_IKEV2)
213         {
214 
215             return;
216         }
217         else
218         {
219 
220             /* Zero out SA information. */
221             fake_socket.nx_tcp_socket_egress_sa = NX_NULL;
222             fake_socket.nx_tcp_socket_egress_sa_data_offset = 0;
223         }
224     }
225 #endif
226 
227     fake_socket.nx_tcp_socket_time_to_live = (UINT)NX_IP_TIME_TO_LIVE;
228 
229     /* Send a RST to indicate the connection was not available.  */
230     _nx_tcp_packet_send_rst(&fake_socket, tcp_header_ptr);
231 }
232 
233