Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FNET DNS doesn't resolve for certain urls #7

Open
RoSchmi opened this issue Mar 17, 2021 · 18 comments
Open

FNET DNS doesn't resolve for certain urls #7

RoSchmi opened this issue Mar 17, 2021 · 18 comments

Comments

@RoSchmi
Copy link

RoSchmi commented Mar 17, 2021

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?

@butok
Copy link
Owner

butok commented Mar 17, 2021

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

@RoSchmi
Copy link
Author

RoSchmi commented Mar 17, 2021

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?

@butok
Copy link
Owner

butok commented Mar 17, 2021

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.

@RoSchmi
Copy link
Author

RoSchmi commented Mar 17, 2021

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

@butok
Copy link
Owner

butok commented Mar 18, 2021

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?

@RoSchmi
Copy link
Author

RoSchmi commented Mar 18, 2021

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
Copy link
Author

RoSchmi commented Mar 25, 2021

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,

@butok
Copy link
Owner

butok commented May 3, 2021

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.

@RoSchmi
Copy link
Author

RoSchmi commented May 3, 2021

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
Copy link
Author

RoSchmi commented May 5, 2021

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

@butok
Copy link
Owner

butok commented May 5, 2021

Yes, please open a discussion.

@egonbeermat
Copy link

@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
Copy link

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.

@RoSchmi
Copy link
Author

RoSchmi commented May 12, 2021

@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
Copy link
Author

RoSchmi commented Aug 20, 2021

The issue seems to be solved here:
vjmuzik#6

@butok
Copy link
Owner

butok commented Aug 22, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants