datapath-windows/ovsext/Conntrack-ftp.c
/*
 *----------------------------------------------------------------------------
 * OvsCtHandleFtp
 *     Extract the FTP control data from the packet and created a related
 *     entry if it's a valid connection. This method doesn't support extended
 *     FTP yet. Supports PORT and PASV commands.
 *     Eg:
 *     'PORT 192,168,137,103,192,22\r\n' -> '192.168.137.103' and 49174
 *     '227 Entering Passive Mode (192,168,137,104,194,14)\r\n' gets extracted
 *      to '192.168.137.104' and 49678
 *----------------------------------------------------------------------------
 */
OvsCtHandleFtp
Extract the FTP control data from the packet and created a related
entry if it's a valid connection. This method doesn't support extended
FTP yet. Supports PORT and PASV commands.
OvsCtHandleFtp Extract the FTP control data from the packet and created a related entry if it ' s a valid connection . This method doesn ' t support extended FTP yet . Supports PORT and PASV commands .
NDIS_STATUS
OvsCtHandleFtp(PNET_BUFFER_LIST curNbl,
               OvsFlowKey *key,
               OVS_PACKET_HDR_INFO *layers,
               UINT64 currentTime,
               POVS_CT_ENTRY entry,
               BOOLEAN request)
{
    NDIS_STATUS status;
    FTP_TYPE ftpType = 0;
    const char *buf;
    char temp[256] = { 0 };
    char ftpMsg[256] = { 0 };
    UINT32 len;
    TCPHdr tcpStorage;
    const TCPHdr *tcp;
    tcp = OvsGetTcpHeader(curNbl, layers, &tcpStorage, &len);
    if (!tcp) {
        return NDIS_STATUS_INVALID_PACKET;
    }
    if (len > sizeof(temp)) {
        len = sizeof(temp);
    }
    buf = OvsGetPacketBytes(curNbl, len,
                            layers->l4Offset + TCP_HDR_LEN(tcp),
                            temp);
    if (buf == NULL) {
        return NDIS_STATUS_INVALID_PACKET;
    }
    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 >= 4) && (OvsStrncmp(FTP_PASV_RSP_PREFIX, ftpMsg, 3) == 0)) {
            ftpType = FTP_TYPE_PASV;
            char *paren;
            paren = strchr(ftpMsg, '(');
            if (paren) {
                req = paren + 1;
            } else {
                req = ftpMsg + 3;
            }
        }
    }
    if (req == NULL) {
        return NDIS_STATUS_SUCCESS;
    }
    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]);
    UINT16 port = ntohs(((arr[4] << 8) | arr[5]));
    switch (ftpType) {
    case FTP_TYPE_PASV:
        ASSERT(ip == key->ipKey.nwSrc);
        OvsCtRelatedEntryCreate(key->ipKey.nwProto,
                                key->l2.dlType,
                                ip,
                                key->ipKey.nwDst,
                                port,
                                0,
                                currentTime,
                                entry);
        break;
    case FTP_TYPE_ACTIVE:
        OvsCtRelatedEntryCreate(key->ipKey.nwProto,
                                key->l2.dlType,
                                key->ipKey.nwDst,
                                ip,
                                ntohs(IPPORT_FTP_DATA),
                                port,
                                currentTime,
                                entry);
        break;
    default:
        OVS_LOG_ERROR("invalid ftp type:%d", ftpType);
        status = NDIS_STATUS_INVALID_PARAMETER;
        break;
    }
    return status;
}
NDIS_STATUS OvsCtHandleFtp ( PNET_BUFFER_LIST curNbl , OvsFlowKey * key , OVS_PACKET_HDR_INFO * layers , UINT64 currentTime , POVS_CT_ENTRY entry , BOOLEAN request ) { NDIS_STATUS status ; FTP_TYPE ftpType = 0 ; const char * buf ; char temp [ 256 ] = { 0 } ; char ftpMsg [ 256 ] = { 0 } ; UINT32 len ; TCPHdr tcpStorage ; const TCPHdr * tcp ; tcp = OvsGetTcpHeader ( curNbl , layers , & tcpStorage , & len ) ; if ( ! tcp ) { return NDIS_STATUS_INVALID_PACKET ; } if ( len > sizeof ( temp ) ) { len = sizeof ( temp ) ; } buf = OvsGetPacketBytes ( curNbl , len , layers -> l4Offset + TCP_HDR_LEN ( tcp ) , temp ) ; if ( buf == NULL ) { return NDIS_STATUS_INVALID_PACKET ; } OvsStrlcpy ( ( char * ) ftpMsg , ( char * ) buf , min ( len , sizeof ( ftpMsg ) ) ) ; char * req = NULL ; if ( request ) { if ( ( len >= 5 ) && ( OvsStrncmp ( " " , ftpMsg , 4 ) == 0 ) ) { ftpType = FTP_TYPE_ACTIVE ; req = ftpMsg + 4 ; } } else { if ( ( len >= 4 ) && ( OvsStrncmp ( FTP_PASV_RSP_PREFIX , ftpMsg , 3 ) == 0 ) ) { ftpType = FTP_TYPE_PASV ; char * paren ; paren = strchr ( ftpMsg , ' ' ) ; if ( paren ) { req = paren + 1 ; } else { req = ftpMsg + 3 ; } } } if ( req == NULL ) { return NDIS_STATUS_SUCCESS ; } 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 ] ) ; UINT16 port = ntohs ( ( ( arr [ 4 ] << 8 ) | arr [ 5 ] ) ) ; switch ( ftpType ) { case FTP_TYPE_PASV : ASSERT ( ip == key -> ipKey . nwSrc ) ; OvsCtRelatedEntryCreate ( key -> ipKey . nwProto , key -> l2 . dlType , ip , key -> ipKey . nwDst , port , 0 , currentTime , entry ) ; break ; case FTP_TYPE_ACTIVE : OvsCtRelatedEntryCreate ( key -> ipKey . nwProto , key -> l2 . dlType , key -> ipKey . nwDst , ip , ntohs ( IPPORT_FTP_DATA ) , port , currentTime , entry ) ; break ; default : OVS_LOG_ERROR ( " " , ftpType ) ; status = NDIS_STATUS_INVALID_PARAMETER ; break ; } return status ; }
OvsCtHandleFtp
     Extract the FTP control data from the packet and created a related
     entry if it's a valid connection.
OvsCtHandleFtp Extract the FTP control data from the packet and created a related entry if it ' s a valid connection .
/* We only care up to 256 */ /* 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
             */ /* PASV command without ( */ /* Not a PORT/PASV control packet */ /* Ensure that the command states Server's IP address */ /* Server's IP */ /* Use intended client's IP */ /* Dynamic port opened on server */ /* We don't know the client port */ /* Server's default IP address */ /* Client's IP address */ /* FTP Data Port is 20 */ /* Port opened up on Client */