FNET icon indicating copy to clipboard operation
FNET copied to clipboard

FNET DNS doesn't resolve for certain urls

Open RoSchmi opened this issue 4 years ago • 18 comments

Board: Teensy 4.1 with NativeEthernet library https://github.com/vjmuzik/NativeEthernet

I'm using this fork of the FNET repository: https://github.com/vjmuzik/FNET

As far as I could see the concerning service 'fnet_dns.c' doesn't differ between the forks.

The dns service resolves fine for different urls, but not for the one which I use to access my Azure Storage Tables: 'prax47.table.core.windows.net'

This url is resolved without issues on different mcus and frameworks, e.g. Wio Terminal with WiFi library or 'EthernetENC' library.

Wireshark captures show this dns request

dnsRequest

and this response

dnsResponse

As I interpret the captures FNET dns service regulary sends the request but doesn't accept the response, complaining about malformed packets.

What could be the reason for this behavior?

RoSchmi avatar Mar 17 '21 11:03 RoSchmi

I suggest to update to the latest version of FNET, where done many DNS-related changes. After, try again.

butok avatar Mar 17 '21 12:03 butok

Thanks for your reply, even though I was quite sure to have already the latest dns related files I exchanged the files (fnet_dns_priv.h, fnet_dns.h, fnet_dns.c and fnet_dns_config.c) against the lates files of your master branch but got the same result. Could you please try if the named url is resolved on your side using your library?

RoSchmi avatar Mar 17 '21 12:03 RoSchmi

I do not have the Eth boards at home-ofice now. But you can debug the issue and detect the corner case. I have feeling, that it has reached the limit of domains 1.2.3.4.5 which was added as a loop protection.

butok avatar Mar 17 '21 13:03 butok

I could track down the error to occur in the method 'static fnet_bool_t _fnet_dns_cmp_name(const char *rr_name, const char *name)'

I found out that if I returned with result = FNET_TRUE irrespectively of the tests done in this method everything worked fine.

if(i == name_length)
{   
    result = FNET_TRUE;
}
else
{
   // RoSchmi
   result = FNET_TRUE;
   //result = FNET_FALSE;
}
return result;

I included some additional debug statements into the code

/************************************************************************
* Compare RR name with requested-name. TBD use it for LLMNR
************************************************************************/

static fnet_bool_t _fnet_dns_cmp_name(const char *rr_name, const char *name) { FNET_ASSERT(rr_name_p != FNET_NULL); FNET_ASSERT(name != FNET_NULL);

fnet_bool_t         result;

fnet_index_t        i = 0;
fnet_uint32_t       name_length = fnet_strlen(name);
fnet_uint32_t       rr_name_length = fnet_strlen(rr_name);
           
// RoSchmi
FNET_DEBUG_DNS((char *)name);
FNET_DEBUG_DNS((char *)rr_name);
    
if((name_length != 0) && ((name_length + 1 /* first length byte */)  == rr_name_length) )
{
    rr_name++; /* Skip first length byte */

    for(i = 0; i < name_length; i++)
    {
        if(name[i] == '.')
        {
            continue; /* Skip length byte for rr_name */
        }

        if(fnet_tolower(rr_name[i]) != fnet_tolower(name[i]))
        {
    
            break; /* Not equal */
        }
    }
}

//RoSchmi
FNET_DEBUG_DNS("name_length: ");
char strLen[5] = {0};
sprintf(strLen,"%i", name_length);
FNET_DEBUG_DNS((char *)strLen);
FNET_DEBUG_DNS("i: ");
sprintf(strLen,"%i", i);
FNET_DEBUG_DNS((char *)strLen);

if(i == name_length)
{
    FNET_DEBUG_DNS("Got wellformed packet");
    result = FNET_TRUE;
}
else
{
    // RoSchmi
    FNET_DEBUG_DNS("Got malformed packet");

    //result = FNET_TRUE;
    result = FNET_FALSE;
}

return result;

}

and got the following output (NTP request before trying to access the Azure Storage Table)

pool.ntp.org ␄pool␃ntp␃org name_length: 12 i: 12 Got wellformed packet In callback... Here is the IP: 195.201.163.190 NTP FAILED: Trying again

UPDATED UTC : 17:58:34 UTC : 17:58:34 Wed 17 Mar 2021 LOC : 17:58:34 LOC : 17:58:34 Wed 17 Mar 2021 UTC EPOCH : 1616003914 LOC EPOCH : 1616003914 UTC-Time is : 2021 3 17 17 58 Local-Time is: 2021 3 17 18 58 Trying to create Table Getting header Going to send http Request prax47.table.core.windows.net 80 Hostname is: prax47.table.core.windows.net Trying to resolve Host IP Connecting to DNS Server. Sending query... prax47.table.core.windows.net ␆prax47␅table␄core␇windows␃net name_length: 29 i: 29 Got wellformed packet prax47.table.core.windows.net ␆prax47␅table␄core␇windows␃net name_length: 29 i: 29 Got wellformed packet prax47.table.core.windows.net ␅table␌db6prdstr07a␅store␄core␇windows␃net name_length: 29 i: 0 Got malformed packet Sending query... Sending query... Sending query... Sending query... Sending query... In callback... Callback returned -1 (1) Found prax4 HTTP/1.1 409 ***

Table is availabel Trying to insert 0 Going to send http Request prax47.table.core.windows.net 80 Hostname is: prax47.table.core.windows.net Trying to resolve Host IP Connecting to DNS Server. Sending query... prax47.table.core.windows.net ␆prax47␅table␄core␇windows␃net name_length: 29 i: 29 Got wellformed packet prax47.table.core.windows.net ␆prax47␅table␄core␇windows␃net name_length: 29 i: 29 Got wellformed packet prax47.table.core.windows.net ␅table␌db6prdstr07a␅store␄core␇windows␃net name_length: 29 i: 0 Got malformed packet Sending query... Sending query... Sending query... Sending query... Sending query... In callback... Callback returned -1 (1)

Setting #define FNET_DNS_COMPRESSION_LIMIT 4 to a higher value (15) didn't solve the issue

It seems that the method has problems with the CNAME entry in the dns response

RoSchmi avatar Mar 17 '21 18:03 RoSchmi

So the third DNS server response contains unexpected CNAME (first 2 are ok). We get table.db6prdstr07a.store.core.windows.net but we are expecting prax47.table.core.windows.net So, what reaction should be?

butok avatar Mar 18 '21 09:03 butok

I don't know, I'm not an expert in this matter. I could imagine that all domains using CNAME records are affected, so the problem should be solved. There should be existing solutions. Perhaps one could ask a question in a specialized forum. For my part (actually no need for high security) I can actually simply ignore the sender validation. Perhaps I will have a better idea later after having looked deeper in the process of analyzing a dns response.

RoSchmi avatar Mar 18 '21 11:03 RoSchmi

Hello, I had a deeper look in the code and found a sequence which might cause the issue.

It's in the file: fnet_dns.c

Line 430 induces a first check if the name in the response is equal to the host-name

Line 430: if(ptr && (_fnet_dns_cmp_name(rr_name, dns_if->host_name) == FNET_TRUE)) /* Check question name */

Then the ptr is incremented so much that now rr_name points to (in my case) the CName, an alias name for the primary url. Since the alias name is necessarily unequal to the primary url, the code in line L445 returns false and the host_name is not resolved. So I wonder if it is correct to have this second test that the names are equal or if this second if clause should be omitted.

L445: if(_fnet_dns_cmp_name(rr_name, dns_if->host_name) == FNET_TRUE)

PS: I'm not at home for the next couple of days, so I cannot answer,

RoSchmi avatar Mar 25 '21 00:03 RoSchmi

The behavior is correct, as we should return rr-records we have requested. But if you will find a non correspondence with a RFC, please inform us.

butok avatar May 03 '21 06:05 butok

