Hacker Newsnew | past | comments | ask | show | jobs | submit | rom1v's commentslogin

On Android, in Settings, Network & internet, Private DNS, you can only provide one in "Private DNS provider hostname" (AFAIK).

Btw, I really don't understand why it does not accept an IP (1.1.1.1), so you have to give an address (one.one.one.one). It would be more sensible to configure a DNS server from an IP rather than from an address to be resolved by a DNS server :/


Private DNS on Android refers to 'DNS over HTTPS' and would normally only accept a hostname.

Normal DNS can normally be changed in your connection settings for a given connection on most flavours of Android.


No, it is not DNS over HTTPS it is DNS over TLS, which is different.

Android 11 and newer support both DoH and DoT.

Where is this option? How can I distinguish the two, the dialog simply asks for a host name

Cloudflare has valid certs for 1.1.1.1

> Private DNS on Android refers to 'DNS over HTTPS'

Yes, sorry, I did not mention it.

So if you want to use DNS over HTTPS on Android, it is not possible to provide a fallback.


> So if you want to use DNS over HTTPS on Android, it is not possible to provide a fallback.

Not true. If the (DoH) host has multiple A/AAAA records (multiple IPs), any decent DoH client would retry its requests over multiple or all of those IPs.


Does Cloudflare offer any hostname that also resolves to a different organization’s resolver (which must also have a TLS certificate for the Cloudflare hostname or DoH clients won’t be able to connect)?

Usually, for plain old DNS, primary and secondary resolvers are from the same provider, serving from distinct IPs.

Yes, but you were talking about DoH. I don’t know how that could plausibly work.

> but you were talking about DoH

DoH hosts can resolve to multiple IPs (and even different IPs for different clients)?

Also see TFA

  It's worth noting that DoH (DNS-over-HTTPS) traffic remained relatively stable as most DoH users use the domain cloudflare-dns.com, configured manually or through their browser, to access the public DNS resolver, rather than by IP address. DoH remained available and traffic was mostly unaffected as cloudflare-dns.com uses a different set of IP addresses.

> DoH hosts can resolve to multiple IPs (and even different IPs for different clients)?

Yes, but not from a different organization. That was GPs point with

> So if you want to use DNS over HTTPS on Android, it is not possible to provide a fallback.

A cross-organizational fallback is not possible with DoH in many clients, but it is with plain old DNS.

> It's worth noting that DoH (DNS-over-HTTPS) traffic remained relatively stable as most DoH users use the domain cloudflare-dns.com

Yes, but that has nothing to do with failovers to an infrastructurally/operationally separate secondary server.


> A cross-organizational fallback is not possible with DoH in many clients, but it is with plain old DNS.

That's client implementation lacking, not some issue inherent to DoH?

   The DoH client is configured with a URI Template, which describes how to construct the URL to use for resolution. Configuration, discovery, and updating of the URI Template is done out of band from this protocol.

  Note that configuration might be manual (such as a user typing URI Templates in a user interface for "options") or automatic (such as URI Templates being supplied in responses from DHCP or similar protocols). DoH servers MAY support more than one URI Template. This allows the different endpoints to have different properties, such as different authentication requirements or service-level guarantees.
https://datatracker.ietf.org/doc/html/rfc8484#section-3

Yes, but this restriction of only a single DoH URL seems to be the norm for many popular implementations. The protocol theoretically allowing better behavior doesn't really help people using these.

Its DNS over TLS. Android does not support DNS over HTTPS except Google's DNS

It does since Android 11.

For a limited set of DoH providers. It does not let you enter a custom DoH URL, only a DoT hostname.

As far as I understand it, it's Google or Cloudflare?

> By making the Send button larger and more prominent, participants were able to spot the button four times faster.

By making the Back button larger and more prominent instead, participants would be able to spot the button four times faster. I suggest to reduce the size of the Send button.


The running joke was that the back button in Longhorn was bigger than the others to make it an easier target to get out of Goatse.


