summaryrefslogtreecommitdiff
path: root/datapath-windows/ovsext/Conntrack-ftp.c
diff options
context:
space:
mode:
authorldejing <ldejing@vmware.com>2022-04-11 18:07:11 +0800
committerAlin-Gabriel Serdean <aserdean@ovn.org>2022-04-22 12:08:38 +0300
commit53b75e91ded95d25c6cae5698ad242ad775ebb40 (patch)
tree913638673d2db7d164b1a07b989167d490efb670 /datapath-windows/ovsext/Conntrack-ftp.c
parent96dc66ddadc35475ed93b25a84874c926f4d9dd3 (diff)
downloadopenvswitch-53b75e91ded95d25c6cae5698ad242ad775ebb40.tar.gz
datapath-windows: Add IPv6 conntrack support on Windows.
Implementation on Windows: Currently, IPv4 conntrack was supported on the windows platform. In this patch we have implemented ipv6 conntrack functions according to the current logic of the IPv4 conntrack. This implementation has included TcpV6(nat and normal scenario), UdpV6(nat and normal scenario), IcmpV6 conntrack of echo request/reply packet and FtpV6(nat and normal scenario). Testing Topology: On the Windows VM runs on the ESXi host, two hyper-v ports attached to the ovs bridge; one hyper-v port worked as client and the other port worked as server. Testing Case: 1. TcpV6 a) Tcp request/reply conntrack for normal scenario. In this scenario, 20::1 as client, 20::2 as server, it will generate following conntrack entry: (Origin(src=20::1, src_port=1555, dst=20::2, dst_port=1556), reply(src=20::2,src_port=1556,dst=20::1,dst_port=1555),protocol=tcp) b) Tcp request/reply conntrack for nat scenario. In this scenario, 20::1 as client, 20::10 as floating ip, 21::3 as server, it will generate following conntrack entry: (Origin(src=20::1, src_port=1555, dst=20::10, dst_port=1556), reply(src=21::3, src_port=1556, dst=20::1, dst_port= 1555),protocol=tcp) 2. UdpV6 a) Udp request/reply conntrack for normal scenario. (Origin(src=20::1, src_port=1555, dst=20::2, dst_port=1556), reply(src=20::2,src_port=1556,dst=20::1,dst_port=1555),protocol=udp) b) Udp request/reply conntrack for nat scenario. (Origin(src=20::1, src_port=1555, dst=20::10, dst_port=1556), reply(src=21::3, src_port=1556, dst=20::1, dst_port= 1555),protocol=udp) 3. IcmpV6: a) Icmpv6 request/reply conntrack for normal scenario. Currently Icmpv6 only support to construct conntrack for echo request/reply packet, take (20::1 -> 20::2) for example, it will generate following conntrack entry: (origin(src = 20::1, dst=20::2), reply(src=20::2, dst=20::1), protocol=icmp) b) Icmp request/reply conntrack for dnat scenario, for example (20::1->20::10->21::3), 20::1 is client, 20::10 is floating ip, 21::3 is server ip. It will generate flow like below: (origin(src=20::1, dst=20::10), reply(src=21::3, dst=20::1), protocol=icmp) 4. FtpV6 a) Ftp request/reply conntrack for normal scenario. In this scenario, take 20::1 as client, 20::2 as server, it will generate two conntrack entries: Ftp active mode (Origin(src=20::1, src_port=1555, dst=20::2, dst_port=21), reply(src=20::2, src_port=21, dst=20::1, dst_port=1555), protocol=tcp) (Origin(src=20::2, src_port=20, dst=20::1, dst_port=1556), reply(src=20::1, src_port=1556, dst=20::2, dst_port=20), protocol=tcp) Ftp passive mode (Origin(src=20::1, src_port=1555, dst=20::2, dst_port=21), reply(src=20::2,src_port=21,dst=20::1,dst_port=1555),protocol=tcp) (Origin(src=20::1, src_port=1556, dst=20::2, dst_port=1557), reply(src=20::2,src_port=1557, dst=20::1, dst_port=1556) protocol=tcp) b) Ftp request/reply conntrack for nat scenario. Ftp passive mode, In this secnario, 20::1 as client, 20::10 as floating ip, 21::3 as server ip. It will generate following flow: (Origin(src=20::1, src_port=1555, dst=20::10, dst_port=21), reply(src=21::3, src_port=21, dst=20::1, dst_port= 1555),protocol=tcp) (Origin(src=20::1, src_port=1556, dst=20::10, dst_port=1557), reply(src=21::3, src_port=1557, dst=20::1, dst_port= 1556),protocol=tcp) 5. Regression test for IpV4 in Antrea project (about 60 test case) Future work: 1) IcmpV6 redirect packet conntrack. 2) IpV6 fragment support on Udp. 3) Support napt for IPv6. 4) FtpV6 active mode for nat. Signed-off-by: ldejing <ldejing@vmware.com> Signed-off-by: Alin-Gabriel Serdean <aserdean@ovn.org>
Diffstat (limited to 'datapath-windows/ovsext/Conntrack-ftp.c')
-rw-r--r--datapath-windows/ovsext/Conntrack-ftp.c159
1 files changed, 142 insertions, 17 deletions
diff --git a/datapath-windows/ovsext/Conntrack-ftp.c b/datapath-windows/ovsext/Conntrack-ftp.c
index ce09a6528..066723685 100644
--- a/datapath-windows/ovsext/Conntrack-ftp.c
+++ b/datapath-windows/ovsext/Conntrack-ftp.c
@@ -14,15 +14,21 @@
* limitations under the License.
*/
+#include <string.h>
#include "Conntrack.h"
#include "PacketParser.h"
+#include "util.h"
/* Eg: 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)*/
#define FTP_PASV_RSP_PREFIX "227"
+#define FTP_EXTEND_PASV_RSP_PREFIX "229"
+#define FTP_EXTEND_ACTIVE_RSP_PREFIX "200"
typedef enum FTP_TYPE {
FTP_TYPE_PASV = 1,
- FTP_TYPE_ACTIVE
+ FTP_TYPE_ACTIVE,
+ FTP_EXTEND_TYPE_PASV,
+ FTP_EXTEND_TYPE_ACTIVE
} FTP_TYPE;
static __inline UINT32
@@ -123,12 +129,11 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
POVS_CT_ENTRY entry,
BOOLEAN request)
{
- NDIS_STATUS status;
+ NDIS_STATUS status = NDIS_STATUS_SUCCESS;
FTP_TYPE ftpType = 0;
const char *buf;
char temp[256] = { 0 };
char ftpMsg[256] = { 0 };
-
UINT32 len;
TCPHdr tcpStorage;
const TCPHdr *tcp;
@@ -156,6 +161,9 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
if ((len >= 5) && (OvsStrncmp("PORT", ftpMsg, 4) == 0)) {
ftpType = FTP_TYPE_ACTIVE;
req = ftpMsg + 4;
+ } else if ((len >= 5) && (OvsStrncmp("EPRT", ftpMsg, 4) == 0)) {
+ ftpType = FTP_EXTEND_TYPE_ACTIVE;
+ req = ftpMsg + 4;
}
} else {
if ((len >= 4) && (OvsStrncmp(FTP_PASV_RSP_PREFIX, ftpMsg, 3) == 0)) {
@@ -176,6 +184,25 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
/* PASV command without ( */
req = ftpMsg + 3;
}
+ } else if ((len >= 4) && (OvsStrncmp(FTP_EXTEND_PASV_RSP_PREFIX, ftpMsg, 3) == 0)) {
+ ftpType = FTP_EXTEND_TYPE_PASV;
+ /* The ftp extended passive mode only contain port info, ip address
+ * is same with the network protocol used by control connection.
+ * 229 Entering Extended Passive Mode (|||port|)
+ * */
+ char *paren;
+ paren = strchr(ftpMsg, '|');
+ if (paren) {
+ req = paren + 3;
+ } else {
+ /* Not a valid EPSV packet. */
+ return NDIS_STATUS_INVALID_PACKET;
+ }
+
+ if (!(*req > '0' && * req < '9')) {
+ /* Not a valid port number. */
+ return NDIS_STATUS_INVALID_PACKET;
+ }
}
}
@@ -184,28 +211,102 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
return NDIS_STATUS_SUCCESS;
}
- UINT32 arr[6] = {0};
- status = OvsCtExtractNumbers(req, len, arr, 6, ',');
+ struct ct_addr clientIp = {0}, serverIp = {0};
+ UINT16 port = 0;
- if (status != NDIS_STATUS_SUCCESS) {
- return status;
- }
+ if (ftpType == FTP_TYPE_ACTIVE || ftpType == FTP_TYPE_PASV) {
+ UINT32 arr[6] = {0};
+ status = OvsCtExtractNumbers(req, len, arr, 6, ',');
+
+ if (status != NDIS_STATUS_SUCCESS) {
+ return status;
+ }
+
+ UINT32 ip = ntohl((arr[0] << 24) | (arr[1] << 16) |
+ (arr[2] << 8) | arr[3]);
+ port = ntohs(((arr[4] << 8) | arr[5]));
+
+ serverIp.ipv4 = ip;
+ clientIp.ipv4 = key->ipKey.nwDst;
+ } else {
+ if (ftpType == FTP_EXTEND_TYPE_ACTIVE) {
+ /** In ftp active mode, we need to parse string like below:
+ * " |2|20::1|50778|", 2 represent address is ipv6, 1 represent
+ * address family is ipv4, "20::1" is ipv6 address, 50779 is port
+ * client need to listen.
+ * **/
+ char *curHdr = NULL;
+ char *nextHdr = NULL;
+ int index = 0;
+ int isIpv6AddressFamily = 0;
+ char ftpStr[1024] = {0x00};
+
+ RtlCopyMemory(ftpStr, req, strlen(req));
+ for (curHdr = ftpStr; *curHdr != '|'; curHdr++);
+ curHdr = curHdr + 1;;
+ do {
+ /** index == 0 parse address family,
+ * index == 1 parse address,
+ * index == 2 parse port **/
+ for (nextHdr = curHdr; *nextHdr != '|'; nextHdr++);
+ *nextHdr = '\0';
+
+ if (*curHdr == '0' || !curHdr || index > 2) {
+ break;
+ }
+
+ if (index == 0 && *curHdr == '1') {
+ isIpv6AddressFamily = 0;
+ } else if (index == 0 && *curHdr == '2') {
+ isIpv6AddressFamily = 1;
+ }
+
+ if (index == 1 && isIpv6AddressFamily) {
+ OvsIpv6StringToAddress(curHdr, &clientIp.ipv6);
+ }
+
+ if (index == 2) {
+ for (char *tmp = curHdr; *tmp != '\0'; tmp++) {
+ port = port * 10 + (*tmp - '0');
+ }
+ port = htons(port);
+ }
+
+ curHdr = nextHdr + 1;
+ index++;
+ } while (1);
+
+ if (index < 2) { /* Not valid packet due to less than three parameter */
+ return NDIS_STATUS_SUCCESS;
+ }
+ serverIp.ipv6 = key->ipv6Key.ipv6Dst;
+ }
+
+ if (ftpType == FTP_EXTEND_TYPE_PASV) {
+ /* Here used to parse the string "229 Entering Extended Passive Mode (|||50522|),
+ * 50522 is the port we want". */
+ char *tmp = req;
+ while (*tmp != '|' && *tmp != '\0') {
+ port = port * 10 + (*tmp - '0');
+ tmp++;
+ }
- UINT32 ip = ntohl((arr[0] << 24) | (arr[1] << 16) |
- (arr[2] << 8) | arr[3]);
- UINT16 port = ntohs(((arr[4] << 8) | arr[5]));
+ port = htons(port);
+
+ serverIp.ipv6 = key->ipv6Key.ipv6Src;
+ clientIp.ipv6 = key->ipv6Key.ipv6Dst;
+ }
+ }
switch (ftpType) {
case FTP_TYPE_PASV:
/* Ensure that the command states Server's IP address */
- ASSERT(ip == key->ipKey.nwSrc);
-
OvsCtRelatedEntryCreate(key->ipKey.nwProto,
key->l2.dlType,
/* Server's IP */
- ip,
+ serverIp,
/* Use intended client's IP */
- key->ipKey.nwDst,
+ clientIp,
/* Dynamic port opened on server */
port,
/* We don't know the client port */
@@ -217,9 +318,33 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
OvsCtRelatedEntryCreate(key->ipKey.nwProto,
key->l2.dlType,
/* Server's default IP address */
- key->ipKey.nwDst,
+ serverIp,
+ /* Client's IP address */
+ clientIp,
+ /* FTP Data Port is 20 */
+ ntohs(IPPORT_FTP_DATA),
+ /* Port opened up on Client */
+ port,
+ currentTime,
+ entry);
+ break;
+ case FTP_EXTEND_TYPE_PASV:
+ OvsCtRelatedEntryCreate(key->ipv6Key.nwProto,
+ key->l2.dlType,
+ serverIp,
+ clientIp,
+ port,
+ 0,
+ currentTime,
+ entry);
+ break;
+ case FTP_EXTEND_TYPE_ACTIVE:
+ OvsCtRelatedEntryCreate(key->ipv6Key.nwProto,
+ key->l2.dlType,
+ /* Server's default IP address */
+ serverIp,
/* Client's IP address */
- ip,
+ clientIp,
/* FTP Data Port is 20 */
ntohs(IPPORT_FTP_DATA),
/* Port opened up on Client */