@@ -64,6 +64,91 @@ OvpnTxAreSockaddrEqual(const SOCKADDR* addr1, const SOCKADDR* addr2) {
6464 return 0 ;
6565}
6666
67+ BOOLEAN
68+ OvpnCheckRecursiveRoutingIPv4 (SOCKADDR_IN* transportAdds, UCHAR* buffer, SIZE_T bufferLength, BOOLEAN tcp)
69+ {
70+ if (transportAdds->sin_family != AF_INET || bufferLength < sizeof (IPV4_HEADER))
71+ return FALSE ; // Not an IPv4 peer or packet too short
72+
73+ // Extract pointers to avoid repeated FIELD_OFFSET calculations
74+ IN_ADDR* srcAddr = (IN_ADDR*)(buffer + FIELD_OFFSET (IPV4_HEADER, SourceAddress));
75+ IN_ADDR* dstAddr = (IN_ADDR*)(buffer + FIELD_OFFSET (IPV4_HEADER, DestinationAddress));
76+ UINT8 packetProtocol = buffer[FIELD_OFFSET (IPV4_HEADER, Protocol)];
77+
78+ // Validate the transport protocol
79+ if ((tcp && packetProtocol != IPPROTO_TCP) || (!tcp && packetProtocol != IPPROTO_UDP))
80+ return FALSE ;
81+
82+ // Extract IP header length
83+ UINT8 ipHeaderLength = (buffer[0 ] & 0x0F ) << 2 ;
84+
85+ // Ensure transport header is accessible
86+ if (bufferLength < ipHeaderLength + sizeof (UINT16) * 2 )
87+ return FALSE ;
88+
89+ // Read transport header efficiently
90+ UCHAR* transportHeader = buffer + ipHeaderLength;
91+ UINT16 packetSrcPort = RtlUshortByteSwap (*(UINT16*)(transportHeader));
92+ UINT16 packetDstPort = RtlUshortByteSwap (*(UINT16*)(transportHeader + 2 ));
93+ UINT16 peerPort = RtlUshortByteSwap (transportAdds->sin_port );
94+
95+ // Check for recursive routing
96+ if (packetDstPort == peerPort &&
97+ RtlCompareMemory (dstAddr, &transportAdds->sin_addr , sizeof (IN_ADDR)) == sizeof (IN_ADDR))
98+ {
99+ LOG_WARN (" Recursive routing detected (IPv4), packet dropped" ,
100+ TraceLoggingIPv4Address (srcAddr->S_un .S_addr , " saddr" ),
101+ TraceLoggingIPv4Address (dstAddr->S_un .S_addr , " daddr" ),
102+ TraceLoggingUInt16 (packetSrcPort, " sport" ),
103+ TraceLoggingUInt16 (packetDstPort, " dport" ),
104+ TraceLoggingUInt8 (packetProtocol, " protocol" ));
105+ return TRUE ;
106+ }
107+
108+ return FALSE ;
109+ }
110+
111+ BOOLEAN
112+ OvpnCheckRecursiveRoutingIPv6 (SOCKADDR_IN6* transportAddr, UCHAR* buffer, SIZE_T bufferLength, BOOLEAN tcp)
113+ {
114+ if (transportAddr->sin6_family != AF_INET6 || bufferLength < sizeof (IPV6_HEADER))
115+ return FALSE ; // Not an IPv6 peer or packet too short
116+
117+ // Extract pointers to avoid repeated FIELD_OFFSET calculations
118+ IN6_ADDR* srcAddr = (IN6_ADDR*)(buffer + FIELD_OFFSET (IPV6_HEADER, SourceAddress));
119+ IN6_ADDR* dstAddr = (IN6_ADDR*)(buffer + FIELD_OFFSET (IPV6_HEADER, DestinationAddress));
120+ UINT8 packetProtocol = buffer[FIELD_OFFSET (IPV6_HEADER, NextHeader)];
121+
122+ // Validate the transport protocol
123+ if ((tcp && packetProtocol != IPPROTO_TCP) || (!tcp && packetProtocol != IPPROTO_UDP))
124+ return FALSE ;
125+
126+ // Ensure transport header is accessible
127+ if (bufferLength < sizeof (IPV6_HEADER) + sizeof (UINT16) * 2 )
128+ return FALSE ;
129+
130+ // Read transport header efficiently
131+ UCHAR* transportHeader = buffer + sizeof (IPV6_HEADER);
132+ UINT16 packetSrcPort = RtlUshortByteSwap (*(UINT16*)(transportHeader));
133+ UINT16 packetDstPort = RtlUshortByteSwap (*(UINT16*)(transportHeader + 2 ));
134+ UINT16 peerPort = RtlUshortByteSwap (transportAddr->sin6_port );
135+
136+ // Check for recursive routing
137+ if (packetDstPort == peerPort &&
138+ RtlCompareMemory (dstAddr, &transportAddr->sin6_addr , sizeof (IN6_ADDR)) == sizeof (IN6_ADDR))
139+ {
140+ LOG_WARN (" Recursive routing detected (IPv6), packet dropped" ,
141+ TraceLoggingIPv6Address (srcAddr->u .Byte , " saddr" ),
142+ TraceLoggingIPv6Address (dstAddr->u .Byte , " daddr" ),
143+ TraceLoggingUInt16 (packetSrcPort, " sport" ),
144+ TraceLoggingUInt16 (packetDstPort, " dport" ),
145+ TraceLoggingUInt8 (packetProtocol, " protocol" ));
146+ return TRUE ;
147+ }
148+
149+ return FALSE ;
150+ }
151+
67152_Must_inspect_result_
68153static
69154NTSTATUS
@@ -114,6 +199,11 @@ OvpnTxProcessPacket(_In_ POVPN_DEVICE device, _In_ POVPN_TXQUEUE queue, _In_ NET
114199 peer = device->IRoutesIPV4 .Find (reinterpret_cast <UCHAR*>(&addr));
115200 }
116201
202+ if ((device->Mode == OVPN_MODE_P2P) && (peer != nullptr ) && (OvpnCheckRecursiveRoutingIPv4 (&peer->TransportAddrs .Remote .IPv4 , buffer->Data , buffer->Len , device->Socket .Tcp ))) {
203+ OvpnPeerCtxRelease (peer);
204+ peer = nullptr ;
205+ }
206+
117207 if (peer != nullptr ) {
118208 OvpnMssDoIPv4 (buffer->Data , buffer->Len , peer->MSS );
119209 }
@@ -125,6 +215,11 @@ OvpnTxProcessPacket(_In_ POVPN_DEVICE device, _In_ POVPN_TXQUEUE queue, _In_ NET
125215 peer = device->IRoutesIPV6 .Find (reinterpret_cast <UCHAR*>(&addr));
126216 }
127217
218+ if ((device->Mode == OVPN_MODE_P2P) && (peer != nullptr ) && (OvpnCheckRecursiveRoutingIPv6 (&peer->TransportAddrs .Remote .IPv6 , buffer->Data , buffer->Len , device->Socket .Tcp ))) {
219+ OvpnPeerCtxRelease (peer);
220+ peer = nullptr ;
221+ }
222+
128223 if (peer != nullptr ) {
129224 OvpnMssDoIPv6 (buffer->Data , buffer->Len , peer->MSS );
130225 }
0 commit comments