As a non-native Ensligh speaker, I asked ChatGPT what the ER acronym means: Emergency Room (I guessed E was for "Emergency" after reading your story, but I didn't know about the 'R').

AI is also helpful to parse the story about how AI is helpful.


I'm French too, and when I was young, I learnt the Basic language before learning English (by reading Basic programs already available on our computer).

So I was able to write FOR … THEN … ELSE blocks without even knowing what the keywords meant (I just know what they did to the program). One day, I explained to my father what I was writing, and I read out loud FOR … "TEN" … "ELCE" (with a strong French accent), and he corrected me by pronouncing the words correctly ("FOR … THEN … ELSE"). I was shocked: "how do you know?" (he knew nothing about Basic or even programming).

I learnt that day that "for", "then" and "else" were not just keywords in the Basic language, but they were actually real words in English.


Precision: Of course, I meant "FOR" and "IF THEN ELSE" separately (the way I wrote it might wrongly suggest there is something like for-then-else).


I think this category is named ciechanow.ski.


Mandatory blog post on XMPP and decentralized protocols: https://signal.org/blog/the-ecosystem-is-moving/


> "XMPP still largely resembles a synchronous protocol with limited support for rich media, which can’t realistically be deployed on mobile devices. If XMPP is so extensible, why haven’t those extensions quickly brought it up to speed with the modern world?"

So, it's not such a gem?


Mandatory objection to this blog post: https://gultsch.de/objection.html


> if anything the velocity of the entire landscape seems to be steadily increasing.

It is, gods make it stop.

"Oh no complicated specification" do you think you're getting paid 100k/year because it's _easy_? Gods.


> This construct works perfectly fine in C

Intuitively, I would say that this is actually undefined behavior (it would probably be difficult to expose a wrong behavior in practice though).

In C specs, I found 6.5.2.2, paragraph 9:

> If the function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function, the behavior is undefined.

We might discuss whether

    void (*)(char *)
is "compatible" with

    void (*)(void *)
but I think it isn't, since:

    void target(void *ptr) {}
    void (*name)(char *ptr) = target;
fails to compile with the error message:

    initialization of ‘void (*)(void *)’ from incompatible pointer type ‘void (*)(char *)’
The compiler explicitly says "incompatible pointer type".

Same for:

    void target(char *ptr) {}
    void (*name)(void *ptr) = target;


> it would probably be difficult to expose a wrong behavior in practice though

Emscripten breaks if you cast function pointers: https://emscripten.org/docs/porting/guidelines/function_poin...


Good point, interesting that I never ran into this issue in real world code bases so far (and I build a lot of code with Emscripten) :)


It's worse than that. This guy takes a void* function and casts it to a char* function, then passes it a char**.

    void (*name)(char *ptr);
    typedef void (*name_func)(char *ptr);

    void target(void *ptr)
    {
       printf("Input %p\n", ptr);
    }


    char *data = "string";
    name = (name_func)target; // Illegal: casting fn that takes void* to a fn that takes char*
    name(&data); // Illegal: passing a char** into a function that takes char*
Before someone mentions qsort(): the comparator function really is supposed to take a void*, and inside the function, you re-cast the void* argument to a pointer type of your desire. If you don't do it in that order, you're using it wrong.