Hi butok, thanks for your answer. I think we should try to solve the problem from the roots: Base of the question is that in my application which uses FNET the url 'prax47.table.core.windows.net' isn't resolved to an Ip-Address. On my side, when I use other platforms with other DNS libraries or the browser on my PC, this special url is resolved to an Ip-Address. As I think, the next step must be to find out if you can confirm my observation that this special url is not resolved by the FNET dns library. (command: int DNSClient::getHostByName(const char *aHostname, IPAddress& aResult, uint16_t timeout) from (here) NativeEthernet library doesn't deliver an IpAddress). If it resolves on your side I have to search for an error on my side, if you can confirm my observation we should discuss whether it should be resolved or not. Kind regards RoSchmi

RoSchmi avatar May 03 '21 09:05 RoSchmi

Hi @butok, May I ask if you are still evaluating my arguments and suggestions or are you staying on your statement that the behavior of your dns client implementation is correct. As I'm not an expert concerning questions about the conformity of dns client implementations with the relevant RFCs I would like to open a discussion on stackoverflow with the title: 'Should RFC conform DNS Clients resolve URLs of Azure Table Storage Accounts which use CNAME records' Please give me feedback if the question should be formulated otherwise. Kind regards RoSchmi

RoSchmi avatar May 05 '21 10:05 RoSchmi

Yes, please open a discussion.

butok avatar May 05 '21 14:05 butok

Done: https://stackoverflow.com/questions/67421802/should-rfc-conform-dns-clients-resolve-urls-of-azure-table-storage-accounts-whic

RoSchmi avatar May 06 '21 16:05 RoSchmi

@RoSchmi Hi, I have the same issue using NativeEthernet on Teensy 4.1, which uses FNET underneath to resolve hostnames. In my case, the host is "api.weather.gov", which FNET fails to resolve. It is an alias record but NSLOOKUP on a PC and other DNS lookup services, browsers, etc. resolve this correctly. If I eliminate the check in fnet_dns.c at L445 as you suggested, it resolves with the correct IP address. I can't really add my 2 cents here onto this discussion, but it seems there are now two simple use cases where valid aliases are not being resolved correctly within FNET.

egonbeermat avatar May 12 '21 16:05 egonbeermat

For a DNS inquiry when the submitted hostname is actually a CNAME, the DNS server should return both the CNAME record and the corresponding A record the CNAME aliases. In this situation, the host name on the A record will obviously not match the initial inquiry, but this is the actual IP that is to be returned from the inquiry.

egonbeermat avatar May 12 '21 16:05 egonbeermat

@egonbeermat Thanks for your help. @butok said: "The behavior is correct, as we should return rr-records we have requested." this is true, but it is only half of the story. In my case the rr-record returned as response on my request for 'prax47.table.core.windows.net' is: '0xa4f7 A prax47.table.core.windows.net CNAME table.db6prdstr07a.store.core.windows.net A 52.245.40.70'

The code on line 430 induces a test wheter the requested hostname is equal to the requested name returned in the rr-record. Line 430: if(ptr && (_fnet_dns_cmp_name(rr_name, dns_if->host_name) == FNET_TRUE)) /* Check question name */ This first test is correct and needed but the second test in code line L445 is not correct. It tests whether the CNAME 'table.db6prdstr07a.store.core.windows.net' is also equal to to the name in the request 'prax47.table.core.windows.net'. Of course it is not equal as 'alias' name means that it is just different. So this second test in line 445 lets resolving fail for all CNAME rr-records.

RoSchmi avatar May 12 '21 16:05 RoSchmi

@butok Opened a discussion here too: https://docs.microsoft.com/en-us/answers/questions/386628/dns-client-fnet-library-doesn39t-resolve-azure-tab.html?childToView=398360#answer-398360

RoSchmi avatar May 17 '21 22:05 RoSchmi

The issue seems to be solved here: https://github.com/vjmuzik/FNET/pull/6

RoSchmi avatar Aug 20 '21 09:08 RoSchmi

Thank you, will review, and apply (if it is correct).

butok avatar Aug 22 '21 20:08 butok