diff options
Diffstat (limited to 'datapath-windows')
-rw-r--r-- | datapath-windows/ovsext/Actions.c | 1 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack-ftp.c | 109 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack-related.c | 30 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack-tcp.c | 53 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack.c | 77 | ||||
-rw-r--r-- | datapath-windows/ovsext/Conntrack.h | 19 |
6 files changed, 211 insertions, 78 deletions
diff --git a/datapath-windows/ovsext/Actions.c b/datapath-windows/ovsext/Actions.c index 20de4db4c..3100532e1 100644 --- a/datapath-windows/ovsext/Actions.c +++ b/datapath-windows/ovsext/Actions.c @@ -2378,7 +2378,6 @@ OvsDoExecuteActions(POVS_SWITCH_CONTEXT switchContext, } OvsExecuteHash(key, (const PNL_ATTR)a); - break; } diff --git a/datapath-windows/ovsext/Conntrack-ftp.c b/datapath-windows/ovsext/Conntrack-ftp.c index 066723685..6775496cf 100644 --- a/datapath-windows/ovsext/Conntrack-ftp.c +++ b/datapath-windows/ovsext/Conntrack-ftp.c @@ -122,12 +122,9 @@ OvsCtExtractNumbers(char *buf, *---------------------------------------------------------------------------- */ NDIS_STATUS -OvsCtHandleFtp(PNET_BUFFER_LIST curNbl, - OvsFlowKey *key, - OVS_PACKET_HDR_INFO *layers, - UINT64 currentTime, - POVS_CT_ENTRY entry, - BOOLEAN request) +OvsCtHandleFtp(PNET_BUFFER_LIST curNbl, OvsFlowKey *key, + OVS_PACKET_HDR_INFO *layers, UINT64 currentTime, + POVS_CT_ENTRY entry) { NDIS_STATUS status = NDIS_STATUS_SUCCESS; FTP_TYPE ftpType = 0; @@ -157,52 +154,51 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl, OvsStrlcpy((char *)ftpMsg, (char *)buf, min(len, sizeof(ftpMsg))); char *req = NULL; - if (request) { - 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; + 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; + } + + if ((len >= 4) && (OvsStrncmp(FTP_PASV_RSP_PREFIX, ftpMsg, 3) == 0)) { + ftpType = FTP_TYPE_PASV; + /* There are various formats for PASV command. We try to support + * some of them. This has been addressed by RFC 2428 - EPSV. + * Eg: + * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). + * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2 + * 227 Entering Passive Mode. h1,h2,h3,h4,p1,p2 + * 227 =h1,h2,h3,h4,p1,p2 + */ + char *paren; + paren = strchr(ftpMsg, '('); + if (paren) { + req = paren + 1; + } else { + /* 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; } - } else { - if ((len >= 4) && (OvsStrncmp(FTP_PASV_RSP_PREFIX, ftpMsg, 3) == 0)) { - ftpType = FTP_TYPE_PASV; - /* There are various formats for PASV command. We try to support - * some of them. This has been addressed by RFC 2428 - EPSV. - * Eg: - * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). - * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2 - * 227 Entering Passive Mode. h1,h2,h3,h4,p1,p2 - * 227 =h1,h2,h3,h4,p1,p2 - */ - char *paren; - paren = strchr(ftpMsg, '('); - if (paren) { - req = paren + 1; - } else { - /* 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; - } + if (!(*req > '0' && * req < '9')) { + /* Not a valid port number. */ + return NDIS_STATUS_INVALID_PACKET; } } @@ -226,8 +222,15 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl, (arr[2] << 8) | arr[3]); port = ntohs(((arr[4] << 8) | arr[5])); - serverIp.ipv4 = ip; - clientIp.ipv4 = key->ipKey.nwDst; + if (ftpType == FTP_TYPE_ACTIVE) { + serverIp.ipv4 = key->ipKey.nwDst; + clientIp.ipv4 = ip; + } + + if (ftpType == FTP_TYPE_PASV) { + 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: @@ -239,7 +242,7 @@ OvsCtHandleFtp(PNET_BUFFER_LIST curNbl, char *nextHdr = NULL; int index = 0; int isIpv6AddressFamily = 0; - char ftpStr[1024] = {0x00}; + char ftpStr[512] = {0x00}; RtlCopyMemory(ftpStr, req, strlen(req)); for (curHdr = ftpStr; *curHdr != '|'; curHdr++); diff --git a/datapath-windows/ovsext/Conntrack-related.c b/datapath-windows/ovsext/Conntrack-related.c index f985c7631..99b1553da 100644 --- a/datapath-windows/ovsext/Conntrack-related.c +++ b/datapath-windows/ovsext/Conntrack-related.c @@ -40,6 +40,7 @@ OvsCtRelatedKeyAreSame(OVS_CT_KEY incomingKey, OVS_CT_KEY entryKey) /* FTP PASV - Client initiates the connection from unknown port */ if ((incomingKey.dl_type == entryKey.dl_type) && (incomingKey.dl_type == htons(ETH_TYPE_IPV4)) && + (incomingKey.nw_proto == IPPROTO_TCP) && (incomingKey.dst.addr.ipv4 == entryKey.src.addr.ipv4) && (incomingKey.dst.port == entryKey.src.port) && (incomingKey.src.addr.ipv4 == entryKey.dst.addr.ipv4) && @@ -49,6 +50,7 @@ OvsCtRelatedKeyAreSame(OVS_CT_KEY incomingKey, OVS_CT_KEY entryKey) if ((incomingKey.dl_type == entryKey.dl_type) && (incomingKey.dl_type == htons(ETH_TYPE_IPV6)) && + (incomingKey.nw_proto == IPPROTO_TCP) && !memcmp(&(incomingKey.dst.addr.ipv6), &(entryKey.src.addr.ipv6), sizeof(incomingKey.dst.addr.ipv6)) && (incomingKey.dst.port == entryKey.src.port) && @@ -65,6 +67,7 @@ OvsCtRelatedKeyAreSame(OVS_CT_KEY incomingKey, OVS_CT_KEY entryKey) */ if ((incomingKey.dl_type == entryKey.dl_type) && (incomingKey.dl_type == htons(ETH_TYPE_IPV4)) && + (incomingKey.nw_proto == IPPROTO_TCP) && (incomingKey.src.addr.ipv4 == entryKey.src.addr.ipv4) && (incomingKey.dst.addr.ipv4 == entryKey.dst.addr.ipv4) && (incomingKey.dst.port == entryKey.dst.port) && @@ -74,6 +77,7 @@ OvsCtRelatedKeyAreSame(OVS_CT_KEY incomingKey, OVS_CT_KEY entryKey) if ((incomingKey.dl_type == entryKey.dl_type) && (incomingKey.dl_type == htons(ETH_TYPE_IPV6)) && + (incomingKey.nw_proto == IPPROTO_TCP) && !memcmp(&(incomingKey.src.addr.ipv6), &(entryKey.src.addr.ipv6), sizeof(incomingKey.src.addr.ipv6)) && !memcmp(&(incomingKey.dst.addr.ipv6), &(entryKey.dst.addr.ipv6), @@ -83,6 +87,31 @@ OvsCtRelatedKeyAreSame(OVS_CT_KEY incomingKey, OVS_CT_KEY entryKey) return TRUE; } + /* Tftp protocol */ + if ((incomingKey.dl_type == entryKey.dl_type) && + (incomingKey.dl_type == htons(ETH_TYPE_IPV4)) && + (incomingKey.nw_proto == IPPROTO_UDP) && + !memcmp(&(incomingKey.src.addr.ipv4), &(entryKey.src.addr.ipv4), + sizeof(incomingKey.src.addr.ipv4)) && + !memcmp(&(incomingKey.dst.addr.ipv4), &(entryKey.dst.addr.ipv4), + sizeof(incomingKey.dst.addr.ipv4)) && + (incomingKey.dst.port == entryKey.dst.port) && + (incomingKey.nw_proto == entryKey.nw_proto)) { + return TRUE; + } + + if ((incomingKey.dl_type == entryKey.dl_type) && + (incomingKey.dl_type == htons(ETH_TYPE_IPV6)) && + (incomingKey.nw_proto == IPPROTO_UDP) && + !memcmp(&(incomingKey.src.addr.ipv6), &(entryKey.src.addr.ipv6), + sizeof(incomingKey.src.addr.ipv6)) && + !memcmp(&(incomingKey.dst.addr.ipv6), &(entryKey.dst.addr.ipv6), + sizeof(incomingKey.dst.addr.ipv6)) && + (incomingKey.dst.port == entryKey.dst.port) && + (incomingKey.nw_proto == entryKey.nw_proto)) { + return TRUE; + } + return FALSE; } @@ -165,7 +194,6 @@ OvsCtRelatedEntryCreate(UINT8 ipProto, } UINT32 hash = OvsExtractCtRelatedKeyHash(&entry->key); - NdisAcquireRWLockWrite(ovsCtRelatedLockObj, &lockState, 0); InsertHeadList(&ovsCtRelatedTable[hash & CT_HASH_TABLE_MASK], &entry->link); diff --git a/datapath-windows/ovsext/Conntrack-tcp.c b/datapath-windows/ovsext/Conntrack-tcp.c index a468c3e6b..77370531c 100644 --- a/datapath-windows/ovsext/Conntrack-tcp.c +++ b/datapath-windows/ovsext/Conntrack-tcp.c @@ -37,6 +37,8 @@ */ #include "Conntrack.h" +#include "NetProto.h" +#include "PacketParser.h" #include <stddef.h> struct tcp_peer { @@ -577,3 +579,54 @@ done: NlMsgEndNested(nlBuf, offset); return status; } + +NDIS_STATUS +OvsCtHandleTftp(PNET_BUFFER_LIST curNbl, OvsFlowKey *key, + OVS_PACKET_HDR_INFO *layers, UINT64 currentTime, + POVS_CT_ENTRY entry) +{ + UDPHdr udpStorage; + const UDPHdr *udp = NULL; + struct ct_addr serverIp; + struct ct_addr clientIp; + NDIS_STATUS status = NDIS_STATUS_SUCCESS; + + udp = OvsGetUdp(curNbl, layers->l4Offset, &udpStorage); + if (!udp) { + return NDIS_STATUS_INVALID_PACKET; + } + + RtlZeroMemory(&serverIp, sizeof(serverIp)); + RtlZeroMemory(&clientIp, sizeof(clientIp)); + + if (OvsCtRelatedLookup(entry->key, currentTime)) { + return NDIS_STATUS_SUCCESS; + } + + if (layers->isIPv4) { + serverIp.ipv4 = key->ipKey.nwDst; + clientIp.ipv4 = key->ipKey.nwSrc; + status = OvsCtRelatedEntryCreate(key->ipKey.nwProto, + key->l2.dlType, + serverIp, + clientIp, + 0, + udp->source, + currentTime, + entry); + } else { + serverIp.ipv6 = key->ipv6Key.ipv6Dst; + clientIp.ipv6 = key->ipv6Key.ipv6Src; + status = OvsCtRelatedEntryCreate(key->ipv6Key.nwProto, + key->l2.dlType, + serverIp, + clientIp, + 0, + udp->source, + currentTime, + entry); + } + + return status; +} + diff --git a/datapath-windows/ovsext/Conntrack.c b/datapath-windows/ovsext/Conntrack.c index 471bf961b..1f3929894 100644 --- a/datapath-windows/ovsext/Conntrack.c +++ b/datapath-windows/ovsext/Conntrack.c @@ -874,13 +874,25 @@ OvsCtSetupLookupCtx(OvsFlowKey *flowKey, return NDIS_STATUS_INVALID_PACKET; } + /* It's only designed for unNat traffic, when reverse traffic comes, + * find the unNat table, if found the nat entry, based on the nat entry + * restore the conntrack, it will be stored in the ctx->key and then use the + * ctx->key lookup the conntrack table to find the corresponded + * entry with the traffic.*/ natEntry = OvsNatLookup(&ctx->key, TRUE); if (natEntry) { - /* Translate address first for reverse NAT */ + /* initial direction 20::1 -> 20::9, reverse direction 21::3 -> 20::1 + * 20::9 could be regarded as nat ip, before convert, ctx->key value + * is "21::3 -> 20::1", after convert, ctx->key value is + * "20::9->20::1" */ ctx->key = natEntry->ctEntry->key; OvsCtKeyReverse(&ctx->key); } else { - if (flowKey->l2.dlType == htons(ETH_TYPE_IPV4)) { + if (OvsNatLookup(&ctx->key, FALSE)) { + /* Do nothing here, this branch here used to exclude traffic + * described in https://github.com/openvswitch/ovs-issues/issues/237 + * */ + } else if (flowKey->l2.dlType == htons(ETH_TYPE_IPV4)) { OvsPickupCtTupleAsLookupKey(&(ctx->key), zone, flowKey); } } @@ -903,6 +915,18 @@ OvsDetectFtp6Packet(OvsFlowKey *key) { ntohs(key->ipv6Key.l4.tpSrc) == IPPORT_FTP)); } +static __inline BOOLEAN +OvsDetectTftpPacket(OvsFlowKey *key) { + return (key->ipKey.nwProto == IPPROTO_UDP && + (ntohs(key->ipKey.l4.tpDst) == IPPORT_TFTP)); +} + +static __inline BOOLEAN +OvsDetectTftp6Packet(OvsFlowKey *key) { + return (key->ipv6Key.nwProto == IPPROTO_UDP && + (ntohs(key->ipv6Key.l4.tpDst) == IPPORT_TFTP)); +} + /* *---------------------------------------------------------------------------- * OvsProcessConntrackEntry @@ -989,7 +1013,9 @@ OvsProcessConntrackEntry(OvsForwardingContext *fwdCtx, if (entry) { NdisAcquireSpinLock(&(entry->lock)); if ((layers->isIPv6 && key->ipv6Key.nwProto == IPPROTO_TCP) || - (!(layers->isIPv6) && key->ipKey.nwProto == IPPROTO_TCP)) { + (!(layers->isIPv6) && key->ipKey.nwProto == IPPROTO_TCP) || + (layers->isIPv6 && key->ipv6Key.nwProto == IPPROTO_UDP) || + (!(layers->isIPv6) && key->ipKey.nwProto == IPPROTO_UDP)) { /* Update the related bit if there is a parent */ if (entry->parent) { state |= OVS_CS_F_RELATED; @@ -1156,12 +1182,11 @@ OvsCtExecute_(OvsForwardingContext *fwdCtx, NDIS_STATUS status = NDIS_STATUS_SUCCESS; BOOLEAN triggerUpdateEvent = FALSE; BOOLEAN entryCreated = FALSE; - BOOLEAN isFtpPacket = FALSE; - BOOLEAN isFtpRequestDirection = FALSE; POVS_CT_ENTRY entry = NULL; POVS_CT_ENTRY parent = NULL; PNET_BUFFER_LIST curNbl = fwdCtx->curNbl; OvsConntrackKeyLookupCtx ctx = { 0 }; + CT_HELPER_METHOD helpMethod = CT_HELPER_NONE; LOCK_STATE_EX lockStateTable; UINT64 currentTime; NdisGetCurrentSystemTime((LARGE_INTEGER *) ¤tTime); @@ -1241,32 +1266,52 @@ OvsCtExecute_(OvsForwardingContext *fwdCtx, OvsCtSetMarkLabel(key, entry, mark, labels, &triggerUpdateEvent); + if (helper && RtlEqualMemory(helper, "ftp", sizeof("ftp"))) { + helpMethod = CT_HELPER_FTP; + } else if (helper && RtlEqualMemory(helper, "tftp", sizeof("tftp"))) { + helpMethod = CT_HELPER_TFTP; + } + + /* This code section was added to compatible with the old version, + * because old version regard all traffic to port 21 as ftp traffic, + * no need to add alg field in ct. Thus, the code was added to keep the + * same behavior for ftp and tftp.*/ if (layers->isIPv6) { - isFtpPacket = OvsDetectFtp6Packet(key); - if (ntohs(key->ipv6Key.l4.tpDst) == IPPORT_FTP) { - isFtpRequestDirection = TRUE; + if (OvsDetectFtp6Packet(key)) { + helpMethod = CT_HELPER_FTP; + } + + if (OvsDetectTftp6Packet(key)) { + helpMethod = CT_HELPER_TFTP; } } else { - isFtpPacket = OvsDetectFtpPacket(key); - if (ntohs(key->ipKey.l4.tpDst) == IPPORT_FTP) { - isFtpRequestDirection = TRUE; + if (OvsDetectFtpPacket(key)) { + helpMethod = CT_HELPER_FTP; + } + + if (OvsDetectTftpPacket(key)) { + helpMethod = CT_HELPER_TFTP; } } - if (isFtpPacket) { - /* FTP parser will always be loaded */ - status = OvsCtHandleFtp(curNbl, key, layers, currentTime, entry, - isFtpRequestDirection); + if (helpMethod == CT_HELPER_FTP) { + status = OvsCtHandleFtp(curNbl, key, layers, currentTime, entry); if (status != NDIS_STATUS_SUCCESS) { OVS_LOG_ERROR("Error while parsing the FTP packet"); } } + if (helpMethod == CT_HELPER_TFTP) { + status = OvsCtHandleTftp(curNbl, key, layers, currentTime, entry); + if (status != NDIS_STATUS_SUCCESS) { + OVS_LOG_ERROR("Error while parsing the TFTP packet"); + } + } + parent = entry->parent; /* The entry should have the same helper name with parent's */ if (!entry->helper_name && (helper || (parent && parent->helper_name))) { - helper = helper ? helper : parent->helper_name; entry->helper_name = OvsAllocateMemoryWithTag(strlen(helper) + 1, OVS_CT_POOL_TAG); diff --git a/datapath-windows/ovsext/Conntrack.h b/datapath-windows/ovsext/Conntrack.h index b68a54f30..deb51c0bc 100644 --- a/datapath-windows/ovsext/Conntrack.h +++ b/datapath-windows/ovsext/Conntrack.h @@ -80,6 +80,12 @@ typedef enum _NAT_ACTION { NAT_ACTION_DST_PORT = 1 << 4, } NAT_ACTION; +typedef enum _CT_HELPER_METHOD { + CT_HELPER_NONE = 0, + CT_HELPER_FTP = 1, + CT_HELPER_TFTP = 2, +} CT_HELPER_METHOD; + typedef struct _OVS_CT_KEY { struct ct_endpoint src; struct ct_endpoint dst; @@ -218,11 +224,10 @@ NDIS_STATUS OvsCtRelatedEntryCreate(UINT8 ipProto, UINT64 currentTime, POVS_CT_ENTRY parent); POVS_CT_ENTRY OvsCtRelatedLookup(OVS_CT_KEY key, UINT64 currentTime); - -NDIS_STATUS OvsCtHandleFtp(PNET_BUFFER_LIST curNbl, - OvsFlowKey *key, - OVS_PACKET_HDR_INFO *layers, - UINT64 currentTime, - POVS_CT_ENTRY entry, - BOOLEAN request); +NDIS_STATUS OvsCtHandleFtp(PNET_BUFFER_LIST curNbl, OvsFlowKey *key, + OVS_PACKET_HDR_INFO *layers, UINT64 currentTime, + POVS_CT_ENTRY entry); +NDIS_STATUS OvsCtHandleTftp(PNET_BUFFER_LIST curNbl, OvsFlowKey *key, + OVS_PACKET_HDR_INFO *layers, UINT64 currentTime, + POVS_CT_ENTRY entry); #endif /* __OVS_CONNTRACK_H_ */ |