Ironically, in K&R, they did exactly this for casting comparator functions for their own version of qsort.

  /* declarations */
  void qsort(void *lineptr[], int left, int right,
             int (*comp)(void *, void *));
  int numcmp(char *, char *);

  /* the offending line */
  qsort((void **) lineptr, 0, nlines-1, 
    (int (*)(void*,void*)(numeric ? numcmp : strcmp));


The C standard mandates that a “pointer to void shall have the same representation and alignment requirements as a pointer to a character type”. In consequence, the same holds for an array of void pointers vs. an array of char pointers. The code therefore seems valid to me, and furthermore at no point is a function called with an argument type different from its formal parameters.

In the GP example, a char** is passed where a char* is expected. That is clearly invalid.


I was more referring to how, in the K&R example, a function of type "int (*)(char *, char *)" is cast to "int (*)(void *, void *)", in contradiction to what they said here:

> Before someone mentions qsort(): the comparator function really is supposed to take a void*, and inside the function, you re-cast the void* argument to a pointer type of your desire. If you don't do it in that order, you're using it wrong.

In contrast, the K&R example is an example of explicitly undefined behavior in the C standard:

The behavior is undefined in the following circumstances:

- A pointer is used to call a function whose type is not compatible with the pointed-to type (6.3.2.3).


> the K&R example is an example of explicitly undefined behavior in the C standard

You can’t blame K&R C for that. It predates “the C standard” by over a decade (1978 vs 1989)

When it was written, what K&R said was C.


The second edition was released in 1988, and it was based on a draft of the first ANSI C standard, and even then, the line stating that this was undefined behavior was already present.

http://jfxpt.com/library/c89-draft.html#A.6.2

> A pointer to a function is converted to point to a function of a different type and used to call a function of a type not compatible with the original type (3.3.4).


The example is still the same in the second edition of K&R, which is based on C89.


Ah, I missed that. However, footnote 41 states “The same representation and alignment requirements are meant to imply interchangeability as arguments to functions […]”, which could be taken as implying compatibility of function types, though the normative wording doesn’t directly support that.


Good point. It would be nice if the C standard were slightly clearer here.


> name(&data); // Illegal: passing a char* into a function that takes char*

I assume this is just a typo in the article. He probably meant `name(data)`.


In C, all pointers are compatible to a void pointer without casting though (e.g. assigning a char pointer to a void pointer or the other way around is completely legal - I think that was the main reason why void pointers were added in the first place - it's basically an 'any pointer'). It's only C++ where this is an error (which is weird on its own, why even allow void pointers in C++ when the only reason they (presumably) exist doesn't work anymore).

The above code still doesn't compile in C because C complains about the function signatures being incompatible, even though the only difference is the argument type which itself is 'equivalent' in C - which I guess could be interepreted as an edge case in the C spec? (IMHO the function prototypes should actually be compatible).


"Compatibility" has a specific meaning in C which isn't the same as what you're describing here. What you're talking about is implicit conversions without narrowing.

Compatibility is essentially about ABI: https://en.cppreference.com/w/c/language/type#Compatible_typ...

The C standard is quite loose about pointer requirements. Conversions between data pointers or between function pointers are allowed, but conversions between each other are not guaranteed. You can read the nitty gritty here: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

POSIX defines stricter requirements for pointers than the C standard. All pointers are compatible, so they have the same size and representation, and conversions between function pointers and void* are explicitly allowed.


Not all pointers. Function pointers, though often used that way, should not be cast to void. ISO C forbids it. (Implementations may allow it.)


ISO C forbids it, but, FWIW, POSIX requires it. So pick your standard I guess.


you can convert a short to an int without casting and it will roundtrip without loss of data; similarly you can roundtrip any data pointer through a void pointer without loss of data. It doesn't mean that an int has the same representation of a short or a void* has (necessarily) the same representation as any other pointer.

In C++ any pointer is also implicitly convertible to a void *, it is the reverse implicit conversion that is prohibited as it is not safe in the general case.

For consistency C++ should also prohibit implicit narrowing conversions (e.g. int to short ); I guess this was thought to break too much existing code and it is generally safer than a pointer conversion (although potentially lossy the behavior is fully defined). Many compilers will warn about it, and narrowing conversions are now prohibited in braced initialization.


Re implicit narrowing conversions, I think most compilers have warnings for this by now both in C and C++, at least in the higher warning levels.


Yes. Simply put, void pointers and struct pointers (the actual breaking example in Curl) are not guaranteed to have the same byte-level representation, by the C standard. (For example, a struct pointer may always be aligned and therefore use fewer bits than a void pointer.) Passing one to a function that expects the other may result in arbitrary breakage.


Maintaining a fork by merging upstream into downstream branches would be a mess: upstream and downstream code would be totally entangled, there would no clean way to edit/remove/reorder downstream commits. You can't easily know what you actually changed (not the full diff, but each "atomic" clean change).

The way the author suggests is way cleaner IMO.


> there would no clean way to edit/remove/reorder downstream commits

Yes, but I consider commits immutable so reordering or editing commits is not a thing that would happen. New commits are appended (either upstream or downstream), and any conflicting changes then of course have to be merged from upstream into downstream.


Merging seems easier? With merging you can get a definite answer about which commits are where. With rebase you’re dealing with changes/patches so the answer is less clear.

But it might be cleaner (for some definition of clean) to have a for which is just N commits on top of the upstream. Which is then rebased periodically.


It depends on whether the downstream only ever consumes upstream changes, or also often contributes changes to upstream. Rebasing in both directions can result in a messy history, too, especially if upstream isn't very careful in how it accepts pull requests.


Agreed, and in the wild I've indeed seen rebasing used significantly more often than merges for this purpose.


Nit: Or @~2 (@ is HEAD, so @^^ is HEAD^^).


> The whole branch will be squashed anyway before it's merged in

That looks like a very wrong process to me. Why would you even want to do that?


Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: